Compare commits

...
Author SHA1 Message Date
MervinPraisonandCursor e67075b799 fix(ci): hub v1.1.4 — grant reusable-workflow caller permissions
Repos with default_workflow_permissions: read reject Auto PR Comment and merge
gate when the caller only grants pull-requests: read but callee jobs need write.

Co-authored-by: Cursor <[email protected]>
2026-09-07 10:58:56 +01:00
Mervin Praison 993114bb55 Merge pull request #268 from MervinPraison/chore/hub-v1.1.3
chore(ci): bump github-automation hub to v1.1.3
2026-09-07 10:53:23 +01:00
MervinPraisonandCursor 8c59d2db85 chore(ci): bump github-automation hub to v1.1.3
Fixes broken reusable workflow refs (v1.1.1 dynamic hub-setup) and review-chain
callable YAML so Auto PR Comment / merge gate / CI-failure Claude run again.

Co-authored-by: Cursor <[email protected]>
2026-09-07 10:53:05 +01:00
MervinPraisonandCursor 15aa219cb3 chore(automation): upgrade to hub v1.1.1 and fix pre-labelled issue Claude trigger
Switch merge-gate, review chain, CI failure, and pipeline workflows to thin
hub callers. Fix auto-issue-comment and claude-dedupe so bot-routed issues
opened with the claude label still dispatch Claude.

Co-authored-by: Cursor <[email protected]>
2026-09-02 13:08:41 +01:00
Mervin Praison 5c88692009 Merge pull request #261 from MervinPraison/claude/issue-260-20260902-meeting-ui
feat: thin meeting-agent UI example (PAI-MEET-UI)
2026-09-02 10:33:55 +01:00
praisonai-triage-agent[bot]andMervin Praison 83c273eba3 fix(compiler): remove extraneous f-string prefix breaking ruff (CI)
CI job `python (3.12)` failed at `ruff check src/praisonaiui` with F541
(f-string without placeholders) on compiler.py:922, blocking pytest before
it ran. Removed the unnecessary `f` prefix on the static og:type meta tag.

Co-authored-by: Mervin Praison <[email protected]>
2026-09-02 09:31:10 +00:00
MervinPraisonandClaude ee44c38297 feat: add thin meeting-agent UI example composing existing features (fixes #260)
Adds examples/python/meeting-agent/ wiring existing attachments, knowledge,
chat and Slack features via YAML/config only. No new package, no new public
exports, no create_app()/server.py params, no eager heavy deps.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-09-02 09:26:05 +00:00
Mervin Praison 8a79913cc4 Merge pull request #228 from MervinPraison/claude/issue-222-20260715-1318
feat: Training Lab UI for praisonai-train agent sessions (STITCH-012)
2026-09-02 10:09:12 +01:00
Mervin Praison af97f31e68 Merge pull request #229 from MervinPraison/claude/issue-217-20260715-run-recorder
feat: Run Flight Recorder — /runs three-pane run debugger (#217)
2026-09-02 10:09:00 +01:00
MervinPraisonandCursor 812c53abaa fix(docs): prevent stale content and full reloads on fast navigation
Abort in-flight markdown fetches, clear the article immediately on route change, and always intercept sidebar links so rapid clicks stay in the SPA instead of showing the wrong page.

Co-authored-by: Cursor <[email protected]>
2026-08-28 12:54:38 +01:00
MervinPraisonandCursor 4bc7497e99 feat(docs): Mintlify-style full-width layout and header navigation
Adopt a three-column docs shell with a centred 720px content column, integrated header tabs, search, and tab-filtered sidebar so navigation matches Mintlify-style sites.

Co-authored-by: Cursor <[email protected]>
2026-08-28 11:16:35 +01:00
MervinPraisonandCursor 4bf74be9c7 fix(docs): render Mermaid diagrams full width like Mintlify
Use useMaxWidth, measure the container width on render/resize, and scale
SVG to 100% of the content column. Widen the docs main area by removing
max-w-3xl so diagrams use space between sidebar and TOC.

Co-authored-by: Cursor <[email protected]>
2026-08-28 10:23:12 +01:00
MervinPraisonandCursor 800883aaf4 test: assert mermaid renders via code component unwrap
Co-authored-by: Cursor <[email protected]>
2026-08-27 14:58:06 +01:00
MervinPraisonandCursor fc28c77e84 fix(docs): detect mermaid fences in code component
Route ```mermaid blocks through the code markdown handler so diagrams
render reliably across react-markdown versions, with pre unwrapping the
MermaidDiagram output.

Co-authored-by: Cursor <[email protected]>
2026-08-27 14:47:03 +01:00
MervinPraisonandCursor 82980cee1a fix(docs): render Mermaid diagrams in React SPA
The mermaid plugin skips React-managed article content to avoid DOM
reconciler crashes, so fenced mermaid blocks showed as raw code. Add a
native MermaidDiagram component with lazy-loaded mermaid@11, theme sync,
and bundled frontend assets.

Co-authored-by: Cursor <[email protected]>
2026-08-27 14:37:34 +01:00
MervinPraisonandCursor 6bfc19a0ee fix(ci): use force_orphan for reliable GitHub Pages deploys
peaceiris was rm-ing gh-pages files then skipping commit when the tree
matched HEAD, leaving llms.txt and sitemap offline. force_orphan replaces
the branch on every deploy.

Co-authored-by: Cursor <[email protected]>
2026-08-26 22:28:25 +01:00
MervinPraisonandCursor 6f855aee3e feat(seo): complete crawl readiness — llms-full, lastmod, auto descriptions
Add llms-full.txt, sitemap lastmod dates, auto meta descriptions from first
paragraph, per-page noindex support, runtime JSON-LD/OG/Twitter updates, a
dedicated Deploy Docs workflow, and corrected SEO documentation.

Co-authored-by: Cursor <[email protected]>
2026-08-26 22:22:09 +01:00
MervinPraisonandCursor 203c57710a ci: allow manual workflow dispatch for docs deploy
Push webhooks stopped firing CI after 13:32 UTC; workflow_dispatch
lets us redeploy GitHub Pages with sitemap, robots.txt, and llms.txt.

Co-authored-by: Cursor <[email protected]>
2026-08-26 17:21:52 +01:00
MervinPraisonandCursor bd6d08b08e feat(seo): add llms.txt, crawl nav, and homepage sitemap entry
Generate llms.txt for AI crawlers, inject static nav links into prerendered
HTML, convert markdown links in noscript content, and include the site root
in sitemap.xml so Google can discover all doc pages once deployed.

Co-authored-by: Cursor <[email protected]>
2026-08-26 17:20:59 +01:00
MervinPraisonandCursor 90feb197b2 fix(docs): stop plugin DOM mutations that crash React SPA navigation
Guard plugin-loader, syntax-highlight, mermaid, and code-copy from touching
React-managed article content; emit flat doc HTML for canonical URLs; add SEO
sitemap/robots and trailing-slash normalisation so sidebar clicks stay stable.

Co-authored-by: Cursor <[email protected]>
2026-08-26 17:17:18 +01:00
MervinPraisonandCursor a391d55f74 fix(frontend): fetch content only when currentPath changes
Avoid re-running the markdown fetch when selectedItem syncs after
aiui:navigate, which was cancelling requests and leaving loading stuck.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:32:03 +01:00
MervinPraisonandCursor a5e6316021 fix(frontend): unstick "Loading content..." after SPA navigation
Reset loadingContent in effect cleanup when a fetch is cancelled, and
fetch only on currentPath changes so selectedItem sync does not abort
the in-flight request.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:31:48 +01:00
MervinPraisonandCursor 3c534c9637 fix(frontend): map /docs/index to /docs/index.md not /docs.md
Stripping a trailing /index segment broke the docs home page fetch,
causing "Content for PraisonAIUI not found" at /docs/index.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:30:49 +01:00
MervinPraisonandCursor e2486fe666 fix(frontend): stop empty pages and stale content on SPA nav
React now owns sidebar navigation content: sync selectedItem on
aiui:navigate, fetch markdown from currentPath with cancel-on-nav,
use canonical URLs without trailing slashes, and add data-nav-path on
sidebar buttons. Plugins teardown hide-mode instead of replacing React
DOM; mkdocs-compat no longer wipes main.flex-1.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:08:55 +01:00
MervinPraisonandCursor 60e9bbe2df fix(frontend): wrap theme tokens in hsl() so backgrounds render
Tailwind utilities used var(--background) directly, but shadcn tokens
store bare HSL components — backgrounds were transparent while prose
text used hsl(var(--foreground)), causing light-on-white in dark mode.
Also replace hardcoded dark anti-flicker with localStorage-aware bootstrap.

Co-authored-by: Cursor <[email protected]>
2026-08-26 12:07:06 +01:00
MervinPraisonandCursor 672070cd13 fix(frontend): restore light-mode contrast on plugin SPA path
Align content-loader and homepage plugins with React prose classes,
extend CSS contrast rules to all article.prose, fix server anti-flicker
hardcoded dark colours, wire theme toggle with localStorage, and add
guardrail tests for the plugin rendering path.

Co-authored-by: Cursor <[email protected]>
2026-08-26 11:23:46 +01:00
MervinPraisonandCursor db0672feec fix(frontend): restore light-mode prose and code contrast
Scope mermaid heading overrides to dark mode, fix hsl() theme tokens in
syntax-highlight, and force readable prose colours for body text, tables,
and code blocks in light mode.

Co-authored-by: Cursor <[email protected]>
2026-08-26 07:50:25 +01:00
MervinPraison 7fe03534de Release v0.3.142 2026-08-26 01:00:01 +00:00
MervinPraisonandCursor 23a193eb22 fix(frontend): complete docs UI P1 — routing, nav, TOC, mermaid
Wire route-manifest template resolution, mobile nav drawer, live TOC from
page headings, Mermaid async rendering via aiui:content-loaded, and
FlexibleLayout footer deduplication.

Co-authored-by: Cursor <[email protected]>
2026-08-25 23:58:43 +01:00
MervinPraison b6dc50180b Release v0.3.141 2026-08-25 22:48:37 +00:00
MervinPraisonandCursor d91c3baf21 fix(frontend): improve docs UI contrast and MkDocs rendering
Fix unreadable light-mode code blocks, transform MkDocs Material syntax
(tabs, icons, grid cards) in both React and plugin paths, and auto-select
nav items from the URL including top-level entries like /docs/index.

Co-authored-by: Cursor <[email protected]>
2026-08-25 23:45:46 +01:00
MervinPraisonandCursor 5c9e8b2356 docs(adp): harden protocol spec after multi-agent validation
Split component catalog schema from instance data, fix theme/slots
validation, clarify navigation model, add implementation status and
CI tests for ADP JSON Schema conformance.

Co-authored-by: Cursor <[email protected]>
2026-08-25 22:47:42 +01:00
MervinPraison a48f3ae4b2 fix(ci): enhance merge gate recovery and streamline auto-merge process 2026-08-25 22:40:35 +01:00
MervinPraison b4d705ce12 fix(ci): recognise Claude replies and unblock stale-FINAL after rebase
Port merge-gate recovery fixes from PraisonAI-Tools so auto-merge resumes after
conflict rebase pushes and MervinPraison Claude finished comments count.
2026-08-15 13:33:36 +01:00
MervinPraison 88c84d0c35 Release v0.3.140 2026-08-01 02:22:54 +00:00
MervinPraison 6d71fa4197 fix: port full scope-creep gates from PraisonAI with UI wording
Align merge gate, conflict/CI fix prompts, FINAL phases, and claude.yml
with PraisonAI lightweight-and-powerful checks — product value, layering
(praisonaiagents / PraisonAI-Tools), and server.py bloat — not Agent-class.
2026-07-31 14:04:16 +01:00
praisonai-triage-agent[bot] 576164960f Merge pull request #250 from MervinPraison/claude/issue-240-20260727-0912
feat: surface degraded knowledge search when embedding model unavailable
2026-07-31 12:08:20 +00:00
praisonai-triage-agent[bot] 9ec612b362 Merge pull request #249 from MervinPraison/claude/issue-235-20260727-0910
fix: prevent cp1252 UnicodeEncodeError in dashboard examples
2026-07-31 12:04:29 +00:00
praisonai-triage-agent[bot] 56760f843c Merge pull request #248 from MervinPraison/claude/issue-238-20260727-0912
fix: require explicit opt-in for GATEWAY_AUTH_TOKEN url auth
2026-07-31 12:00:49 +00:00
praisonai-triage-agent[bot] 39123500d5 Merge pull request #214 from MervinPraison/claude/issue-209-20260714-fix
fix: dedupe aiui:prefill-composer listener across chat re-navigations
2026-07-31 11:57:08 +00:00
praisonai-triage-agent[bot] 4098e5da4b Merge pull request #213 from MervinPraison/claude/issue-207-20260714-fix
fix: overview approval polling stacks duplicate click handlers (#207)
2026-07-31 11:53:16 +00:00
MervinPraison b3daa2fcfa Release v0.3.139 2026-07-31 11:52:38 +00:00
praisonai-triage-agent[bot] 7c7c121940 Merge pull request #215 from MervinPraison/claude/issue-211-20260714-work-hub-chat
feat: Work Hub Chat tab sends messages to agent via existing transport
2026-07-31 11:49:54 +00:00
praisonai-triage-agent[bot] c1da3fe0ae Merge pull request #212 from MervinPraison/claude/issue-210-20260714-1010
fix: honest gateway reachability probe on onboarding Screen 1
2026-07-31 11:48:48 +00:00
praisonai-triage-agent[bot]andMervin Praison a44776b18e fix: surface AC-4 opt-in on cross-origin CORS block in gateway probe
The reachability probe used default cors mode, so a cross-origin CORS
block rejected the fetch (landing in the 'network' branch) instead of
producing an opaque response. That made the 'opaque' branch and its
"Continue anyway" checkbox (AC-4) dead code. Now a rejected fetch on a
cross-origin URL maps to 'opaque' (ambiguous: CORS-blocked or down) so
the opt-in checkbox renders, while same-origin rejections remain a
definitive 'network' error.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 10:56:40 +00:00
MervinPraison 0e095d73fe fix: unblock FINAL @claude when review bots stay silent
Port PraisonAI review-chain parity: 30-minute required-reviewer timeout,
skip Copilot in scheduled FINAL sweep, and selftests for timeout path.
2026-07-31 11:53:09 +01:00
praisonai-triage-agent[bot]andMervin Praison d9836a955e fix: drop superseded #238 token-auth changes (already landed via #251)
Main's #251/#253/#258 implements the #238 fix with a stricter, more secure
design: AIUI_URL_TOKEN / GATEWAY_AUTH_TOKEN alone are inert; URL-token auth
activates only on explicit opt-in (AIUI_REQUIRE_TOKEN, YAML auth.requireToken,
require_auth). This branch's earlier variant treated AIUI_URL_TOKEN presence
(and YAML auth.urlToken) as an opt-in signal, which forced 401 and broke
test_token_auth_optin.py::test_aiui_url_token_alone_does_not_force_401.

Revert server.py to main's canonical logic and drop the now-conflicting
tests/unit/test_gateway_token_optin.py (its cases are covered by main's
tests/unit/test_token_auth_optin.py).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 06:34:03 +00:00
praisonai-triage-agent[bot]andMervin Praison 0f986461f9 fix: require explicit opt-in for GATEWAY_AUTH_TOKEN url auth (fixes #238)
GATEWAY_AUTH_TOKEN leaked into an interactive shell no longer silently
enforces 401 on every /api/* route in standalone create_app(). Enforcement
now requires explicit intent via AIUI_URL_TOKEN, AIUI_REQUIRE_TOKEN=1, or
YAML auth.urlToken. Secured gateway deployments keep working.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 06:32:39 +00:00
MervinPraisonandClaude 6ffc84e9ba fix: scope overview approval re-bind to re-rendered subtrees (fixes #207)
refreshApprovals re-rendered only #ov-metrics and #ov-attention but then
called bindEvents on the whole overview root, stacking click/keydown
listeners on unchanged shell nodes (agent rows, omnibar) on every 10s poll.
Scope the re-bind to the two re-rendered subtrees so stale nodes keep a
single listener. paint() still does the full-tree bind on initial render.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-30 06:32:21 +00:00
MervinPraisonandClaude d4aa8c2ec4 feat: wire Work Hub Chat tab to agent via shared mini-chat transport (fixes #211)
Add mini-chat.js reusing the existing /api/chat/ws protocol (run_content/
run_completed/run_error) and wire work-hub.js renderChat() to stream real
agent replies instead of only appending a local DOM bubble. Sessions/agents
rebind per card and the WebSocket is torn down on card/tab switch.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-30 06:32:14 +00:00
MervinPraisonandClaude c4be709f8d fix: dedupe aiui:prefill-composer listener across chat re-navigations (fixes #209)
Register the Code Studio prefill listener as a module-scope singleton via
ensurePrefillListener() and remove it in cleanup(), preventing duplicate
window handlers from stacking on repeated SPA navigation between /chat and
/code-studio.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-30 06:32:06 +00:00
praisonai-triage-agent[bot]andMervin Praison 92adfc6f6e fix: honest gateway reachability probe on onboarding Screen 1 (fixes #210)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 06:32:04 +00:00
MervinPraison 90315326f7 Release v0.3.138 2026-07-30 01:56:27 +00:00
MervinPraison 0719c41399 fix: auto-trigger conflict and CI fixes without FINAL review gate
Remove the FINAL @claude prerequisite from merge-conflict and CI-failure
workflows, clear pipeline/blocked:conflict after rebase completion, add
bot-pr-recovery cron, and update gate selftests.
2026-07-29 18:15:42 +01:00
praisonai-triage-agent[bot] d008b6a250 Merge pull request #216 from MervinPraison/claude/issue-208-20260714-i18n-memory
feat: wire i18n strings and per-turn memory search into context ring UI
2026-07-29 14:38:03 +00:00
praisonai-triage-agent[bot]andMervin Praison 05fb59e890 feat: surface degraded knowledge search when embedding model unavailable (fixes #240)
Rebased onto latest main. Reconciled with the overlapping degraded-mode
work already merged from #234:
- Adopt main's canonical _is_embedding_error / _embedding_error naming,
  embedding health dict, and richer /v1/embeddings fallback (503 vs 500).
- Keep _is_embedding_unavailable helper (used by main's test suite).
- Align SimpleKnowledgeManager fallback-test to main's "local" mode.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 13:11:17 +00:00
praisonai-triage-agent[bot]andMervin Praison 8067429e83 fix: prevent cp1252 UnicodeEncodeError in dashboard examples (fixes #235)
Add examples/python/_shared/console.py with safe_print/icon helpers
mirroring the CLI _supports_unicode/_icon pattern, and wire safe_print
into the gateway and channel examples so emoji output degrades to ASCII
on legacy Windows consoles instead of crashing before the server starts.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 13:07:27 +00:00
MervinPraisonandClaude 631ae74a29 feat: wire i18n strings and per-turn memory search into context ring UI (fixes #208)
Gap A: chat.js now loads locale strings via /api/i18n and renders ring
tooltip, compaction banner, compacted flash, and memory chip through a
t() helper with English fallback.

Gap B: refreshMemoryChip() posts the last user message to
/api/memory/search and shows per-turn hit count instead of the total
stored memory count from GET /api/memory.

Gap C: role="progressbar" and aria-value* moved to the ring wrapper div;
the send button is now type="button" with a send-only label.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-29 13:05:17 +00:00
praisonai-triage-agent[bot] e85f6778dd Merge pull request #258 from MervinPraison/claude/issue-256-20260729-120000
fix: stop full-suite pollution flaking auth timing + health cache tests
2026-07-29 11:39:19 +00:00
praisonai-triage-agent[bot] d6354fade0 Merge pull request #257 from MervinPraison/claude/issue-255-20260729-000000
fix: Windows-safe test_default_sqlite_url (stub HOME/USERPROFILE)
2026-07-29 11:35:43 +00:00
MervinPraisonandClaude b16a5f6056 fix: stop full-suite pollution flaking auth timing + health cache tests (fixes #256)
Reset the global _features registry in the test_server client fixture so a
feature leaked by an earlier crashing test cannot slow /health and flake the
deep-health cache/timing assertions. Make test_timing_attack_resistance
noise-resistant by comparing the median of repeated samples with a warm-up
instead of a single sample, so CPU contention under the full suite no longer
trips the variance threshold.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-29 09:28:32 +00:00
MervinPraisonandClaude 6521beb7b2 fix: stub HOME/USERPROFILE in test_default_sqlite_url for Windows (fixes #255)
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-29 09:21:35 +00:00
praisonai-triage-agent[bot]andMervin Praison 4d685af1da fix: correct timeline row selected-highlight CSS selector in /runs
The selected-row highlight targeted .rr-timeline-row.selected but rows
render with class .db-timeline-row, so clicking a timeline row never
visually highlighted it. Align the selector to .db-timeline-row.selected.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <[email protected]>
2026-07-16 07:55:06 +00:00
MervinPraisonandClaude a1c7a3c279 feat: add Run Flight Recorder /runs three-pane debugger (fixes #217)
Merges chat turns, trace spans, log lines and errors into one per-session
timeline. Reuses existing APIs only. Adds formatDuration/emptyState/
traceStatusBadge/timelineRow helpers, registers the runs page (Control,
order 22), and deep-links from Traces, Command Center and Work Hub.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-16 07:55:06 +00:00
praisonai-triage-agent[bot]andMervin Praison 10f3bbe1ce fix(training): correct agent_id filter, apply dropdown source, and view nav order
- features/training.py: derive agent_id in _summarize_session so the
  /api/training/sessions?agent_id= filter actually matches (was always None).
- training-lab.js: fetch /api/agents/definitions (returns `id`) instead of
  /api/agents (returns `agent_id`) so the apply dropdown carries valid agent
  IDs matching the registry; fall back to agent_id defensively.
- agents.js: set the agent_id URL param before selectPage('training') so the
  Training Lab picks up the filter on initial render.
- tests: add regression test for agent_id session filtering.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:47:40 +00:00
praisonai-triage-agent[bot]andMervin Praison c66a33c5d3 feat: add Training Lab UI for praisonai-train sessions (fixes #222)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:26:32 +00:00
181 changed files with 13659 additions and 3161 deletions

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
{
"templateRepo": "MervinPraison/github-automation-template",
"stack": "claude",
"profile": "sdk",
"mode": "hub",
"hubRef": "v1.1.4",
"templateVersion": "1.1.4",
"installedAt": "2026-09-07T09:58:50Z"
}
@@ -32,4 +32,13 @@ const comment = ciFix.buildCiFixComment({
});
assert('comment mentions product guardrails', comment.includes('Product guardrails'));
const skip = ciFix.shouldSkipCiFix({
comments: [],
headSha: 'abc1234567890abcdef1234567890abcdef12',
labels: [],
claudeInProgress: false,
failedChecks: [{ name: 'python', workflow: 'CI' }],
});
assert('ci fix without FINAL review allowed', !skip.skip);
process.exit(failed ? 1 : 0);
+4 -5
View File
@@ -46,10 +46,9 @@ function hasRecentCiFixComment(comments, headSha) {
});
}
function shouldSkipCiFix({ comments, headSha, labels, hasFinal, claudeInProgress, failedChecks }) {
function shouldSkipCiFix({ comments, headSha, labels, claudeInProgress, failedChecks }) {
if (!failedChecks.length) return { skip: true, reason: 'no failed checks' };
if (labels.includes(CI_FIX_LABEL)) return { skip: true, reason: 'ci fix pending' };
if (!hasFinal) return { skip: true, reason: 'awaiting final claude review trigger' };
if (claudeInProgress) return { skip: true, reason: 'claude in progress' };
if (hasCiFixCommentForSha(comments, headSha)) {
return { skip: true, reason: 'already commented for this sha' };
@@ -159,12 +158,14 @@ function buildCiFixComment({ headSha, failedChecks, failureSummaries }) {
'',
'**Product guardrails (AGENTS.md):**',
'- Do not disturb PraisonAIUI contracts or frontend/backend layering to accommodate scope creep.',
'- Core agent runtime belongs in praisonaiagents; agent-callable tools belong in PraisonAI-Tools — not here.',
'- Prefer existing YAML config, plugins, and feature modules over new server.py/create_app() params or knobs with no live consumer.',
'- Tests must continue to guard backward compatibility and UX behaviour — passing CI by lowering test standards is not acceptable.',
'- If the feature does not genuinely add product value, recommend reverting or narrowing scope instead of patching around failures.',
'',
'## What to do',
'1. State your verdict: **legitimate fix**, **regression fix**, or **needs human review** — and why (1–3 sentences).',
'2. Fix root cause with **minimal changes**; never bloat the Agent class with extra params.',
'2. Fix root cause with **minimal changes**; never bloat server.py or create_app() with extra params.',
exampleTest
? `3. Run failing tests locally, e.g. \`pytest ${exampleTest} -q\`, plus any related tests touched by the PR.`
: '3. Run failing tests locally with targeted pytest, plus any related tests touched by the PR.',
@@ -221,7 +222,6 @@ async function maybeTriggerCiFixClaude(github, owner, repo, prNumber, core, opts
return { skipped: true, reason: 'no failed checks yet (may be pending)' };
}
const hasFinal = mergeGate.hasFinalClaudeReviewTrigger(ctx.comments);
const claudeInProgress = await mergeGate.hasInProgressClaudeAssistant(
github, owner, repo, prNumber
);
@@ -229,7 +229,6 @@ async function maybeTriggerCiFixClaude(github, owner, repo, prNumber, core, opts
comments: ctx.comments,
headSha,
labels,
hasFinal,
claudeInProgress,
failedChecks: failedRuns,
});
+21 -2
View File
@@ -21,8 +21,27 @@ module.exports = {
'SCOPE: Focus ONLY on PraisonAIUI (src/praisonaiui, src/frontend, tests, docs). '
+ 'Do NOT expand into praisonaiagents or the monorepo unless the PR explicitly requires it.',
finalClaudeProductValue:
'4. Product value: review whether the change genuinely adds PraisonAIUI UX value and correct '
+ 'layering (UI/frontend here; core agent logic belongs in praisonaiagents). Reject scope creep.',
'4. Product value: review in depth whether the change genuinely adds PraisonAIUI UX value — '
+ 'never add features for the sake of adding them. It must strengthen the UI (simpler, '
+ 'more user-friendly, robust). If it does not clearly add value, request changes or recommend '
+ 'rejecting/closing rather than merging scope creep.\n'
+ '5. Layering: UI/frontend/server features here; core agent runtime belongs in praisonaiagents '
+ '(PraisonAI monorepo). Agent-callable tools → PraisonAI-Tools. Do not pull monorepo or SDK '
+ 'scope into this repo unless the PR explicitly requires it.\n'
+ '6. Do not bloat server.py or create_app() with new params — prefer existing YAML config, '
+ 'plugins, and feature modules; only add params if absolutely required. Reject knobs/exports '
+ 'with no live consumer.',
mergeGateProductValue:
'Confirm product value gate: change strengthens PraisonAIUI UX (no scope creep). The aim is a '
+ 'LIGHTWEIGHT AND POWERFUL package — BLOCK changes that add params/modules/exports duplicating '
+ 'existing UI capabilities (YAML config, plugins, feature modules, existing server hooks), or '
+ 'add knobs/fields with no live consumer, i.e. scope creep for the sake of it.',
mergeGateLayering:
'Layering routing: BLOCK if core agent logic was added here instead of praisonaiagents; BLOCK if '
+ 'agent-callable tools were added here instead of PraisonAI-Tools.',
mergeGateServerBloat:
'Do not bloat server.py or create_app() with additional params — only if absolutely required; '
+ 'prefer existing config/plugin patterns.',
agentPyChecks: false,
reviewBotLogins: [
'coderabbitai[bot]',
+1 -1
View File
@@ -205,7 +205,7 @@ const headAfterRebase = conflictIso(-21 * 60 * 1000);
const rebaseComments = [conflictTrigger, rebaseDone, finalAfterRebase];
assert('conflict blocks before rebase done', mg.hasRecentConflictComment([conflictTrigger], headAfterRebase));
assert('conflict clears after rebase + FINAL on HEAD', !mg.hasRecentConflictComment(rebaseComments, headAfterRebase));
assert('conflict still blocks without FINAL on HEAD', mg.hasRecentConflictComment(
assert('conflict clears after rebase without FINAL on HEAD', !mg.hasRecentConflictComment(
[conflictTrigger, rebaseDone],
headAfterRebase
));
+43 -3
View File
@@ -67,7 +67,11 @@ function isClaudeTriggerNoise(c) {
function isClaudeFinalReplyComment(c) {
const login = (c.user?.login || '').toLowerCase();
if (!login.includes('praisonai-triage')) return false;
const fromAutomation =
login.includes('praisonai-triage') ||
login.includes('github-actions') ||
AUTO_ACTORS.some((a) => a.toLowerCase() === login);
if (!fromAutomation) return false;
return (c.body || '').includes('Claude finished');
}
@@ -89,15 +93,47 @@ function isConflictRebaseTriggerComment(c) {
function isConflictRebaseCompletionComment(c) {
const login = (c.user?.login || '').toLowerCase();
if (!login.includes('praisonai-triage') && !login.includes('github-actions')) return false;
const fromAutomation =
login.includes('praisonai-triage') ||
login.includes('github-actions') ||
AUTO_ACTORS.some((a) => a.toLowerCase() === login);
if (!fromAutomation) return false;
const body = (c.body || '').toLowerCase();
return (
body.includes('rebase complete') ||
body.includes('rebase onto') ||
body.includes('force-pushed') ||
(body.includes('conflict') && body.includes('resolved'))
);
}
/** HEAD landed after conflict rebase but no FINAL @claude since that push. */
function needsFinalReReviewAfterConflictRebase(comments, headPushedAt) {
if (!headPushedAt) return false;
const headTime = new Date(headPushedAt).getTime();
const conflictTriggers = comments.filter(isConflictRebaseTriggerComment);
if (conflictTriggers.length === 0) return false;
const latestConflict = conflictTriggers.reduce((a, b) =>
new Date(a.created_at) > new Date(b.created_at) ? a : b
);
const conflictTime = new Date(latestConflict.created_at).getTime();
if (headTime <= conflictTime) return false;
const rebaseDone = comments.some(
(c) =>
new Date(c.created_at).getTime() > conflictTime && isConflictRebaseCompletionComment(c)
);
if (!rebaseDone) return false;
const finalsAfterHead = comments.filter(
(c) =>
isFinalClaudeTriggerComment(c) &&
new Date(c.created_at).getTime() >= headTime - 60000
);
return finalsAfterHead.length === 0;
}
function conflictRebaseQuiescent(comments, headPushedAt) {
const conflictTriggers = comments.filter(isConflictRebaseTriggerComment);
if (conflictTriggers.length === 0) return true;
@@ -113,7 +149,7 @@ function conflictRebaseQuiescent(comments, headPushedAt) {
);
if (!rebaseDone) return false;
return finalClaudeCompletedOnSha(comments, headPushedAt);
return true;
}
function hasRecentConflictComment(comments, headPushedAt = null) {
@@ -238,6 +274,9 @@ function shouldSkipStaleFinalRecovery(comments, headPushedAt, headPusherLogin =
if (headPusherLogin && isClaudeAutomationLogin(headPusherLogin)) {
return { skip: true, reason: 'head pushed by Claude automation' };
}
if (needsFinalReReviewAfterConflictRebase(comments, headPushedAt)) {
return { skip: false, reason: '' };
}
if (isPushSoonAfterLatestFinal(comments, headPushedAt)) {
return {
skip: true,
@@ -846,6 +885,7 @@ module.exports = {
hasRecentConflictComment,
isConflictRebaseTriggerComment,
isConflictRebaseCompletionComment,
needsFinalReReviewAfterConflictRebase,
conflictRebaseQuiescent,
hasHumanChangesRequested,
hasAnyChangesRequested,
@@ -0,0 +1,90 @@
#!/usr/bin/env node
const chain = require('./pr-review-chain.js');
let failed = 0;
function assert(name, cond) {
if (!cond) {
console.error('FAIL:', name);
failed++;
} else {
console.log('ok:', name);
}
}
const coderabbit = {
user: { login: 'coderabbitai[bot]' },
body: '<!-- summarize by coderabbit.ai --> summary',
created_at: '2026-07-02T07:16:00Z',
};
const greptile = {
user: { login: 'greptile-apps[bot]' },
body: '<h3>Greptile Summary</h3><p>Looks good</p>',
created_at: '2026-07-02T07:19:00Z',
};
const copilotKick = {
user: { login: 'MervinPraison' },
body: '@copilot Do a thorough review',
created_at: '2026-07-02T07:20:00Z',
};
const copilotReply = {
user: { login: 'copilot-swe-agent' },
body: 'Copilot review here',
created_at: '2026-07-02T07:22:00Z',
};
assert('prior not ready without greptile', !chain.priorReviewersReady([coderabbit]).ready);
assert('prior ready with coderabbit + greptile', chain.priorReviewersReady([coderabbit, greptile]).ready);
assert('copilot not ready before trigger', !chain.copilotReviewReady([coderabbit, greptile]).ready);
assert(
'copilot ready after reply',
chain.copilotReviewReady([coderabbit, greptile, copilotKick, copilotReply]).ready
);
assert(
'claude not ready before copilot',
!chain.claudeFinalReady([coderabbit, greptile]).ready
);
assert(
'claude ready after full chain',
chain.claudeFinalReady([coderabbit, greptile, copilotKick, copilotReply]).ready
);
assert(
'claude timeout fallback when copilot triggered but silent',
chain.claudeFinalReady([coderabbit, greptile, copilotKick], [], { allowCopilotTimeout: true }).ready
);
assert(
'no timeout fallback without copilot trigger',
!chain.claudeFinalReady([coderabbit, greptile], [], { allowCopilotTimeout: true }).ready
);
assert(
'skipCopilot proceeds after prior reviewers',
chain.claudeFinalReady([coderabbit, greptile], [], { skipCopilot: true }).ready
);
const oldPr = new Date(Date.now() - 31 * 60 * 1000).toISOString();
assert(
'prior not ready without coderabbit before timeout',
!chain.priorReviewersReady([greptile], [], { prCreatedAt: new Date().toISOString(), requiredWaitMs: 30 * 60 * 1000 }).ready
);
assert(
'prior timeout when coderabbit silent after 30m',
chain.priorReviewersReady([greptile], [], { prCreatedAt: oldPr, requiredWaitMs: 30 * 60 * 1000 }).ready
);
assert(
'claude FINAL timeout when required reviewer silent and no prior FINAL',
chain.claudeFinalReady([greptile], [], { prCreatedAt: oldPr, requiredWaitMs: 30 * 60 * 1000 }).ready
);
assert(
'claude FINAL timeout auto-skips copilot without explicit skipCopilot',
chain.claudeFinalReady([greptile], [], { prCreatedAt: oldPr, requiredWaitMs: 30 * 60 * 1000 }).copilotSkipped
);
const finalClaude = {
user: { login: 'github-actions[bot]' },
body: '@claude You are the FINAL architecture reviewer for this PR.',
created_at: '2026-07-02T07:25:00Z',
};
assert(
'claude FINAL not re-posted when already triggered',
!chain.claudeFinalReady([greptile, finalClaude], [], { prCreatedAt: oldPr, requiredWaitMs: 0 }).ready
);
process.exit(failed ? 1 : 0);
+21 -2
View File
@@ -16,6 +16,7 @@ const CLAUDE_TRIGGER_LOGINS = new Set(['MervinPraison', 'github-actions[bot]']);
const REQUIRED_PRIOR = ['coderabbit', 'greptile'];
const OPTIONAL_PRIOR = ['qodo', 'gemini'];
const OPTIONAL_PRIOR_WAIT_MS = 20 * 60 * 1000;
const REQUIRED_PRIOR_WAIT_MS = 30 * 60 * 1000;
function loginOf(item) {
return (item?.user?.login || '').toLowerCase();
@@ -75,11 +76,23 @@ function priorReviewerStatus(comments, reviews = []) {
function priorReviewersReady(comments, reviews = [], options = {}) {
const waitMs = options.optionalWaitMs ?? OPTIONAL_PRIOR_WAIT_MS;
const requiredWaitMs = options.requiredWaitMs ?? REQUIRED_PRIOR_WAIT_MS;
const prCreatedAt = options.prCreatedAt || null;
const status = priorReviewerStatus(comments, reviews);
const missingRequired = REQUIRED_PRIOR.filter((id) => !status[id]);
if (missingRequired.length) {
if (prCreatedAt) {
const age = Date.now() - new Date(prCreatedAt).getTime();
if (age >= requiredWaitMs) {
return {
ready: true,
reason: `required reviewer timeout (${missingRequired.join(', ')} silent after ${Math.round(requiredWaitMs / 60000)}m)`,
status,
requiredTimeout: true,
};
}
}
return { ready: false, reason: `waiting for ${missingRequired.join(', ')}`, status };
}
@@ -157,8 +170,13 @@ function claudeFinalReady(comments, reviews = [], options = {}) {
if (!prior.ready) {
return { ready: false, reason: prior.reason };
}
if (isSkipCopilot(options)) {
return { ready: true, reason: 'copilot skipped', copilotSkipped: true };
if (isSkipCopilot(options) || prior.requiredTimeout) {
return {
ready: true,
reason: prior.requiredTimeout ? prior.reason : 'copilot skipped',
copilotSkipped: true,
requiredTimeout: prior.requiredTimeout,
};
}
const copilot = copilotReviewReady(comments, reviews);
if (copilot.ready) {
@@ -283,6 +301,7 @@ module.exports = {
isSkipCopilot,
REQUIRED_PRIOR,
OPTIONAL_PRIOR,
REQUIRED_PRIOR_WAIT_MS,
COPILOT_REVIEW_BODY,
priorReviewerStatus,
priorReviewersReady,
+4 -3
View File
@@ -24,7 +24,7 @@ jobs:
trigger-claude:
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issues' && !contains(toJSON(github.event.issue.labels), 'claude'))
github.event_name == 'issues'
runs-on: ubuntu-latest
permissions:
issues: write
@@ -52,7 +52,8 @@ jobs:
});
const labels = (issue.labels || []).map(l => typeof l === 'string' ? l : l.name);
if (!labels.includes('claude')) {
const hadClaude = labels.includes('claude');
if (!hadClaude) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -60,7 +61,7 @@ jobs:
labels: ['claude'],
});
} else {
console.log(`Issue #${issueNumber} already has 'claude' label.`);
console.log(`Issue #${issueNumber} already has 'claude' label — dispatching Claude only.`);
}
const body = [
+11 -787
View File
@@ -1,14 +1,5 @@
name: Auto PR Comment
# Review chain: CodeRabbit/Qodo/Gemini review first → Copilot → Claude (final)
# For human PRs: CodeRabbit/Qodo auto-review → this workflow triggers Copilot → then Claude
# For bot PRs: CodeRabbit/Qodo skip bots, so we trigger them explicitly first
#
# IMPORTANT: @copilot ignores bot comments. All @copilot mentions must use
# PAT_TOKEN so the comment posts as MervinPraison (a real user).
#
# Claude trigger runs IN-BAND (same workflow) to avoid GitHub Actions
# blocking bot-triggered workflows with action_required approval gates.
on:
issue_comment:
types: [created]
@@ -17,793 +8,26 @@ on:
pull_request:
types: [opened, synchronize]
pull_request_target:
types: [synchronize]
types: [opened, synchronize]
schedule:
- cron: '30 3,9,15,21 * * *'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number for manual FINAL (leave empty to sweep all open PRs)'
required: false
type: number
env:
REVIEW_CHAIN_SKIP_COPILOT: '1'
permissions:
contents: read
issues: write
pull-requests: write
env:
MAX_POLL_ATTEMPTS: 20
POLL_DELAY_MS: 30000
CLAUDE_TRIGGER_LOGINS: '["MervinPraison","github-actions[bot]"]'
# GH_TOKEN (user PAT) posts as MervinPraison for @copilot; fallback to github.token for @claude
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
CLAUDE_UI_SCOPE: 'SCOPE: Focus ONLY on PraisonAIUI (src/praisonaiui, src/frontend, tests, docs). Do not expand into praisonaiagents or the monorepo unless the issue explicitly requires it.'
CLAUDE_FINAL_PHASES_COMPACT: "**Phase 1: Review per AGENTS.md** (lazy imports, backward compat, import-time <200ms; SDK/product value gate — genuine UI value, correct UI vs praisonaiagents layering, no scope creep)\n**Phase 2: FIX valid issues** found by prior reviewers — push to THIS branch\n**Phase 3: Final verdict** — approve PR if ready, else request changes"
CLAUDE_FINAL_PHASES_DETAILED: "**Phase 1: Review per AGENTS.md**\n1. Protocol-driven: check heavy implementations vs core SDK\n2. Backward compatible: ensure zero feature regressions\n3. Performance: no hot-path regressions (lazy imports, import-time <200ms)\n4. SDK/product value: review whether the change genuinely adds value — stronger PraisonAIUI UX and correct layering (UI/frontend here; core agent logic belongs in praisonaiagents). Reject scope creep; request changes or recommend closing if value is unclear\n\n**Phase 2: FIX Valid Issues**\n5. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix\n6. Push all code fixes directly to THIS branch (do NOT create a new PR)\n7. Comment a summary of exact files modified and what you skipped\n\n**Phase 3: Final Verdict**\n8. If all issues are resolved, approve the PR / close the Issue\n9. If blocking issues remain, request changes / leave clear action items"
jobs:
# ================================================================
# HUMAN PRs: Trigger @copilot AFTER CodeRabbit posts its summary
# ================================================================
copilot-after-coderabbit:
if: |
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.user.login == 'coderabbitai[bot]' &&
contains(github.event.comment.body, 'summarize by coderabbit')
runs-on: ubuntu-latest
permissions:
pull-requests: write
outputs:
pr_number: ${{ steps.trigger.outputs.pr_number }}
triggered: ${{ steps.trigger.outputs.triggered }}
steps:
- name: Post Copilot review request (as user via PAT)
id: trigger
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const comments = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});
// Check for duplicates — posted by MervinPraison (PAT) or github-actions[bot] (legacy)
const alreadyPosted = comments.data.some(c =>
c.body.includes('@copilot') &&
(c.user.login === 'MervinPraison' || c.user.login === 'github-actions[bot]')
);
if (alreadyPosted) {
console.log('Copilot already triggered, skipping');
core.setOutput('triggered', 'false');
core.setOutput('pr_number', context.issue.number.toString());
return;
}
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above from Qodo, Coderabbit, and Gemini first — incorporate their findings.\n\nReview areas:\n1. **Bloat check**: Are changes minimal and focused? Any unnecessary code or scope creep?\n2. **Security**: Any hardcoded secrets, unsafe eval/exec, missing input validation?\n3. **Performance**: Any module-level heavy imports? Hot-path regressions?\n4. **Tests**: Are tests included? Do they cover the changes adequately?\n5. **Backward compat**: Any public API changes without deprecation?\n6. **Code quality**: DRY violations, naming conventions, error handling?\n7. **Address reviewer feedback**: If Qodo, Coderabbit, or Gemini flagged valid issues, include them in your review\n8. Suggest specific improvements with code examples where possible'
});
core.setOutput('triggered', 'true');
core.setOutput('pr_number', context.issue.number.toString());
# Fallback: Trigger @copilot after Qodo review (if Coderabbit doesn't fire)
copilot-after-qodo:
if: |
github.event_name == 'pull_request_review' &&
github.event.review.user.login == 'qodo-code-review[bot]'
runs-on: ubuntu-latest
permissions:
pull-requests: write
outputs:
pr_number: ${{ steps.trigger.outputs.pr_number }}
triggered: ${{ steps.trigger.outputs.triggered }}
steps:
- name: Post Copilot review request (as user via PAT)
id: trigger
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const comments = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@copilot') &&
(c.user.login === 'MervinPraison' || c.user.login === 'github-actions[bot]')
);
if (alreadyPosted) {
console.log('Copilot already triggered, skipping');
core.setOutput('triggered', 'false');
core.setOutput('pr_number', context.issue.number.toString());
return;
}
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above first.\n\nReview areas:\n1. **Bloat check**: Are changes minimal and focused?\n2. **Security**: Any hardcoded secrets, unsafe eval/exec, missing input validation?\n3. **Performance**: Any module-level heavy imports? Hot-path regressions?\n4. **Tests**: Are tests included? Do they cover the changes adequately?\n5. **Backward compat**: Any public API changes without deprecation?\n6. **Code quality**: DRY violations, naming conventions, error handling?\n7. Suggest specific improvements with code examples where possible'
});
core.setOutput('triggered', 'true');
core.setOutput('pr_number', context.issue.number.toString());
# ================================================================
# FALLBACK: Claude trigger for cases where Copilot chain fails/skips
# Ensures Claude always runs after sufficient review time
# ================================================================
claude-fallback-timeout:
if: |
github.event_name == 'pull_request' &&
github.event.action == 'opened'
runs-on: ubuntu-latest
timeout-minutes: 20
review-chain:
# Grant union of callee job permissions (repos with default_workflow_permissions: read
# reject reusable calls when the caller ceiling is lower than any callee job).
permissions:
issues: write
pull-requests: write
steps:
- name: Wait for review window (15 min)
run: sleep 900
- name: Check if Claude already triggered
id: check_claude
uses: actions/github-script@v7
env:
TRIGGER_LOGINS: ${{ env.CLAUDE_TRIGGER_LOGINS }}
PR_NUMBER: ${{ github.event.pull_request.number }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const triggerLogins = JSON.parse(process.env.TRIGGER_LOGINS);
const comments = await github.rest.issues.listComments({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@claude') && triggerLogins.includes(c.user.login)
);
core.setOutput('already_triggered', alreadyPosted ? 'true' : 'false');
core.setOutput('comments_count', comments.data.length.toString());
const botReviews = comments.data.filter(c =>
['coderabbitai[bot]', 'qodo-code-review[bot]', 'gemini-code-assist[bot]',
'copilot-swe-agent', 'Copilot', 'greptile-apps[bot]'].some(bot =>
c.user.login.toLowerCase().includes(bot.toLowerCase())
)
);
core.setOutput('review_count', botReviews.length.toString());
- name: Aggregate reviews and trigger Claude
if: steps.check_claude.outputs.already_triggered != 'true'
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const comments = await github.rest.issues.listComments({issue_number: pr, owner: context.repo.owner, repo: context.repo.repo, per_page: 100});
const reviews = {coderabbit: [], qodo: [], gemini: [], copilot: [], greptile: [], others: []};
comments.data.forEach(c => {
const login = c.user.login.toLowerCase();
const body = c.body.substring(0, 500);
if (login.includes('coderabbit')) reviews.coderabbit.push(body);
else if (login.includes('qodo')) reviews.qodo.push(body);
else if (login.includes('gemini')) reviews.gemini.push(body);
else if (login.includes('copilot')) reviews.copilot.push(body);
else if (login.includes('greptile')) reviews.greptile.push(body);
else if (c.user.type === 'Bot') reviews.others.push(body);
});
const summaryParts = [];
if (reviews.coderabbit.length) summaryParts.push('CodeRabbit: ' + reviews.coderabbit.length + ' comments');
if (reviews.qodo.length) summaryParts.push('Qodo: ' + reviews.qodo.length + ' comments');
if (reviews.gemini.length) summaryParts.push('Gemini: ' + reviews.gemini.length + ' comments');
if (reviews.copilot.length) summaryParts.push('Copilot: ' + reviews.copilot.length + ' comments');
if (reviews.greptile.length) summaryParts.push('Greptile: ' + reviews.greptile.length + ' comments');
const reviewSummary = summaryParts.length ? summaryParts.join(' | ') : 'No bot reviews detected';
const scope = process.env.CLAUDE_UI_SCOPE;
const phases = process.env.CLAUDE_FINAL_PHASES_COMPACT;
const claudeBody = '@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAIUI (not a fork), you are able to make modifications to this branch and push directly. ' + scope + ' Read ALL prior reviewer comments. ' + reviewSummary + '.\n\n' +
'Review Context: ' + comments.data.length + ' total comments, ' +
(reviews.coderabbit.length + reviews.qodo.length + reviews.gemini.length + reviews.copilot.length + reviews.greptile.length) + ' bot reviews.\n\n' +
phases;
await github.rest.issues.createComment({issue_number: pr, owner: context.repo.owner, repo: context.repo.repo, body: claudeBody});
console.log('Claude fallback triggered on PR #' + pr + ' with ' + reviewSummary);
# ================================================================
# Claude FINAL review — polls for Copilot's response, then triggers
# This runs IN-BAND under the PAT context (MervinPraison), avoiding
# the action_required approval gate that blocks bot-triggered workflows.
# ================================================================
claude-after-copilot:
needs: [copilot-after-coderabbit]
if: |
always() &&
needs.copilot-after-coderabbit.result == 'success' &&
needs.copilot-after-coderabbit.outputs.triggered == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Wait for Copilot to respond (poll)
id: poll
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-coderabbit.outputs.pr_number }}
MAX_POLL_ATTEMPTS: ${{ env.MAX_POLL_ATTEMPTS }}
POLL_DELAY_MS: ${{ env.POLL_DELAY_MS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const owner = context.repo.owner;
const repo = context.repo.repo;
// Poll for Copilot's response — check every 30s for up to 10 minutes
const maxAttempts = parseInt(process.env.MAX_POLL_ATTEMPTS, 10);
const delayMs = parseInt(process.env.POLL_DELAY_MS, 10);
for (let i = 0; i < maxAttempts; i++) {
console.log(`Poll attempt ${i + 1}/${maxAttempts}...`);
const comments = await github.rest.issues.listComments({
issue_number: pr,
owner,
repo,
per_page: 50,
sort: 'created',
direction: 'desc'
});
// Look for Copilot's response (copilot-swe-agent or Copilot)
const copilotResponse = comments.data.find(c =>
(c.user.login === 'copilot-swe-agent' ||
c.user.login === 'Copilot' ||
c.user.login.toLowerCase().includes('copilot')) &&
c.user.type === 'Bot'
);
if (copilotResponse) {
console.log(`Copilot responded at ${copilotResponse.created_at}`);
core.setOutput('copilot_responded', 'true');
return;
}
// Also check PR reviews for Copilot
const reviews = await github.rest.pulls.listReviews({
pull_number: pr,
owner,
repo
});
const copilotReview = reviews.data.find(r =>
r.user.login.toLowerCase().includes('copilot')
);
if (copilotReview) {
console.log(`Copilot review submitted at ${copilotReview.submitted_at}`);
core.setOutput('copilot_responded', 'true');
return;
}
if (i < maxAttempts - 1) {
console.log(`Copilot hasn't responded yet, waiting ${delayMs/1000}s...`);
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
console.log('Copilot did not respond within timeout, triggering Claude anyway');
core.setOutput('copilot_responded', 'timeout');
- name: Check if Claude already triggered
id: check_claude
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-coderabbit.outputs.pr_number }}
TRIGGER_LOGINS: ${{ env.CLAUDE_TRIGGER_LOGINS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const triggerLogins = JSON.parse(process.env.TRIGGER_LOGINS);
const comments = await github.rest.issues.listComments({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@claude') && triggerLogins.includes(c.user.login)
);
core.setOutput('already_triggered', alreadyPosted ? 'true' : 'false');
- name: Trigger Claude final review
if: steps.check_claude.outputs.already_triggered != 'true'
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-coderabbit.outputs.pr_number }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const scope = process.env.CLAUDE_UI_SCOPE;
const phases = process.env.CLAUDE_FINAL_PHASES_DETAILED;
await github.rest.issues.createComment({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAIUI (not a fork), you are able to make modifications to this branch and push directly. ' + scope + ' Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.\n\n' + phases
});
console.log(`Claude triggered on PR #${pr}`);
- name: Sync pipeline status labels
if: steps.check_claude.outputs.already_triggered != 'true'
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-coderabbit.outputs.pr_number }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
const pr = parseInt(process.env.PR_NUMBER, 10);
await ps.ensurePipelineLabels(github, context.repo.owner, context.repo.repo, core);
await ps.syncPipelineLabels(github, context.repo.owner, context.repo.repo, pr, core);
# ================================================================
# Claude after Qodo fallback path (same polling approach)
# ================================================================
claude-after-copilot-qodo:
needs: [copilot-after-qodo]
if: |
always() &&
needs.copilot-after-qodo.result == 'success' &&
needs.copilot-after-qodo.outputs.triggered == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
issues: write
pull-requests: write
steps:
- name: Wait for Copilot to respond (poll)
id: poll
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-qodo.outputs.pr_number }}
MAX_POLL_ATTEMPTS: ${{ env.MAX_POLL_ATTEMPTS }}
POLL_DELAY_MS: ${{ env.POLL_DELAY_MS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const owner = context.repo.owner;
const repo = context.repo.repo;
const maxAttempts = parseInt(process.env.MAX_POLL_ATTEMPTS, 10);
const delayMs = parseInt(process.env.POLL_DELAY_MS, 10);
for (let i = 0; i < maxAttempts; i++) {
console.log(`Poll attempt ${i + 1}/${maxAttempts}...`);
const comments = await github.rest.issues.listComments({
issue_number: pr, owner, repo,
per_page: 50, sort: 'created', direction: 'desc'
});
const copilotResponse = comments.data.find(c =>
(c.user.login === 'copilot-swe-agent' ||
c.user.login === 'Copilot' ||
c.user.login.toLowerCase().includes('copilot')) &&
c.user.type === 'Bot'
);
if (copilotResponse) {
console.log(`Copilot responded at ${copilotResponse.created_at}`);
core.setOutput('copilot_responded', 'true');
return;
}
const reviews = await github.rest.pulls.listReviews({
pull_number: pr, owner, repo
});
const copilotReview = reviews.data.find(r =>
r.user.login.toLowerCase().includes('copilot')
);
if (copilotReview) {
console.log(`Copilot review submitted at ${copilotReview.submitted_at}`);
core.setOutput('copilot_responded', 'true');
return;
}
if (i < maxAttempts - 1) {
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
console.log('Copilot did not respond within timeout, triggering Claude anyway');
core.setOutput('copilot_responded', 'timeout');
- name: Check if Claude already triggered
id: check_claude
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-qodo.outputs.pr_number }}
TRIGGER_LOGINS: ${{ env.CLAUDE_TRIGGER_LOGINS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const triggerLogins = JSON.parse(process.env.TRIGGER_LOGINS);
const comments = await github.rest.issues.listComments({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@claude') && triggerLogins.includes(c.user.login)
);
core.setOutput('already_triggered', alreadyPosted ? 'true' : 'false');
- name: Trigger Claude final review
if: steps.check_claude.outputs.already_triggered != 'true'
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ needs.copilot-after-qodo.outputs.pr_number }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const scope = process.env.CLAUDE_UI_SCOPE;
const phases = process.env.CLAUDE_FINAL_PHASES_DETAILED;
await github.rest.issues.createComment({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAIUI (not a fork), you are able to make modifications to this branch and push directly. ' + scope + ' Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.\n\n' + phases
});
console.log(`Claude triggered on PR #${pr}`);
# ================================================================
# Claude after Gemini — restores the trigger lost from the deleted
# chain-claude-after-copilot.yml workflow.
# Fires when Gemini posts a review comment on a PR or issue.
# ================================================================
claude-after-gemini:
if: |
github.event_name == 'issue_comment' &&
(
github.event.comment.user.login == 'gemini-code-assist[bot]' ||
contains(github.event.comment.body, 'Review completed by Gemini CLI') ||
contains(github.event.comment.body, 'The fix is ready for review. Please test')
)
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Check if Claude already triggered
id: check_claude
uses: actions/github-script@v7
env:
TRIGGER_LOGINS: ${{ env.CLAUDE_TRIGGER_LOGINS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const triggerLogins = JSON.parse(process.env.TRIGGER_LOGINS);
const comments = await github.rest.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@claude') && triggerLogins.includes(c.user.login)
);
core.setOutput('already_triggered', alreadyPosted ? 'true' : 'false');
- name: Post Claude analysis request (Lead Engineer)
if: steps.check_claude.outputs.already_triggered != 'true'
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const scope = process.env.CLAUDE_UI_SCOPE;
const phases = process.env.CLAUDE_FINAL_PHASES_DETAILED;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@claude You are the Lead Engineer. If the branch is under MervinPraison/PraisonAIUI (not a fork), you are able to make modifications to this branch and push directly. ' + scope + ' Read ALL analysis and reviews above carefully (Gemini, CodeRabbit, Qodo, Copilot, etc).\n\n' + phases
});
# ================================================================
# Recovery: re-post FINAL @claude after push or when chain missed
# ================================================================
claude-review-recovery:
if: |
github.event_name == 'pull_request_target' &&
github.event.action == 'synchronize'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: read
steps:
- uses: actions/checkout@v4
- name: Re-post FINAL Claude review when stale or missing
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const mergeGate = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/merge-gate.js'));
const chain = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pr-review-chain.js'));
const pr = context.payload.pull_request.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
const comments = await mergeGate.listAllComments(github, owner, repo, pr);
const headPushedAt = (await mergeGate.getHeadCommitDate(github, owner, repo, pr))
|| context.payload.pull_request.updated_at;
const headPusher = context.payload.sender?.login || null;
const hasFinal = mergeGate.hasFinalClaudeReviewTrigger(comments);
const isStale = mergeGate.isStaleFinalAfterPush(comments, headPushedAt);
if (mergeGate.shouldSkipFinalRecovery(comments, headPushedAt)) {
core.info('Recent @claude within 35min and FINAL not stale — skip recovery');
return;
}
if (await mergeGate.hasInProgressClaudeAssistant(github, owner, repo, pr)) {
core.info('Claude workflow in progress — skip recovery');
return;
}
const finalBody = mergeGate.FINAL_CLAUDE_REVIEW_BODY;
const staleOpts = { allowStaleRepost: true, skipCopilot: true, optionalWaitMs: 0 };
const missingOpts = { allowCopilotTimeout: true, optionalWaitMs: 0 };
if (hasFinal && isStale) {
const gate = mergeGate.shouldSkipStaleFinalRecovery(comments, headPushedAt, headPusher);
if (gate.skip) {
core.info(`Skip stale-FINAL recovery: ${gate.reason}`);
return;
}
const result = await chain.maybeTriggerClaudeFinal(
github, owner, repo, pr, finalBody, core, staleOpts
);
if (result.posted) core.info(`Posted stale-FINAL recovery @claude on PR #${pr}`);
return;
}
if (hasFinal) {
core.info('FINAL Claude review current on HEAD — skip recovery');
return;
}
const result = await chain.maybeTriggerClaudeFinal(
github, owner, repo, pr, finalBody, core, missingOpts
);
if (result.posted) core.info(`Posted missing FINAL Claude review on PR #${pr}`);
- name: Sync pipeline status labels
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
const pr = context.payload.pull_request.number;
await ps.ensurePipelineLabels(github, context.repo.owner, context.repo.repo, core);
await ps.syncPipelineLabels(github, context.repo.owner, context.repo.repo, pr, core);
# Scheduled + manual: post missing or stale FINAL @claude on all open PRs
post-missing-claude-final:
if: |
github.event_name == 'schedule' ||
(github.event_name == 'workflow_dispatch' && !inputs.pr_number)
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: read
steps:
- uses: actions/checkout@v4
- name: Post missing/stale FINAL @claude on open PRs
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const mergeGate = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/merge-gate.js'));
const chain = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pr-review-chain.js'));
const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const prs = await github.paginate(github.rest.pulls.list, {
owner, repo, state: 'open', per_page: 100,
});
let posted = 0;
for (const pr of prs) {
if (pr.draft) continue;
const comments = await mergeGate.listAllComments(github, owner, repo, pr.number);
const headPushedAt = (await mergeGate.getHeadCommitDate(github, owner, repo, pr.number)) || pr.updated_at;
const hasFinal = mergeGate.hasFinalClaudeReviewTrigger(comments);
const isStale = mergeGate.isStaleFinalAfterPush(comments, headPushedAt);
if (hasFinal && !isStale) continue;
if (mergeGate.hasRecentClaudeTrigger(comments, 10)) {
core.info(`PR #${pr.number}: @claude within 10min — skip`);
continue;
}
if (await mergeGate.hasInProgressClaudeAssistant(github, owner, repo, pr.number)) {
core.info(`PR #${pr.number}: Claude in progress — skip`);
continue;
}
if (hasFinal && isStale) {
const gate = mergeGate.shouldSkipStaleFinalRecovery(comments, headPushedAt);
if (gate.skip) {
core.info(`PR #${pr.number}: skip stale — ${gate.reason}`);
continue;
}
}
const opts = hasFinal && isStale
? { allowStaleRepost: true, skipCopilot: true, optionalWaitMs: 0 }
: { allowCopilotTimeout: true, optionalWaitMs: 0 };
const result = await chain.maybeTriggerClaudeFinal(
github, owner, repo, pr.number,
mergeGate.FINAL_CLAUDE_REVIEW_BODY, core, opts
);
if (result.posted) {
posted++;
core.info(`Posted Claude FINAL on PR #${pr.number}`);
}
await ps.syncPipelineLabels(github, owner, repo, pr.number, core);
if (posted >= 10) break;
}
core.info(`Missing/stale Claude FINAL sweep complete (${posted} posted)`);
# ================================================================
# BOT PRs: CodeRabbit → Claude directly (skip Copilot when no user PAT)
# Copilot ignores github-actions[bot] comments; bot PRs use this path.
# ================================================================
claude-after-coderabbit-bot-pr:
if: |
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.user.login == 'coderabbitai[bot]' &&
contains(github.event.comment.body, 'summarize by coderabbit')
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: read
steps:
- name: Trigger Claude final review on bot PR
uses: actions/github-script@v7
env:
TRIGGER_LOGINS: ${{ env.CLAUDE_TRIGGER_LOGINS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = context.issue.number;
const { data: pull } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr,
});
const author = pull.user.login;
const isBot = author === 'github-actions[bot]' ||
author === 'praisonai-triage-agent[bot]' ||
pull.user.type === 'Bot';
if (!isBot) {
console.log('Human PR — Copilot chain handles Claude trigger');
return;
}
const triggerLogins = JSON.parse(process.env.TRIGGER_LOGINS);
const comments = await github.rest.issues.listComments({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@claude') && triggerLogins.includes(c.user.login)
);
if (alreadyPosted) {
console.log('Claude already triggered on PR #' + pr);
return;
}
await github.rest.issues.createComment({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@claude You are the FINAL architecture reviewer on this bot-authored PR. Push fixes directly to THIS branch (do NOT open a new PR). ' + process.env.CLAUDE_UI_SCOPE + ' Read ALL CodeRabbit/Qodo comments above.\n\n' + process.env.CLAUDE_FINAL_PHASES_COMPACT
});
console.log('Claude final review triggered on bot PR #' + pr);
# ================================================================
# Manual: trigger Claude final review on any PR
# ================================================================
claude-manual-dispatch:
if: github.event_name == 'workflow_dispatch' && inputs.pr_number
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Trigger Claude final review
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ inputs.pr_number }}
TRIGGER_LOGINS: ${{ env.CLAUDE_TRIGGER_LOGINS }}
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const pr = parseInt(process.env.PR_NUMBER, 10);
const triggerLogins = JSON.parse(process.env.TRIGGER_LOGINS);
const comments = await github.rest.issues.listComments({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
});
const alreadyPosted = comments.data.some(c =>
c.body.includes('@claude') && triggerLogins.includes(c.user.login)
);
if (alreadyPosted) {
console.log('Claude already triggered on PR #' + pr);
return;
}
await github.rest.issues.createComment({
issue_number: pr,
owner: context.repo.owner,
repo: context.repo.repo,
body: '@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAIUI (not a fork), you are able to make modifications to this branch and push directly. ' + process.env.CLAUDE_UI_SCOPE + ' Read all prior reviewer comments.\n\n' + process.env.CLAUDE_FINAL_PHASES_COMPACT
});
console.log('Claude manually triggered on PR #' + pr);
# ================================================================
# BOT PRs: kick CodeRabbit + Qodo
# ================================================================
bot-pr-trigger-reviews:
if: |
github.event_name == 'pull_request' &&
github.event.action == 'opened' &&
(
github.event.pull_request.user.login == 'github-actions[bot]' ||
github.event.pull_request.user.login == 'praisonai-triage-agent[bot]' ||
github.event.pull_request.user.type == 'Bot'
)
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Trigger CodeRabbit and Qodo reviews
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const chain = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/bot-pr-review-chain.js'));
const pr = context.payload.pull_request.number;
await chain.kickReviewChain(github, context.repo.owner, context.repo.repo, pr, core);
- name: Sync pipeline status labels
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
const pr = context.payload.pull_request.number;
await ps.ensurePipelineLabels(github, context.repo.owner, context.repo.repo, core);
await ps.syncPipelineLabels(github, context.repo.owner, context.repo.repo, pr, core);
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.4
+23
View File
@@ -0,0 +1,23 @@
name: Bot PR Recovery
on:
schedule:
- cron: '*/15 * * * *'
workflow_dispatch:
inputs:
pr_number:
description: 'Specific PR number to kick (optional)'
required: false
type: string
permissions:
pull-requests: write
issues: write
jobs:
recover:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.4
pr_number: ${{ github.event.inputs.pr_number || '' }}
+6 -76
View File
@@ -1,17 +1,14 @@
name: Auto CI Failure → Claude
# Detects internal PRs with failing CI and posts @claude with extracted failure details.
on:
workflow_run:
workflows: [CI]
workflows: [Core Tests, Optimized Test Suite]
types: [completed]
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
pr_number:
description: 'Optional PR number to process (default: scan blocked PRs)'
required: false
type: string
schedule:
@@ -21,10 +18,6 @@ concurrency:
group: ci-failure-scan-${{ github.repository }}-${{ github.event.pull_request.number || github.event.workflow_run.id || github.run_id }}
cancel-in-progress: true
env:
# PAT posts as MervinPraison so issue_comment triggers claude.yml (GITHUB_TOKEN cannot chain workflows)
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
permissions:
pull-requests: read
issues: write
@@ -32,71 +25,8 @@ permissions:
jobs:
detect-and-trigger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Detect CI failures and trigger Claude
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const ciFix = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/ci-failure-claude.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const baseRepo = `${owner}/${repo}`;
async function processPR(prNumber) {
return ciFix.maybeTriggerCiFixClaude(github, owner, repo, prNumber, core);
}
let results = [];
if (context.eventName === 'workflow_run') {
const wr = context.payload.workflow_run;
const result = await ciFix.processWorkflowRunFailure(
github, owner, repo, wr, core
);
results.push({ event: 'workflow_run', workflow: wr.name, ...result });
} else if (context.eventName === 'pull_request') {
results.push({
pr: context.payload.pull_request.number,
...(await processPR(context.payload.pull_request.number)),
});
} else {
let prNumbers = [];
if (context.eventName === 'workflow_dispatch' && context.payload.inputs?.pr_number) {
prNumbers = [Number(context.payload.inputs.pr_number)];
} else {
const prs = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
});
for (const pr of prs) {
if (pr.draft) continue;
const headRepo = pr.head?.repo?.full_name;
if (headRepo && headRepo !== baseRepo) continue;
const { data: issue } = await github.rest.issues.get({
owner,
repo,
issue_number: pr.number,
});
const labels = issue.labels.map((l) => l.name);
if (labels.includes('pipeline/blocked:ci') || labels.includes(ciFix.CI_FIX_LABEL)) {
prNumbers.push(pr.number);
}
}
}
for (const num of prNumbers) {
results.push({ pr: num, ...(await processPR(num)) });
}
}
core.summary.addRaw('```json\n' + JSON.stringify(results, null, 2) + '\n```');
await core.summary.write();
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.4
pr_number: ${{ github.event.inputs.pr_number || '' }}
+2
View File
@@ -5,6 +5,7 @@ on:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
python:
@@ -65,3 +66,4 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
force_orphan: true
+25 -468
View File
@@ -1,46 +1,30 @@
name: Claude PR Merge Gate
# Read-only Claude assesses merge readiness; GH_TOKEN merges (no @claude, no gh pr review).
# Does not overlap with merge-conflict-claude.yml or auto-pr-comment @claude chains.
on:
schedule:
# Scan for merge-ready PRs every 10 minutes (assess runs only when candidates exist).
- cron: '*/10 * * * *'
workflow_dispatch:
inputs:
pr_number:
description: 'Optional PR number (scan all open internal PRs if empty)'
required: false
type: string
merge_method:
description: 'Merge method'
required: false
type: choice
default: merge
options:
- merge
- squash
- rebase
options: [merge, squash, rebase]
workflow_run:
workflows:
- Claude Assistant
- CI
types:
- completed
- Core Tests
types: [completed]
repository_dispatch:
types:
- claude-merge-gate
types: [claude-merge-gate]
concurrency:
group: claude-merge-gate-${{ github.repository }}-${{ github.event.inputs.pr_number || github.event.client_payload.pr_number || github.event.workflow_run.id || 'scan' }}
cancel-in-progress: false
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
MAX_CANDIDATES: 3
DISPATCH_PR_NUMBER: ${{ github.event.inputs.pr_number || github.event.client_payload.pr_number || '' }}
permissions:
contents: read
pull-requests: read
@@ -59,7 +43,9 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: MervinPraison/github-automation-template/.github/actions/[email protected]
with:
hub_ref: v1.1.4
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
@@ -67,472 +53,43 @@ jobs:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Dispatch merge gate when PR pipeline is ready
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const path = require('path');
const mergeGate = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/merge-gate.js'));
const mergeGate = require(path.join(process.env.HUB_SCRIPTS, 'merge-gate.js'));
const wr = context.payload.workflow_run;
const owner = context.repo.owner;
const repo = context.repo.repo;
if (wr.conclusion !== 'success') {
core.info(`Skip dispatch: ${wr.name} conclusion=${wr.conclusion}`);
return;
}
const allowed = ['Claude Assistant', 'CI'];
if (!allowed.includes(wr.name)) {
core.info(`Skip dispatch: workflow ${wr.name}`);
return;
}
if (wr.conclusion !== 'success') return;
const allowed = ['Claude Assistant', 'Core Tests'];
if (!allowed.includes(wr.name)) return;
const prNumber = await mergeGate.resolvePrNumberFromWorkflowRun(github, owner, repo, wr);
if (!prNumber) {
core.info('Skip dispatch: could not resolve PR from workflow run');
return;
}
if (!prNumber) return;
const fromClaude = wr.name === 'Claude Assistant';
const check = await mergeGate.evaluatePipelineQuiescent(
github, owner, repo, prNumber, core, {
skipGlobalClaudeRunCheck: fromClaude,
skipRecentClaudeCooldown: fromClaude,
}
);
if (!check.ready) {
core.info(`PR #${prNumber} not ready: ${check.reasons.join(', ')}`);
return;
}
const check = await mergeGate.evaluatePipelineQuiescent(github, owner, repo, prNumber, core, {
skipGlobalClaudeRunCheck: fromClaude,
skipRecentClaudeCooldown: fromClaude,
});
if (!check.ready) return;
await github.rest.repos.createDispatchEvent({
owner,
repo,
event_type: 'claude-merge-gate',
owner, repo, event_type: 'claude-merge-gate',
client_payload: { pr_number: prNumber },
});
core.info(`Dispatched merge gate for PR #${prNumber} after ${wr.name}`);
scan-candidates:
merge-gate:
if: github.event_name != 'workflow_run'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: write
actions: read
id-token: write
outputs:
matrix: ${{ steps.scan.outputs.matrix }}
has_candidates: ${{ steps.scan.outputs.has_candidates }}
steps:
- uses: actions/checkout@v4
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Scan open PRs for merge gate eligibility
id: scan
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const path = require('path');
const mergeGate = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/merge-gate.js'));
const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const maxCandidates = parseInt(process.env.MAX_CANDIDATES || '5', 10);
const inputPr = String(process.env.DISPATCH_PR_NUMBER || '').trim();
const candidates = [];
const skipped = [];
if (inputPr) {
const n = parseInt(inputPr, 10);
if (Number.isNaN(n)) {
throw new Error(`Invalid pr_number input: ${inputPr}`);
}
const result = await mergeGate.evaluatePipelineQuiescent(github, owner, repo, n, core);
if (result.ready) {
candidates.push({ pr_number: n, head_sha: result.headSha });
} else {
skipped.push({ pr: n, reasons: result.reasons });
}
} else {
const prNumbers = await mergeGate.listPrNumbersForMergeGateScan(
github, owner, repo, core
);
const selected = await mergeGate.selectMergeGateCandidates(
github, owner, repo, prNumbers, maxCandidates, core
);
candidates.push(...selected.candidates);
skipped.push(...selected.skipped);
}
core.info('Skipped: ' + JSON.stringify(skipped));
core.setOutput('matrix', JSON.stringify({ include: candidates }));
core.setOutput('has_candidates', candidates.length > 0 ? 'true' : 'false');
core.summary.addRaw('## Merge gate scan\n');
core.summary.addRaw(`Candidates: ${candidates.length}\n`);
core.summary.addRaw('```json\n' + JSON.stringify({ candidates, skipped }, null, 2) + '\n```');
await core.summary.write();
if (inputPr && skipped.length === 1 && skipped[0].pr === parseInt(inputPr, 10)) {
const reasons = skipped[0].reasons;
const body = [
'**Merge gate scan** — not eligible for auto-merge.',
'',
...reasons.map((r) => `- \`${r}\``),
'',
'**Actions:** wait for CI and the Claude review chain, or add label `needs-manual-review` and merge manually.',
'**Opt out:** label `no-auto-merge`.',
].join('\n');
await github.rest.issues.createComment({
owner, repo, issue_number: skipped[0].pr, body,
});
} else if (inputPr && candidates.length === 1) {
await github.rest.issues.createComment({
owner, repo, issue_number: candidates[0].pr_number,
body: '**Merge gate scan** — eligible for assessment. Claude merge gate will assess and may auto-merge if `MERGE_GATE_VERDICT: APPROVE`.',
});
}
await ps.syncOpenPullRequests(github, owner, repo, { maxPrs: 10 }, core);
claude-assess:
needs: scan-candidates
if: needs.scan-candidates.outputs.has_candidates == 'true'
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.scan-candidates.outputs.matrix) }}
permissions:
contents: read
pull-requests: read
issues: write
actions: read
id-token: write
steps:
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Mark merge gate active
id: mark_active
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
core.setOutput('started_at', new Date().toISOString());
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ matrix.pr_number }},
labels: ['claude-merge-gate-active'],
});
- name: Stash merge gate helpers
run: |
# Keep scripts together so require('./gate-config.js') works from /tmp
mkdir -p /tmp/merge-gate-scripts /tmp/gh-actions
cp .github/scripts/merge-gate.js .github/scripts/gate-config.js /tmp/merge-gate-scripts/
cp -R .github/actions/claude-code-action /tmp/gh-actions/
- name: Fetch PR branch
env:
PR_NUMBER: ${{ matrix.pr_number }}
run: |
git fetch origin "pull/${PR_NUMBER}/head:pr-${PR_NUMBER}"
git checkout "pr-${PR_NUMBER}"
mkdir -p .github/actions
rm -rf .github/actions/claude-code-action
cp -R /tmp/gh-actions/claude-code-action .github/actions/
- name: Claude merge gate assessment (read-only)
id: assess
uses: ./.github/actions/claude-code-action
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
CLAUDE_CODE_SUBAGENT_MODEL: inherit
ANTHROPIC_DEFAULT_SONNET_MODEL: claude-sonnet-4-6
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ steps.app-token.outputs.token }}
model: claude-opus-4-8
trigger_phrase: '@claude-merge-gate-internal'
direct_prompt: |
You are the MERGE GATE reviewer for PraisonAI PR #${{ matrix.pr_number }}.
READ-ONLY: do not modify code, commit, push, rebase, or create branches.
CRITICAL OUTPUT RULE:
Post exactly one PR comment via GitHub MCP containing either:
MERGE_GATE_VERDICT: APPROVE
or
MERGE_GATE_VERDICT: BLOCK
followed by a short rationale on the next lines.
NEVER include @claude in any comment. NEVER mention merge conflict resolution.
Review checklist:
1. Read AGENTS.md and the PR diff on the current branch.
2. Read all PR comments and reviews (FINAL architecture reviewer / Lead Engineer must have run).
3. Confirm SDK value gate: change strengthens praisonaiagents (no scope creep).
4. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.
5. If agent.py adds >100 lines or new Agent __init__ params, respond MERGE_GATE_VERDICT: BLOCK (manual review required).
6. BLOCK if labels security/breaking-change/needs-manual-review/release, sensitive paths (.github/workflows, auth, pyproject.toml), secrets in diff, PR >800 lines or >30 files, or SDK changes without tests. Label `merge-gate-ci-only` exempts CI-only changes under `.github/workflows/`, `.github/actions/`, or merge-gate scripts.
7. Confirm no CHANGES_REQUESTED reviews and CI green on HEAD ${{ matrix.head_sha }}.
8. If ready to merge: MERGE_GATE_VERDICT: APPROVE. Otherwise: MERGE_GATE_VERDICT: BLOCK with reasons.
Do not approve or merge via GitHub UI/API — only post the verdict comment.
disallowed_tools: |
Bash
Edit
Write
Replace
allowed_tools: |
View
GlobTool
GrepTool
Read
timeout_minutes: 15
- name: Post fallback BLOCK if Opus did not comment
id: fallback_verdict
if: steps.assess.outcome != 'success'
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const mergeGate = require('/tmp/merge-gate-scripts/merge-gate.js');
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = ${{ matrix.pr_number }};
const ctx = await mergeGate.loadPrContext(github, owner, repo, prNumber);
const minCreatedAt = new Date(Date.now() - 25 * 60 * 1000).toISOString();
const existing = mergeGate.findMergeGateVerdict(
ctx.comments, minCreatedAt, ctx.headPushedAt, { excludeAutomatedFallback: true }
);
if (existing) {
core.info(`Opus verdict already posted: ${existing}`);
return;
}
const check = await mergeGate.evaluatePipelineQuiescent(
github, owner, repo, prNumber, core, { forMergeStep: true }
);
const lines = [
'MERGE_GATE_VERDICT: BLOCK',
'',
'Automated fallback — Opus merge gate assessment did not complete.',
];
if (check.ready) {
lines.push('Deterministic gates passed, but Opus MERGE_GATE_VERDICT is required before merge.');
} else {
lines.push('Blockers:', ...check.reasons.map((r) => `- ${r}`));
}
await github.rest.issues.createComment({
owner, repo, issue_number: prNumber,
body: lines.join('\n'),
});
core.info('Posted fallback BLOCK — Opus verdict required');
- name: Require Opus MERGE_GATE_VERDICT
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const mergeGate = require('/tmp/merge-gate-scripts/merge-gate.js');
const comments = await mergeGate.listAllComments(
github, context.repo.owner, context.repo.repo, ${{ matrix.pr_number }}
);
const ctx = await mergeGate.loadPrContext(
github, context.repo.owner, context.repo.repo, ${{ matrix.pr_number }}
);
const minCreatedAt = new Date(Date.now() - 25 * 60 * 1000).toISOString();
const verdict = mergeGate.findMergeGateVerdict(
comments, minCreatedAt, ctx.headPushedAt, { excludeAutomatedFallback: true }
);
if (!verdict) {
core.setFailed(
'Opus merge gate assessment must post MERGE_GATE_VERDICT on this PR (automated fallback APPROVE is not accepted).'
);
return;
}
core.info(`Opus merge gate verdict: ${verdict}`);
core.setOutput('verdict', verdict);
- name: Remove merge gate active label
if: always()
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const prNumber = ${{ matrix.pr_number }};
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'claude-merge-gate-active',
});
core.info(`Removed claude-merge-gate-active from PR #${prNumber}`);
} catch (e) {
core.info(`Label claude-merge-gate-active already removed or missing on PR #${prNumber}`);
}
- name: Fail job if assessment failed
if: steps.assess.outcome == 'failure'
run: exit 1
merge-only:
needs: [scan-candidates, claude-assess]
if: |
always() &&
needs.scan-candidates.outputs.has_candidates == 'true' &&
needs.claude-assess.result == 'success'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.scan-candidates.outputs.matrix) }}
permissions:
contents: write
pull-requests: write
issues: write
actions: read
id-token: write
steps:
- uses: actions/checkout@v4
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Re-check gates and merge
uses: actions/github-script@v7
env:
MERGE_METHOD: ${{ github.event.inputs.merge_method || 'merge' }}
SCAN_HEAD_SHA: ${{ matrix.head_sha }}
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const path = require('path');
const mergeGate = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/merge-gate.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = ${{ matrix.pr_number }};
const scanHeadSha = process.env.SCAN_HEAD_SHA;
const removeLabels = async () => {
try {
await github.rest.issues.removeLabel({
owner, repo, issue_number: prNumber, name: 'claude-merge-gate-active',
});
} catch (e) {
core.info('Label claude-merge-gate-active already removed or missing');
}
};
try {
const ctx = await mergeGate.loadPrContext(github, owner, repo, prNumber);
const comments = ctx.comments;
const verdictMin = new Date(Date.now() - 25 * 60 * 1000).toISOString();
const verdict = mergeGate.findMergeGateVerdict(
comments, verdictMin, ctx.headPushedAt, { excludeAutomatedFallback: true }
);
if (verdict !== 'APPROVE') {
core.info(`Skip merge: verdict=${verdict || 'NONE'}`);
await removeLabels();
return;
}
const check = await mergeGate.evaluatePipelineQuiescent(
github, owner, repo, prNumber, core, { forMergeStep: true }
);
if (!check.ready) {
core.info(`Skip merge: ${check.reasons.join(', ')}`);
await removeLabels();
return;
}
if (check.headSha !== scanHeadSha) {
core.info(`Skip merge: HEAD moved ${scanHeadSha.slice(0, 7)} → ${check.headSha.slice(0, 7)}`);
await removeLabels();
return;
}
const method = process.env.MERGE_METHOD || 'merge';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
let merged = false;
for (let attempt = 1; attempt <= 3; attempt++) {
try {
await github.rest.pulls.merge({
owner, repo, pull_number: prNumber, merge_method: method,
});
merged = true;
break;
} catch (e) {
const msg = (e.message || '').toLowerCase();
if (attempt < 3 && msg.includes('base branch was modified')) {
core.info(`Merge attempt ${attempt} failed (base moved), retrying in 8s...`);
await sleep(8000);
const recheck = await mergeGate.evaluatePipelineQuiescent(
github, owner, repo, prNumber, core, { forMergeStep: true }
);
if (!recheck.ready) {
core.info(`Skip merge retry: ${recheck.reasons.join(', ')}`);
await removeLabels();
return;
}
continue;
}
throw e;
}
}
if (!merged) {
core.info('Skip merge: exhausted retries');
await removeLabels();
return;
}
await github.rest.issues.addLabels({
owner, repo, issue_number: prNumber, labels: ['auto-merged-by-gate'],
});
await github.rest.issues.createComment({
owner, repo, issue_number: prNumber,
body: [
'Merged by **Claude PR merge gate** (`claude-merge-gate.yml`).',
`Verdict: MERGE_GATE_VERDICT: APPROVE`,
`SHA: \`${check.headSha.slice(0, 7)}\``,
`Method: ${method}`,
].join('\n'),
});
core.info(`Merged PR #${prNumber}`);
} finally {
await removeLabels();
}
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.4
pr_number: ${{ github.event.inputs.pr_number || github.event.client_payload.pr_number || '' }}
merge_method: ${{ github.event.inputs.merge_method || 'merge' }}
+6 -531
View File
@@ -1,543 +1,18 @@
name: Claude Assistant
# Triggers:
# - issues:opened → lightweight triage (labels + auto-claude for owner)
# - issues:labeled → full implementation when `claude` label applied
# - issues:assigned → full implementation when issue assigned to Claude
# - issue_comment → full implementation when @claude mentioned (issues + PRs)
# - pull_request_review → full implementation when @claude mentioned in review
# - pull_request_review_comment → full implementation when @claude mentioned inline
#
# Escalate an issue with the `claude` label OR an @claude comment — not both.
# If both fire within 3 minutes, the comment trigger is skipped (dedupe job).
#
# Focus: CLAUDE only. Copilot and CodeRabbit are GitHub Apps that react to PRs
# automatically — no workflow file needed. auto-pr-comment.yml orchestrates the
# CodeRabbit → Copilot → Claude review chain for PRs.
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, labeled, assigned]
types: [assigned, labeled, opened]
pull_request_review:
types: [submitted]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number for Claude implementation'
required: true
type: string
jobs:
# ================================================================
# Job 1 — Issue triage (runs on ANY new issue, including external users)
# Posts welcome comment + triage labels. Auto-adds `claude` for owner issues.
# ================================================================
issue-triage:
if: |
github.event_name == 'issues' &&
github.event.action == 'opened' &&
!contains(toJSON(github.event.issue.labels), 'claude')
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
steps:
- name: Generate GitHub App Token
id: app-token
continue-on-error: true
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Resolve GitHub token
id: github-token
run: |
if [ -n "${{ steps.app-token.outputs.token }}" ]; then
echo "token=${{ steps.app-token.outputs.token }}" >> "$GITHUB_OUTPUT"
else
echo "token=${{ secrets.GITHUB_TOKEN }}" >> "$GITHUB_OUTPUT"
fi
- name: Triage and acknowledge issue
uses: actions/github-script@v7
with:
github-token: ${{ steps.github-token.outputs.token }}
script: |
const issue = context.payload.issue;
const title = (issue.title || '').toLowerCase();
const body = (issue.body || '').toLowerCase();
const content = title + ' ' + body;
const isOwner = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(
issue.author_association
);
const labels = [];
if (content.includes('feature request') || content.includes('[feature')) {
labels.push('enhancement');
} else if (content.includes('bug') || content.includes('error') || content.includes('crash') || content.includes('traceback')) {
labels.push('bug');
} else if (content.includes('question') || content.includes('how do i') || content.includes('how to')) {
labels.push('question');
}
if (content.includes('security') || content.includes('cve') || content.includes('vulnerability')) {
labels.push('security');
}
if (content.includes('performance') || content.includes('slow') || content.includes('memory leak')) {
labels.push('performance');
}
if (content.includes('documentation') || content.includes('docs')) {
labels.push('documentation');
}
if (content.includes('typescript') || content.includes('javascript') || content.includes('npm')) {
labels.push('javascript');
}
if (content.includes('frontend') || content.includes('react') || content.includes('vite')) {
labels.push('frontend');
}
if (content.includes('example') || content.includes('yaml')) {
labels.push('examples');
}
if (labels.length > 0) {
await github.rest.issues.addLabels({
issue_number: issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels
});
}
if (!isOwner) {
await github.rest.issues.createComment({
issue_number: issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: [
`👋 Thanks for opening this issue, @${issue.user.login}!`,
'',
'A maintainer will review this shortly. In the meantime:',
'- Make sure you\'ve included steps to reproduce (for bugs)',
'- Check [existing issues](https://github.com/MervinPraison/PraisonAIUI/issues) for duplicates',
'- Review [AGENTS.md](https://github.com/MervinPraison/PraisonAIUI/blob/main/AGENTS.md) for project conventions',
'',
'_A maintainer can trigger deeper analysis by commenting `@claude` on this issue._'
].join('\n')
});
}
if (isOwner) {
await github.rest.issues.addLabels({
issue_number: issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['claude']
});
}
# ================================================================
# Job 2 — Full Claude Code implementation
# Triggers on: labeled `claude`, @claude comments, assignments
#
# Dedup: label + @claude comment on the same issue fires two events.
# Skip the comment trigger when `claude` was labelled within 3 minutes.
# ================================================================
claude-dedupe:
if: |
github.event_name == 'workflow_dispatch' ||
(
github.event.action != 'opened' &&
(github.event.action != 'labeled' || github.event.label.name == 'claude') &&
(github.event_name != 'issue_comment' || contains(github.event.comment.body, '@claude')) &&
(
!contains(github.actor, '[bot]') ||
github.actor == 'github-actions[bot]' ||
github.actor == 'praisonai-triage-agent[bot]'
) &&
github.actor != 'dependabot[bot]' &&
github.actor != 'cursor[bot]' &&
github.actor != 'renovate[bot]'
)
runs-on: ubuntu-latest
outputs:
proceed: ${{ steps.check.outputs.proceed }}
permissions:
issues: read
pull-requests: read
steps:
- name: Skip duplicate comment after fresh claude label
id: check
uses: actions/github-script@v7
with:
script: |
if (context.eventName === 'workflow_dispatch') {
core.setOutput('proceed', 'true');
return;
}
if (context.eventName !== 'issue_comment' || context.payload.issue?.pull_request) {
core.setOutput('proceed', 'true');
return;
}
const issue = context.payload.issue;
const hasClaude = (issue.labels || []).some(l => l.name === 'claude');
if (!hasClaude) {
core.setOutput('proceed', 'true');
return;
}
const events = await github.rest.issues.listEvents({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
per_page: 30,
});
const windowMs = 3 * 60 * 1000;
const recentLabel = events.data.find(e =>
e.event === 'labeled' &&
e.label?.name === 'claude' &&
(Date.now() - new Date(e.created_at).getTime()) < windowMs
);
if (recentLabel) {
core.info('Skipping: claude label was added within 3 minutes — label trigger already handles this issue.');
core.setOutput('proceed', 'false');
return;
}
core.setOutput('proceed', 'true');
claude-response:
needs: claude-dedupe
env:
ISSUE_NUMBER_RESOLVED: ${{ github.event.issue.number || github.event.pull_request.number || inputs.issue_number }}
if: needs.claude-dedupe.outputs.proceed == 'true'
concurrency:
group: claude-${{ github.event.issue.number || github.event.pull_request.number || inputs.issue_number || github.run_id }}
cancel-in-progress: true
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
actions: read
id-token: write
steps:
- name: Generate GitHub App Token
id: app-token
continue-on-error: true
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Resolve GitHub token
id: github-token
run: |
if [ -n "${{ steps.app-token.outputs.token }}" ]; then
echo "token=${{ steps.app-token.outputs.token }}" >> "$GITHUB_OUTPUT"
else
echo "token=${{ secrets.GITHUB_TOKEN }}" >> "$GITHUB_OUTPUT"
fi
- name: Check for Fork PR
id: check_fork
uses: actions/github-script@v7
with:
github-token: ${{ steps.github-token.outputs.token }}
script: |
const isPR = context.eventName === 'pull_request' ||
context.eventName === 'pull_request_review' ||
context.eventName === 'pull_request_review_comment' ||
(context.payload.issue && context.payload.issue.pull_request);
if (isPR) {
core.setOutput('is_pr_review', 'true');
const prNumber = context.payload.pull_request
? context.payload.pull_request.number
: context.payload.issue.number;
core.setOutput('pr_number', String(prNumber));
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
core.setOutput('pr_branch', pr.data.head.ref);
const headRepo = pr.data.head.repo?.full_name || context.repo.full_name;
core.setOutput('head_repo', headRepo);
let mergeState = '';
try {
const gql = await github.graphql(
`query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) { mergeStateStatus }
}
}`,
{ owner: context.repo.owner, repo: context.repo.repo, number: prNumber }
);
mergeState = (gql.repository.pullRequest.mergeStateStatus || '').toUpperCase();
} catch (e) {
core.warning(`GraphQL mergeStateStatus failed: ${e.message}`);
}
if (!mergeState) {
mergeState = (pr.data.mergeable_state || pr.data.merge_state_status || '').toUpperCase();
}
core.setOutput('merge_state', mergeState);
if (headRepo !== `${context.repo.owner}/${context.repo.repo}`) {
core.setOutput('is_fork', 'true');
core.setOutput('clone_url', pr.data.head.repo.clone_url);
core.setOutput('branch', pr.data.head.ref);
return;
}
core.setOutput('is_fork', 'false');
return;
}
core.setOutput('is_pr_review', 'false');
core.setOutput('is_fork', 'false');
core.setOutput('merge_state', '');
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
token: ${{ steps.github-token.outputs.token }}
ref: ${{ steps.check_fork.outputs.is_pr_review == 'true' && format('refs/pull/{0}/head', steps.check_fork.outputs.pr_number) || github.ref }}
- name: Checkout PR branch for edits
if: steps.check_fork.outputs.is_pr_review == 'true' && steps.check_fork.outputs.is_fork != 'true'
env:
PR_BRANCH: ${{ steps.check_fork.outputs.pr_branch }}
run: |
git checkout "${PR_BRANCH}"
git config --local user.name "MervinPraison"
git config --local user.email "[email protected]"
echo "On branch: $(git branch --show-current)"
- name: Fetch PR branch and Setup Remote
if: steps.check_fork.outputs.is_pr_review == 'true' && steps.check_fork.outputs.is_fork == 'true'
env:
PR_BRANCH: ${{ steps.check_fork.outputs.pr_branch }}
run: |
git fetch origin pull/${{ steps.check_fork.outputs.pr_number }}/head:"${PR_BRANCH}"
git checkout "${PR_BRANCH}"
git remote set-url origin file://$(pwd)
- name: Run Claude PR final review
if: steps.check_fork.outputs.is_pr_review == 'true'
uses: anthropics/claude-code-action@beta
env:
GH_TOKEN: ${{ steps.github-token.outputs.token }}
with:
allowed_bots: 'praisonai-triage-agent[bot]'
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ steps.github-token.outputs.token }}
model: claude-opus-4-8
trigger_phrase: "@claude"
timeout_minutes: "30"
direct_prompt: |
${{ steps.check_fork.outputs.is_fork == 'true' && 'CRITICAL: FORK PR — comment only, do not push.\n\n' || 'PR on MervinPraison/PraisonAIUI — SAME REPO, NOT A FORK. You HAVE push permission to this branch. NEVER say this is a fork.\n\n' }}
${{ steps.check_fork.outputs.is_fork != 'true' && steps.check_fork.outputs.merge_state == 'DIRTY' && format('PRIORITY — RESOLVE MERGE CONFLICTS (branch: {0}, PR #{1}):\n- DO NOT create a new branch or PR\n- git fetch origin main && git rebase origin/main\n- Resolve conflicts: keep this PR intent, merge in main newer logic\n- git add -A && git rebase --continue (repeat until done)\n- git push --force-with-lease origin {0}\n- Run targeted pytest/ruff on changed paths\n- Comment files resolved and what you skipped\n- Only after conflicts are resolved, proceed with review phases below if still needed\n\n', steps.check_fork.outputs.pr_branch, steps.check_fork.outputs.pr_number) || '' }}
${{ steps.check_fork.outputs.merge_state != 'DIRTY' && format('CONTEXT: PR #{0} on branch {1}. merge_state={2}.\n\n', steps.check_fork.outputs.pr_number, steps.check_fork.outputs.pr_branch, steps.check_fork.outputs.merge_state) || '' }}
You are the Lead Engineer doing FINAL review on this open PR in MervinPraison/PraisonAIUI.
Read ALL reviewer comments (CodeRabbit, Gemini, Qodo, Copilot, human). Follow AGENTS.md.
SCOPE: src/praisonaiui, src/frontend, tests, docs only.
**Phase 1 — Review** architecture, security, tests, backward compat, import-time budget.
**Phase 2 — FIX (mandatory)** implement every VALID issue on THIS branch. Push commits before Phase 3.
Do NOT ask the author to fix. Do NOT open a new PR. Do NOT claim fork restrictions unless is_fork is true.
**Phase 3 — Verdict** approve only after fixes are pushed and tests pass; else request changes with specifics.
git config --global user.name "MervinPraison"
git config --global user.email "[email protected]"
gh auth setup-git
git status
git branch --show-current
allowed_tools: |
Bash(git:*)
Bash(python:*)
Bash(pip:*)
Bash(pytest:*)
Bash(ruff:*)
Bash(gh:*)
Bash(npm:*)
View
GlobTool
GrepTool
BatchTool
Edit
Replace
- name: Run Claude Code Action
if: steps.check_fork.outputs.is_pr_review != 'true'
uses: anthropics/claude-code-action@beta
env:
GH_TOKEN: ${{ steps.github-token.outputs.token }}
with:
allowed_bots: 'praisonai-triage-agent[bot]'
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ steps.github-token.outputs.token }}
model: claude-opus-4-8
mode: ${{ github.event_name == 'workflow_dispatch' && 'agent' || 'tag' }}
trigger_phrase: "@claude"
label_trigger: "claude"
timeout_minutes: "30"
direct_prompt: |
${{ steps.check_fork.outputs.is_fork == 'true' && 'CRITICAL: THIS IS A PULL REQUEST FROM A FORK. YOU DO NOT HAVE PUSH PERMISSIONS TO THIS REPOSITORY. ONLY READ FILES, VALIDATE CODE, AND PROVIDE YOUR COMMENTS/FEEDBACK DIRECTLY IN THIS PR VIA COMMENTS. DO NOT ATTEMPT TO PUSH OR CREATE PULL REQUESTS.\n\n' || 'NOTE: The branch is under MervinPraison/PraisonAIUI (not a fork). You are able to make modifications and push directly to this branch.\n\n' }}
You are implementing changes in **MervinPraison/PraisonAIUI** (YAML-driven server-driven UI with agentic chat).
Follow `AGENTS.md` at the repository root. If a conflict arises between this prompt and `AGENTS.md`, `AGENTS.md` wins.
═══════════════════════════════════════════════════════════════
STEP 0 — GIT & GITHUB CLI
═══════════════════════════════════════════════════════════════
git config --global user.name "MervinPraison"
git config --global user.email "[email protected]"
gh auth setup-git
═══════════════════════════════════════════════════════════════
STEP 1 — READ GUIDELINES
═══════════════════════════════════════════════════════════════
Read `AGENTS.md` and any `docs/principles.md`. Key invariants:
• Cold import of `praisonaiui` must stay under 200 ms; module count must not grow.
• Heavy / optional deps (`mcp`, `langchain`, `llama_index`, `semantic_kernel`,
`slack_sdk`, `discord.py`, `botbuilder.core`, `openai`, `anthropic`, `mistralai`,
`google.generativeai`) must be **lazy-imported** — never eager.
• Public API is verb-first. New classes in `src/praisonaiui/message.py` ending
in `Message` with a verb prefix (Ask*, Do*, Request*, …) are forbidden —
use a module-level `async def` verb helper instead (see `prompt`, `error`).
• Deprecations must emit a runtime `warnings.warn(..., DeprecationWarning, stacklevel=2)`
on first access, not only in the docstring.
• Deterministic serialisation in anything reaching the wire (sorted keys, stable field
order). See existing `to_dict` patterns.
• Multi-agent + async safe: no global mutable state without a lock.
═══════════════════════════════════════════════════════════════
STEP 2 — ARCHITECTURE VALIDATION & ROUTING (MANDATORY before any code)
═══════════════════════════════════════════════════════════════
Answer these questions inline in your response, then proceed only if you pass:
ROUTING:
1. **Core aiui** (`src/praisonaiui/`) — protocols, message types, server, features.
2. **Features** (`src/praisonaiui/features/`) — opt-in capabilities (MCP, platforms, lifecycle, audio, auth, sharing, etc.).
3. **UI builders** (`src/praisonaiui/ui.py`) — declarative component helpers.
4. **Frontend** (`src/frontend/`) — React components / stores / SSE handlers.
5. **Tests** (`tests/unit/`, `tests/integration/`) — new features require both smoke and real-agentic tests.
6. **Docs** (`docs/`) — canonical name per feature, migration table for renames.
EXTERNAL REPOS (do NOT edit from within this repo — route the work to the right place and stop):
• Core SDK: `MervinPraison/PraisonAI` (`praisonaiagents`, `praisonai`) — agent runtime.
• Tools: `MervinPraison/PraisonAI-Tools` — tool implementations.
• Docs site: `MervinPraison/PraisonAIDocs` — product docs.
If the requested change belongs in an external repo, comment on the issue explaining
where it should live and DO NOT open a PR in this repo.
CONCEPTUAL CHECKS (if ANY fails — add a comment, do NOT open a PR):
• Does it duplicate an existing public symbol in `src/praisonaiui/__init__.py`?
• Does it add new class-first message types (`class Ask*Message`, `class *Message`
with a verb in the name)? → Use a verb-first helper instead.
• Does it add a new hard dependency to `pyproject.toml` `[project] dependencies`?
→ Move to `[project.optional-dependencies]` and wrap imports lazily.
• Does it break backward compat (rename, signature change, removal)? → Add
a deprecation alias that emits `DeprecationWarning`; never hard-remove before the
documented removal version (e.g. `0.5.0`).
═══════════════════════════════════════════════════════════════
STEP 3 — IMPLEMENT
═══════════════════════════════════════════════════════════════
Single branch for the whole flow (reuse the same name in STEP 5):
BRANCH="claude/issue-${{ env.ISSUE_NUMBER_RESOLVED }}-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH"
Make minimal, focused changes:
• Stay within the files listed in the issue's "Scope" / "Files to change" section.
• Prefer extending existing modules over adding new ones.
• No emojis, no comments, no markdown except where the user asked for it.
• Python ≥ 3.10 style (`list[...]` not `List[...]`, `X | None` not `Optional[X]`).
═══════════════════════════════════════════════════════════════
STEP 4 — TEST / VERIFY
═══════════════════════════════════════════════════════════════
Run these targeted checks (NOT the full suite):
# 1. Lint on only the files you changed:
CHANGED=$(git diff --name-only origin/main...HEAD | grep -E '\.py$' | tr '\n' ' ')
[ -n "$CHANGED" ] && ruff check $CHANGED
# 2. Unit tests for the module(s) you touched:
pytest tests/unit/<your_new_test_file>.py -v --tb=short
# 3. Import-time invariant (MUST stay under 200 ms cold):
python -c "import time, sys; t=time.time(); import praisonaiui; dt=(time.time()-t)*1000; heavy=[m for m in sys.modules if any(h in m for h in ['langchain','llama_index','mcp','slack','discord','botbuilder','openai.','anthropic.','mistralai','google.generativeai'])]; print(f'{dt:.1f}ms modules={len(sys.modules)} leaked={heavy}'); assert heavy == [], f'Heavy deps leaked: {heavy}'"
If anything fails, fix the root cause (never skip, xfail, or delete the test).
═══════════════════════════════════════════════════════════════
STEP 5 — COMMIT, PUSH, OPEN PR (MANDATORY if you produced commits)
═══════════════════════════════════════════════════════════════
git add -A
git commit -m "feat: <short summary> (fixes #${{ env.ISSUE_NUMBER_RESOLVED }})"
git push -u origin "$BRANCH"
REPO="${{ github.repository }}"
COUNT=$(gh pr list --repo "$REPO" --head "$BRANCH" --json number --jq 'length')
if [ "$COUNT" -gt 0 ]; then
gh pr list --repo "$REPO" --head "$BRANCH" --json url --jq '.[0].url'
else
gh pr create --repo "$REPO" --base main --head "$BRANCH" \
--title "feat: <short title>" \
--body "Fixes #${{ env.ISSUE_NUMBER_RESOLVED }}
## Summary
<what changed in one paragraph>
## Acceptance criteria
<copy from the issue; tick boxes only with commit SHA + file path evidence>
## Test evidence
\`\`\`
<paste pytest output>
\`\`\`
"
fi
CRITICAL: Do NOT stop after `git push`. You MUST complete `gh pr create` (or print the
existing PR URL from the step above) and post that URL on the issue. Never ask a
human to open the PR manually.
═══════════════════════════════════════════════════════════════
STEP 6 — RESPOND TO REVIEW FEEDBACK (if this run was triggered by a review comment)
═══════════════════════════════════════════════════════════════
If you were invoked by a PR review comment, you are the Lead Engineer for this PR:
• Read ALL reviewer comments in chronological order (CodeRabbit → Copilot → human).
• Fix every VALID issue by pushing commits to THIS branch (do NOT open a new PR).
• Reply with a summary of which comments you addressed, which you disagreed with (and why).
• Never ship a fix that removes/weakens a test.
allowed_tools: |
Bash(git:*)
Bash(python:*)
Bash(pip:*)
Bash(pytest:*)
Bash(ruff:*)
Bash(gh:*)
Bash(npm:*)
Bash(npx:*)
Bash(python -m pytest:*)
Bash(python -m pip:*)
Bash(python -m ruff:*)
View
GlobTool
GrepTool
BatchTool
Edit
Replace
mcp__github__get_issue
mcp__github__get_issue_comments
mcp__github__update_issue
claude:
uses: MervinPraison/github-automation-template/.github/workflows/claud[email protected]
secrets: inherit
with:
hub_ref: v1.1.4
+41
View File
@@ -0,0 +1,41 @@
name: Deploy Docs
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: write
pages: write
id-token: write
concurrency:
group: deploy-docs
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install AIUI
run: pip install -e .
- name: Build docs with AIUI
run: |
aiui build --output site --minify
cp CNAME site/CNAME
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
force_orphan: true
+18 -149
View File
@@ -1,7 +1,5 @@
name: Auto Merge Conflict → Claude
# Detects internal PRs with mergeStateStatus=DIRTY and posts @claude to trigger claude.yml.
on:
push:
branches: [main]
@@ -12,11 +10,10 @@ on:
- cron: '0 */6 * * *'
concurrency:
group: merge-conflict-scan-${{ github.repository }}
group: merge-conflict-scan-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
env:
# PAT posts as MervinPraison so issue_comment triggers claude.yml (GITHUB_TOKEN cannot chain workflows)
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
permissions:
@@ -27,157 +24,29 @@ jobs:
detect-and-trigger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: MervinPraison/github-automation-template/.github/actions/[email protected]
with:
hub_ref: v1.1.4
- name: Detect conflicting PRs and trigger Claude
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const mg = require(path.join(process.env.HUB_SCRIPTS, 'merge-gate.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const baseRepo = `${owner}/${repo}`;
const COOLDOWN_MS = 12 * 60 * 60 * 1000;
const AUTO_ACTORS = ['github-actions[bot]', 'MervinPraison'];
const LABEL = 'claude-conflict-pending';
const COMMENT_BODY = [
'@claude this PR has merge conflicts with `main`.',
'Please rebase onto latest `main`, resolve conflicts (keep this PR\'s intent, merge in newer main logic),',
'run targeted tests, and force-push with `--force-with-lease`.',
'Comment which files you resolved.'
].join(' ');
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function getMergeState(prNumber) {
const query = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
mergeStateStatus
maintainerCanModify
isDraft
headRef { repository { nameWithOwner } }
}
}
}
`;
for (let attempt = 0; attempt < 3; attempt++) {
const result = await github.graphql(query, { owner, repo, number: prNumber });
const prGql = result.repository.pullRequest;
const status = (prGql?.mergeStateStatus || '').toUpperCase();
if (status && status !== 'UNKNOWN') {
return {
status,
isDraft: prGql.isDraft,
headRepo: prGql.headRef?.repository?.nameWithOwner,
maintainerCanModify: prGql.maintainerCanModify === true,
};
}
if (attempt < 2) await sleep(10000);
}
const pr = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
return {
status: (pr.data.mergeable_state || '').toUpperCase(),
isDraft: pr.data.draft,
headRepo: pr.data.head.repo?.full_name,
maintainerCanModify: pr.data.maintainer_can_modify === true,
};
const prs = await github.paginate(github.rest.pulls.list, { owner, repo, state: 'open', per_page: 50 });
for (const pr of prs) {
if (pr.draft) continue;
if (pr.head?.repo?.full_name !== baseRepo) continue;
const state = await mg.getMergeState(github, owner, repo, pr.number);
if (state.status !== 'DIRTY') continue;
const { data: comments } = await github.rest.issues.listComments({ owner, repo, issue_number: pr.number, per_page: 100 });
if (mg.hasRecentConflictComment(comments)) continue;
const body = '@claude this PR has merge conflicts with `main`. Rebase onto latest main, resolve conflicts, run tests, force-push with --force-with-lease.';
await github.rest.issues.createComment({ owner, repo, issue_number: pr.number, body });
await github.rest.issues.addLabels({ owner, repo, issue_number: pr.number, labels: ['claude-conflict-pending'] });
}
function hasFinalClaudeReviewTrigger(comments) {
return comments.some((c) => {
const body = (c.body || '').toLowerCase();
if (!AUTO_ACTORS.includes(c.user.login)) return false;
if (!body.includes('@claude')) return false;
if (body.includes('merge conflict')) return false;
return body.includes('final architecture reviewer') || body.includes('lead engineer');
});
}
function hasRecentAutoComment(comments) {
const cutoff = Date.now() - COOLDOWN_MS;
return comments.some((c) => {
if (!AUTO_ACTORS.includes(c.user.login)) return false;
const body = (c.body || '').toLowerCase();
if (!body.includes('@claude') || !body.includes('merge conflict')) return false;
return new Date(c.created_at).getTime() > cutoff;
});
}
async function processPR(prNumber) {
const { status, isDraft, headRepo, maintainerCanModify } = await getMergeState(prNumber);
core.info(`PR #${prNumber}: mergeState=${status}, head=${headRepo}, draft=${isDraft}, maintainerCanModify=${maintainerCanModify}`);
const { data: issue } = await github.rest.issues.get({
owner,
repo,
issue_number: prNumber,
});
const labels = issue.labels.map((l) => l.name);
if (status !== 'DIRTY' && labels.includes(LABEL)) {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: prNumber,
name: LABEL,
});
core.info(`Removed ${LABEL} from PR #${prNumber}`);
}
if (status !== 'DIRTY') return { skipped: true, reason: 'not dirty' };
if (isDraft) return { skipped: true, reason: 'draft' };
if (headRepo && headRepo !== baseRepo && !maintainerCanModify) {
return { skipped: true, reason: 'fork without maintainer edits' };
}
if (labels.includes(LABEL)) {
return { skipped: true, reason: 'conflict resolution pending' };
}
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber,
per_page: 100,
});
if (hasRecentAutoComment(comments)) {
return { skipped: true, reason: 'recent auto comment' };
}
if (!hasFinalClaudeReviewTrigger(comments)) {
return { skipped: true, reason: 'awaiting final claude review trigger' };
}
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: [LABEL],
});
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: COMMENT_BODY,
});
return { triggered: true };
}
let prNumbers = [];
if (context.eventName === 'pull_request') {
prNumbers = [context.payload.pull_request.number];
} else {
const prs = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
});
prNumbers = prs.map((p) => p.number);
}
const results = [];
for (const num of prNumbers) {
results.push({ pr: num, ...(await processPR(num)) });
}
core.summary.addRaw('```json\n' + JSON.stringify(results, null, 2) + '\n```');
await core.summary.write();
+4 -27
View File
@@ -1,7 +1,5 @@
name: Pipeline Status Sync
# Sync pipeline/* stage and blocker labels on open internal PRs.
on:
schedule:
- cron: '*/10 * * * *'
@@ -15,28 +13,7 @@ permissions:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Sync pipeline labels on open PRs
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const path = require('path');
const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
await ps.syncOpenPullRequests(
github, context.repo.owner, context.repo.repo,
{ maxPrs: 30, dispatchMergeGate: true }, core
);
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.4
+13 -4
View File
@@ -9,6 +9,14 @@ site:
radius: "md"
darkMode: true
seo:
siteUrl: "https://ui.praison.ai"
titleTemplate: "%s | %s"
defaultImage: "/icon.svg"
robots:
index: true
follow: true
# Mintlify-style navigation: few tabs, many groups per tab
navigation:
tabs:
@@ -73,11 +81,12 @@ navigation:
# Navbar actions
navbar:
primary:
type: "github"
href: "https://github.com/MervinPraison/PraisonAIUI"
type: "button"
label: "Get started"
href: "/docs/getting-started/quickstart"
links:
- label: "Submit Issues"
href: "https://github.com/MervinPraison/PraisonAIUI/issues"
- label: "GitHub"
href: "https://github.com/MervinPraison/PraisonAIUI"
# Footer
footer:
+54 -51
View File
@@ -1,73 +1,76 @@
# SEO
Built-in SEO features for better search engine visibility.
Built-in SEO for documentation sites — sitemap, robots, llms.txt, per-page meta tags, and crawlable static HTML.
## Automatic Meta Tags
## Configuration
PraisonAIUI generates meta tags from your configuration:
Top-level `seo` block in `aiui.template.yaml`:
```yaml
site:
title: "My Documentation"
description: "Comprehensive guides for my product"
seo:
siteUrl: "https://ui.praison.ai"
titleTemplate: "%s | %s"
defaultImage: "/icon.svg"
robots:
index: true
follow: true
twitter:
handle: "@yourhandle"
```
Generates:
```html
<title>My Documentation</title>
<meta name="description" content="Comprehensive guides for my product">
```
`siteUrl` is required for absolute canonical URLs, sitemap, and social tags.
## Page-Level Overrides
## Build outputs
Use frontmatter to override per-page:
`aiui build` automatically generates:
| File | Purpose |
|------|---------|
| `sitemap.xml` | All doc URLs with `lastmod` dates |
| `robots.txt` | Crawl rules + sitemap pointer |
| `llms.txt` | AI crawler index ([llmstxt.org](https://llmstxt.org)) |
| `llms-full.txt` | Full markdown export for AI tools |
| `docs/**/*.html` | Per-route HTML with meta tags + crawl nav |
| `.nojekyll` | GitHub Pages Jekyll bypass |
No extra flags are needed — SEO files are emitted whenever `content.docs` is configured.
## Page-level overrides
Use frontmatter on any markdown page:
```markdown
---
title: "Custom Page Title"
description: "Custom meta description for this page"
description: "Custom meta description for search snippets"
noindex: true
---
# Page Content
```
## SEO Configuration
If `description` is omitted, the first paragraph is used automatically.
## Per-page HTML includes
Each route HTML file contains:
- `<link rel="canonical">` (absolute HTTPS)
- `<meta name="description">`
- Open Graph tags (`og:title`, `og:description`, `og:url`, `og:type`, `og:image`)
- Twitter Card tags
- JSON-LD `TechArticle` schema
- Static `<nav>` with links to every doc page (for non-JS crawlers)
- `<noscript>` pre-rendered page content
## Runtime (SPA navigation)
When users navigate via the sidebar, React updates title, canonical, OG, Twitter, robots, and JSON-LD to match the current page.
## Deploy
GitHub Pages deploy runs via the **Deploy Docs** workflow on every push to `main`. Submit your sitemap in [Google Search Console](https://search.google.com/search-console):
```yaml
site:
seo:
titleTemplate: "%s | My Site"
defaultImage: "/og-image.png"
twitterHandle: "@myhandle"
```
## Open Graph
Automatic Open Graph tags for social sharing:
```html
<meta property="og:title" content="Page Title">
<meta property="og:description" content="Page description">
<meta property="og:image" content="/og-image.png">
<meta property="og:type" content="website">
```
## Sitemap
Generate a sitemap during build:
```bash
aiui build --sitemap
```
Creates `sitemap.xml` with all pages.
## Robots.txt
```yaml
site:
seo:
robots:
index: true
follow: true
https://your-domain.com/sitemap.xml
```
+69
View File
@@ -0,0 +1,69 @@
# Application Design Protocol (ADP)
Declarative UI design standard for describing application layout, navigation, components, and theming from YAML or JSON manifests.
**Status:** v1alpha1 research draft — see [implementation-status.md](./implementation-status.md) for what is implemented today.
## Documents
| Document | Description |
|----------|-------------|
| [Research report](../application-design-protocol-report.md) | 46 standards compared; YAML vs JSON debate; design principles |
| [spec.md](./spec.md) | Normative specification (draft) |
| [validation-rules.md](./validation-rules.md) | Cross-reference rules R1–R30 |
| [aiui-mapping.md](./aiui-mapping.md) | PraisonAIUI field mapping |
| [implementation-status.md](./implementation-status.md) | Feature implementation tracker |
## Schemas
| File | Purpose |
|------|---------|
| [schema/application.schema.json](./schema/application.schema.json) | Root Application kind |
| [schema/component-catalog.schema.json](./schema/component-catalog.schema.json) | Catalog meta-schema |
| [schema/theme.schema.json](./schema/theme.schema.json) | Theme preset or DTCG tokens |
| [catalogs/default.catalog.json](./catalogs/default.catalog.json) | Default component and layout catalog |
## Examples
| File | Description |
|------|-------------|
| [examples/minimal.application.yaml](./examples/minimal.application.yaml) | Smallest valid app |
| [examples/docs-site.application.yaml](./examples/docs-site.application.yaml) | Full docs site |
| [examples/landing-page.application.yaml](./examples/landing-page.application.yaml) | Zone-based layout |
## Validate locally
```bash
pip install jsonschema pyyaml
pytest tests/unit/test_adp_schemas.py -v
```
## Quick start
```yaml
schemaVersion: 1
apiVersion: adp.io/v1alpha1
kind: Application
metadata:
name: my-app
version: "1.0.0"
spec:
site:
title: "My App"
theme:
preset: zinc
darkMode: true
templates:
docs:
layout: TwoColumnLayout
slots:
main: { type: DocContent }
routes:
- match: "/docs/**"
template: docs
content:
docs:
dir: "./docs"
```
+138
View File
@@ -0,0 +1,138 @@
# PraisonAIUI → ADP Field Mapping
Field-by-field mapping from current `aiui.template.yaml` (`Config` model in `src/praisonaiui/schema/models.py`) to ADP `Application` spec.
**Compatibility:** Flat `aiui.template.yaml` files work with the PraisonAIUI compiler today. ADP envelope format is **planned** — see [implementation-status.md](./implementation-status.md).
---
## Envelope (new in ADP)
| ADP field | PraisonAIUI today | Status | Change |
|-----------|-------------------|--------|--------|
| `schemaVersion: 1` | `schemaVersion: 1` | Implemented | Compatible |
| `apiVersion: adp.io/v1alpha1` | Not present | Planned | Add when envelope parser lands |
| `kind: Application` | Not present | Planned | Add when envelope parser lands |
| `metadata.name` | Not present | Planned | Derive from `site.title` slug |
| `metadata.version` | Not present | Planned | Recommend SemVer |
## Top-level → spec wrapper
| PraisonAIUI (flat) | ADP (envelope) | Status | Change |
|--------------------|----------------|--------|--------|
| `site:` | `spec.site:` | Planned | Wrap under `spec` |
| `site.theme` | `spec.theme:` | Planned | Promote theme to spec level |
| `navigation:` | `spec.navigation:` | Partial | Tabs compiled; not rendered |
| `navbar:` | `spec.navbar:` | Partial | Compiled; not rendered |
| `footer:` | `spec.footer:` | Partial | Compiled; not rendered |
| `search:` | `spec.search:` | Partial | Compiled; not rendered |
| `content:` | `spec.content:` | Implemented | Same |
| `components:` | `spec.components:` | Implemented | Same |
| `templates:` | `spec.templates:` | Implemented | Same |
| `routes:` | `spec.routes:` | Partial | Compiled; routing not honoured |
| `dependencies:` | `spec.dependencies:` | Implemented | Same |
| `logo:` (top-level) | Future ADP field | Implemented | Top-level on `Config`, not under `site` |
| `style:`, `chat:`, `auth:`, `dashboard:` | Not in ADP v1alpha1 | N/A | Separate kinds in future |
## Navigation fields
| Field | PraisonAIUI | ADP | Status | Notes |
|-------|-------------|-----|--------|-------|
| `navigation.tabs[]` | Mintlify-style tabs | `spec.navigation.tabs` | Partial | Compiled, not rendered |
| `content.docs.nav.mode` | `NavConfig.mode` | Same | Gap | Defined but unused by compiler |
| Top-level `navigation.mode` | Not present | Removed from ADP | N/A | Use `content.docs.nav.mode` instead |
## Theme fields
| Field | PraisonAIUI | ADP | Status |
|-------|-------------|-----|--------|
| `site.theme.preset` | Implemented | `spec.theme.preset` | Planned (envelope) |
| `site.theme.radius` | Implemented | Same | Same |
| `site.theme.darkMode` | Implemented | Same | Same |
| `theme.tokens` | Not present | DTCG file ref | Planned |
## Component fields
| Field | PraisonAIUI | ADP | Status |
|-------|-------------|-----|--------|
| `components.{id}.type` | String literal | Catalog allowlist | Planned (R6) |
| `components.{id}.props` | `dict[str, Any]` | Catalog schema | Planned (R7) |
## Template fields
| Field | PraisonAIUI | ADP | Status |
|-------|-------------|-----|--------|
| `templates.{id}.layout` | String | Catalog enum | Same values |
| `templates.{id}.slots` | `{ ref \| type }` | Same | Same |
| `templates.{id}.zones` | Widget arrays | Same | Same |
| Slots + zones on same template | Allowed | R13: one or the other | Stricter in ADP |
## Route fields
| Field | PraisonAIUI | ADP | Status |
|-------|-------------|-----|--------|
| `routes[].match` | Glob string | Same | Same |
| `routes[].template` | Template key | Same | Same |
| Runtime route resolution | Not implemented | R28 required | Gap |
## Migration example
### Today (PraisonAIUI)
```yaml
schemaVersion: 1
site:
title: "My Docs"
theme:
preset: zinc
templates:
docs:
layout: TwoColumnLayout
slots:
main: { type: DocContent }
routes:
- match: "/docs/**"
template: docs
```
### Target (ADP)
```yaml
schemaVersion: 1
apiVersion: adp.io/v1alpha1
kind: Application
metadata:
name: my-docs
version: "1.0.0"
spec:
site:
title: "My Docs"
theme:
preset: zinc
templates:
docs:
layout: TwoColumnLayout
slots:
main: { type: DocContent }
routes:
- match: "/docs/**"
template: docs
content:
docs:
dir: "./docs"
```
## Breaking vs compatible changes
| Change | Breaking? | Mitigation |
|--------|-----------|------------|
| Add envelope fields | No | Envelope parser normalises to flat `Config` |
| Catalog validation | Soft break | Warn first, error in strict mode |
| Route runtime resolution | No (fix) | Frontend change |
| R13 slots/zones exclusivity | Soft break | Warn on violation |
| Remove chat/dashboard from ADP | No | Separate kinds in future |
@@ -0,0 +1,128 @@
{
"name": "adp-default-catalog",
"version": "1.0.0",
"description": "Default ADP component and layout catalog for PraisonAIUI",
"components": {
"Header": {
"description": "Site header with logo and navigation",
"props": {
"type": "object",
"properties": {
"logoText": { "type": "string" },
"logoHref": { "type": "string", "default": "/" }
},
"required": ["logoText"],
"additionalProperties": false
},
"aria": { "role": "banner" },
"slots": ["header"]
},
"Footer": {
"description": "Site footer",
"props": {
"type": "object",
"properties": {
"text": { "type": "string" }
},
"additionalProperties": false
},
"aria": { "role": "contentinfo" },
"slots": ["footer"]
},
"DocsSidebar": {
"description": "Documentation sidebar navigation",
"props": {
"type": "object",
"properties": {
"source": { "type": "string", "enum": ["docs-nav", "manual"], "default": "docs-nav" }
},
"additionalProperties": false
},
"aria": { "role": "navigation" },
"slots": ["left", "leftSidebar"]
},
"DocContent": {
"description": "Main documentation content area",
"props": { "type": "object", "additionalProperties": false },
"aria": { "role": "main" },
"slots": ["main"]
},
"Toc": {
"description": "Table of contents for current page",
"props": { "type": "object", "additionalProperties": false },
"aria": { "role": "navigation" },
"slots": ["right", "rightSidebar"]
},
"HeroBanner": {
"description": "Hero banner with title and CTA",
"props": {
"type": "object",
"properties": {
"title": { "type": "string" },
"subtitle": { "type": "string" },
"ctaLabel": { "type": "string" },
"ctaHref": { "type": "string" }
},
"required": ["title"],
"additionalProperties": false
},
"slots": ["hero"]
},
"SocialLinks": {
"description": "Social media link row",
"props": {
"type": "object",
"properties": {
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"platform": { "type": "string" },
"href": { "type": "string" }
},
"required": ["platform", "href"],
"additionalProperties": false
}
}
},
"additionalProperties": false
},
"slots": ["footer"]
},
"Copyright": {
"description": "Copyright notice",
"props": {
"type": "object",
"properties": {
"text": { "type": "string" }
},
"required": ["text"],
"additionalProperties": false
},
"slots": ["footer"]
}
},
"layouts": {
"ThreeColumnLayout": {
"description": "Header + left sidebar + main + right TOC + footer",
"slots": ["header", "left", "main", "right", "footer"]
},
"TwoColumnLayout": {
"description": "Sidebar + main content",
"slots": ["left", "main"]
},
"CenteredLayout": {
"description": "Centred single column",
"slots": ["main"]
},
"FullWidthLayout": {
"description": "Full-width content",
"slots": ["header", "main", "footer"]
},
"FlexibleLayout": {
"description": "WordPress-style zone grid",
"zones": ["header", "topNav", "hero", "leftSidebar", "main", "rightSidebar", "bottomNav", "footer"]
}
}
}
@@ -0,0 +1,104 @@
schemaVersion: 1
apiVersion: adp.io/v1alpha1
kind: Application
metadata:
name: praisonaiui-docs
version: "1.0.0"
labels:
generator: praisonaiui
spec:
site:
title: "PraisonAIUI Docs"
description: "Documentation for PraisonAIUI - YAML-driven website generator"
ui: shadcn
theme:
preset: zinc
radius: md
darkMode: true
navigation:
tabs:
- tab: "Documentation"
groups:
- group: "Getting Started"
icon: rocket
prefix: getting-started
pages:
- index
- getting-started/installation
- getting-started/quickstart
- group: "Core Concepts"
icon: lightbulb
prefix: concepts
pages:
- concepts/architecture
- concepts/configuration
- concepts/templates
- tab: "API Reference"
groups:
- group: "API Reference"
icon: code
prefix: api
pages:
- api/cli
- api/python
navbar:
primary:
type: github
href: "https://github.com/MervinPraison/PraisonAIUI"
links:
- label: "Submit Issues"
href: "https://github.com/MervinPraison/PraisonAIUI/issues"
footer:
socials:
github: "https://github.com/MervinPraison/PraisonAI"
links:
- header: "Resources"
items:
- label: "GitHub"
href: "https://github.com/MervinPraison/PraisonAI"
search:
enabled: true
provider: fusejs
content:
docs:
dir: "./docs"
include:
- "**/*.md"
- "**/*.mdx"
nav:
mode: manual
components:
header_main:
type: Header
props:
logoText: "PraisonAIUI"
footer_main:
type: Footer
props:
text: "© 2026 PraisonAI"
sidebar_docs:
type: DocsSidebar
props:
source: docs-nav
templates:
docs:
layout: ThreeColumnLayout
slots:
header: { ref: header_main }
left: { ref: sidebar_docs }
main: { type: DocContent }
footer: { ref: footer_main }
routes:
- match: "/docs/**"
template: docs
@@ -0,0 +1,58 @@
schemaVersion: 1
apiVersion: adp.io/v1alpha1
kind: Application
metadata:
name: colorful-landing
version: "1.0.0"
spec:
site:
title: "Colorful Docs"
description: "Zone-based landing page with hero and footer widgets"
ui: shadcn
theme:
preset: rose
radius: xl
darkMode: true
content:
docs:
dir: "./docs"
nav:
mode: auto
collapsible: true
templates:
docs:
layout: FlexibleLayout
zones:
hero:
- type: HeroBanner
props:
title: "Colorful Documentation"
subtitle: "Vibrant, playful, and beautifully designed"
ctaLabel: "Get Started"
ctaHref: "/docs/getting-started/quickstart"
rightSidebar:
- type: Toc
footer:
- type: SocialLinks
props:
links:
- platform: Twitter
href: "https://twitter.com"
- platform: GitHub
href: "https://github.com"
- type: Copyright
props:
text: "Made with love by Colorful Team"
routes:
- match: "/docs/**"
template: docs
a11y:
skipToContent: true
reduceMotion: false
@@ -0,0 +1,32 @@
schemaVersion: 1
apiVersion: adp.io/v1alpha1
kind: Application
metadata:
name: minimal-docs
version: "1.0.0"
spec:
site:
title: "Minimal Docs"
description: "Smallest valid ADP Application manifest"
ui: shadcn
theme:
preset: zinc
radius: md
darkMode: true
content:
docs:
dir: "./docs"
templates:
docs:
layout: TwoColumnLayout
slots:
main: { type: DocContent }
routes:
- match: "/docs/**"
template: docs
@@ -0,0 +1,36 @@
# ADP Implementation Status
Honest status of ADP v1alpha1 features against the PraisonAIUI reference implementation.
**Last updated:** August 2026
| Feature | Spec reference | Status | Notes |
|---------|----------------|--------|-------|
| JSON Schema validation in CLI | spec §6 | Planned | Schemas published; no `aiui validate --adp` yet |
| ADP envelope parsing (`apiVersion/kind/spec`) | spec §3 | Planned | Flat `aiui.template.yaml` works today |
| Component catalog validation (R6–R7) | spec §5 | Planned | Catalog split to `catalogs/default.catalog.json` |
| `$yaml:` / `$json:` file includes | spec §7 | Planned | Not implemented in compiler |
| Strict mode unknown-field rejection (R4) | validation-rules R4 | Planned | Pydantic allows extra fields on some models |
| Route-driven template resolution (R28) | validation-rules R28 | Gap | Frontend hardcodes `templates.docs` |
| Sidebar nav mode (R29) | validation-rules R29 | Gap | Filesystem-only sidebar today |
| Catalog ARIA roles at render (R30) | validation-rules R30 | Gap | No catalog-driven a11y in renderer |
| `navigation.tabs` rendering | spec §4.3 | Gap | Compiled to manifest but not consumed by React |
| DTCG token file validation (R26) | validation-rules R26 | Planned | Preset shorthand works via Tailwind |
| Published `$schema` URLs | README | Partial | Local schemas only; `https://adp.io/` is placeholder |
## What works today
- Flat `aiui.template.yaml` → Pydantic `Config` → compiler → JSON manifests → React SPA
- Components, templates, routes, theme presets, content scanning
- ADP example manifests validate against `application.schema.json` (standalone)
- Unit tests in `tests/unit/test_adp_schemas.py`
## Migration path
1. Add envelope normalisation layer before `Config.model_validate`
2. Wire `route-manifest.json` into frontend routing (R28)
3. Honour `navigation.tabs` and `content.docs.nav.mode` (R29)
4. Add `aiui validate --schema adp` using published JSON Schema
5. Apply catalog ARIA hints at render time (R30)
See [aiui-mapping.md](./aiui-mapping.md) for field-level compatibility.
@@ -0,0 +1,449 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "application.schema.json",
"title": "ADP Application",
"description": "Application Design Protocol — Application kind manifest",
"type": "object",
"required": ["schemaVersion", "apiVersion", "kind", "metadata", "spec"],
"additionalProperties": false,
"patternProperties": {
"^x-adp-": {}
},
"properties": {
"schemaVersion": {
"type": "integer",
"const": 1,
"description": "ADP envelope version"
},
"apiVersion": {
"type": "string",
"const": "adp.io/v1alpha1"
},
"kind": {
"type": "string",
"const": "Application"
},
"metadata": {
"type": "object",
"required": ["name"],
"additionalProperties": false,
"patternProperties": {
"^x-adp-": {}
},
"properties": {
"name": { "type": "string", "minLength": 1 },
"version": { "type": "string" },
"labels": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"annotations": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
},
"spec": {
"type": "object",
"required": ["site", "templates", "routes"],
"additionalProperties": false,
"patternProperties": {
"^x-adp-": {}
},
"properties": {
"site": { "$ref": "#/$defs/site" },
"theme": { "$ref": "#/$defs/theme" },
"navigation": { "$ref": "#/$defs/navigation" },
"navbar": { "$ref": "#/$defs/navbar" },
"footer": { "$ref": "#/$defs/footer" },
"search": { "$ref": "#/$defs/search" },
"components": { "$ref": "#/$defs/components" },
"templates": { "$ref": "#/$defs/templates" },
"routes": { "$ref": "#/$defs/routes" },
"content": { "$ref": "#/$defs/content" },
"dependencies": { "$ref": "#/$defs/dependencies" },
"seo": { "$ref": "#/$defs/seo" },
"i18n": { "$ref": "#/$defs/i18n" },
"a11y": { "$ref": "#/$defs/a11y" }
}
}
},
"$defs": {
"site": {
"type": "object",
"required": ["title"],
"additionalProperties": false,
"patternProperties": {
"^x-adp-": {}
},
"properties": {
"title": { "type": "string" },
"description": { "type": "string" },
"ui": {
"type": "string",
"enum": ["shadcn", "mui", "chakra"],
"default": "shadcn"
},
"routeBaseDocs": { "type": "string", "default": "/docs" },
"customCss": { "type": "string" },
"plugins": {
"type": "array",
"items": { "type": "string" }
}
}
},
"theme": {
"oneOf": [
{
"title": "Preset theme",
"type": "object",
"additionalProperties": false,
"properties": {
"preset": {
"type": "string",
"enum": [
"zinc", "slate", "stone", "gray", "neutral",
"red", "orange", "amber", "yellow", "lime", "green",
"emerald", "teal", "cyan", "sky", "blue", "indigo",
"violet", "purple", "fuchsia", "pink", "rose"
]
},
"radius": {
"type": "string",
"enum": ["none", "sm", "md", "lg", "xl"]
},
"darkMode": { "type": "boolean" }
},
"required": ["preset"]
},
{
"title": "DTCG token reference",
"type": "object",
"additionalProperties": false,
"properties": {
"tokens": {
"type": "string",
"description": "Path or URL to DTCG 2025.10 compliant tokens.json"
},
"darkMode": { "type": "boolean" }
},
"required": ["tokens"]
}
]
},
"slotRef": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"required": ["ref"],
"additionalProperties": false,
"properties": {
"ref": { "type": "string" }
}
},
{
"type": "object",
"required": ["type"],
"additionalProperties": false,
"properties": {
"type": { "type": "string" },
"props": {
"type": "object",
"additionalProperties": true
}
}
}
]
},
"widget": {
"type": "object",
"required": ["type"],
"additionalProperties": false,
"properties": {
"type": { "type": "string" },
"props": {
"type": "object",
"additionalProperties": true
}
}
},
"components": {
"type": "object",
"additionalProperties": {
"type": "object",
"required": ["type"],
"additionalProperties": false,
"properties": {
"type": { "type": "string" },
"props": {
"type": "object",
"additionalProperties": true
}
}
}
},
"template": {
"type": "object",
"required": ["layout"],
"allOf": [
{
"oneOf": [
{ "required": ["slots"] },
{ "required": ["zones"] }
]
}
],
"additionalProperties": false,
"properties": {
"layout": {
"type": "string",
"enum": [
"ThreeColumnLayout",
"TwoColumnLayout",
"CenteredLayout",
"FullWidthLayout",
"FlexibleLayout"
]
},
"slots": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/slotRef" }
},
"zones": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": { "$ref": "#/$defs/widget" }
}
}
}
},
"templates": {
"type": "object",
"minProperties": 1,
"additionalProperties": { "$ref": "#/$defs/template" }
},
"route": {
"type": "object",
"required": ["match", "template"],
"additionalProperties": false,
"properties": {
"match": { "type": "string" },
"template": { "type": "string" },
"slots": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/slotRef" }
}
}
},
"routes": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/route" }
},
"navGroup": {
"type": "object",
"required": ["group"],
"additionalProperties": false,
"properties": {
"group": { "type": "string" },
"icon": { "type": "string" },
"prefix": { "type": "string" },
"pages": {
"type": "array",
"items": { "type": "string" }
}
}
},
"navTab": {
"type": "object",
"required": ["tab"],
"additionalProperties": false,
"properties": {
"tab": { "type": "string" },
"url": { "type": "string" },
"groups": {
"type": "array",
"items": { "$ref": "#/$defs/navGroup" }
}
}
},
"navigation": {
"type": "object",
"additionalProperties": false,
"properties": {
"tabs": {
"type": "array",
"items": { "$ref": "#/$defs/navTab" }
}
}
},
"navbar": {
"type": "object",
"additionalProperties": false,
"properties": {
"primary": {
"type": "object",
"additionalProperties": false,
"properties": {
"type": { "type": "string", "enum": ["button", "github"] },
"label": { "type": "string" },
"href": { "type": "string" }
}
},
"links": {
"type": "array",
"items": {
"type": "object",
"required": ["label", "href"],
"additionalProperties": false,
"properties": {
"label": { "type": "string" },
"href": { "type": "string" }
}
}
}
}
},
"footer": {
"type": "object",
"additionalProperties": false,
"properties": {
"socials": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"links": {
"type": "array",
"items": {
"type": "object",
"required": ["header"],
"additionalProperties": false,
"properties": {
"header": { "type": "string" },
"items": {
"type": "array",
"items": {
"type": "object",
"required": ["label", "href"],
"additionalProperties": false,
"properties": {
"label": { "type": "string" },
"href": { "type": "string" }
}
}
}
}
}
}
}
},
"search": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": { "type": "boolean" },
"provider": {
"type": "string",
"enum": ["fusejs", "lunrjs", "pagefind"]
}
}
},
"dependencies": {
"type": "object",
"additionalProperties": false,
"properties": {
"shadcn": {
"type": "array",
"items": { "type": "string" }
}
}
},
"contentSource": {
"type": "object",
"required": ["dir"],
"additionalProperties": false,
"properties": {
"dir": { "type": "string" },
"include": {
"type": "array",
"items": { "type": "string" }
},
"exclude": {
"type": "array",
"items": { "type": "string" }
},
"indexFiles": {
"type": "array",
"items": { "type": "string" }
},
"nav": {
"type": "object",
"additionalProperties": false,
"properties": {
"mode": { "type": "string", "enum": ["auto", "manual"] },
"sort": { "type": "string", "enum": ["filesystem", "alpha", "date"] },
"collapsible": { "type": "boolean" },
"maxDepth": { "type": "integer", "minimum": 1, "maximum": 10 }
},
"allOf": [
{
"if": {
"properties": { "mode": { "const": "manual" } },
"required": ["mode"]
},
"then": {
"description": "Manual sidebar mode requires navigation.tabs at spec level"
}
}
]
}
}
},
"content": {
"type": "object",
"additionalProperties": false,
"properties": {
"docs": { "$ref": "#/$defs/contentSource" },
"blog": { "$ref": "#/$defs/contentSource" }
}
},
"seo": {
"type": "object",
"additionalProperties": false,
"properties": {
"titleTemplate": { "type": "string" },
"defaultImage": { "type": "string" },
"twitter": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
},
"i18n": {
"type": "object",
"additionalProperties": false,
"properties": {
"defaultLocale": { "type": "string" },
"locales": { "type": "array", "items": { "type": "string" } },
"rtlLocales": { "type": "array", "items": { "type": "string" } },
"fallbackLocale": { "type": "string" },
"translationsDir": { "type": "string" }
}
},
"a11y": {
"type": "object",
"additionalProperties": false,
"properties": {
"skipToContent": { "type": "boolean" },
"focusVisible": { "type": "boolean" },
"reduceMotion": { "type": "boolean" },
"ariaLabels": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "component-catalog.schema.json",
"title": "ADP Component Catalog",
"description": "Allowlisted component types for ADP Application manifests",
"type": "object",
"required": ["name", "version", "components"],
"additionalProperties": false,
"patternProperties": {
"^x-adp-": {}
},
"properties": {
"name": { "type": "string" },
"version": { "type": "string" },
"description": { "type": "string" },
"components": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/componentType" }
},
"layouts": {
"type": "object",
"additionalProperties": { "$ref": "#/$defs/layoutType" }
}
},
"$defs": {
"componentType": {
"type": "object",
"required": ["description", "props"],
"additionalProperties": false,
"properties": {
"description": { "type": "string" },
"props": { "type": "object" },
"aria": {
"type": "object",
"additionalProperties": false,
"properties": {
"role": { "type": "string" },
"label": { "type": "string" }
}
},
"slots": {
"type": "array",
"items": { "type": "string" }
},
"deprecated": { "type": "boolean" },
"x-sunset": { "type": "string", "format": "date" }
}
},
"layoutType": {
"oneOf": [
{
"title": "Slot-based layout",
"type": "object",
"required": ["description", "slots"],
"additionalProperties": false,
"properties": {
"description": { "type": "string" },
"slots": {
"type": "array",
"items": { "type": "string" },
"minItems": 1
}
}
},
{
"title": "Zone-based layout",
"type": "object",
"required": ["description", "zones"],
"additionalProperties": false,
"properties": {
"description": { "type": "string" },
"zones": {
"type": "array",
"items": { "type": "string" },
"minItems": 1
}
}
}
]
}
}
}
@@ -0,0 +1,47 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "theme.schema.json",
"title": "ADP Theme",
"description": "Theme configuration — preset shorthand or DTCG 2025.10 token reference",
"oneOf": [
{
"title": "Preset theme",
"type": "object",
"additionalProperties": false,
"properties": {
"preset": {
"type": "string",
"enum": [
"zinc", "slate", "stone", "gray", "neutral",
"red", "orange", "amber", "yellow", "lime", "green",
"emerald", "teal", "cyan", "sky", "blue", "indigo",
"violet", "purple", "fuchsia", "pink", "rose"
]
},
"radius": {
"type": "string",
"enum": ["none", "sm", "md", "lg", "xl"],
"default": "md"
},
"darkMode": {
"type": "boolean",
"default": true
}
},
"required": ["preset"]
},
{
"title": "DTCG token reference",
"type": "object",
"additionalProperties": false,
"properties": {
"tokens": {
"type": "string",
"description": "Path or URL to DTCG 2025.10 compliant tokens.json"
},
"darkMode": { "type": "boolean" }
},
"required": ["tokens"]
}
]
}
+314
View File
@@ -0,0 +1,314 @@
# Application Design Protocol (ADP) — Normative Specification
**Version:** v1alpha1 (draft)
**Status:** Draft — not yet normative
**Date:** August 2026
This document uses [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119) keywords: MUST, MUST NOT, SHOULD, MAY.
---
## 1. Scope
ADP defines a declarative format for describing **application UI design**: site metadata, theming, navigation, reusable components, page templates, and URL routing. It does NOT define:
- Server-side APIs or data models
- Agent orchestration or workflow graphs
- Infrastructure or deployment configuration
- Executable code or templating logic in manifests
Implementations MUST treat ADP manifests as **data**, not code.
---
## 2. Terminology
| Term | Definition |
|------|------------|
| **Manifest** | A YAML or JSON document conforming to this spec |
| **Application** | The root `kind: Application` manifest describing a complete UI |
| **Component** | A named, reusable UI block with a `type` and `props` |
| **Template** | A layout definition assigning components to slots or zones |
| **Slot** | A named region within a layout (e.g. `header`, `main`) |
| **Zone** | An ordered list of widgets in a slot (WordPress-style) |
| **Route** | A URL pattern mapping to a template |
| **Catalog** | Published JSON Schema defining allowed component types |
| **Compiler** | Tool that validates and emits runtime JSON manifests |
| **Renderer** | Runtime that consumes compiled manifests and renders UI |
---
## 3. Document envelope
Every ADP manifest MUST include:
```yaml
schemaVersion: 1 # Integer; ADP envelope version
apiVersion: adp.io/v1alpha1
kind: Application # Application | Theme | ComponentCatalog (future)
metadata:
name: string # Required; unique identifier
version: string # SHOULD use SemVer
labels: object # MAY contain key-value pairs
annotations: object # MAY contain tooling metadata
spec: object # Required; kind-specific payload
```
### 3.1 Versioning policy
- `schemaVersion` — integer bumped on breaking envelope changes
- `apiVersion` — string group/version (e.g. `adp.io/v1alpha1`, `adp.io/v1`)
- `metadata.version` — application SemVer (independent of protocol version)
- Breaking changes MUST increment `apiVersion` (e.g. v1alpha1 → v1)
- Deprecated fields MUST include `deprecated: true` and SHOULD include `x-sunset` date
### 3.2 Authoring formats
Manifests MAY be authored as YAML (`.application.yaml`) or JSON (`.application.json`). Semantics MUST be identical. Runtimes MUST NOT consume YAML directly; compilers MUST normalise to JSON before validation.
---
## 4. Application spec
An `Application` spec MUST contain at minimum:
| Field | Required | Description |
|-------|----------|-------------|
| `site.title` | YES | Application display name |
| `templates` | YES | At least one template |
| `routes` | YES | At least one route |
All other fields are OPTIONAL.
### 4.1 Site (`spec.site`)
```yaml
site:
title: string # Required
description: string # Optional
ui: shadcn # UI framework hint; default shadcn
routeBaseDocs: /docs # Base path for documentation routes
```
### 4.2 Theme (`spec.theme`)
Theme MAY use preset shorthand or reference a DTCG token file:
```yaml
theme:
preset: zinc # Tailwind-style preset name
radius: md # none | sm | md | lg | xl
darkMode: true
# OR
tokens: $yaml: ./theme.tokens.json # DTCG 2025.10 file
```
### 4.3 Navigation
ADP separates **top tab bar** from **sidebar source**:
```yaml
navigation:
tabs: # Top tab bar (Mintlify-style)
- tab: Documentation
groups:
- group: Getting Started
pages: [index, getting-started/installation]
content:
docs:
dir: ./docs
nav:
mode: auto # auto | manual — sidebar source
sort: filesystem
collapsible: true
maxDepth: 4
```
- **`navigation.tabs`** — top-level tab bar with grouped pages
- **`content.docs.nav.mode: auto`** — sidebar generated from filesystem scan
- **`content.docs.nav.mode: manual`** — sidebar driven by `navigation.tabs` groups
- Renderers MUST honour `content.docs.nav.mode` when building sidebar (R29)
### 4.4 Components (`spec.components`)
```yaml
components:
header_main:
type: Header # MUST exist in component catalog
props:
logoText: PraisonAIUI
```
Rules:
- Component IDs MUST be unique within the manifest
- `type` MUST match an entry in the published component catalog
- `props` MUST validate against the catalog JSON Schema for that type
### 4.5 Templates (`spec.templates`)
```yaml
templates:
docs:
layout: ThreeColumnLayout
slots:
header: { ref: header_main }
left: { ref: sidebar_docs }
main: { type: DocContent }
right: null # Explicitly hide slot
landing:
layout: FlexibleLayout
zones:
hero:
- type: HeroBanner
props: { title: "Welcome" }
```
Rules:
- `layout` MUST be a known layout type in the catalog
- Each slot value MUST be `{ ref: id }`, `{ type: ComponentType }`, or `null`
- Zones MUST use zone names valid for `FlexibleLayout`
- A template MUST declare either `slots` or `zones`, not both (R13)
### 4.6 Routes (`spec.routes`)
```yaml
routes:
- match: /docs/changelog
template: changelog
slots: # Optional per-route slot overrides
right: null
- match: /docs/**
template: docs
```
Rules:
- Routes MUST be ordered most-specific-first
- `match` MUST be a glob pattern
- `template` MUST reference a key in `spec.templates`
- Renderers MUST resolve routes at runtime using compiled `route-manifest.json`
### 4.7 Content (`spec.content`)
```yaml
content:
docs:
dir: ./docs
include: ["**/*.md", "**/*.mdx"]
exclude: []
nav:
mode: auto
sort: filesystem
collapsible: true
maxDepth: 4
```
---
## 5. Component catalog
Implementations MUST publish a `component-catalog.schema.json` (meta-schema) and a catalog instance such as [`catalogs/default.catalog.json`](./catalogs/default.catalog.json):
```json
{
"name": "adp-default-catalog",
"version": "1.0.0",
"components": {
"Header": {
"description": "Site header with logo and navigation",
"props": {
"type": "object",
"properties": { "logoText": { "type": "string" } },
"required": ["logoText"],
"additionalProperties": false
},
"aria": { "role": "banner" },
"slots": ["header"]
}
},
"layouts": {
"ThreeColumnLayout": {
"description": "Header + sidebar + main + TOC + footer",
"slots": ["header", "left", "main", "right", "footer"]
}
}
}
```
Custom component types MUST be registered via plugin schema layers. Unknown types MUST cause validation failure in strict mode.
---
## 6. Compilation pipeline
A conforming compiler MUST:
1. Parse YAML or JSON manifest
2. Normalise to JSON
3. Validate against `application.schema.json` (JSON Schema 2020-12)
4. Validate cross-reference rules (see [validation-rules.md](./validation-rules.md))
5. Validate component props against catalog schema
6. Emit runtime manifests:
- `ui-config.json` — site, components, templates, theme, navigation
- `route-manifest.json` — ordered routes with template refs
- `docs-nav.json` — filesystem-derived navigation (if mode auto)
---
## 7. File composition
Manifests MAY include external files using Backstage-style placeholders:
```yaml
theme:
$yaml: ./theme.yaml
navigation:
$yaml: ./navigation.yaml
```
Rules:
- Paths MUST be relative to the containing manifest
- Path traversal (`../../`) MUST be rejected
- Supported placeholders: `$yaml:`, `$json:`, `$text:`
---
## 8. Extensions
Vendor extensions MUST use the `x-adp-` prefix:
```yaml
spec:
site:
x-adp-customAnalytics: true
```
Implementations MUST preserve unknown `x-adp-*` fields. Non-prefixed unknown fields MUST be rejected in strict mode.
---
## 9. Conformance
An implementation is **ADP-conformant** if and only if it:
1. Accepts manifests with `apiVersion: adp.io/v1alpha1` and `kind: Application`
2. Validates all MUST-level requirements in this spec and validation-rules.md
3. Rejects manifests with unknown fields in strict mode
4. Emits runtime JSON manifests from valid Application specs
5. Resolves routes to templates at render time
---
## 10. Related documents
- [Research report](../application-design-protocol-report.md)
- [Implementation status](./implementation-status.md)
- [PraisonAIUI mapping](./aiui-mapping.md)
- [JSON Schema: application](./schema/application.schema.json)
- [JSON Schema: component catalog](./schema/component-catalog.schema.json)
- [JSON Schema: theme](./schema/theme.schema.json)
- [Examples](./examples/)
+115
View File
@@ -0,0 +1,115 @@
# ADP Validation Rules
Cross-reference validation rules for Application Design Protocol manifests. These constraints cannot be expressed in JSON Schema alone and MUST be enforced by conforming compilers.
Rules use RFC 2119 keywords: MUST, MUST NOT, SHOULD, MAY.
Inspired by AWP validation rules R1–R32 pattern.
---
## Envelope rules
| Rule | Level | Description |
|------|-------|-------------|
| **R1** | MUST | `schemaVersion` MUST equal `1` for `apiVersion: adp.io/v1alpha1` |
| **R2** | MUST | `kind` MUST be `Application` for root manifests |
| **R3** | MUST | `metadata.name` MUST be unique within a deployment scope |
| **R4** | MUST NOT | Unknown top-level fields outside `x-adp-*` namespace in strict mode |
## Component rules
| Rule | Level | Description |
|------|-------|-------------|
| **R5** | MUST | Every `spec.components` entry MUST have a unique ID |
| **R6** | MUST | Every component `type` MUST exist in the published component catalog |
| **R7** | MUST | Component `props` MUST validate against catalog JSON Schema for that type |
| **R8** | MUST NOT | A component ID be referenced by `ref:` unless it exists in `spec.components` |
| **R9** | SHOULD | Unused components (defined but never referenced) SHOULD emit a warning |
## Template rules
| Rule | Level | Description |
|------|-------|-------------|
| **R10** | MUST | Every `spec.templates` entry MUST declare a valid `layout` from the catalog |
| **R11** | MUST | Slot names in `templates.*.slots` MUST be valid for the declared layout |
| **R12** | MUST | Zone names in `templates.*.zones` MUST be valid for `FlexibleLayout` |
| **R13** | MUST | Each template MUST declare either `slots` or `zones`, not both |
| **R14** | MUST | Inline slot `{ type: X }` types MUST exist in the component catalog |
| **R15** | MUST | Slot `{ ref: id }` MUST resolve to a component in `spec.components` |
## Route rules
| Rule | Level | Description |
|------|-------|-------------|
| **R16** | MUST | Every route `template` MUST reference a key in `spec.templates` |
| **R17** | MUST | Routes MUST be ordered most-specific-first (longer/more precise patterns before wildcards) |
| **R18** | MUST | Route slot overrides MUST use valid slot names for the target template's layout |
| **R19** | SHOULD | At least one route SHOULD match the site root or docs base path |
## Content and navigation rules
| Rule | Level | Description |
|------|-------|-------------|
| **R20** | MUST | If `content.docs.dir` is declared, the directory MUST exist at compile time |
| **R21** | MUST | If `content.docs.nav.mode` is `manual`, `navigation.tabs` MUST be non-empty |
| **R22** | SHOULD | If `content.docs.nav.mode` is `auto`, a content source MUST be declared |
Navigation model:
- **`navigation.tabs`** — top tab bar (Mintlify-style)
- **`content.docs.nav.mode`** — sidebar source: `auto` (filesystem scan) or `manual` (use `navigation.tabs` groups)
## File include rules
| Rule | Level | Description |
|------|-------|-------------|
| **R23** | MUST NOT | `$yaml:`, `$json:`, or `$text:` paths traverse outside the project root |
| **R24** | MUST | Included files MUST parse as valid YAML/JSON/text respectively |
| **R25** | MUST NOT | Circular file includes (A includes B includes A) |
## Theme rules
| Rule | Level | Description |
|------|-------|-------------|
| **R26** | MUST | If `theme.tokens` is declared, the referenced file MUST exist and validate against DTCG 2025.10 |
| **R27** | MUST NOT | Both `theme.preset` and `theme.tokens` be declared simultaneously |
## Renderer conformance (target — not yet implemented in PraisonAIUI)
These rules define the target behaviour for ADP-conformant renderers. See [implementation-status.md](./implementation-status.md).
| Rule | Level | Description |
|------|-------|-------------|
| **R28** | MUST | Renderers MUST resolve the active template from `route-manifest.json` at runtime |
| **R29** | MUST | Renderers MUST honour `content.docs.nav.mode` when building sidebar |
| **R30** | MUST | Renderers MUST apply ARIA roles from catalog for each rendered component |
---
## Validation pipeline order
```
1. Parse YAML/JSON
2. Resolve $yaml/$json/$text includes (R23–R25)
3. JSON Schema validate (application.schema.json)
4. Cross-ref rules R1–R27
5. Component props validate against catalog (R6–R7)
6. Emit runtime manifests
7. Runtime conformance R28–R30 (renderer responsibility)
```
## Error format
Validation failures MUST report:
```json
{
"rule": "R8",
"path": "spec.templates.docs.slots.header.ref",
"message": "Component ref 'missing_header' not found in spec.components",
"severity": "error"
}
```
Warnings (R9) use `"severity": "warning"`.
@@ -0,0 +1,427 @@
# Application Design Protocol (ADP) — Research Report
**Version:** 1.0 (draft)
**Date:** August 2026
**Scope:** UI, layout, navigation, theming — declarative application design from text manifests
**Status:** Research and recommendation; not yet a published standard
---
## 1. Executive summary
There is no single existing standard for **designing full application UI from a declarative text file**. Instead, the problem is addressed in fragments:
- **Docs-site generators** (Mintlify, PraisonAIUI, Hugo) declare navigation and layout in config files.
- **Form libraries** (JSON Forms, RJSF) declare layout trees from JSON Schema.
- **Agent UI protocols** (A2UI, AG-UI) declare streaming component surfaces for LLM-generated UI.
- **Catalog standards** (OpenUI, Backstage) declare component metadata without runtime layout.
- **Design token standards** (DTCG 2025.10) declare theming without structure.
**Recommendation:** Define an **Application Design Protocol (ADP)** that synthesises proven patterns from 46 surveyed standards into a UI-only manifest format.
PraisonAIUI already implements approximately 60% of this model. ADP formalises, extends, and publishes what exists today.
---
## 2. Problem statement
### 2.1 What we need
A protocol that lets a developer (or LLM) describe an application's visual design — pages, navigation, components, themes, routes — in **one or more text files**, without writing application code.
### 2.2 What exists today (fragmented)
| Need | Who solves it | Gap |
|------|---------------|-----|
| Docs site from config | Mintlify, PraisonAIUI, Docusaurus | No shared spec; Mintlify uses JSON, others use YAML or JS |
| Component catalog | OpenUI, A2UI | No layout or routing |
| Layout trees | JSON Forms uiSchema | Forms only, not app shells |
| Theming | DTCG, Material 3 | Tokens only, no pages |
| Agent-generated UI | A2UI | Runtime streaming, not human-authored static sites |
| Software metadata | Backstage | Catalog entities, not UI composition |
### 2.3 Design goals for ADP
1. **Human-readable** — editable without IDE plugins
2. **LLM-safe** — structural schema rejects unknown fields
3. **Portable** — same manifest renders on any ADP-compliant runtime
4. **Validatable** — fail fast at build time, not in the browser
5. **Extensible** — plugins add catalog entries, not inline code
6. **Accessible** — ARIA hints required in component catalog
---
## 3. Standards landscape — 46 protocols in 10 categories
Each entry describes **how UI/layout/navigation is declared** — the primary comparison dimension.
### Category A: Web platform baseline (5)
| Standard | Format | How UI/layout/navigation is declared | Schema | Versioning |
|----------|--------|--------------------------------------|--------|------------|
| **HTML + CSS** | `.html` + `.css` | Semantic elements; CSS Flexbox/Grid; `<nav>` + links | Living spec grammar | Browser Baseline |
| **Web Components + DSD** | HTML + JS | Custom element tree; slots; Declarative Shadow DOM | DOM IDL | Platform flags |
| **WAI-ARIA + APG** | HTML attributes | Landmarks, widget roles, keyboard patterns | WAI-ARIA 1.2 | Rec track |
| **DTCG Design Tokens** | JSON | Token groups: `$value`, `$type`, `{alias}` refs — **no layout** | DTCG 2025.10 | Date editions |
| **OpenUI** | YAML/JSON | Component catalog: `components{id: props}` — **no layout tree** | Prop definitions | Per-library version |
### Category B: Schema-driven forms and layout (3)
| Standard | Format | How UI/layout/navigation is declared | Schema | Versioning |
|----------|--------|--------------------------------------|--------|------------|
| **JSON Forms** | JSON Schema + UI Schema | `VerticalLayout`, `Control`, `Categorization` with `scope` pointers | JSON Schema + uiSchema | Package SemVer |
| **RJSF** | JSON Schema + uiSchema | Schema-tree mirroring; `ui:widget`, `ui:options` | React convention | Package SemVer |
| **Google A2UI** | JSONL stream | Flat adjacency-list; `createSurface`; catalog-constrained types | JSON Schema catalog | v0.9.1 / v1.0 RC |
### Category C: Docs-site generators (6)
| Standard | Format | How UI/layout/navigation is declared | Schema | Versioning |
|----------|--------|--------------------------------------|--------|------------|
| **Mintlify** | JSON (`docs.json`) | `navigation.groups[].pages[]`; `$schema` URL; `$ref` splitting | Published JSON Schema URL | Platform |
| **PraisonAIUI** | YAML | `components` → `templates{layout, slots, zones}` → `routes` | Pydantic (internal) | `schemaVersion: 1` |
| **Docusaurus** | JS config | `themeConfig.navbar`, plugin sidebar config | TypeScript types | Package SemVer |
| **Hugo** | TOML/YAML | `menu.main[]`, theme selection | Hugo schema | Release train |
| **Jekyll** | YAML | Frontmatter per page; `_data/` nav | Conventions | SemVer |
| **Gatsby** | JS/TS | `siteMetadata` + `plugins[]` | JS object | Major versions |
### Category D: Native declarative UI — reference only (5)
| Standard | Format | Serialised wire format? | Navigation model |
|----------|--------|-------------------------|------------------|
| **Jetpack Compose** | Kotlin | No | `NavHost` + routes |
| **SwiftUI** | Swift | No | `NavigationStack` |
| **Flutter** | Dart | No | `Router` / `Navigator` |
| **Qt QML** | `.qml` | Yes | `StackView`, bindings |
| **XAML** | XML | Yes (dialect-fragmented) | `Frame`, `NavigationView` |
### Category E: Design systems (2)
| Standard | Format | Theming model |
|----------|--------|---------------|
| **Material Design 3** | DTCG JSON | reference → system → component token tiers |
| **Bootstrap 5.3** | SCSS → CSS vars | Sass maps → `--bs-*` custom properties |
### Category F: Design-to-code bridges — not source-of-truth (3)
| Standard | Output | Why not ADP source |
|----------|--------|-------------------|
| **Figma MCP** | React+Tailwind context | Proprietary; bridge only |
| **Webflow export** | HTML/CSS/JS ZIP | No schema; paid export |
| **Framer export** | React bundles | Platform lock-in |
### Category G: Component documentation (1)
| Standard | Format | Navigation |
|----------|--------|------------|
| **Storybook CSF 3** | TS modules | Sidebar via `title` path hierarchy |
### Category H: Configuration and packaging (12)
| Standard | Format | Composition mechanism | ADP borrow |
|----------|--------|----------------------|------------|
| **Kubernetes CRD** | YAML | `apiVersion/kind/spec`; structural OpenAPI | Structural validation |
| **Helm** | YAML + templates | Subcharts; values merge; `values.schema.json` | Defaults + overrides |
| **Backstage catalog** | YAML | `$yaml:`/`$json:` includes; relation graph | Envelope + includes |
| **OpenAPI 3.1** | YAML/JSON | `$ref`, `components` registry | JSON Schema foundation |
| **AsyncAPI 3.x** | YAML/JSON | Channels → messages | Future event UI |
| **JSON Schema 2020-12** | JSON | `$ref`, `$defs`, conditionals | Validation dialect |
| **CloudEvents** | JSON envelope | Fixed envelope + opaque payload | Future event wrapper |
| **Docker Compose** | YAML | Multi-file merge; profiles | Override stacking |
| **CUE** | CUE | Unify schema + data | Power-user compile layer |
| **Jsonnet** | Jsonnet → JSON | `import` + merge | Theme variants |
| **Pkl** | `.pkl` | `amends`, mixins | Typed config model |
| **OCI Artifact** | JSON manifest | Multi-layer blobs | Bundle packaging |
### Category I: Agent and workflow protocols (7)
| Standard | Format | UI/state declaration | ADP borrow |
|----------|--------|---------------------|------------|
| **MCP** | JSON-RPC | Tool schemas — no UI layout | Future widget actions |
| **AG-UI** | Streaming JSON | EventType enum; snapshots + deltas | Streaming model |
| **A2A** | Proto → JSON-RPC | Agent Cards | Transport |
| **AWP** | Multi-file YAML | 7 layers; rules R1–R32 | Layer + validation model |
| **LangGraph** | workflow.yaml | Graph nodes + edges | Layout graph |
| **AutoGen** | ComponentModel JSON | `{provider, type, version, config}` | Pluggable components |
| **CrewAI** | JSONC/YAML | Agent arrays — weak schema | Anti-pattern |
### Category J: Application packaging (2)
| Standard | Format | Application declaration |
|----------|--------|------------------------|
| **OAM** | YAML | `Application` with `components[]`, `traits[]` |
| **CNAB** | bundle.json | Parameters, credentials, actions |
---
## 4. How they do it — mechanism comparison matrix
| Mechanism | Standards | How it works | ADP |
|-----------|-----------|--------------|-----|
| **Envelope document** | K8s, Backstage, OAM, AWP | `apiVersion` + `kind` + `metadata` + `spec` | Adopt |
| **Component registry + ref** | PraisonAIUI, OpenUI | Named map; templates use `ref:` | Adopt |
| **Layout + slots** | PraisonAIUI, JSON Forms | Layout type + named regions | Adopt (unified) |
| **Route → template** | PraisonAIUI, Flutter | URL glob → template | Adopt |
| **Navigation tree** | Mintlify, Storybook | Hierarchical groups → pages | Adopt |
| **Design token file** | DTCG, Material 3 | Token JSON with aliases | Adopt |
| **Catalog allowlist** | A2UI, OpenUI | Closed component vocabulary | Adopt |
| **Schema + uiSchema split** | JSON Forms, RJSF | Data vs presentation | Partial |
| **Streaming surfaces** | A2UI, AG-UI | Incremental JSON updates | Future |
| **Layered spec** | AWP, Helm | Separate files merged at compile | Adopt |
| **File includes** | Backstage, Mintlify | `$yaml:` / `$ref` external files | Adopt |
| **Structural pruning** | K8s CRD | Reject unknown fields | Adopt |
| **Validation rules R1–Rn** | AWP | Cross-ref beyond JSON Schema | Adopt |
| **JS executable config** | Docusaurus, Gatsby | Code config | Reject |
| **Visual canvas** | Figma, Webflow | Proprietary designer | Reject |
| **Code-only UI** | Compose, SwiftUI | No wire format | Out of scope |
---
## 5. Side-by-side: four closest analogues
| Dimension | PraisonAIUI | Mintlify | A2UI | Backstage |
|-----------|-------------|----------|------|-----------|
| **Authoring format** | YAML | JSON | JSON (stream) | YAML |
| **Envelope** | `schemaVersion` only | Flat JSON | Message `version` | `apiVersion/kind/metadata/spec` |
| **Navigation** | `navigation.tabs[]` + filesystem | `navigation.groups[]` | N/A | N/A (metadata catalog) |
| **Components** | `components{id: type, props}` | N/A | Catalog + adjacency list | Entity kinds |
| **Layout** | `templates{layout, slots, zones}` | Theme only | Surfaces | N/A |
| **Routes** | `routes{match, template}` | Page paths in nav | N/A | N/A |
| **Schema published** | Pydantic only | `$schema` URL | JSON Schema catalog | JSON Schema per kind |
| **Runtime** | React SPA | Hosted platform | Any renderer | Catalog API |
| **Primary use** | Docs sites | Docs sites | Agent-generated UI | Software inventory |
**Synthesis:** ADP combines PraisonAIUI's composition model, Mintlify's schema publishing, A2UI's catalog allowlist, and Backstage's envelope and file includes.
---
## 6. YAML vs alternatives — structured debate
### 6.1 The assumption
YAML is the best authoring format for application design manifests.
### 6.2 Counter-evidence
**Mintlify** — the closest commercial docs-site analogue — uses **JSON** (`docs.json`) with a published `$schema` URL for IDE autocomplete. This works well for flat-to-moderately-nested config but becomes verbose for deep layout trees.
**A2UI** uses **JSON** as both authoring and wire format because LLMs emit structured JSON reliably and ambiguity is unacceptable at runtime.
**Docusaurus and Gatsby** use **JavaScript/TypeScript** config for programmatic power — but this sacrifices portability and LLM generation safety.
### 6.3 Format comparison
| Format | Strengths | Weaknesses for ADP |
|--------|-----------|-------------------|
| **YAML** | Comments; readable nesting; LLM-friendly; PraisonAIUI continuity | Ambiguous typing; merge key footguns; no native DRY |
| **JSON** | Unambiguous; `$schema` IDE support; Mintlify-proven | No comments; verbose for layout trees |
| **TOML** | Clear flat tables (Hugo) | Poor for nested templates/zones |
| **CUE / Jsonnet / Pkl** | Typed composition without templating | Learning curve; not LLM-default |
| **HCL** | Modules, expressions | Ecosystem-bound; overkill for UI-only |
| **JS/TS** | Full programmatic power | Not portable; not LLM-safe |
### 6.4 Recommendation
```
Author (human/LLM) → YAML (default) or JSON (alternate)
↓
ADP compiler/validator (JSON Schema 2020-12)
↓
Normalised JSON manifest (runtime)
↓
UI renderer (catalog-constrained)
```
- **Primary authoring:** YAML — best for nested `templates` / `zones` trees
- **Alternate authoring:** JSON — for teams preferring Mintlify-style `$schema` tooling
- **Never at runtime:** YAML — always compile to JSON before serve
- **Composition:** `$yaml:` file includes (Backstage), not Helm Go templates
- **Power users:** Optional CUE/Jsonnet compiles to YAML before validation
**Verdict:** YAML remains the recommended default, but ADP MUST accept JSON as an equivalent authoring format with identical semantics.
---
## 7. ADP design principles
1. **Declarative, not executable** — manifests describe intent; runtimes render; no inline code or templating logic in core spec.
2. **Schema-first** — JSON Schema 2020-12 is canonical; YAML is authoring convenience.
3. **Structural strictness** — unknown fields rejected in strict mode (K8s CRD pattern).
4. **Catalog allowlist** — component `type` must exist in published catalog (A2UI pattern).
5. **Envelope consistency** — every document uses `apiVersion`, `kind`, `metadata`, `spec`.
6. **Separation of concerns** — theme, navigation, components, templates, routes are distinct spec sections.
7. **Compile, don't interpret** — YAML → validated JSON manifest → static assets at build time.
8. **Accessibility by default** — catalog entries include ARIA role hints (WAI-ARIA pattern).
9. **Versioned protocol** — `schemaVersion` integer + `apiVersion` string; breaking changes bump version.
10. **Extension namespace** — `x-adp-*` prefix reserved; plugins register catalog layers.
11. **File composition** — `$yaml:` includes for modular configs (Backstage pattern).
12. **Route-driven rendering** — URL resolution selects template; no hardcoded layout in renderer.
---
## 8. Proposed ADP document model
```yaml
schemaVersion: 1
apiVersion: adp.io/v1alpha1
kind: Application
metadata:
name: my-docs-site
version: "1.0.0"
labels: {}
spec:
site:
title: "My Site"
description: "..."
theme:
preset: zinc # or DTCG token ref
radius: md
darkMode: true
navigation:
mode: auto # auto | manual
tabs: [...]
components:
header_main:
type: Header
props: { logoText: "..." }
templates:
docs:
layout: ThreeColumnLayout
slots:
header: { ref: header_main }
main: { type: DocContent }
routes:
- match: "/docs/**"
template: docs
content:
docs:
dir: "./docs"
```
### Data flow
```
application.yaml → Parse → JSON Schema validate → Cross-ref rules (R1–R30)
→ Compile → ui-config.json + route-manifest.json + docs-nav.json
→ React / static renderer
```
---
## 9. PraisonAIUI alignment and gaps
### Already aligned
| PraisonAIUI today | ADP equivalent |
|-------------------|----------------|
| `schemaVersion: 1` | `schemaVersion` + `apiVersion` |
| `components` + `ref:` | `spec.components` + slot refs |
| `templates.layout` + `slots` | `spec.templates` |
| `routes` | `spec.routes` |
| `site.theme` | `spec.theme` |
| Compiler → JSON manifests | ADP compile pipeline |
| Pydantic validation | JSON Schema + cross-ref rules |
### Gaps to close
| Gap | ADP fix |
|-----|---------|
| No published JSON Schema | Publish `application.schema.json` |
| `navigation.tabs` compiled but not rendered | Mandate runtime consumption in spec |
| `route-manifest.json` not used for routing | Mandate route-driven template resolution |
| Dual slots + zones models | Unified: zones = ordered slot arrays |
| Closed hardcoded component types | Published `component-catalog.schema.json` |
| No envelope (`kind`, `metadata`) | Add Backstage-style envelope |
---
## 10. Migration path
Existing `aiui.template.yaml` files remain valid. Migration steps:
1. Add `apiVersion: adp.io/v1alpha1` and `kind: Application` (optional during transition).
2. Wrap top-level keys under `spec:` (compiler accepts both shapes during v1alpha1).
3. Rename `site` fields unchanged; map `navigation`, `templates`, `routes` as-is.
4. Publish catalog; register custom component types via plugin schema layers.
See [adp/aiui-mapping.md](./adp/aiui-mapping.md) for field-by-field mapping.
---
## 11. Open questions
1. **Should ADP standardise layout type names** (`ThreeColumnLayout`) or allow runtime-defined layouts?
2. **Should navigation support both filesystem-auto and manual tabs** in one spec, or require a mode switch?
3. **Should agent-driven surfaces (A2UI) be a separate `kind: Surface`** or embedded in Application?
4. **Should theme reference DTCG token files directly** or use simplified preset shorthand?
---
## 12. Appendix A — Standards index
| # | Standard | URL |
|---|----------|-----|
| 1 | A2UI | https://a2ui.org/ |
| 2 | AG-UI | https://docs.ag-ui.com/ |
| 3 | AWP | https://github.com/veegee82/agent-workflow-protocol |
| 4 | AsyncAPI | https://www.asyncapi.com/ |
| 5 | Backstage catalog | https://backstage.io/docs/features/software-catalog/descriptor-format |
| 6 | Bootstrap | https://getbootstrap.com/ |
| 7 | CloudEvents | https://cloudevents.io/ |
| 8 | CNAB | https://cnab.io/ |
| 9 | CrewAI | https://docs.crewai.com/ |
| 10 | CUE | https://cuelang.org/ |
| 11 | Docusaurus | https://docusaurus.io/ |
| 12 | DTCG Design Tokens | https://www.designtokens.org/ |
| 13 | Figma Code Connect | https://developers.figma.com/docs/code-connect/ |
| 14 | Framer | https://www.framer.com/ |
| 15 | Gatsby | https://www.gatsbyjs.com/ |
| 16 | Helm | https://helm.sh/ |
| 17 | Hugo | https://gohugo.io/ |
| 18 | Jekyll | https://jekyllrb.com/ |
| 19 | JSON Forms | https://jsonforms.io/ |
| 20 | JSON Schema | https://json-schema.org/ |
| 21 | Kubernetes CRD | https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ |
| 22 | LangGraph | https://langchain-ai.github.io/langgraph/ |
| 23 | Material Design 3 | https://m3.material.io/ |
| 24 | MCP | https://modelcontextprotocol.io/ |
| 25 | Mintlify | https://mintlify.com/docs |
| 26 | OAM | https://oam.dev/ |
| 27 | OCI Artifact | https://opencontainers.org/ |
| 28 | OpenAPI | https://www.openapis.org/ |
| 29 | OpenUI | https://openuispec.org/ |
| 30 | Pkl | https://pkl-lang.org/ |
| 31 | PraisonAIUI | https://github.com/MervinPraison/PraisonAIUI |
| 32 | RJSF | https://rjsf-team.github.io/react-jsonschema-form/ |
| 33 | Storybook CSF | https://storybook.js.org/docs/api/csf |
| 34 | W3C ARIA APG | https://www.w3.org/WAI/ARIA/apg/ |
| 35 | Web Components | https://web.dev/articles/declarative-shadow-dom |
| 36 | Webflow | https://webflow.com/ |
| 37 | AutoGen | https://microsoft.github.io/autogen/ |
| 38 | A2A | https://google.github.io/A2A/ |
| 39 | Jsonnet | https://jsonnet.org/ |
| 40 | Docker Compose | https://docs.docker.com/compose/ |
| 41 | Qt QML | https://doc.qt.io/qt-6/qmlapplications.html |
| 42 | XAML | https://learn.microsoft.com/en-us/windows/apps/develop/platform/xaml/xaml-overview |
| 43 | Jetpack Compose | https://developer.android.com/develop/ui/compose |
| 44 | SwiftUI | https://developer.apple.com/xcode/swiftui/ |
| 45 | HTML + CSS | https://html.spec.whatwg.org/ |
| 46 | Flutter | https://flutter.dev/ |
---
## 13. Conclusion
ADP is feasible and largely prefigured by PraisonAIUI's existing architecture. The research across 46 standards yields a clear synthesis:
- **Envelope** from Backstage/K8s
- **Composition** from PraisonAIUI (components → templates → routes)
- **Catalog** from A2UI/OpenUI
- **Theming** from DTCG
- **Validation** from AWP (structural schema + R-rules)
- **Authoring** in YAML (default) with JSON alternate (Mintlify pattern)
**Status:** Research draft — see [adp/implementation-status.md](./adp/implementation-status.md) for implementation gaps.
The draft spec, JSON Schema files, and example manifests are published alongside this report in [`docs/protocols/adp/`](./adp/).
@@ -25,6 +25,7 @@ from praisonaiui.server import create_app
# Use shared seed data helper
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from _shared.console import safe_print as print
from _shared.seed_data import seed_demo_data
seed_demo_data()
+1
View File
@@ -20,6 +20,7 @@ import sys
# Use shared seed data helper
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from _shared.console import safe_print as print
from _shared.seed_data import seed_demo_data
+1
View File
@@ -26,6 +26,7 @@ import time
import praisonaiui as aiui
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '_shared'))
from console import safe_print as print
from stream_bridge import StreamBridge
try:
+6
View File
@@ -4,9 +4,15 @@ Demonstrates ALL 16 PraisonAIUI features with real API calls.
Run: aiui run app.py
"""
import os
import sys
from starlette.testclient import TestClient
from praisonaiui.server import create_app
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from _shared.console import safe_print as print
def test_all_features():
"""Test all 16 feature APIs with real data."""
@@ -0,0 +1,12 @@
# Meeting Agent example — copy to .env and fill in. Never commit real secrets.
# Used by the PraisonAI agent (PAI-MEET-CORE) for summarization/embeddings.
OPENAI_API_KEY=
# Optional: enable Slack summary delivery via the built-in SlackChannelAdapter.
# Leave blank to run dashboard-only (no Slack required).
SLACK_BOT_TOKEN=
SLACK_APP_TOKEN=
# Local dev server port for `python app.py`.
MEETING_AGENT_PORT=8000
+49
View File
@@ -0,0 +1,49 @@
# Meeting Agent (thin UI example)
A lightweight PraisonAIUI example that wires **existing** features together via
YAML/config to build a meeting assistant dashboard. It adds no agent-runtime
logic and no agent-callable tools.
## What this example includes
| Page | Built from |
|------|-----------|
| Upload | `attachments` feature (`POST /api/chat/attachments`) + status copy |
| Meetings | dashboard page (`aiui.table` / `aiui.metric`) |
| Meeting detail | tabbed dashboard page — Transcript / Summary / Action items |
| Chat | `@aiui.reply` with a system prompt enforcing *search meetings first* + citation chips |
Slack delivery (`/meeting-summary <id>`) uses the existing
`SlackChannelAdapter` and is **optional** — the dashboard runs without any Slack
tokens (dashboard-only mode). `slack_sdk` is imported lazily, only when tokens
are present.
## Run
```bash
cp .env.example .env # optional; dashboard works without any tokens
aiui run app.py
# or
python app.py # honours MEETING_AGENT_PORT
```
## Where the rest lives (routed out)
This repo intentionally hosts only the thin UI slice. The agent and tools live
in separate repositories:
- **Agent core** (`build_agent`, instructions, summarization pipeline, storage,
status state machine) → `MervinPraison/PraisonAI` (**PAI-MEET-CORE**).
- **Tools** (`search_meetings`, transcription, indexing, etc.) →
`MervinPraison/PraisonAI-Tools` (**PAI-MEET-TOOLS**).
Point this UI at your running agent via the standard PraisonAI provider/jobs
configuration; no changes to `praisonaiui` internals are required.
## Environment
See `.env.example`:
- `OPENAI_API_KEY` — used by the agent (PAI-MEET-CORE).
- `SLACK_BOT_TOKEN`, `SLACK_APP_TOKEN` — optional Slack delivery.
- `MEETING_AGENT_PORT` — local dev port.
@@ -0,0 +1,46 @@
# Meeting Agent — PraisonAIUI example config (PAI-MEET-UI, issue #260)
# Composes existing features (attachments, knowledge, chat, Slack) via YAML.
# Run with: aiui run app.py
site:
title: Meeting Agent
description: Upload meetings, browse summaries and action items, ask questions.
logo: "🗓️"
theme:
preset: slate
darkMode: true
radius: md
style: dashboard
layout:
mode: dashboard
dashboard:
sidebar: true
pageHeader: true
pages:
- upload
- meetings
- meeting-detail
- chat
chat:
enabled: true
name: Meeting Assistant
features:
streaming: true
reasoning: true
tools: true
fileUpload: true
feedback: true
input:
placeholder: "Ask about a past meeting..."
starters:
- label: "What did we decide about billing?"
message: "What did we decide about billing?"
icon: "🔎"
- label: "List open action items"
message: "List open action items and their owners"
icon: "✅"
+252
View File
@@ -0,0 +1,252 @@
"""Meeting Agent — thin PraisonAIUI example (PAI-MEET-UI, issue #260).
Composes existing PraisonAIUI features via YAML/config only:
- Upload page → reuses the ``attachments`` feature (POST /api/chat/attachments)
- Meetings list → dashboard page built from ``aiui.ui`` helpers
- Meeting detail → tabbed dashboard page (Transcript / Summary / Action items)
- Chat → system prompt enforces "search meetings first" + citation chips
- Slack delivery → optional, via the existing SlackChannelAdapter (lazy slack_sdk)
This example adds NO agent-runtime logic and NO agent-callable tools. Those live in
external repositories:
- Agent core → MervinPraison/PraisonAI (PAI-MEET-CORE)
- Tools → MervinPraison/PraisonAI-Tools (PAI-MEET-TOOLS)
The dashboard runs without any Slack tokens (dashboard-only mode). Heavy deps
(openai, slack_sdk, chromadb) are never imported eagerly here.
Run:
aiui run app.py
"""
from __future__ import annotations
import os
import praisonaiui as aiui
from praisonaiui.server import create_app
CHAT_SYSTEM_PROMPT = (
"You are a meeting assistant. For any question about past meetings, decisions, "
"owners, or action items you MUST call the search_meetings tool first and answer "
"only from the retrieved transcripts and summaries. Never answer historical "
"questions from memory. Cite every claim with a citation chip showing the meeting "
"title linked to its detail page."
)
SAMPLE_MEETINGS: list[dict] = [
{
"id": "m-1001",
"title": "Q3 Planning Kickoff",
"date": "2026-07-01",
"status": "Ready",
"duration": "48m",
"transcript": "Alice: Let's align on Q3 goals...\nBob: Priorities are onboarding and billing.",
"summary": "Team aligned on Q3 priorities: onboarding revamp and billing reliability.",
"actions": [
{"task": "Draft onboarding spec", "owner": "Alice", "due": "2026-07-08"},
{"task": "Audit billing retries", "owner": "Bob", "due": "2026-07-10"},
],
},
{
"id": "m-1002",
"title": "Billing Reliability Review",
"date": "2026-07-09",
"status": "Summarizing",
"duration": "32m",
"transcript": "Bob: Retry storms caused duplicate charges...\nCara: We need idempotency keys.",
"summary": "Root-caused duplicate charges to missing idempotency keys; fix scheduled.",
"actions": [
{"task": "Add idempotency keys", "owner": "Cara", "due": "2026-07-16"},
],
},
]
def _meeting(meeting_id: str) -> dict | None:
return next((m for m in SAMPLE_MEETINGS if m["id"] == meeting_id), None)
def _status_variant(status: str) -> str:
return {
"Ready": "default",
"Indexing": "secondary",
"Summarizing": "secondary",
"Transcribing": "secondary",
"Uploading": "secondary",
"Error": "destructive",
}.get(status, "outline")
aiui.set_style("dashboard")
aiui.set_branding(title="Meeting Agent", logo="🗓️")
aiui.set_pages(["upload", "meetings", "meeting-detail", "chat"])
aiui.set_dashboard(sidebar=True, page_header=True)
aiui.set_chat_features(file_upload=True, feedback=True)
@aiui.page("upload", title="Upload", icon="⬆️", group="Meetings", order=1)
async def upload_page():
steps = ["Uploading", "Transcribing", "Summarizing", "Indexing", "Ready"]
return aiui.layout(
[
aiui.text("Drop an audio or transcript file to add a meeting."),
aiui.alert(
"Files are uploaded via the built-in attachments feature "
"(POST /api/chat/attachments). Transcription, summarization and "
"indexing run in the PraisonAI agent (PAI-MEET-CORE).",
variant="info",
title="How it works",
),
aiui.card(
"Processing pipeline",
footer=" → ".join(steps),
),
aiui.text(
"On error the pipeline surfaces a retry action via the standard "
"chat status events; no bespoke state machine lives in the UI."
),
]
)
@aiui.page("meetings", title="Meetings", icon="📋", group="Meetings", order=2)
async def meetings_page():
rows = [
[
m["title"],
m["date"],
m["status"],
str(len(m["actions"])),
m["duration"],
]
for m in SAMPLE_MEETINGS
]
return aiui.layout(
[
aiui.metric("Meetings", value=len(SAMPLE_MEETINGS)),
aiui.table(
headers=["Title", "Date", "Status", "Actions", "Duration"],
rows=rows,
),
]
)
@aiui.page("meeting-detail", title="Meeting detail", icon="📝", group="Meetings", order=3)
async def meeting_detail_page():
meeting = SAMPLE_MEETINGS[0]
action_rows = [[a["task"], a["owner"], a["due"]] for a in meeting["actions"]]
return aiui.layout(
[
aiui.text(meeting["title"]),
aiui.badge(meeting["status"], variant=_status_variant(meeting["status"])),
aiui.tabs(
[
{
"label": "Transcript",
"children": [aiui.code_block(meeting["transcript"], language="text")],
},
{
"label": "Summary",
"children": [aiui.text(meeting["summary"])],
},
{
"label": "Action items",
"children": [
aiui.table(
headers=["Task", "Owner", "Due"],
rows=action_rows,
)
],
},
]
),
]
)
@aiui.reply
async def on_message(message: str):
await aiui.think("Searching meetings before answering...")
hits = [
m
for m in SAMPLE_MEETINGS
if message.lower() in (m["title"] + " " + m["summary"]).lower()
]
if not hits:
hits = SAMPLE_MEETINGS
top = hits[0]
await aiui.say(top["summary"])
await aiui.action_buttons(
[
{
"name": f"open:{m['id']}",
"label": f"📎 {m['title']}",
}
for m in hits
]
)
def _slack_adapter():
"""Construct a Slack adapter only when tokens are configured (lazy slack_sdk)."""
bot = os.environ.get("SLACK_BOT_TOKEN", "")
app_token = os.environ.get("SLACK_APP_TOKEN", "")
if not bot or not app_token:
return None
from praisonaiui.features.platform_adapters.slack import SlackChannelAdapter
return SlackChannelAdapter({"bot_token": bot, "app_token": app_token})
def _summary_blocks(meeting: dict) -> list[dict]:
action_lines = "\n".join(
f"• {a['task']} — {a['owner']} (due {a['due']})" for a in meeting["actions"]
)
return [
{"type": "header", "text": {"type": "plain_text", "text": meeting["title"]}},
{"type": "section", "text": {"type": "mrkdwn", "text": f"*Date:* {meeting['date']}"}},
{"type": "section", "text": {"type": "mrkdwn", "text": meeting["summary"]}},
{"type": "section", "text": {"type": "mrkdwn", "text": f"*Action items*\n{action_lines}"}},
{
"type": "context",
"elements": [{"type": "mrkdwn", "text": f"Dashboard: /meeting-detail#{meeting['id']}"}],
},
]
async def post_meeting_summary(meeting_id: str, channel_id: str) -> bool:
"""Deliver a meeting summary to Slack (/meeting-summary <id>).
Returns False when Slack is not configured — the dashboard still works.
"""
meeting = _meeting(meeting_id)
if meeting is None:
return False
adapter = _slack_adapter()
if adapter is None:
return False
await adapter.start()
try:
await adapter.send_message(
channel_id,
meeting["summary"],
blocks=_summary_blocks(meeting),
)
finally:
await adapter.stop()
return True
app = create_app()
if __name__ == "__main__":
import uvicorn
host = os.environ.get("HOST", "127.0.0.1")
port = int(os.environ.get("MEETING_AGENT_PORT", "8000"))
uvicorn.run(app, host=host, port=port)
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "aiui"
version = "0.3.137"
version = "0.3.142"
description = "YAML-driven website generator - CLI and compiler"
readme = "README.md"
license = {text = "MIT"}
+1 -3
View File
@@ -11,9 +11,7 @@
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Documentation</title>
<script>
// Anti-flicker: apply dark mode class before first paint
// Default to dark to prevent flash; React will correct if needed
document.documentElement.classList.add('dark');
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=__AIUI_DARK_DEFAULT__;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
</head>
+903 -2
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -89,6 +89,7 @@
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"lucide-react": "^0.563.0",
"mermaid": "^11.17.2",
"react-day-picker": "^9.13.0",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^4.5.4",
+274 -119
View File
@@ -1,15 +1,18 @@
import { useEffect, useState } from 'react'
import { applyTheme } from './themes'
import { useEffect, useMemo, useState } from 'react'
import { applyTheme, applyStoredThemePreference } from './themes'
import './index.css'
import type { UIConfig, DocsNav, RouteManifest, NavItem } from './types'
import { Header } from './Header'
import { Sidebar } from './Sidebar'
import { Sidebar, MobileNavSheet } from './Sidebar'
import { Content } from './Content'
import { ZoneWidgets } from './Widgets'
import { Toc } from './Toc'
import { Footer } from './Footer'
import { ChatLayout, AgentUILayout, CopilotWidget, PlaygroundLayout } from './layouts'
import { LocaleProvider } from './i18n'
import { resolveTemplate, shouldShowToc } from './resolver'
import { normalizeDocPath } from './pathUtils'
import { detectActiveTabIndex, filterNavByTab } from './docs/navTabs'
function SkipLink({ enabled }: { enabled?: boolean }) {
if (!enabled) return null
@@ -31,12 +34,30 @@ export default function App() {
const [error, setError] = useState<string | null>(null)
const [selectedItem, setSelectedItem] = useState<NavItem | null>(null)
const [activeItemPath, setActiveItemPath] = useState<string>('')
const [currentPath, setCurrentPath] = useState(() => normalizeDocPath(window.location.pathname))
const [mobileNavOpen, setMobileNavOpen] = useState(false)
const [activeTabIndex, setActiveTabIndex] = useState(0)
// Helper function to find nav item by path
const navTabs = config.navigation?.tabs ?? []
const filteredNav = useMemo<DocsNav>(() => {
if (!navTabs.length) return nav
return { items: filterNavByTab(nav.items ?? [], navTabs[activeTabIndex]) }
}, [nav, navTabs, activeTabIndex])
useEffect(() => {
if (navTabs.length) {
setActiveTabIndex(detectActiveTabIndex(navTabs, currentPath))
}
}, [currentPath, navTabs])
// Helper function to find nav item by path (searches top-level items and nested children)
const findNavItemByPath = (navData: DocsNav, path: string): NavItem | null => {
const normalizedPath = normalizeDocPath(path)
const findItem = (items: NavItem[]): NavItem | null => {
for (const item of items) {
if (item.path === path || item.path === path.replace(/^\//, '')) {
const itemPath = normalizeDocPath(item.path ?? '')
if (itemPath === normalizedPath) {
return item
}
if (item.children) {
@@ -47,94 +68,190 @@ export default function App() {
return null
}
// Search all nav groups
if (navData.items) {
for (const group of navData.items) {
if (group.children) {
const found = findItem(group.children)
if (found) return found
}
}
}
return null
return navData.items ? findItem(navData.items) : null
}
// Update SEO meta tags dynamically
const updateSEO = (title: string, path: string, description?: string) => {
// Update title using SEO titleTemplate if available
const titleTemplate = config.seo?.titleTemplate || '%s | %s'
const siteName = config.site?.title || 'Documentation'
const seoOrigin = (cfg: UIConfig) => (cfg.seo?.siteUrl || window.location.origin).replace(/\/+$/, '')
const formatSeoTitle = (title: string, cfg: UIConfig) => {
const titleTemplate = cfg.seo?.titleTemplate || '%s | %s'
const siteName = cfg.site?.title || 'Documentation'
if (titleTemplate.includes('%s')) {
// Replace first %s with page title, second %s (if exists) with site name
let formattedTitle = titleTemplate.replace('%s', title)
if (formattedTitle.includes('%s')) {
formattedTitle = formattedTitle.replace('%s', siteName)
}
document.title = formattedTitle
} else {
document.title = `${title} | ${siteName}`
return formattedTitle
}
return `${title} | ${siteName}`
}
const updateSEO = (
title: string,
path: string,
description?: string,
configOverride?: UIConfig,
noindex?: boolean,
) => {
const cfg = configOverride ?? config
const canonicalPath = normalizeDocPath(path)
const formattedTitle = formatSeoTitle(title, cfg)
const metaDescription = description || `${title} - ${cfg.site?.description || ''}`
const absoluteUrl = `${seoOrigin(cfg)}${canonicalPath}`
document.title = formattedTitle
// Update canonical URL
let canonical = document.querySelector('link[rel="canonical"]') as HTMLLinkElement
if (!canonical) {
canonical = document.createElement('link')
canonical.rel = 'canonical'
document.head.appendChild(canonical)
}
canonical.href = window.location.origin + path
canonical.href = absoluteUrl
// Update meta description
let metaDesc = document.querySelector('meta[name="description"]') as HTMLMetaElement
if (!metaDesc) {
metaDesc = document.createElement('meta')
metaDesc.name = 'description'
document.head.appendChild(metaDesc)
}
metaDesc.content = description || `${title} - ${config.site?.description || ''}`
metaDesc.content = metaDescription
// Update Open Graph tags
let ogTitle = document.querySelector('meta[property="og:title"]') as HTMLMetaElement
if (!ogTitle) {
ogTitle = document.createElement('meta')
ogTitle.setAttribute('property', 'og:title')
document.head.appendChild(ogTitle)
}
ogTitle.content = title
let ogUrl = document.querySelector('meta[property="og:url"]') as HTMLMetaElement
if (!ogUrl) {
ogUrl = document.createElement('meta')
ogUrl.setAttribute('property', 'og:url')
document.head.appendChild(ogUrl)
}
ogUrl.content = window.location.origin + path
// Update Twitter meta tags if configured
if (config.seo?.twitter) {
Object.entries(config.seo.twitter).forEach(([key, value]) => {
let twitterMeta = document.querySelector(`meta[name="twitter:${key}"]`) as HTMLMetaElement
if (!twitterMeta) {
twitterMeta = document.createElement('meta')
twitterMeta.name = `twitter:${key}`
document.head.appendChild(twitterMeta)
}
twitterMeta.content = value
})
}
// Set default image if available
if (config.seo?.defaultImage) {
let ogImage = document.querySelector('meta[property="og:image"]') as HTMLMetaElement
if (!ogImage) {
ogImage = document.createElement('meta')
ogImage.setAttribute('property', 'og:image')
document.head.appendChild(ogImage)
const ensureMeta = (selector: string, create: () => HTMLMetaElement) => {
let el = document.querySelector(selector) as HTMLMetaElement | null
if (!el) {
el = create()
document.head.appendChild(el)
}
ogImage.content = config.seo.defaultImage
return el
}
ensureMeta('meta[name="robots"]', () => {
const el = document.createElement('meta')
el.name = 'robots'
return el
}).content = noindex ? 'noindex, nofollow' : 'index, follow'
ensureMeta('meta[property="og:title"]', () => {
const el = document.createElement('meta')
el.setAttribute('property', 'og:title')
return el
}).content = formattedTitle
ensureMeta('meta[property="og:description"]', () => {
const el = document.createElement('meta')
el.setAttribute('property', 'og:description')
return el
}).content = metaDescription
ensureMeta('meta[property="og:url"]', () => {
const el = document.createElement('meta')
el.setAttribute('property', 'og:url')
return el
}).content = absoluteUrl
ensureMeta('meta[property="og:type"]', () => {
const el = document.createElement('meta')
el.setAttribute('property', 'og:type')
return el
}).content = 'article'
ensureMeta('meta[name="twitter:card"]', () => {
const el = document.createElement('meta')
el.name = 'twitter:card'
return el
}).content = 'summary'
ensureMeta('meta[name="twitter:title"]', () => {
const el = document.createElement('meta')
el.name = 'twitter:title'
return el
}).content = formattedTitle
ensureMeta('meta[name="twitter:description"]', () => {
const el = document.createElement('meta')
el.name = 'twitter:description'
return el
}).content = metaDescription
if (cfg.seo?.twitter?.handle) {
ensureMeta('meta[name="twitter:site"]', () => {
const el = document.createElement('meta')
el.name = 'twitter:site'
return el
}).content = cfg.seo.twitter.handle
}
if (cfg.seo?.defaultImage) {
const image = cfg.seo.defaultImage.startsWith('http')
? cfg.seo.defaultImage
: `${seoOrigin(cfg)}${cfg.seo.defaultImage}`
ensureMeta('meta[property="og:image"]', () => {
const el = document.createElement('meta')
el.setAttribute('property', 'og:image')
return el
}).content = image
ensureMeta('meta[name="twitter:image"]', () => {
const el = document.createElement('meta')
el.name = 'twitter:image'
return el
}).content = image
}
let jsonLd = document.querySelector('script#aiui-jsonld') as HTMLScriptElement | null
if (!jsonLd) {
jsonLd = document.createElement('script')
jsonLd.type = 'application/ld+json'
jsonLd.id = 'aiui-jsonld'
document.head.appendChild(jsonLd)
}
jsonLd.textContent = JSON.stringify({
'@context': 'https://schema.org',
'@type': 'TechArticle',
headline: title,
description: metaDescription,
url: absoluteUrl,
isPartOf: {
'@type': 'WebSite',
name: cfg.site?.title || 'Documentation',
url: `${seoOrigin(cfg)}/`,
},
})
}
const selectNavItem = (item: NavItem) => {
const path = normalizeDocPath(item.path || '/')
setSelectedItem(item)
setActiveItemPath(item.path || item.title)
updateSEO(item.title, path, item.description, undefined, item.noindex)
}
// Keep React nav state in sync when plugins perform SPA navigation
useEffect(() => {
const onPluginNavigate = (event: Event) => {
const detail = (event as CustomEvent<{ path?: string }>).detail
const path = normalizeDocPath(detail?.path ?? window.location.pathname)
setCurrentPath(path)
setMobileNavOpen(false)
const found = findNavItemByPath(nav, path)
if (found) {
selectNavItem(found)
return
}
if (path === '/') {
const docsHome = findNavItemByPath(nav, '/docs/index')
if (docsHome) {
selectNavItem(docsHome)
}
}
}
window.addEventListener('aiui:navigate', onPluginNavigate)
return () => window.removeEventListener('aiui:navigate', onPluginNavigate)
}, [nav, config])
useEffect(() => {
async function loadManifests() {
try {
@@ -156,19 +273,33 @@ export default function App() {
// Apply theme from YAML config
const theme = configData.site?.theme
const yamlDark = theme?.darkMode !== false
applyTheme(
theme?.preset || 'zinc',
theme?.darkMode !== false,
yamlDark,
theme?.radius || 'md'
)
applyStoredThemePreference(yamlDark)
// Handle initial URL path for SPA routing
const currentPath = window.location.pathname
if (currentPath && currentPath !== '/') {
const found = findNavItemByPath(navData, currentPath)
const initialPath = normalizeDocPath(window.location.pathname)
setCurrentPath(initialPath)
if (initialPath !== window.location.pathname) {
window.history.replaceState(null, '', initialPath + window.location.search + window.location.hash)
}
if (initialPath !== '/') {
const found = findNavItemByPath(navData, initialPath)
if (found) {
setSelectedItem(found)
setActiveItemPath(found.path || found.title)
updateSEO(found.title, initialPath, found.description, configData, found.noindex)
}
} else {
const docsHome = findNavItemByPath(navData, '/docs/index')
if (docsHome) {
setSelectedItem(docsHome)
setActiveItemPath(docsHome.path || docsHome.title)
updateSEO(docsHome.title, normalizeDocPath(docsHome.path || '/docs/index'), docsHome.description, configData, docsHome.noindex)
}
}
} catch (err) {
@@ -184,19 +315,21 @@ export default function App() {
// Handle browser back/forward navigation in a separate effect
useEffect(() => {
const handlePopState = () => {
const path = window.location.pathname
const path = normalizeDocPath(window.location.pathname)
setCurrentPath(path)
const found = findNavItemByPath(nav, path)
if (found) {
setSelectedItem(found)
setActiveItemPath(found.path || found.title)
// Use updateSEO function for consistency
updateSEO(found.title, path)
selectNavItem(found)
} else if (path === '/') {
setSelectedItem(null)
setActiveItemPath('')
// Reset title to site title
document.title = config.site?.title || 'Documentation'
const docsHome = findNavItemByPath(nav, '/docs/index')
if (docsHome) {
selectNavItem(docsHome)
} else {
setSelectedItem(null)
setActiveItemPath('')
document.title = config.site?.title || 'Documentation'
}
}
}
@@ -205,18 +338,47 @@ export default function App() {
}, [nav, config])
const handleItemClick = (item: NavItem) => {
setSelectedItem(item)
setActiveItemPath(item.path || item.title)
// Use History API for SEO-friendly URLs
const path = item.path || `/${item.title.toLowerCase().replace(/\s+/g, '-')}`
const path = normalizeDocPath(item.path || `/${item.title.toLowerCase().replace(/\s+/g, '-')}`)
window.history.pushState({ path }, item.title, path)
// Update SEO meta tags
updateSEO(item.title, path)
window.dispatchEvent(new CustomEvent('aiui:navigate', { detail: { path } }))
}
const templateMatch = resolveTemplate(
currentPath.replace(/^\//, ''),
routes,
config.templates ?? {},
)
const activeTemplateKey = templateMatch?.template ?? 'docs'
const activeTemplate = config.templates?.[activeTemplateKey] ?? config.templates?.docs
const layout = templateMatch?.layout ?? activeTemplate?.layout ?? 'ThreeColumnLayout'
const zones = activeTemplate?.zones
const showToc = shouldShowToc(templateMatch)
const showGlobalFooter = true
const docsChrome = (
<>
<MobileNavSheet
open={mobileNavOpen}
onOpenChange={setMobileNavOpen}
nav={filteredNav}
activeItem={activeItemPath}
onItemClick={handleItemClick}
title={config.site?.title || 'Navigation'}
/>
<Header
config={config}
templateKey={activeTemplateKey}
onMenuClick={() => setMobileNavOpen(true)}
navTabs={navTabs}
activeTabIndex={activeTabIndex}
onTabChange={setActiveTabIndex}
/>
</>
)
if (loading) {
return (
<div className="dark flex items-center justify-center min-h-screen bg-background">
<div className="flex items-center justify-center min-h-screen bg-background">
<span className="text-muted-foreground">Loading...</span>
</div>
)
@@ -224,53 +386,49 @@ export default function App() {
if (error) {
return (
<div className="dark flex flex-col items-center justify-center min-h-screen gap-4 bg-background">
<div className="flex flex-col items-center justify-center min-h-screen gap-4 bg-background">
<h2 className="text-xl font-semibold text-destructive">Failed to load</h2>
<p className="text-muted-foreground">{error}</p>
</div>
)
}
// Determine layout from templates config
const layout = config.templates?.docs?.layout || 'ThreeColumnLayout'
const zones = config.templates?.docs?.zones
// Render based on layout type
const renderLayout = () => {
switch (layout) {
case 'TwoColumnLayout':
// Sidebar + Content (no TOC)
return (
<div className="flex">
<Sidebar nav={nav} activeItem={activeItemPath} onItemClick={handleItemClick} />
<Content config={config} routes={routes} selectedItem={selectedItem} />
<Content config={config} routes={routes} selectedItem={selectedItem} currentPath={currentPath} />
</div>
)
case 'CenteredLayout':
// Centered content, no sidebar
return (
<div className="flex justify-center">
<div className="w-full max-w-4xl px-6">
{zones?.hero && zones.hero.length > 0 && <ZoneWidgets widgets={zones.hero} />}
<Content config={config} routes={routes} selectedItem={selectedItem} />
<Content config={config} routes={routes} selectedItem={selectedItem} currentPath={currentPath} />
</div>
</div>
)
case 'FullWidthLayout':
// Full width content
return (
<div className="px-6">
{zones?.hero && zones.hero.length > 0 && <ZoneWidgets widgets={zones.hero} />}
<Content config={config} routes={routes} selectedItem={selectedItem} />
<div className="flex">
{(nav?.items?.length ?? 0) > 0 && (
<Sidebar nav={nav} activeItem={activeItemPath} onItemClick={handleItemClick} />
)}
<div className="flex-1 px-6">
{zones?.hero && zones.hero.length > 0 && <ZoneWidgets widgets={zones.hero} />}
<Content config={config} routes={routes} selectedItem={selectedItem} currentPath={currentPath} />
</div>
</div>
)
case 'FlexibleLayout': {
// WordPress-style zones layout with navigation invariant
// When docs nav exists but no leftSidebar zone configured, render default nav
const hasExplicitLeftSidebar = (zones?.leftSidebar?.length ?? 0) > 0
const hasNavigation = (nav?.items?.length ?? 0) > 0
const shouldRenderNavigation = hasExplicitLeftSidebar || hasNavigation
return (
<div className="flex flex-col">
{zones?.hero && zones.hero.length > 0 && <ZoneWidgets widgets={zones.hero} />}
@@ -285,9 +443,9 @@ export default function App() {
</aside>
)}
<div className="flex-1">
<Content config={config} routes={routes} selectedItem={selectedItem} />
<Content config={config} routes={routes} selectedItem={selectedItem} currentPath={currentPath} />
</div>
<Toc selectedItem={selectedItem} zones={zones} />
<Toc selectedItem={selectedItem} zones={zones} showToc={showToc} />
</div>
{zones?.bottomNav && zones.bottomNav.length > 0 && (
<div className="border-t p-4 bg-muted/30">
@@ -304,12 +462,11 @@ export default function App() {
}
case 'ThreeColumnLayout':
default:
// Classic: Sidebar + Content + TOC with zones
return (
<div className="flex">
<Sidebar nav={nav} activeItem={activeItemPath} onItemClick={handleItemClick} />
<Content config={config} routes={routes} selectedItem={selectedItem} />
<Toc selectedItem={selectedItem} zones={zones} />
<div className="docs-shell flex w-full min-h-[calc(100vh-3.5rem)]">
<Sidebar nav={filteredNav} activeItem={activeItemPath} onItemClick={handleItemClick} />
<Content config={config} routes={routes} selectedItem={selectedItem} currentPath={currentPath} />
{showToc && <Toc selectedItem={selectedItem} zones={zones} showToc={showToc} />}
</div>
)
}
@@ -347,14 +504,13 @@ export default function App() {
// Dashboard is handled entirely by plugin dashboard.js — React yields
return null
case 'custom':
// For custom, show docs with copilot widget if chat enabled
if (config.chat?.enabled) {
return (
<div className="min-h-screen bg-background text-foreground">
<SkipLink enabled={config.a11y?.skipToContent} />
<Header config={config} />
{docsChrome}
{renderLayout()}
<Footer config={config} />
{showGlobalFooter && <Footer config={config} templateKey={activeTemplateKey} />}
<CopilotWidget config={config.chat} layout={config.layout} />
</div>
)
@@ -362,23 +518,22 @@ export default function App() {
return (
<div className="min-h-screen bg-background text-foreground">
<SkipLink enabled={config.a11y?.skipToContent} />
<Header config={config} />
{docsChrome}
{renderLayout()}
<Footer config={config} />
{showGlobalFooter && <Footer config={config} templateKey={activeTemplateKey} />}
</div>
)
case 'docs':
default:
// Docs mode - optionally with copilot widget
if (config.chat?.enabled) {
const layoutMode = config.layout?.mode
if (layoutMode && ['bottom-right', 'bottom-left', 'top-right', 'top-left'].includes(layoutMode)) {
return (
<div className="min-h-screen bg-background text-foreground">
<SkipLink enabled={config.a11y?.skipToContent} />
<Header config={config} />
{docsChrome}
{renderLayout()}
<Footer config={config} />
{showGlobalFooter && <Footer config={config} templateKey={activeTemplateKey} />}
<CopilotWidget config={config.chat} layout={config.layout} />
</div>
)
@@ -387,9 +542,9 @@ export default function App() {
return (
<div className="min-h-screen bg-background text-foreground">
<SkipLink enabled={config.a11y?.skipToContent} />
<Header config={config} />
{docsChrome}
{renderLayout()}
<Footer config={config} />
{showGlobalFooter && <Footer config={config} templateKey={activeTemplateKey} />}
</div>
)
}
+133 -50
View File
@@ -1,109 +1,191 @@
// Content component — markdown rendering and landing page
import { useEffect, useState } from 'react'
import { Children, isValidElement, useEffect, useRef, useState } from 'react'
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import { Separator } from '@/components/ui/separator'
import { SHADCN_THEMES } from './themes'
import { enhanceMkdocsDom } from './markdown/mkdocsEnhance'
import { preprocessMkdocsMarkdown } from './markdown/mkdocsPreprocess'
import { MermaidDiagram } from './markdown/MermaidDiagram'
import { slugify } from './markdown/slug'
import { MobileToc } from './Toc'
import { docPathToMarkdown, isInternalDocHref, normalizeDocHref, normalizeDocPath } from './pathUtils'
import type { UIConfig, NavItem, RouteManifest } from './types'
interface ContentProps {
config: UIConfig
routes: RouteManifest
selectedItem: NavItem | null
currentPath: string
}
export function Content({ config, routes, selectedItem }: ContentProps) {
export function Content({ config, routes, selectedItem, currentPath }: ContentProps) {
const [markdown, setMarkdown] = useState<string>('')
const [loadedPath, setLoadedPath] = useState('')
const [loadingContent, setLoadingContent] = useState(false)
const articleRef = useRef<HTMLElement>(null)
const theme = config.site?.theme
// Load markdown content when selected item changes
// Load markdown from URL path (source of truth) to avoid stale selectedItem races
useEffect(() => {
if (!selectedItem?.path) {
setMarkdown('')
const urlPath = normalizeDocPath(currentPath)
if (urlPath === '/') {
setLoadingContent(false)
setLoadedPath('')
if (!selectedItem?.path) {
setMarkdown('')
}
return
}
const mdUrl = docPathToMarkdown(urlPath)
const pageTitle = urlPath.split('/').pop()?.replace(/-/g, ' ') ?? 'page'
const controller = new AbortController()
setMarkdown('')
setLoadedPath('')
setLoadingContent(true)
const loadContent = async () => {
setLoadingContent(true)
try {
// Convert path like /docs/getting-started/installation to docs/getting-started/installation.md
const docPath = (selectedItem.path ?? '').replace(/^\//, '') + '.md'
const response = await fetch(`/${docPath}`)
const response = await fetch(mdUrl, { signal: controller.signal })
if (controller.signal.aborted) return
if (response.ok) {
const content = await response.text()
setMarkdown(content)
setMarkdown(preprocessMkdocsMarkdown(content))
setLoadedPath(urlPath)
window.dispatchEvent(new CustomEvent('aiui:content-loaded', {
detail: { path: urlPath },
}))
} else {
setMarkdown(`*Content for **${selectedItem.title}** not found.*`)
setMarkdown(`*Content for **${pageTitle}** not found.*`)
setLoadedPath(urlPath)
}
} catch {
setMarkdown(`*Failed to load content for **${selectedItem.title}**.*`)
} catch (err) {
if (controller.signal.aborted) return
setMarkdown(`*Failed to load content for **${pageTitle}**.*`)
setLoadedPath(urlPath)
} finally {
setLoadingContent(false)
if (!controller.signal.aborted) {
setLoadingContent(false)
}
}
}
loadContent()
}, [selectedItem])
return () => {
controller.abort()
setLoadingContent(false)
}
}, [currentPath, selectedItem?.path])
useEffect(() => {
if (!markdown || !articleRef.current) return
const article = articleRef.current
const frame = window.requestAnimationFrame(() => {
enhanceMkdocsDom(article)
})
return () => window.cancelAnimationFrame(frame)
}, [markdown])
const headingId = (children?: React.ReactNode) => slugify(String(children ?? ''))
const mermaidChartFromPre = (children?: React.ReactNode): string | null => {
try {
const child = Children.only(children)
if (!isValidElement<{ className?: string; children?: React.ReactNode }>(child)) return null
const className = child.props.className ?? ''
if (!className.includes('language-mermaid')) return null
return String(child.props.children ?? '').replace(/\n$/, '').trim()
} catch {
return null
}
}
// Custom components for react-markdown with Tailwind styling
const markdownComponents = {
h1: ({ children }: { children?: React.ReactNode }) => <h1 className="text-3xl font-bold mt-8 mb-4">{children}</h1>,
h2: ({ children }: { children?: React.ReactNode }) => <h2 className="text-2xl font-semibold mt-8 mb-4 text-primary">{children}</h2>,
h3: ({ children }: { children?: React.ReactNode }) => <h3 className="text-xl font-semibold mt-6 mb-3">{children}</h3>,
h4: ({ children }: { children?: React.ReactNode }) => <h4 className="text-lg font-semibold mt-4 mb-2">{children}</h4>,
p: ({ children }: { children?: React.ReactNode }) => <p className="my-3 text-muted-foreground leading-relaxed">{children}</p>,
a: ({ href, children }: { href?: string; children?: React.ReactNode }) => <a href={href} className="text-primary hover:underline">{children}</a>,
h1: ({ children }: { children?: React.ReactNode }) => <h1 id={headingId(children)} className="text-3xl font-bold mt-8 mb-4 scroll-mt-20">{children}</h1>,
h2: ({ children }: { children?: React.ReactNode }) => <h2 id={headingId(children)} className="text-2xl font-semibold mt-8 mb-4 text-primary scroll-mt-20">{children}</h2>,
h3: ({ children }: { children?: React.ReactNode }) => <h3 id={headingId(children)} className="text-xl font-semibold mt-6 mb-3 scroll-mt-20">{children}</h3>,
h4: ({ children }: { children?: React.ReactNode }) => <h4 id={headingId(children)} className="text-lg font-semibold mt-4 mb-2 scroll-mt-20">{children}</h4>,
p: ({ children }: { children?: React.ReactNode }) => <p className="my-3 text-foreground leading-relaxed">{children}</p>,
a: ({ href, children }: { href?: string; children?: React.ReactNode }) => {
const seoHref = href && isInternalDocHref(href) ? normalizeDocHref(href) : href
return (
<a href={seoHref} className="text-primary hover:underline">
{children}
</a>
)
},
ul: ({ children }: { children?: React.ReactNode }) => <ul className="list-disc pl-6 my-4 space-y-1">{children}</ul>,
ol: ({ children }: { children?: React.ReactNode }) => <ol className="list-decimal pl-6 my-4 space-y-1">{children}</ol>,
li: ({ children }: { children?: React.ReactNode }) => <li className="text-muted-foreground">{children}</li>,
blockquote: ({ children }: { children?: React.ReactNode }) => <blockquote className="border-l-4 border-primary pl-4 my-4 italic text-muted-foreground">{children}</blockquote>,
li: ({ children }: { children?: React.ReactNode }) => <li className="text-foreground">{children}</li>,
blockquote: ({ children }: { children?: React.ReactNode }) => <blockquote className="border-l-4 border-primary pl-4 my-4 italic text-foreground/80">{children}</blockquote>,
code: ({ className, children }: { className?: string; children?: React.ReactNode }) => {
// Check if this is inside a pre block (fenced code block)
if (className?.includes('language-mermaid')) {
return <MermaidDiagram chart={String(children ?? '').replace(/\n$/, '').trim()} />
}
const isInline = !className && String(children).indexOf('\n') === -1
if (isInline) {
return <code className="bg-primary/10 text-primary px-1.5 py-0.5 rounded text-sm font-mono">{children}</code>
}
// Block code - rendered by pre wrapper
return <code className="block font-mono">{children}</code>
return <code className={`block font-mono text-foreground ${className ?? ''}`}>{children}</code>
},
pre: ({ children }: { children?: React.ReactNode }) => {
if (isValidElement(children) && children.type === MermaidDiagram) {
return children
}
const chart = mermaidChartFromPre(children)
if (chart) return <MermaidDiagram chart={chart} />
return (
<pre className="bg-muted text-foreground border border-border p-4 rounded-lg text-sm overflow-auto my-4 font-mono whitespace-pre">{children}</pre>
)
},
pre: ({ children }: { children?: React.ReactNode }) => (
<pre className="bg-muted p-4 rounded-lg text-sm overflow-auto my-4 font-mono whitespace-pre">{children}</pre>
),
table: ({ children }: { children?: React.ReactNode }) => <div className="overflow-auto my-4"><table className="w-full border-collapse text-sm">{children}</table></div>,
thead: ({ children }: { children?: React.ReactNode }) => <thead className="bg-muted/50">{children}</thead>,
tr: ({ children }: { children?: React.ReactNode }) => <tr className="border-b">{children}</tr>,
th: ({ children }: { children?: React.ReactNode }) => <th className="px-4 py-2 text-left font-medium">{children}</th>,
td: ({ children }: { children?: React.ReactNode }) => <td className="px-4 py-2 text-muted-foreground">{children}</td>,
td: ({ children }: { children?: React.ReactNode }) => <td className="px-4 py-2 text-foreground">{children}</td>,
hr: () => <hr className="my-6 border-border" />,
strong: ({ children }: { children?: React.ReactNode }) => <strong className="font-semibold text-foreground">{children}</strong>,
em: ({ children }: { children?: React.ReactNode }) => <em>{children}</em>,
}
const contentReady = loadedPath === normalizeDocPath(currentPath) && markdown.length > 0
if (selectedItem) {
return (
<main id="main-content" className="flex-1 p-8 max-w-3xl">
{loadingContent ? (
<div className="text-muted-foreground">Loading content...</div>
) : markdown ? (
<article className="prose max-w-none">
<Markdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
{markdown}
</Markdown>
</article>
) : (
<div className="bg-muted/50 border rounded-lg p-6">
<p className="text-muted-foreground">
Content for <strong className="text-primary">{selectedItem.title}</strong> would be displayed here.
</p>
</div>
)}
<main id="main-content" className="docs-main flex-1 min-w-0">
<div className="docs-main-inner mx-auto w-full max-w-[720px] px-6 py-8 lg:px-8">
<MobileToc selectedItem={selectedItem} />
{loadingContent && (
<div className="text-muted-foreground animate-pulse">Loading content...</div>
)}
{contentReady && (
<article
key={currentPath}
ref={articleRef}
className="prose prose-neutral dark:prose-invert max-w-none prose-pre:bg-muted prose-pre:text-foreground prose-code:text-foreground"
>
<Markdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
{markdown}
</Markdown>
</article>
)}
{!loadingContent && !contentReady && loadedPath === normalizeDocPath(currentPath) && (
<div className="bg-muted/50 border rounded-lg p-6">
<p className="text-muted-foreground">
Content for <strong className="text-primary">{selectedItem.title}</strong> would be displayed here.
</p>
</div>
)}
</div>
</main>
)
}
return (
<main className="flex-1 p-8 max-w-3xl">
<main id="main-content" className="docs-main flex-1 min-w-0">
<div className="docs-main-inner mx-auto w-full max-w-[720px] px-6 py-8 lg:px-8">
<h1 className="text-4xl font-bold tracking-tight mb-4">
{config.site?.title || 'Documentation'}
</h1>
@@ -118,7 +200,7 @@ export function Content({ config, routes, selectedItem }: ContentProps) {
<p className="text-sm text-muted-foreground mb-2">
<strong>Current theme from YAML:</strong>
</p>
<pre className="text-primary text-sm">
<pre className="bg-muted text-foreground border border-border p-3 rounded-lg text-sm overflow-auto">
{`site:
theme:
preset: "${theme?.preset || 'zinc'}"
@@ -150,9 +232,10 @@ export function Content({ config, routes, selectedItem }: ContentProps) {
<p className="text-muted-foreground mb-4">
<span className="font-medium text-primary">{routes.routes?.length || 0}</span> routes configured.
</p>
<pre className="bg-muted p-4 rounded-lg text-sm overflow-auto">
<pre className="bg-muted text-foreground border border-border p-4 rounded-lg text-sm overflow-auto">
{JSON.stringify(routes.routes?.slice(0, 3), null, 2)}
</pre>
</div>
</main>
)
}
+2 -3
View File
@@ -1,9 +1,8 @@
// Footer component
import type { UIConfig } from './types'
export function Footer({ config }: { config: UIConfig }) {
// Resolve footer component via template slot ref (e.g., footer_main)
const footerSlot = config.templates?.docs?.slots?.footer
export function Footer({ config, templateKey = 'docs' }: { config: UIConfig; templateKey?: string }) {
const footerSlot = config.templates?.[templateKey]?.slots?.footer
const footerRef = footerSlot?.ref
const footerComponent = footerRef
? config.components?.[footerRef]
+130 -30
View File
@@ -1,10 +1,28 @@
// Header component
import type { UIConfig } from './types'
// Header component — Mintlify-style docs chrome
import { Github, Menu, Search } from 'lucide-react'
import type { NavTabConfig, UIConfig } from './types'
import { LocaleSwitcher } from './i18n'
import { Button } from '@/components/ui/button'
import { ThemeToggle } from '@/components/theme-toggle'
export function Header({ config }: { config: UIConfig }) {
// Resolve header component via template slot ref (e.g., header_main)
const headerSlot = config.templates?.docs?.slots?.header
interface HeaderProps {
config: UIConfig
templateKey?: string
onMenuClick?: () => void
navTabs?: NavTabConfig[]
activeTabIndex?: number
onTabChange?: (index: number) => void
}
export function Header({
config,
templateKey = 'docs',
onMenuClick,
navTabs,
activeTabIndex = 0,
onTabChange,
}: HeaderProps) {
const headerSlot = config.templates?.[templateKey]?.slots?.header
const headerRef = headerSlot?.ref
const headerComponent = headerRef
? config.components?.[headerRef]
@@ -16,56 +34,138 @@ export function Header({ config }: { config: UIConfig }) {
cta?: { label: string; href: string }
} | undefined
// Get logo configuration - support both header.logoImage and config.logo
const logoConfig = config.logo
const isDarkMode = document.documentElement.classList.contains('dark')
const logoSrc = header?.logoImage || (logoConfig ? (isDarkMode ? (logoConfig.dark || logoConfig.light) : (logoConfig.light || logoConfig.dark)) : null)
const logoHref = logoConfig?.href || '/'
const logoText = header?.logoText || config.site?.title || 'PraisonAIUI'
const tabs = navTabs ?? config.navigation?.tabs ?? []
const navbar = config.navbar
const navbarLinks = navbar?.links ?? header?.links ?? []
const primary = navbar?.primary ?? (header?.cta ? { type: 'button' as const, label: header.cta.label, href: header.cta.href } : undefined)
const showMintlifyNav = tabs.length > 0
const onLogoClick = (event: React.MouseEvent) => {
event.preventDefault()
window.history.pushState({}, '', logoHref)
window.dispatchEvent(new CustomEvent('aiui:navigate', { detail: { path: logoHref } }))
}
const onSearchClick = () => {
window.dispatchEvent(new CustomEvent('aiui:search-open'))
}
return (
<header className="sticky top-0 z-50 border-b border-border/50 bg-background/80 backdrop-blur-xl supports-[backdrop-filter]:bg-background/60">
<div className="max-w-screen-2xl mx-auto flex h-16 items-center px-6 gap-8">
<a href={logoHref} className="flex items-center gap-3 group cursor-pointer" onClick={(e) => {
e.preventDefault()
window.history.pushState({}, '', logoHref)
window.location.reload()
}}>
<header
className="sticky top-0 z-50 border-b border-border/40 bg-background/90 backdrop-blur-xl supports-[backdrop-filter]:bg-background/75"
data-aiui-header-tabs={showMintlifyNav ? 'true' : undefined}
>
<div className="flex h-14 items-center gap-4 px-4 lg:px-6">
{onMenuClick && (
<Button
type="button"
variant="ghost"
size="icon"
className="md:hidden shrink-0 -ml-1"
onClick={onMenuClick}
aria-label="Open navigation menu"
>
<Menu className="h-5 w-5" />
</Button>
)}
<a
href={logoHref}
className="flex items-center gap-2.5 group cursor-pointer shrink-0 min-w-0"
onClick={onLogoClick}
>
{logoSrc ? (
<img
src={logoSrc}
alt="Logo"
className="w-8 h-8 rounded-lg shadow-lg shadow-primary/20 group-hover:shadow-primary/40 transition-shadow object-contain"
<img
src={logoSrc}
alt="Logo"
className="h-7 w-7 rounded-md object-contain"
/>
) : (
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-primary/80 to-primary flex items-center justify-center shadow-lg shadow-primary/20 group-hover:shadow-primary/40 transition-shadow">
<span className="text-primary-foreground text-xs font-bold">AI</span>
<div className="h-7 w-7 rounded-md bg-gradient-to-br from-primary/80 to-primary flex items-center justify-center">
<span className="text-primary-foreground text-[10px] font-bold">AI</span>
</div>
)}
<span className="font-semibold text-lg tracking-tight">{header?.logoText || config.site?.title || 'PraisonAIUI'}</span>
<span className="font-semibold text-[15px] tracking-tight truncate hidden sm:inline">{logoText}</span>
</a>
<nav className="hidden md:flex items-center gap-1 flex-1">
{header?.links?.map((link) => (
{showMintlifyNav && (
<nav className="hidden md:flex items-center gap-1 ml-2" aria-label="Primary docs sections">
{tabs.map((tab, index) => (
<button
key={tab.tab}
type="button"
onClick={() => onTabChange?.(index)}
className={`px-3 py-1.5 text-sm rounded-md transition-colors ${index === activeTabIndex
? 'text-foreground font-medium'
: 'text-muted-foreground hover:text-foreground'
}`}
>
{tab.tab}
</button>
))}
</nav>
)}
{!showMintlifyNav && (
<nav className="hidden md:flex items-center gap-1 flex-1 ml-2">
{navbarLinks.map((link) => (
<a
key={link.href}
href={link.href}
className="px-3 py-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors rounded-md hover:bg-muted/50"
>
{link.label}
</a>
))}
</nav>
)}
<div className="flex-1 min-w-0" />
{config.search?.enabled !== false && showMintlifyNav && (
<button
type="button"
onClick={onSearchClick}
className="hidden sm:flex items-center gap-2 h-9 w-full max-w-[220px] px-3 text-sm text-muted-foreground border border-border/60 rounded-lg bg-muted/30 hover:bg-muted/50 transition-colors"
aria-label="Search documentation"
>
<Search className="h-4 w-4 shrink-0" />
<span className="flex-1 text-left truncate">Search...</span>
<kbd className="hidden lg:inline text-[10px] font-medium text-muted-foreground/80 border border-border/60 rounded px-1.5 py-0.5">⌘K</kbd>
</button>
)}
<div className="flex items-center gap-1.5 shrink-0">
{showMintlifyNav && navbarLinks.map((link) => (
<a
key={link.href}
href={link.href}
className="px-3 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors rounded-md hover:bg-muted/50"
className="hidden lg:inline-flex px-3 py-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
>
{link.label}
</a>
))}
</nav>
<div className="flex items-center gap-2">
<LocaleSwitcher />
{header?.cta && (
{primary && (
<a
href={header.cta.href}
className="inline-flex items-center justify-center rounded-md text-sm font-medium bg-primary text-primary-foreground shadow h-9 px-4 hover:bg-primary/90 transition-colors"
href={primary.href}
target={primary.href.startsWith('http') ? '_blank' : undefined}
rel={primary.href.startsWith('http') ? 'noopener noreferrer' : undefined}
className="inline-flex items-center justify-center gap-1.5 rounded-lg text-sm font-medium bg-primary text-primary-foreground h-9 px-3.5 hover:bg-primary/90 transition-colors"
>
{header.cta.label}
{primary.type === 'github' && <Github className="h-4 w-4" />}
{primary.label ?? (primary.type === 'github' ? 'GitHub' : 'Get started')}
</a>
)}
<ThemeToggle />
<LocaleSwitcher />
</div>
</div>
</header>
+79 -23
View File
@@ -1,55 +1,111 @@
// Sidebar component — navigation tree
// Sidebar component — Mintlify-style navigation tree
import { ChevronRight } from 'lucide-react'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator'
import type { NavItem } from './types'
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
} from '@/components/ui/sheet'
import { normalizeDocPath } from './pathUtils'
import type { DocsNav, NavItem } from './types'
interface SidebarProps {
nav: { items?: NavItem[] }
interface NavTreeProps {
nav: DocsNav
activeItem: string
onItemClick: (item: NavItem) => void
}
export function Sidebar({ nav, activeItem, onItemClick }: SidebarProps) {
export function NavTree({ nav, activeItem, onItemClick }: NavTreeProps) {
const renderItem = (item: NavItem, depth = 0) => {
const isActive = (item.path || item.title) === activeItem
const hasChildren = item.children && item.children.length > 0
if (hasChildren) {
return (
<div key={item.title + (item.path || '')}>
<div className="flex items-center gap-2 px-3 py-1.5 text-xs font-semibold text-muted-foreground/70 uppercase tracking-widest mt-4 first:mt-0">
<div key={item.title + (item.path || '')} className="mb-4">
<div className="flex items-center gap-1 px-3 py-1.5 text-[11px] font-semibold text-muted-foreground/80 uppercase tracking-wider">
{item.title}
</div>
<div className="space-y-0.5">
<div className="space-y-0.5 mt-1">
{item.children!.map((child) => renderItem(child, depth + 1))}
</div>
</div>
)
}
const href = normalizeDocPath(item.path || '/')
return (
<button
<a
key={item.title + (item.path || '')}
onClick={() => onItemClick(item)}
className={`w-full text-left px-3 py-1.5 text-sm rounded-md transition-all duration-150 ${isActive
? 'bg-primary/10 text-primary font-medium border-l-2 border-primary'
: 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
href={href}
data-nav-path={item.path || ''}
onClick={(event) => {
event.preventDefault()
onItemClick(item)
}}
className={`group flex items-center gap-1.5 w-full text-left px-3 py-1.5 text-[13px] rounded-md transition-colors ${isActive
? 'text-primary font-medium bg-primary/10'
: 'text-muted-foreground hover:text-foreground hover:bg-muted/40'
}`}
style={{ paddingLeft: `${12 + depth * 12}px` }}
style={{ paddingLeft: `${12 + depth * 10}px` }}
>
{item.title}
</button>
{depth > 0 && (
<ChevronRight className={`h-3 w-3 shrink-0 opacity-0 group-hover:opacity-40 ${isActive ? 'opacity-60 text-primary' : ''}`} />
)}
<span className="truncate">{item.title}</span>
</a>
)
}
return (
<aside className="w-64 min-w-[16rem] border-r border-border/50 hidden md:block">
<ScrollArea className="h-[calc(100vh-4rem)] py-4 px-2">
<nav className="space-y-0.5">
{nav.items?.map((group) => renderItem(group))}
</nav>
<Separator className="my-4" />
<nav className="space-y-0.5 pb-6">
{nav.items?.map((group) => renderItem(group))}
</nav>
)
}
interface SidebarProps extends NavTreeProps {
nav: DocsNav
}
export function Sidebar({ nav, activeItem, onItemClick }: SidebarProps) {
return (
<aside className="docs-sidebar w-[17rem] min-w-[17rem] shrink-0 hidden md:block border-r border-border/40">
<ScrollArea className="h-[calc(100vh-3.5rem)] sticky top-14">
<div className="py-5 px-2">
<NavTree nav={nav} activeItem={activeItem} onItemClick={onItemClick} />
</div>
</ScrollArea>
</aside>
)
}
interface MobileNavSheetProps extends NavTreeProps {
open: boolean
onOpenChange: (open: boolean) => void
title?: string
}
export function MobileNavSheet({ open, onOpenChange, nav, activeItem, onItemClick, title = 'Navigation' }: MobileNavSheetProps) {
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent side="left" className="w-72 p-0">
<SheetHeader className="border-b px-4 py-3">
<SheetTitle>{title}</SheetTitle>
</SheetHeader>
<ScrollArea className="h-[calc(100vh-4rem)] px-2 py-4">
<NavTree
nav={nav}
activeItem={activeItem}
onItemClick={(item) => {
onItemClick(item)
onOpenChange(false)
}}
/>
</ScrollArea>
</SheetContent>
</Sheet>
)
}
+137 -41
View File
@@ -1,51 +1,147 @@
// Table of Contents & right sidebar component
import { useCallback, useEffect, useState } from 'react'
import type { NavItem, ZonesConfig } from './types'
import { ZoneWidgets } from './Widgets'
export function Toc({ selectedItem, zones }: { selectedItem: NavItem | null; zones?: ZonesConfig }) {
const rightSidebarWidgets = zones?.rightSidebar || []
interface TocHeading {
id: string
text: string
level: number
}
function collectHeadings(): TocHeading[] {
const article = document.querySelector('#main-content article') ?? document.querySelector('article.prose')
if (!article) return []
return Array.from(article.querySelectorAll('h2[id], h3[id], h4[id]')).map((el) => ({
id: el.id,
text: el.textContent?.trim() ?? '',
level: Number(el.tagName.slice(1)),
}))
}
function usePageHeadings(selectedItem: NavItem | null) {
const [headings, setHeadings] = useState<TocHeading[]>([])
const [activeId, setActiveId] = useState('')
const refreshHeadings = useCallback(() => {
setHeadings(collectHeadings())
}, [])
useEffect(() => {
refreshHeadings()
const timer = window.setTimeout(refreshHeadings, 100)
const timer2 = window.setTimeout(refreshHeadings, 500)
return () => {
window.clearTimeout(timer)
window.clearTimeout(timer2)
}
}, [selectedItem, refreshHeadings])
useEffect(() => {
if (!headings.length) return
const observer = new IntersectionObserver(
(entries) => {
const visible = entries
.filter((entry) => entry.isIntersecting)
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)
if (visible[0]?.target.id) {
setActiveId(visible[0].target.id)
}
},
{ rootMargin: '-20% 0px -70% 0px', threshold: 0 },
)
for (const heading of headings) {
const el = document.getElementById(heading.id)
if (el) observer.observe(el)
}
return () => observer.disconnect()
}, [headings])
return { headings, activeId }
}
function TocLinks({ headings, activeId }: { headings: TocHeading[]; activeId: string }) {
if (headings.length === 0) {
return <p className="text-sm text-muted-foreground">No sections on this page.</p>
}
return (
<aside className="w-64 hidden lg:block border-l border-border/50">
<div className="sticky top-20 px-4 py-6 space-y-4">
{/* Table of Contents */}
<div>
<h4 className="text-xs font-semibold text-muted-foreground/70 uppercase tracking-widest mb-4">
On this page
</h4>
<nav className="space-y-2 text-sm">
{selectedItem ? (
<div className="space-y-2">
<a href="#" className="flex items-center gap-2 text-primary font-medium">
<span className="w-1 h-1 rounded-full bg-primary" />
{selectedItem.title}
</a>
<a href="#overview" className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors pl-3">
Overview
</a>
<a href="#usage" className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors pl-3">
Usage
</a>
</div>
) : (
<div className="space-y-2">
<a href="#theme" className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors">
<span className="w-1 h-1 rounded-full bg-muted-foreground/30" />
Theme Configuration
</a>
<a href="#presets" className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors">
<span className="w-1 h-1 rounded-full bg-muted-foreground/30" />
Available Presets
</a>
</div>
)}
</nav>
</div>
<div className="space-y-2.5">
{headings.map((heading) => {
const isActive = heading.id === activeId
return (
<a
key={heading.id}
href={`#${heading.id}`}
className={`flex items-start gap-2 text-[13px] leading-snug transition-colors ${heading.level === 3 ? 'pl-3' : heading.level === 4 ? 'pl-5' : ''
} ${isActive
? 'text-primary font-medium'
: 'text-muted-foreground hover:text-foreground'
}`}
>
<span
className={`mt-[0.45rem] h-1.5 w-1.5 shrink-0 rounded-full ${isActive ? 'bg-primary' : 'bg-muted-foreground/30'
}`}
/>
<span>{heading.text}</span>
</a>
)
})}
</div>
)
}
{/* Zone Widgets (excluding Toc) */}
{rightSidebarWidgets.filter(w => w.type !== 'Toc').length > 0 && (
<div className="pt-4 border-t border-border/50">
<ZoneWidgets widgets={rightSidebarWidgets.filter(w => w.type !== 'Toc')} />
export function MobileToc({ selectedItem }: { selectedItem: NavItem | null }) {
const { headings, activeId } = usePageHeadings(selectedItem)
if (!selectedItem || headings.length === 0) return null
return (
<details className="lg:hidden border border-border/60 rounded-lg mb-6 px-4 py-3 bg-muted/20">
<summary className="text-sm font-medium cursor-pointer">On this page</summary>
<nav className="mt-3">
<TocLinks headings={headings} activeId={activeId} />
</nav>
</details>
)
}
export function Toc({
selectedItem,
zones,
showToc = true,
}: {
selectedItem: NavItem | null
zones?: ZonesConfig
showToc?: boolean
}) {
const { headings, activeId } = usePageHeadings(selectedItem)
const rightSidebarWidgets = zones?.rightSidebar || []
if (!showToc && rightSidebarWidgets.filter((w) => w.type !== 'Toc').length === 0) {
return null
}
return (
<aside className="docs-toc w-[16rem] min-w-[16rem] shrink-0 hidden lg:block">
<div className="sticky top-14 h-[calc(100vh-3.5rem)] overflow-y-auto px-4 py-6">
{showToc && (
<div>
<h4 className="text-[11px] font-semibold text-muted-foreground/80 uppercase tracking-wider mb-4">
On this page
</h4>
<nav>
<TocLinks headings={headings} activeId={activeId} />
</nav>
</div>
)}
{rightSidebarWidgets.filter((w) => w.type !== 'Toc').length > 0 && (
<div className="pt-4 mt-4 border-t border-border/40">
<ZoneWidgets widgets={rightSidebarWidgets.filter((w) => w.type !== 'Toc')} />
</div>
)}
</div>
+5 -11
View File
@@ -6,22 +6,16 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
type Theme = "light" | "dark" | "system"
import { setThemePreference, type ThemePreference } from "../themes"
interface ThemeToggleProps {
theme?: Theme
onThemeChange?: (theme: Theme) => void
theme?: ThemePreference
onThemeChange?: (theme: ThemePreference) => void
}
export function ThemeToggle({ onThemeChange }: ThemeToggleProps) {
const setTheme = (newTheme: Theme) => {
if (newTheme === "system") {
const systemDark = window.matchMedia("(prefers-color-scheme: dark)").matches
document.documentElement.classList.toggle("dark", systemDark)
} else {
document.documentElement.classList.toggle("dark", newTheme === "dark")
}
const setTheme = (newTheme: ThemePreference) => {
setThemePreference(newTheme)
onThemeChange?.(newTheme)
}
+89
View File
@@ -0,0 +1,89 @@
import type { NavItem, NavTabConfig } from '../types'
function sectionTitle(item: NavItem): string {
return item.title.trim().toLowerCase()
}
function collectPaths(item: NavItem): string[] {
const paths: string[] = []
if (item.path) paths.push(item.path.toLowerCase())
for (const child of item.children ?? []) {
paths.push(...collectPaths(child))
}
return paths
}
function pathMatchesPage(docPath: string, page: string): boolean {
const normalizedPage = page.replace(/^\/+/, '').toLowerCase()
const normalizedPath = docPath.replace(/\/+$/, '').toLowerCase()
if (normalizedPage === 'index') {
return normalizedPath.endsWith('/index') || normalizedPath === '/docs'
}
const suffix = `/${normalizedPage}`
return normalizedPath.endsWith(suffix) || normalizedPath.endsWith(`${suffix}/index`)
}
/** Whether a sidebar group belongs to the given navigation tab (from topnav plugin logic). */
export function navItemBelongsToTab(item: NavItem, tab: NavTabConfig): boolean {
if (!tab.groups?.length) return false
const header = sectionTitle(item)
const paths = collectPaths(item)
for (const grp of tab.groups) {
const groupName = grp.group.toLowerCase()
if (header === groupName) return true
if (grp.prefix) {
const prefix = grp.prefix.toLowerCase()
if (header === prefix || header === prefix.replace(/-/g, ' ')) return true
const prefixPath = `/docs/${prefix}`
if (paths.some((path) => path === prefixPath || path.startsWith(`${prefixPath}/`))) {
return true
}
}
if (grp.pages?.some((page) => paths.some((path) => pathMatchesPage(path, page)))) {
return true
}
if (!item.children?.length && grp.pages?.some((page) => {
const slug = page.split('/').pop()?.replace(/-/g, ' ') ?? ''
return header === slug || header === page.toLowerCase()
})) {
return true
}
}
return false
}
/** Pick the active tab index from the current URL path. */
export function detectActiveTabIndex(tabs: NavTabConfig[], path: string): number {
const normalized = path.toLowerCase()
let bestMatch = -1
let bestMatchLen = 0
for (let i = 0; i < tabs.length; i++) {
const tab = tabs[i]
for (const grp of tab.groups ?? []) {
if (!grp.prefix) continue
const needle = `/${grp.prefix.toLowerCase()}/`
if (normalized.includes(needle) && needle.length > bestMatchLen) {
bestMatch = i
bestMatchLen = needle.length
}
}
}
if (bestMatch >= 0) return bestMatch
return 0
}
export function filterNavByTab(items: NavItem[], tab: NavTabConfig | undefined): NavItem[] {
if (!tab) return items
return items.filter((item) => navItemBelongsToTab(item, tab))
}
+171 -32
View File
@@ -12,37 +12,37 @@
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 12px);
--radius-4xl: calc(var(--radius) + 16px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--color-background: hsl(var(--background));
--color-foreground: hsl(var(--foreground));
--color-card: hsl(var(--card));
--color-card-foreground: hsl(var(--card-foreground));
--color-popover: hsl(var(--popover));
--color-popover-foreground: hsl(var(--popover-foreground));
--color-primary: hsl(var(--primary));
--color-primary-foreground: hsl(var(--primary-foreground));
--color-secondary: hsl(var(--secondary));
--color-secondary-foreground: hsl(var(--secondary-foreground));
--color-muted: hsl(var(--muted));
--color-muted-foreground: hsl(var(--muted-foreground));
--color-accent: hsl(var(--accent));
--color-accent-foreground: hsl(var(--accent-foreground));
--color-destructive: hsl(var(--destructive));
--color-border: hsl(var(--border));
--color-input: hsl(var(--input));
--color-ring: hsl(var(--ring));
--color-chart-1: hsl(var(--chart-1));
--color-chart-2: hsl(var(--chart-2));
--color-chart-3: hsl(var(--chart-3));
--color-chart-4: hsl(var(--chart-4));
--color-chart-5: hsl(var(--chart-5));
--color-sidebar: hsl(var(--sidebar));
--color-sidebar-foreground: hsl(var(--sidebar-foreground));
--color-sidebar-primary: hsl(var(--sidebar-primary));
--color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
--color-sidebar-accent: hsl(var(--sidebar-accent));
--color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
--color-sidebar-border: hsl(var(--sidebar-border));
--color-sidebar-ring: hsl(var(--sidebar-ring));
}
/* Color variables are injected via theme.css at build time.
@@ -52,7 +52,146 @@
* {
@apply border-border outline-ring/50;
}
html,
body {
@apply bg-background text-foreground;
background-color: hsl(var(--background));
color: hsl(var(--foreground));
}
}
@layer components {
/* Readable prose in light and dark mode */
.prose-neutral {
--tw-prose-body: hsl(var(--foreground));
--tw-prose-headings: hsl(var(--foreground));
--tw-prose-bold: hsl(var(--foreground));
--tw-prose-counters: hsl(var(--muted-foreground));
--tw-prose-bullets: hsl(var(--muted-foreground));
--tw-prose-pre-code: hsl(var(--foreground));
--tw-prose-pre-bg: hsl(var(--muted));
--tw-prose-code: hsl(var(--foreground));
}
.prose pre,
.prose-neutral :where(pre) {
@apply bg-muted text-foreground border border-border;
color: hsl(var(--foreground)) !important;
background-color: hsl(var(--muted)) !important;
}
.prose pre code,
.prose-neutral :where(pre code) {
@apply text-foreground bg-transparent;
color: inherit !important;
}
.prose :not(pre) > code {
@apply bg-primary/10 text-primary;
}
.prose .aiui-feature-grid > li {
@apply list-none;
}
.prose .aiui-tabs pre {
@apply my-2;
}
.mermaid-diagram {
display: block;
width: 100%;
margin: 1.5rem 0;
padding: 1rem 1.25rem;
border-radius: 12px;
overflow-x: auto;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.mermaid-diagram-svg {
width: 100%;
min-width: 100%;
display: block;
}
:root:not(.dark) .mermaid-diagram:not(.mermaid-error) {
background: hsl(var(--muted));
border: 1px solid hsl(var(--border));
}
.dark .mermaid-diagram:not(.mermaid-error) {
background: rgba(15, 23, 42, 0.5);
border: 1px solid rgba(148, 163, 184, 0.15);
}
.mermaid-diagram:not(.mermaid-error):hover {
border-color: rgba(20, 184, 166, 0.4);
box-shadow: 0 0 24px rgba(13, 148, 136, 0.12);
}
.mermaid-diagram svg {
width: 100% !important;
max-width: 100%;
height: auto !important;
display: block;
}
.mermaid-diagram .nodeLabel,
.mermaid-diagram .label div,
.mermaid-diagram .cluster-label .nodeLabel {
color: #ffffff !important;
fill: #ffffff !important;
font-family: "Inter", system-ui, -apple-system, sans-serif !important;
font-weight: 500 !important;
}
.mermaid-diagram .edgeLabel {
color: #e2e8f0 !important;
fill: #e2e8f0 !important;
background-color: rgba(15, 23, 42, 0.85) !important;
padding: 2px 6px;
border-radius: 4px;
}
.mermaid-diagram .cluster-label .nodeLabel {
font-weight: 600 !important;
font-size: 0.95em;
}
.mermaid-diagram .node rect,
.mermaid-diagram .node circle,
.mermaid-diagram .node polygon {
rx: 8;
ry: 8;
}
/* Mintlify-style docs shell */
.docs-shell {
width: 100%;
}
.docs-main-inner {
min-height: calc(100vh - 3.5rem);
}
}
/* Prose readability — must beat @tailwindcss/typography defaults (unlayered) */
article.prose :where(p, li, td, th, blockquote, strong, em, h1, h3, h4, h5, h6) {
color: hsl(var(--foreground)) !important;
-webkit-text-fill-color: unset !important;
opacity: 1 !important;
}
article.prose :where(h2) {
color: hsl(var(--primary)) !important;
-webkit-text-fill-color: unset !important;
opacity: 1 !important;
}
article.prose .aiui-feature-grid > li {
color: hsl(var(--foreground)) !important;
}
.dark article.prose.dark\:prose-invert :where(p, li, td, th, blockquote, strong, h1, h2, h3, h4) {
color: hsl(var(--foreground)) !important;
-webkit-text-fill-color: unset !important;
}
@@ -0,0 +1,98 @@
import { useEffect, useId, useRef, useState } from 'react'
import { fitMermaidSvg, getMermaidConfig, isDarkMode } from './mermaidThemes'
let renderCounter = 0
function nextRenderId(baseId: string): string {
renderCounter += 1
return `mermaid-${baseId.replace(/:/g, '')}-${renderCounter}`
}
export function MermaidDiagram({ chart }: { chart: string }) {
const baseId = useId()
const containerRef = useRef<HTMLDivElement>(null)
const svgRef = useRef<HTMLDivElement>(null)
const bindFunctionsRef = useRef<((element: Element) => void) | undefined>(undefined)
const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading')
const [errorMessage, setErrorMessage] = useState('')
const [svgMarkup, setSvgMarkup] = useState('')
useEffect(() => {
const container = containerRef.current
if (!container) return
let cancelled = false
const render = async () => {
setStatus('loading')
setErrorMessage('')
setSvgMarkup('')
const mermaid = (await import('mermaid')).default
mermaid.initialize(getMermaidConfig(isDarkMode()))
const styles = getComputedStyle(container)
const paddingX = parseFloat(styles.paddingLeft) + parseFloat(styles.paddingRight)
const containerWidth = container.clientWidth - paddingX
try {
const { svg, bindFunctions } = await mermaid.render(nextRenderId(baseId), chart)
if (cancelled) return
bindFunctionsRef.current = bindFunctions
setSvgMarkup(fitMermaidSvg(svg, containerWidth))
setStatus('ready')
} catch (err) {
if (cancelled) return
setStatus('error')
setErrorMessage(err instanceof Error ? err.message : 'Failed to render diagram')
}
}
void render()
const observer = new ResizeObserver(() => {
void render()
})
observer.observe(container)
const themeObserver = new MutationObserver(() => {
void render()
})
themeObserver.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class'],
})
return () => {
cancelled = true
observer.disconnect()
themeObserver.disconnect()
}
}, [chart, baseId])
useEffect(() => {
if (status !== 'ready' || !svgRef.current) return
bindFunctionsRef.current?.(svgRef.current)
}, [status, svgMarkup])
if (status === 'error') {
return (
<pre className="mermaid-diagram mermaid-error text-destructive text-sm my-4 p-4 rounded-lg border border-destructive/30 bg-destructive/5 overflow-x-auto">
{errorMessage}
</pre>
)
}
return (
<div
ref={containerRef}
className={`mermaid-diagram w-full${status === 'loading' ? ' mermaid-loading text-muted-foreground text-sm' : ''}`}
aria-busy={status === 'loading'}
aria-label={status === 'loading' ? 'Loading diagram' : 'Mermaid diagram'}
>
{status === 'loading' ? 'Loading diagram…' : null}
{svgMarkup ? (
<div ref={svgRef} className="mermaid-diagram-svg w-full" dangerouslySetInnerHTML={{ __html: svgMarkup }} />
) : null}
</div>
)
}
+118
View File
@@ -0,0 +1,118 @@
/** Mermaid theme config — aligned with plugins/mermaid.js */
export const MERMAID_DARK_THEME = {
theme: 'base' as const,
themeVariables: {
background: 'transparent',
mainBkg: '#0d9488',
primaryColor: '#0d9488',
primaryBorderColor: '#14b8a6',
primaryTextColor: '#ffffff',
secondaryColor: '#6366f1',
secondaryBorderColor: '#818cf8',
secondaryTextColor: '#ffffff',
tertiaryColor: '#e11d48',
tertiaryBorderColor: '#fb7185',
tertiaryTextColor: '#ffffff',
textColor: '#f1f5f9',
labelTextColor: '#f1f5f9',
lineColor: '#94a3b8',
arrowheadColor: '#cbd5e1',
nodeBorder: '#14b8a6',
clusterBkg: 'rgba(13, 148, 136, 0.08)',
clusterBorder: 'rgba(20, 184, 166, 0.4)',
defaultLinkColor: '#94a3b8',
edgeLabelBackground: 'rgba(15, 23, 42, 0.85)',
nodeTextColor: '#ffffff',
actorBkg: '#0d9488',
actorBorder: '#14b8a6',
actorTextColor: '#ffffff',
actorLineColor: '#64748b',
signalColor: '#cbd5e1',
signalTextColor: '#f1f5f9',
activationBorderColor: '#14b8a6',
activationBkgColor: 'rgba(13, 148, 136, 0.2)',
sequenceNumberColor: '#ffffff',
noteBkgColor: 'rgba(99, 102, 241, 0.2)',
noteBorderColor: '#818cf8',
noteTextColor: '#f1f5f9',
titleColor: '#f8fafc',
fontFamily: '"Inter", system-ui, -apple-system, sans-serif',
fontSize: '16px',
},
}
export const MERMAID_LIGHT_THEME = {
theme: 'base' as const,
themeVariables: {
background: 'transparent',
mainBkg: '#0d9488',
primaryColor: '#0d9488',
primaryBorderColor: '#0f766e',
primaryTextColor: '#ffffff',
secondaryColor: '#6366f1',
secondaryBorderColor: '#4f46e5',
secondaryTextColor: '#ffffff',
tertiaryColor: '#e11d48',
tertiaryBorderColor: '#be123c',
tertiaryTextColor: '#ffffff',
textColor: '#1e293b',
labelTextColor: '#334155',
lineColor: '#94a3b8',
arrowheadColor: '#64748b',
nodeBorder: '#0f766e',
clusterBkg: 'rgba(13, 148, 136, 0.06)',
clusterBorder: 'rgba(15, 118, 110, 0.3)',
defaultLinkColor: '#94a3b8',
edgeLabelBackground: 'rgba(255, 255, 255, 0.9)',
nodeTextColor: '#ffffff',
actorBkg: '#0d9488',
actorBorder: '#0f766e',
actorTextColor: '#ffffff',
actorLineColor: '#cbd5e1',
signalColor: '#64748b',
signalTextColor: '#1e293b',
noteBkgColor: 'rgba(99, 102, 241, 0.1)',
noteBorderColor: '#6366f1',
noteTextColor: '#1e293b',
titleColor: '#0f172a',
fontFamily: '"Inter", system-ui, -apple-system, sans-serif',
fontSize: '16px',
},
}
export function isDarkMode(): boolean {
return document.documentElement.classList.contains('dark')
}
export function getMermaidConfig(dark: boolean) {
const theme = dark ? MERMAID_DARK_THEME : MERMAID_LIGHT_THEME
return {
startOnLoad: false,
securityLevel: 'strict' as const,
...theme,
flowchart: {
useMaxWidth: true,
htmlLabels: true,
curve: 'basis' as const,
},
sequence: {
useMaxWidth: true,
wrap: true,
},
er: { useMaxWidth: true },
gantt: { useMaxWidth: true },
}
}
/** Ensure rendered SVG stretches to the diagram container (Mintlify-style). */
export function fitMermaidSvg(svg: string, containerWidth: number): string {
const width = Math.max(Math.floor(containerWidth), 320)
return svg.replace(/<svg([^>]*)>/, (_match, attrs: string) => {
const cleaned = attrs
.replace(/\swidth="[^"]*"/g, '')
.replace(/\sheight="[^"]*"/g, '')
.replace(/\sstyle="[^"]*"/g, '')
return `<svg${cleaned} width="${width}" style="width:100%;max-width:100%;height:auto;display:block;">`
})
}
@@ -0,0 +1,55 @@
/** Post-render class-only fixes for MkDocs-style content. No DOM moves — React owns the tree. */
export function enhanceMkdocsDom(root: HTMLElement): void {
const articles = new Set<HTMLElement>()
if (root.matches('article.prose, #main-content article')) {
articles.add(root)
}
root.querySelectorAll<HTMLElement>('article.prose, #main-content article').forEach((el) => articles.add(el))
for (const article of articles) {
hideRawDivParagraphs(article)
enhanceFeatureGrid(article)
}
}
/** Hide MkDocs artefact paragraphs — never remove nodes React may still own. */
function hideRawDivParagraphs(article: HTMLElement): void {
for (const p of article.querySelectorAll('p')) {
const text = p.textContent?.trim() ?? ''
if (/^<\/?div[\s>]/.test(text) || text === '</div>') {
p.classList.add('hidden')
}
}
}
function enhanceFeatureGrid(article: HTMLElement): void {
for (const ul of article.querySelectorAll('ul')) {
if (ul.classList.contains('aiui-feature-grid')) continue
const firstLi = ul.querySelector('li')
const looksLikeCards = Boolean(
firstLi?.textContent?.includes('YAML-Driven')
|| firstLi?.textContent?.includes('Component Slots')
|| firstLi?.querySelector('strong'),
)
if (!looksLikeCards) continue
ul.classList.add(
'aiui-feature-grid',
'grid',
'grid-cols-1',
'md:grid-cols-2',
'gap-4',
'my-6',
'list-none',
'pl-0',
)
for (const li of ul.querySelectorAll('li')) {
li.classList.add('border', 'border-border', 'rounded-lg', 'p-4', 'bg-card')
}
}
}
/** No-op — React article must not receive foreign plugin nodes. */
export function teardownMkdocsEnhancements(_root: HTMLElement): void {}
@@ -0,0 +1,100 @@
/** MkDocs Material syntax → standard markdown for react-markdown. */
export const MKDOCS_ICON_MAP: Record<string, string> = {
':material-file-document:': '📄',
':material-puzzle:': '🧩',
':material-palette:': '🎨',
':material-rocket-launch:': '🚀',
':material-code-tags:': '💻',
':material-cog:': '⚙️',
':material-lightning-bolt:': '⚡',
':material-shield:': '🛡️',
':material-database:': '🗄️',
':material-web:': '🌐',
':material-book:': '📖',
':material-star:': '⭐',
':material-check:': '✅',
':material-close:': '❌',
':material-alert:': '⚠️',
':material-information:': 'ℹ️',
}
const TAB_HEADING_PREFIX = '\u200Btab:'
export function replaceMkdocsIcons(text: string): string {
let result = text
for (const [shortcode, emoji] of Object.entries(MKDOCS_ICON_MAP)) {
result = result.replaceAll(shortcode, emoji)
}
return result
.replace(/:material-[\w-]+:/g, '•')
.replace(/:octicons-[\w-]+(?:-\d+)?:/g, '•')
}
export function stripMkdocsGridWrappers(text: string): string {
return text
.replace(/<div[^>]*markdown[^>]*>\s*/gi, '')
.replace(/<\/div>\s*/gi, '')
}
/** Convert `=== "Title"` tab groups to headings the DOM enhancer recognises. */
export function convertMkdocsTabs(md: string): string {
const lines = md.split('\n')
const out: string[] = []
let i = 0
while (i < lines.length) {
const tabMatch = lines[i].match(/^===\s+"([^"]+)"\s*$/)
if (!tabMatch) {
out.push(lines[i])
i++
continue
}
const title = tabMatch[1]
i++
while (i < lines.length && lines[i].trim() === '') i++
const block: string[] = []
while (i < lines.length) {
if (/^===\s+"[^"]+"\s*$/.test(lines[i])) break
if (lines[i].trim() === '' && i + 1 < lines.length && /^===\s+"[^"]+"\s*$/.test(lines[i + 1])) break
if (lines[i].startsWith(' ') || lines[i].trimStart().startsWith('```')) {
block.push(lines[i].replace(/^ /, ''))
i++
continue
}
if (block.length > 0 && lines[i].trim() === '') {
block.push('')
i++
continue
}
break
}
out.push(`### ${TAB_HEADING_PREFIX}${title}`)
out.push('')
out.push(...block)
out.push('')
}
return out.join('\n')
}
export function preprocessMkdocsMarkdown(md: string): string {
let result = stripMkdocsGridWrappers(md)
result = replaceMkdocsIcons(result)
result = convertMkdocsTabs(result)
return result
}
export function isMkdocsTabHeading(text: string): boolean {
return text.startsWith(TAB_HEADING_PREFIX) || text.startsWith('tab:')
}
export function mkdocsTabTitle(text: string): string {
return text.replace(/^\u200Btab:/, '').replace(/^tab:/, '')
}
+8
View File
@@ -0,0 +1,8 @@
export function slugify(text: string): string {
return text
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '')
}
+37
View File
@@ -0,0 +1,37 @@
/** Canonical docs path: no trailing slash except root. */
export function normalizeDocPath(path: string): string {
const cleaned = (path || '/').replace(/\/+$/, '')
return cleaned || '/'
}
/** Normalise an internal docs href for SEO-friendly crawlable links. */
export function normalizeDocHref(href: string): string {
if (!href || href.startsWith('#')) return href
try {
const url = new URL(href, window.location.origin)
if (url.origin !== window.location.origin) return href
return normalizeDocPath(url.pathname) + url.search + url.hash
} catch {
return href
}
}
export function isInternalDocHref(href?: string): boolean {
if (!href || href.startsWith('#')) return false
if (href.startsWith('/docs')) return true
try {
const url = new URL(href, window.location.origin)
return url.origin === window.location.origin && url.pathname.startsWith('/docs')
} catch {
return false
}
}
/** Map a docs URL path to a markdown file path (leading slash, .md suffix). */
export function docPathToMarkdown(path: string): string {
const normalized = normalizeDocPath(path)
if (normalized === '/') {
return '/docs/index.md'
}
return `${normalized}.md`
}
+64
View File
@@ -0,0 +1,64 @@
import type { RouteManifest, SlotConfig, TemplateConfig } from './types'
export interface TemplateMatch {
template: string
layout: string
slots: Record<string, SlotConfig | null | undefined>
slotOverrides?: Record<string, SlotConfig | null>
}
export function matchPattern(path: string, pattern: string): boolean {
const normalizedPath = path.replace(/^\/+|\/+$/g, '')
const normalizedPattern = pattern.replace(/^\/+|\/+$/g, '')
const regexPattern = normalizedPattern
.replace(/\*\*/g, '{{GLOB}}')
.replace(/\*/g, '[^/]+')
.replace(/\{\{GLOB\}\}/g, '.*')
return new RegExp(`^${regexPattern}$`).test(normalizedPath)
}
export function resolveTemplate(
path: string,
manifest: RouteManifest,
templates: Record<string, TemplateConfig>,
): TemplateMatch | null {
const routes = manifest.routes ?? []
const sortedRoutes = [...routes].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0))
for (const route of sortedRoutes) {
if (!matchPattern(path, route.pattern)) continue
const template = templates[route.template]
if (!template) {
console.warn(`Template "${route.template}" not found`)
return null
}
return {
template: route.template,
layout: template.layout ?? 'ThreeColumnLayout',
slots: template.slots ?? {},
slotOverrides: route.slotOverrides,
}
}
return null
}
export function mergedSlot(
slotName: string,
match: TemplateMatch | null,
): SlotConfig | null | undefined {
if (!match) return undefined
if (match.slotOverrides && slotName in match.slotOverrides) {
return match.slotOverrides[slotName]
}
return match.slots[slotName]
}
export function shouldShowToc(match: TemplateMatch | null): boolean {
const right = mergedSlot('right', match)
return right !== null
}
+42 -1
View File
@@ -136,7 +136,9 @@ export const NAMED_THEME_PRESETS = {
export type NamedThemePreset = keyof typeof NAMED_THEME_PRESETS
export type ThemePreset = typeof THEME_PRESETS[number]
export const THEME_STORAGE_KEY = 'aiui-theme-preference'
export type ThemePreference = 'light' | 'dark' | 'system'
export const RADIUS_PRESETS = {
none: '0',
@@ -146,6 +148,8 @@ export const RADIUS_PRESETS = {
xl: '1rem',
} as const
export type ThemePreset = typeof THEME_PRESETS[number]
export type RadiusPreset = keyof typeof RADIUS_PRESETS
// CSS variable names that shadcn/Tailwind expects
@@ -199,6 +203,43 @@ export function isDarkMode(): boolean {
return document.documentElement.classList.contains('dark')
}
/**
* Apply stored user theme preference over YAML default dark mode.
*/
export function applyStoredThemePreference(yamlDefaultDark: boolean): void {
let stored: string | null = null
try {
stored = localStorage.getItem(THEME_STORAGE_KEY)
} catch {
return
}
if (stored === 'light') {
applyDarkMode(false)
} else if (stored === 'dark') {
applyDarkMode(true)
} else if (stored === 'system') {
applyDarkMode(window.matchMedia('(prefers-color-scheme: dark)').matches)
} else {
applyDarkMode(yamlDefaultDark)
}
}
/**
* Persist and apply a theme preference.
*/
export function setThemePreference(preference: ThemePreference): void {
try {
localStorage.setItem(THEME_STORAGE_KEY, preference)
} catch {
// ignore storage failures
}
if (preference === 'system') {
applyDarkMode(window.matchMedia('(prefers-color-scheme: dark)').matches)
} else {
applyDarkMode(preference === 'dark')
}
}
/**
* Get list of available theme presets
*/
+55 -1
View File
@@ -4,6 +4,8 @@ export interface NavItem {
title: string
href?: string
path?: string
description?: string
noindex?: boolean
children?: NavItem[]
}
@@ -24,6 +26,8 @@ export interface SEOConfig {
titleTemplate?: string
defaultImage?: string
twitter?: Record<string, string>
siteUrl?: string
robots?: { index?: boolean; follow?: boolean }
}
export interface I18nConfig {
@@ -47,6 +51,44 @@ export interface LogoConfig {
href?: string
}
export interface NavTabGroupConfig {
group: string
icon?: string
prefix?: string
pages?: string[]
}
export interface NavTabConfig {
tab: string
url?: string
groups?: NavTabGroupConfig[]
}
export interface NavigationConfig {
tabs?: NavTabConfig[]
}
export interface NavbarLinkConfig {
label: string
href: string
}
export interface NavbarPrimaryConfig {
type?: 'button' | 'github'
label?: string
href: string
}
export interface NavbarConfig {
primary?: NavbarPrimaryConfig
links?: NavbarLinkConfig[]
}
export interface SearchConfig {
enabled?: boolean
provider?: string
}
export interface WidgetConfig {
type: string
props?: Record<string, unknown>
@@ -89,6 +131,13 @@ export interface UIConfig {
i18n?: I18nConfig
a11y?: A11yConfig
logo?: LogoConfig
navigation?: NavigationConfig
navbar?: NavbarConfig
search?: SearchConfig
footer?: {
socials?: Record<string, string>
links?: { header: string; items: NavbarLinkConfig[] }[]
}
}
export interface DocsNav {
@@ -96,7 +145,12 @@ export interface DocsNav {
}
export interface RouteManifest {
routes?: { pattern: string; template: string }[]
routes?: {
pattern: string
template: string
priority?: number
slotOverrides?: Record<string, SlotConfig | null>
}[]
}
// Message element types (matching Python schema)
+1 -1
View File
@@ -1,3 +1,3 @@
"""Version information."""
__version__ = "0.3.137"
__version__ = "0.3.142"
+362 -41
View File
@@ -65,7 +65,8 @@ class Compiler:
# Ensure output directory exists
output_dir.mkdir(parents=True, exist_ok=True)
files: list[str] = []
(output_dir / ".nojekyll").touch()
files: list[str] = [".nojekyll"]
indent = None if minify else 2
@@ -111,6 +112,11 @@ class Compiler:
nav = self._generate_docs_nav()
route_files = self._generate_route_pages(output_dir, nav)
files.extend(route_files)
files.extend(self._generate_sitemap(output_dir, nav))
files.extend(self._generate_robots(output_dir))
files.extend(self._generate_llms_txt(output_dir, nav))
files.extend(self._generate_llms_full_txt(output_dir, nav))
self._patch_homepage_seo(output_dir, nav)
return CompileResult(success=True, files=files)
@@ -322,6 +328,8 @@ class Compiler:
"titleTemplate": self.config.seo.title_template,
"defaultImage": self.config.seo.default_image,
"twitter": self.config.seo.twitter,
"siteUrl": self.config.seo.site_url or self._site_url(),
"robots": self.config.seo.robots,
}
# A11y configuration - basic implementation for frontend
@@ -441,6 +449,7 @@ class Compiler:
output_dir / "index.html",
)
self._patch_antiflicker(output_dir / "index.html")
self._patch_static_shell(output_dir / "index.html")
# Create 404.html as a copy of patched index.html
# for SPA routing on static hosts like GitHub Pages
shutil.copy(
@@ -470,15 +479,39 @@ class Compiler:
self._copy_plugins(output_dir, frontend_dir)
def _patch_antiflicker(self, html_path: Path) -> None:
"""Patch anti-flicker script in index.html to respect darkMode."""
"""Patch theme bootstrap in index.html to respect darkMode."""
theme = self.config.site.theme
dark_mode = theme.dark_mode if theme else True
html = html_path.read_text(encoding="utf-8")
if not dark_mode:
# Remove the dark class addition for light-mode sites
html = html.replace("__AIUI_DARK_DEFAULT__", "true" if dark_mode else "false")
html_path.write_text(html, encoding="utf-8")
def _patch_static_shell(self, html_path: Path) -> None:
"""Patch built index.html for static hosts (GitHub Pages).
- Strip trailing slashes from the URL bar before React hydrates.
- Load plugin-loader.js (not included in the Vite bundle).
"""
html = html_path.read_text(encoding="utf-8")
canonical_script = (
'<script id="aiui-canonical-url">'
"(function(){var p=location.pathname.replace(/\\/+$/, '')||'/';"
"if(p!==location.pathname){history.replaceState(null,'',"
"p+location.search+location.hash);}})();"
"</script>"
)
if 'id="aiui-canonical-url"' not in html:
html = html.replace("<head>", f"<head>\n {canonical_script}", 1)
if 'rel="sitemap"' not in html:
html = html.replace(
"document.documentElement.classList.add('dark');",
"/* light mode — no dark class */",
"<head>",
'<head>\n <link rel="sitemap" type="application/xml" href="/sitemap.xml" />',
1,
)
if "plugin-loader.js" not in html:
html = html.replace(
"</body>",
' <script src="/plugins/plugin-loader.js"></script>\n</body>',
)
html_path.write_text(html, encoding="utf-8")
@@ -528,8 +561,10 @@ class Compiler:
def _generate_route_pages(self, output_dir: Path, nav: dict) -> list[str]:
"""Generate per-route HTML files for SPA fallback and SEO.
For each page in the docs navigation, creates an index.html at
the route path (e.g. _site/docs/concepts/configuration/index.html).
For each page in the docs navigation, creates a flat HTML file at
the route path (e.g. _site/docs/concepts/configuration.html).
GitHub Pages serves /docs/concepts/configuration from that file
without appending a trailing slash.
Each file is a copy of the SPA shell with page-specific:
- <title> tag
- <meta name="description">
@@ -554,15 +589,16 @@ class Compiler:
path = page["path"] # e.g. "/docs/concepts/configuration"
title = page["title"] # e.g. "YAML Configuration"
# Build file system path
# Build file system path — flat .html file so static hosts (GitHub Pages)
# serve /docs/testing without a trailing-slash redirect.
relative = path.lstrip("/")
page_dir = output_dir / relative
page_dir.mkdir(parents=True, exist_ok=True)
page_file = page_dir / "index.html"
page_file = output_dir / f"{relative}.html"
page_file.parent.mkdir(parents=True, exist_ok=True)
# Build page-specific HTML
page_title = f"{title} | {site_title}"
page_desc = f"{title} - {site_desc}"
page_desc = page.get("description") or f"{title} - {site_desc}"
page_noindex = bool(page.get("noindex"))
html = template_html
@@ -579,50 +615,283 @@ class Compiler:
)
# Add canonical URL, OG tags, and noscript content before </head>
seo_tags = self._build_seo_tags(path, page_title, page_desc)
seo_tags = self._build_seo_tags(path, page_title, page_desc, noindex=page_noindex)
json_ld = self._build_json_ld(path, title, page_desc)
# Try to load markdown content for noscript pre-rendering
noscript_content = self._get_noscript_content(output_dir, path)
crawl_nav = self._build_crawl_nav_html(nav)
noscript_block = crawl_nav
if noscript_content:
noscript_block += noscript_content
# Inject SEO tags before </head>
html = html.replace(
"</head>",
f"{seo_tags}\n</head>",
f"{seo_tags}\n{json_ld}\n</head>",
)
# Inject noscript block inside <div id="root">
if noscript_content:
html = html.replace(
'<div id="root"></div>',
f'<div id="root"><noscript>{noscript_content}</noscript></div>',
)
# Inject noscript crawl content inside <div id="root">
html = html.replace(
'<div id="root"></div>',
f'<div id="root"><noscript>{noscript_block}</noscript></div>',
)
page_file.write_text(html, encoding="utf-8")
files.append(f"{relative}/index.html")
files.append(f"{relative}.html")
return files
def _collect_nav_pages(self, nav: dict) -> list[dict]:
"""Recursively collect all pages from docs-nav.json."""
pages: list[dict] = []
for item in nav.get("items", []):
if item.get("path"):
pages.append({"path": item["path"], "title": item.get("title", "")})
for child in item.get("children", []):
if child.get("path"):
pages.append({"path": child["path"], "title": child.get("title", "")})
# Handle deeper nesting if present
for grandchild in child.get("children", []):
if grandchild.get("path"):
pages.append(
{"path": grandchild["path"], "title": grandchild.get("title", "")}
)
def walk(items: list[dict]) -> None:
for item in items:
if item.get("path"):
pages.append(
{
"path": item["path"],
"title": item.get("title", ""),
"description": item.get("description", ""),
"noindex": bool(item.get("noindex")),
}
)
if item.get("children"):
walk(item["children"])
walk(nav.get("items", []))
return pages
def _build_seo_tags(self, path: str, title: str, description: str) -> str:
def _site_url(self) -> str | None:
if self.config.seo and self.config.seo.site_url:
return self.config.seo.site_url.rstrip("/")
for candidate in (self.base_path / "CNAME", self.base_path / "docs" / "CNAME"):
if candidate.exists():
domain = candidate.read_text(encoding="utf-8").strip()
if domain and "." in domain:
return f"https://{domain.rstrip('/')}"
return None
def _absolute_url(self, path: str) -> str:
site = self._site_url()
if not site:
return path
if not path.startswith("/"):
path = f"/{path}"
return f"{site}{path}"
def _generate_sitemap(self, output_dir: Path, nav: dict) -> list[str]:
site = self._site_url()
if not site:
return []
urls = []
site_root = self._absolute_url("/")
root_lastmod = self._format_lastmod(self.base_path / "docs" / "index.md")
urls.append(self._sitemap_url_entry(site_root, root_lastmod))
for page in self._collect_nav_pages(nav):
if page.get("noindex"):
continue
path = page["path"].rstrip("/") or "/"
loc = self._absolute_url(path)
lastmod = self._format_lastmod(self._resolve_md_source(path))
urls.append(self._sitemap_url_entry(loc, lastmod))
xml = (
'<?xml version="1.0" encoding="UTF-8"?>\n'
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
+ "\n".join(urls)
+ "\n</urlset>\n"
)
(output_dir / "sitemap.xml").write_text(xml, encoding="utf-8")
return ["sitemap.xml"]
@staticmethod
def _sitemap_url_entry(loc: str, lastmod: str | None) -> str:
safe_loc = Compiler._escape_html(loc)
if lastmod:
return f" <url><loc>{safe_loc}</loc><lastmod>{lastmod}</lastmod></url>"
return f" <url><loc>{safe_loc}</loc></url>"
@staticmethod
def _format_lastmod(path: Path | None) -> str | None:
if not path or not path.is_file():
return None
from datetime import UTC, datetime
mtime = path.stat().st_mtime
return datetime.fromtimestamp(mtime, tz=UTC).strftime("%Y-%m-%d")
def _resolve_md_source(self, route_path: str) -> Path | None:
"""Map a docs route path to its source markdown file."""
if not self.config.content or not self.config.content.docs:
return None
base = self.config.site.route_base_docs.rstrip("/")
if not route_path.startswith(base):
return None
rel = route_path[len(base) :].lstrip("/")
docs_dir = self.base_path / self.config.content.docs.dir
candidates = [
docs_dir / f"{rel}.md",
docs_dir / rel / "index.md",
docs_dir / rel / "README.md",
]
if rel in ("", "index"):
candidates.insert(0, docs_dir / "index.md")
for candidate in candidates:
if candidate.is_file():
return candidate
return None
def _generate_robots(self, output_dir: Path) -> list[str]:
robots = self.config.seo.robots if self.config.seo else None
allow_index = robots.get("index", True) if robots else True
allow_follow = robots.get("follow", True) if robots else True
lines = ["User-agent: *"]
if allow_index:
lines.append("Allow: /")
else:
lines.append("Disallow: /")
if not allow_follow:
lines.append("Disallow: /docs/")
site = self._site_url()
if site:
lines.append(f"Sitemap: {site}/sitemap.xml")
lines.append(f"# LLM index: {site}/llms.txt")
(output_dir / "robots.txt").write_text("\n".join(lines) + "\n", encoding="utf-8")
return ["robots.txt"]
def _generate_llms_txt(self, output_dir: Path, nav: dict) -> list[str]:
"""Generate llms.txt index for AI crawlers (llmstxt.org convention)."""
site = self._site_url()
if not site:
return []
site_title = self.config.site.title
site_desc = self.config.site.description or f"Documentation for {site_title}"
lines = [
f"# {site_title}",
"",
f"> {site_desc}",
"",
"## Documentation",
"",
]
for page in self._collect_nav_pages(nav):
if page.get("noindex"):
continue
path = page["path"].rstrip("/") or "/"
title = page["title"]
desc = page.get("description") or title
url = self._absolute_url(path)
lines.append(f"- [{title}]({url}): {desc}")
lines.extend(["", "## Full export", "", f"- [Complete documentation]({site}/llms-full.txt): All pages in one file"])
content = "\n".join(lines).rstrip() + "\n"
(output_dir / "llms.txt").write_text(content, encoding="utf-8")
return ["llms.txt"]
def _generate_llms_full_txt(self, output_dir: Path, nav: dict) -> list[str]:
"""Generate llms-full.txt — concatenated markdown for AI crawlers."""
site = self._site_url()
if not site:
return []
sections: list[str] = []
for page in self._collect_nav_pages(nav):
if page.get("noindex"):
continue
md_path = self._resolve_md_source(page["path"])
if not md_path:
continue
body = self._strip_frontmatter(md_path.read_text(encoding="utf-8")).strip()
if not body:
continue
url = self._absolute_url(page["path"].rstrip("/") or "/")
title = page["title"]
sections.append(f"# {title}\n\nSource: {url}\n\n{body}")
if not sections:
return []
(output_dir / "llms-full.txt").write_text("\n\n---\n\n".join(sections) + "\n", encoding="utf-8")
return ["llms-full.txt"]
@staticmethod
def _strip_frontmatter(content: str) -> str:
if content.startswith("---"):
end_idx = content.find("---", 3)
if end_idx != -1:
return content[end_idx + 3 :].lstrip("\n")
return content
def _patch_homepage_seo(self, output_dir: Path, nav: dict) -> None:
"""Add canonical and crawl hints to root index.html."""
index_path = output_dir / "index.html"
if not index_path.exists():
return
docs_home = "/docs/index"
for page in self._collect_nav_pages(nav):
if page["path"].rstrip("/").endswith("/docs/index") or page["path"] == "/docs/index":
docs_home = page["path"].rstrip("/") or "/docs/index"
break
site_title = self.config.site.title
site_desc = self.config.site.description or f"Documentation for {site_title}"
page_title = f"{site_title}"
seo_tags = self._build_seo_tags(docs_home, page_title, site_desc)
crawl_nav = self._build_crawl_nav_html(nav)
html = index_path.read_text(encoding="utf-8")
html = html.replace(
"<title>Documentation</title>",
f"<title>{self._escape_html(page_title)}</title>",
)
html = html.replace(
'content="Documentation built with PraisonAIUI"',
f'content="{self._escape_html(site_desc)}"',
)
if "</head>" in html and 'rel="canonical"' not in html:
html = html.replace("</head>", f"{seo_tags}\n</head>", 1)
if '<div id="root"></div>' in html:
html = html.replace(
'<div id="root"></div>',
f'<div id="root"><noscript>{crawl_nav}</noscript></div>',
)
index_path.write_text(html, encoding="utf-8")
def _build_crawl_nav_html(self, nav: dict) -> str:
"""Static nav links for non-JS crawlers."""
links: list[str] = []
for page in self._collect_nav_pages(nav):
path = page["path"].rstrip("/") or "/"
title = self._escape_html(page["title"])
url = self._escape_html(self._absolute_url(path))
links.append(f'<li><a href="{url}">{title}</a></li>')
if not links:
return ""
return (
'<nav aria-label="Documentation">'
f'<ul>{"".join(links)}</ul>'
"</nav>"
)
def _build_seo_tags(self, path: str, title: str, description: str, *, noindex: bool = False) -> str:
"""Build canonical, OG, and Twitter meta tags."""
d = self._escape_html(description)
p = self._escape_html(path)
canonical = self._escape_html(self._absolute_url(path))
og_url = canonical
# Extract original page title by removing the site title suffix if present
site_title = self.config.site.title
@@ -646,15 +915,19 @@ class Compiler:
t = self._escape_html(title)
tags = [
f' <link rel="canonical" href="{p}" />',
f' <link rel="canonical" href="{canonical}" />',
f' <meta property="og:title" content="{t}" />',
f' <meta property="og:description" content="{d}" />',
f' <meta property="og:url" content="{p}" />',
f' <meta property="og:url" content="{og_url}" />',
' <meta property="og:type" content="article" />',
]
# Add default OG image if configured
if self.config.seo and self.config.seo.default_image:
og_image = self._escape_html(self.config.seo.default_image)
image = self.config.seo.default_image
if not image.startswith(("http://", "https://")):
image = self._absolute_url(image)
og_image = self._escape_html(image)
tags.append(f' <meta property="og:image" content="{og_image}" />')
# Add Twitter card tags
@@ -667,8 +940,34 @@ class Compiler:
handle = self._escape_html(self.config.seo.twitter["handle"])
tags.append(f' <meta name="twitter:site" content="{handle}" />')
robots = self.config.seo.robots if self.config.seo else None
if noindex:
tags.append(' <meta name="robots" content="noindex, nofollow" />')
elif robots:
index = "index" if robots.get("index", True) else "noindex"
follow = "follow" if robots.get("follow", True) else "nofollow"
tags.append(f' <meta name="robots" content="{index}, {follow}" />')
return "\n".join(tags)
def _build_json_ld(self, path: str, title: str, description: str) -> str:
url = self._absolute_url(path)
site_url = self._site_url()
payload: dict = {
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": title,
"description": description,
"url": url,
}
if site_url:
payload["isPartOf"] = {
"@type": "WebSite",
"name": self.config.site.title,
"url": f"{site_url}/",
}
return f' <script type="application/ld+json">{json.dumps(payload, ensure_ascii=False)}</script>'
def _get_noscript_content(self, output_dir: Path, path: str) -> str:
"""Load markdown file and convert to simple HTML for noscript block."""
# Try to find the corresponding markdown file
@@ -736,14 +1035,36 @@ class Compiler:
# List items
if re.match(r"^[-*+]\s+", stripped):
text = re.sub(r"^[-*+]\s+", "", stripped)
result.append(f"<li>{text}</li>")
result.append(f"<li>{Compiler._inline_md_to_html(text)}</li>")
continue
# Paragraphs
result.append(f"<p>{stripped}</p>")
result.append(f"<p>{Compiler._inline_md_to_html(stripped)}</p>")
return "\n".join(result)
@staticmethod
def _inline_md_to_html(text: str) -> str:
"""Convert inline markdown (links, emphasis) for noscript HTML."""
escaped = (
text.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
)
def link_repl(match: re.Match[str]) -> str:
label = match.group(1)
href = match.group(2)
if href.startswith("/") or href.startswith("http://") or href.startswith("https://"):
safe_href = href.replace('"', "&quot;")
return f'<a href="{safe_href}">{label}</a>'
return label
escaped = re.sub(r"\[([^\]]+)\]\(([^)]+)\)", link_repl, escaped)
escaped = re.sub(r"\*\*([^*]+)\*\*", r"<strong>\1</strong>", escaped)
escaped = re.sub(r"`([^`]+)`", r"<code>\1</code>", escaped)
return escaped
@staticmethod
def _escape_html(text: str) -> str:
"""Escape HTML special characters for meta tags."""
+39
View File
@@ -15,6 +15,8 @@ class DocPage:
slug: str
title: str
order: int = 0
description: str = ""
noindex: bool = False
frontmatter: dict = field(default_factory=dict)
@@ -82,6 +84,10 @@ class DocsScanner:
# Determine title (from frontmatter or first heading)
title = frontmatter.get("title") or self._extract_title(content) or slug
description = str(frontmatter.get("description", "") or "").strip()
if not description:
description = self._extract_description(content)
noindex = bool(frontmatter.get("noindex", False))
# Extract order from frontmatter or filename
order = frontmatter.get("order", 0)
@@ -96,9 +102,42 @@ class DocsScanner:
slug=slug,
title=title,
order=order,
description=description,
noindex=noindex,
frontmatter=frontmatter,
)
def _extract_description(self, content: str) -> str:
"""First paragraph after frontmatter — used for meta description when omitted."""
if content.startswith("---"):
end_idx = content.find("---", 3)
if end_idx != -1:
content = content[end_idx + 3 :]
in_code = False
for line in content.splitlines():
stripped = line.strip()
if stripped.startswith("```"):
in_code = not in_code
continue
if in_code or not stripped:
continue
if stripped.startswith("#"):
continue
if stripped.startswith(("-", "*", "+", "|", ">", "!", "---")):
continue
text = stripped
text = re.sub(r"!\[([^\]]*)\]\([^)]+\)", r"\1", text)
text = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", text)
text = re.sub(r"\*\*([^*]+)\*\*", r"\1", text)
text = re.sub(r"\*([^*]+)\*", r"\1", text)
text = re.sub(r"`([^`]+)`", r"\1", text)
text = re.sub(r"\s+", " ", text).strip()
if len(text) >= 20:
return text[:160].rstrip()
return ""
def _path_to_slug(self, file_path: Path) -> str:
"""Convert a file path to a URL slug."""
rel_path = file_path.relative_to(self.docs_dir)
+12 -1
View File
@@ -13,6 +13,8 @@ class NavItem:
title: str
path: str
description: str = ""
noindex: bool = False
children: list["NavItem"] = field(default_factory=list)
@@ -38,7 +40,12 @@ class NavBuilder:
full_path = f"{self.base_path}/{page.slug}".rstrip("/")
# Create NavItem for this page
item = NavItem(title=page.title, path=full_path)
item = NavItem(
title=page.title,
path=full_path,
description=page.description,
noindex=page.noindex,
)
# Determine parent path
parts = page.slug.split("/")
@@ -76,6 +83,10 @@ class NavBuilder:
def _item_to_dict(self, item: NavItem) -> dict:
"""Convert a NavItem to dictionary."""
result = {"title": item.title, "path": item.path}
if item.description:
result["description"] = item.description
if item.noindex:
result["noindex"] = True
if item.children:
result["children"] = [self._item_to_dict(child) for child in item.children]
return result
+1
View File
@@ -83,6 +83,7 @@ def auto_register_defaults() -> None:
(".workflows", "WorkflowsFeature"),
(".guardrails", "GuardrailsFeature"),
(".eval", "EvalFeature"),
(".training", "TrainingFeature"),
(".telemetry", "TelemetryFeature"),
(".tracing", "TracingFeature"),
(".security", "SecurityFeature"),
+27 -18
View File
@@ -26,16 +26,23 @@ from ._base import BaseFeatureProtocol
logger = logging.getLogger(__name__)
_EMBEDDING_ERROR_MARKERS = (
"does not have access",
"model_not_found",
"does not exist or you do not have access",
"notfounderror",
)
def _is_embedding_error(err_msg: str) -> bool:
"""True when an error string indicates an unavailable embedding model."""
lowered = err_msg.lower()
return any(marker in lowered for marker in _EMBEDDING_ERROR_MARKERS)
def _is_embedding_unavailable(err: BaseException) -> bool:
"""Detect an embedding model access / not-found failure."""
msg = str(err).lower()
return (
"does not have access" in msg
or "model_not_found" in msg
or "does not exist" in msg
or "notfounderror" in msg
)
"""Detect an embedding model access / not-found failure from an exception."""
return _is_embedding_error(str(err))
# ── Knowledge Protocol ───────────────────────────────────────────────
@@ -102,14 +109,14 @@ class KnowledgeProtocol(ABC):
"""Get corpus statistics."""
return {"total": 0}
def last_search_meta(self) -> Dict[str, Any]:
"""Metadata for the most recent search: {"mode": ..., "error": ...}."""
return {"mode": "vector", "error": None}
def health(self) -> Dict[str, Any]:
"""Health check for this backend."""
return {"status": "ok", "provider": self.__class__.__name__}
def last_search_meta(self) -> Dict[str, Any]:
"""Metadata about the most recent search (mode, error)."""
return {"mode": "vector", "error": None}
# ── Simple Knowledge Manager (Default, no deps) ─────────────────────
@@ -264,7 +271,7 @@ class SDKKnowledgeManager(KnowledgeProtocol):
"using local in-memory index"
)
self._sdk_knowledge = None
elif _is_embedding_unavailable(e):
elif _is_embedding_error(err_msg):
self._embedding_unavailable = True
self._embedding_error = err_msg
logger.warning("Embedding model unavailable: %s", e)
@@ -275,6 +282,10 @@ class SDKKnowledgeManager(KnowledgeProtocol):
self._sdk_probed = True
return self._sdk_knowledge
def last_search_meta(self) -> Dict[str, Any]:
"""Metadata for the most recent search: {"mode": ..., "error": ...}."""
return dict(self._last_search_meta)
def store(
self,
text: str,
@@ -331,10 +342,11 @@ class SDKKnowledgeManager(KnowledgeProtocol):
for i, r in enumerate(results[:limit])
]
except BaseException as e:
err_msg = str(e)
logger.warning("SDK knowledge search failed: %s; falling back to local", e)
if _is_embedding_unavailable(e):
if _is_embedding_error(err_msg):
self._embedding_unavailable = True
self._embedding_error = str(e)
self._embedding_error = err_msg
# Fallback to local text search
query_lower = query.lower()
@@ -361,9 +373,6 @@ class SDKKnowledgeManager(KnowledgeProtocol):
self._last_search_meta = {"mode": "local", "error": None}
return results
def last_search_meta(self) -> Dict[str, Any]:
return dict(self._last_search_meta)
def add_file(
self,
file_path: str,
+380
View File
@@ -0,0 +1,380 @@
"""Training Lab feature — read-mostly proxy for praisonai-train sessions.
Architecture:
TrainingFeature (BaseFeatureProtocol)
├── reads JSON session files from ~/.praison/train/*.json
└── optionally delegates apply to praisonai_train.train.agents.apply_training
The praisonai-train package is an optional dependency. When it is not installed
the feature degrades gracefully: session listing/detail still work from the raw
JSON storage, while apply returns a 503 with an install hint.
"""
from __future__ import annotations
import json
import logging
import os
from pathlib import Path
from typing import Any
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from ._base import BaseFeatureProtocol
logger = logging.getLogger(__name__)
_EARLY_STOP_THRESHOLD = 9.5
def _storage_dir() -> Path:
"""Resolve the praisonai-train JSON storage directory."""
override = os.environ.get("PRAISON_TRAIN_DIR")
if override:
return Path(override).expanduser()
return Path.home() / ".praison" / "train"
def _train_available() -> bool:
"""Return True when the praisonai-train package can be imported."""
import importlib.util
return importlib.util.find_spec("praisonai_train") is not None
def _train_version() -> str | None:
try:
from importlib.metadata import version
return version("praisonai-train")
except Exception:
return None
def _iter_scores(iterations: list[dict[str, Any]]) -> list[float]:
scores: list[float] = []
for it in iterations:
score = it.get("score")
if isinstance(score, (int, float)):
scores.append(float(score))
return scores
def _best_iteration_index(iterations: list[dict[str, Any]]) -> int | None:
best_idx: int | None = None
best_score = float("-inf")
for idx, it in enumerate(iterations):
score = it.get("score")
if isinstance(score, (int, float)) and float(score) > best_score:
best_score = float(score)
best_idx = idx
return best_idx
def _summarize_session(session_id: str, path: Path, data: dict[str, Any]) -> dict[str, Any]:
"""Build a session summary row (parity with praisonai-train list)."""
report = data.get("report") or {}
metadata = report.get("metadata") or data.get("metadata") or {}
iterations = data.get("iterations") or report.get("iterations") or []
completed = int(report.get("total_iterations", len(iterations)) or 0)
requested = metadata.get("target_iterations")
requested = int(requested) if isinstance(requested, (int, float)) else completed
mode = metadata.get("mode", "llm")
agent_id = metadata.get("agent_id") or data.get("agent_id")
scores = _iter_scores(iterations)
avg_score = report.get("avg_score")
if avg_score is None and scores:
avg_score = sum(scores) / len(scores)
improvement = report.get("improvement")
if improvement is None and len(scores) >= 2:
improvement = scores[-1] - scores[0]
passed = report.get("passed")
early_stopped = bool(requested > completed and mode == "llm")
try:
stat = path.stat()
size_bytes = stat.st_size
modified_at = _iso_from_mtime(stat.st_mtime)
except OSError:
size_bytes = 0
modified_at = None
return {
"session_id": session_id,
"agent_id": agent_id,
"completed_iterations": completed,
"requested_iterations": requested,
"early_stopped": early_stopped,
"avg_score": round(float(avg_score), 4) if avg_score is not None else None,
"improvement": round(float(improvement), 4) if improvement is not None else None,
"passed": passed,
"status_label": _status_label(passed, completed),
"mode": mode,
"size_bytes": size_bytes,
"modified_at": modified_at,
}
def _iso_from_mtime(mtime: float) -> str:
from datetime import datetime, timezone
return datetime.fromtimestamp(mtime, tz=timezone.utc).replace(microsecond=0).isoformat()
def _status_label(passed: Any, completed: int) -> str:
if completed == 0:
return "INCOMPLETE"
if passed is True:
return "PASSED"
if passed is False:
return "NEEDS WORK"
return "UNKNOWN"
def _load_session_file(path: Path) -> dict[str, Any]:
with path.open("r", encoding="utf-8") as fh:
return json.load(fh)
class TrainingFeature(BaseFeatureProtocol):
"""Training Lab — inspect praisonai-train agent sessions and apply profiles."""
feature_name = "training"
feature_description = "Inspect praisonai-train agent sessions and apply training profiles"
@property
def name(self) -> str:
return self.feature_name
@property
def description(self) -> str:
return self.feature_description
def routes(self) -> list[Route]:
return [
Route("/api/training/status", self._status, methods=["GET"]),
Route("/api/training/sessions", self._list_sessions, methods=["GET"]),
Route("/api/training/sessions/{session_id}", self._get_session, methods=["GET"]),
Route("/api/training/sessions/{session_id}/apply", self._apply, methods=["POST"]),
]
async def health(self) -> dict[str, Any]:
available = _train_available()
return {
"status": "ok" if available else "degraded",
"feature": self.name,
"train_package_available": available,
}
# ── storage helpers ──────────────────────────────────────────────
def _read_sessions(self, storage: Path) -> list[dict[str, Any]]:
if not storage.exists():
return []
summaries: list[dict[str, Any]] = []
for path in storage.glob("*.json"):
session_id = path.stem
try:
data = _load_session_file(path)
except (OSError, json.JSONDecodeError):
logger.warning("Skipping unreadable training session: %s", path)
continue
summaries.append(_summarize_session(session_id, path, data))
summaries.sort(key=lambda s: s.get("modified_at") or "", reverse=True)
return summaries
# ── route handlers ───────────────────────────────────────────────
async def _status(self, request: Request) -> JSONResponse:
storage = _storage_dir()
available = _train_available()
sessions = self._read_sessions(storage)
warnings: list[str] = []
if not available:
warnings.append(
"praisonai-train not installed. Install with: pip install praisonai-train"
)
return JSONResponse(
{
"status": "ok" if available else "degraded",
"feature": self.name,
"train_package_available": available,
"train_package_version": _train_version(),
"storage_dir": str(storage),
"storage_backend": "json",
"session_count": len(sessions),
"sqlite_supported": False,
"warnings": warnings,
}
)
async def _list_sessions(self, request: Request) -> JSONResponse:
storage = _storage_dir()
try:
limit = int(request.query_params.get("limit", "50"))
except ValueError:
limit = 50
agent_id = request.query_params.get("agent_id")
sessions = self._read_sessions(storage)
if agent_id:
sessions = [s for s in sessions if s.get("agent_id") == agent_id]
limited = sessions[: max(limit, 0)]
return JSONResponse({"sessions": limited, "count": len(limited)})
async def _get_session(self, request: Request) -> JSONResponse:
session_id = request.path_params["session_id"]
storage = _storage_dir()
path = storage / f"{session_id}.json"
if not path.exists():
return JSONResponse(
{"error": f"Session not found: {session_id}"}, status_code=404
)
try:
data = _load_session_file(path)
except (OSError, json.JSONDecodeError):
return JSONResponse(
{"error": f"Corrupt session JSON: {session_id}"}, status_code=422
)
report = data.get("report") or {}
iterations = list(data.get("iterations") or report.get("iterations") or [])
best_idx = _best_iteration_index(iterations)
for idx, it in enumerate(iterations):
it["is_best"] = idx == best_idx
summary = _summarize_session(session_id, path, data)
best_iteration = iterations[best_idx] if best_idx is not None else None
return JSONResponse(
{
"session_id": session_id,
"report": report,
"iterations": iterations,
"best_iteration": best_iteration,
"best_iteration_num": (
best_iteration.get("iteration_num", best_idx + 1)
if best_iteration is not None
else None
),
"early_stopped": summary["early_stopped"],
"early_stop_reason": (
"score_threshold"
if summary["early_stopped"]
and _iter_scores(iterations)
and _iter_scores(iterations)[-1] >= _EARLY_STOP_THRESHOLD
else None
),
"requested_iterations": summary["requested_iterations"],
"completed_iterations": summary["completed_iterations"],
"avg_score": summary["avg_score"],
"improvement": summary["improvement"],
"passed": summary["passed"],
"mode": summary["mode"],
"scenarios": data.get("scenarios") or [],
}
)
async def _apply(self, request: Request) -> JSONResponse:
session_id = request.path_params["session_id"]
storage = _storage_dir()
path = storage / f"{session_id}.json"
if not path.exists():
return JSONResponse(
{"error": f"Session not found: {session_id}"}, status_code=404
)
if not _train_available():
return JSONResponse(
{
"error": "praisonai-train is not installed",
"hint": "pip install praisonai-train",
},
status_code=503,
)
try:
body = await request.json()
except Exception:
body = {}
agent_id = body.get("agent_id")
if not agent_id:
return JSONResponse({"error": "agent_id is required"}, status_code=422)
iteration = body.get("iteration")
from .agents import get_agent_registry
registry = get_agent_registry()
agent_def = registry.get(agent_id)
if agent_def is None:
return JSONResponse(
{"error": f"Agent not found: {agent_id}"}, status_code=404
)
try:
result = self._apply_training(agent_def, session_id, iteration)
except Exception as exc:
logger.exception("apply_training failed for session %s", session_id)
return JSONResponse({"error": str(exc)}, status_code=500)
return JSONResponse(
{
"success": True,
"session_id": session_id,
"agent_id": agent_id,
"iteration_applied": result.get("iteration_applied"),
"quality_score": result.get("quality_score"),
"suggestions_count": result.get("suggestions_count", 0),
"hook_id": result.get("hook_id", f"training_hook_{session_id}"),
"message": f"Training profile applied to agent '{agent_id}'",
}
)
def _apply_training(
self, agent_def: dict[str, Any], session_id: str, iteration: int | None
) -> dict[str, Any]:
from praisonai_train.train.agents import apply_training # type: ignore
from praisonaiagents import Agent # type: ignore
agent = Agent(
name=agent_def.get("name", agent_def.get("id", "agent")),
instructions=agent_def.get("instructions", agent_def.get("description", "")),
llm=agent_def.get("model"),
)
apply_training(agent, session_id=session_id, iteration=iteration)
hook_id = getattr(agent, "_training_hook_id", f"training_hook_{session_id}")
storage = _storage_dir()
applied_iteration = iteration
quality_score = None
suggestions_count = 0
try:
data = _load_session_file(storage / f"{session_id}.json")
iterations = list(data.get("iterations") or [])
idx = _best_iteration_index(iterations) if iteration is None else None
chosen = None
if idx is not None:
chosen = iterations[idx]
applied_iteration = chosen.get("iteration_num", idx + 1)
elif iteration is not None:
for it in iterations:
if it.get("iteration_num") == iteration:
chosen = it
break
if chosen is not None:
quality_score = chosen.get("score")
suggestions_count = len(chosen.get("suggestions") or [])
except (OSError, json.JSONDecodeError):
pass
return {
"iteration_applied": applied_iteration,
"quality_score": quality_score,
"suggestions_count": suggestions_count,
"hook_id": hook_id,
}
+3 -1
View File
@@ -187,9 +187,11 @@ class A11yConfig(BaseModel):
class SEOConfig(BaseModel):
"""SEO configuration."""
title_template: str = Field(default="%s", alias="titleTemplate")
title_template: str = Field(default="%s | %s", alias="titleTemplate")
default_image: Optional[str] = Field(default=None, alias="defaultImage")
twitter: Optional[dict[str, str]] = None
site_url: Optional[str] = Field(default=None, alias="siteUrl")
robots: Optional[dict[str, bool]] = None
class DependenciesConfig(BaseModel):
+68 -7
View File
@@ -687,12 +687,21 @@ def _build_html(style: str) -> str:
title = f"{_site_title} Dashboard" if style == "dashboard" else _site_title
cache_bust = int(_server_start_time)
# Anti-flicker: dark background + hide React content until plugins render
# Anti-flicker: hide React content until plugins render (uses theme CSS vars)
anti_flicker = ""
theme_bootstrap = (
'<script id="aiui-theme-bootstrap">'
"(function(){try{var t=localStorage.getItem('aiui-theme-preference');"
"if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches))"
"document.documentElement.classList.add('dark');"
"else if(t==='light')document.documentElement.classList.remove('dark');"
"}catch(e){}})();"
"</script>"
)
if style == "docs":
anti_flicker = (
'<style id="aiui-anti-flicker">'
"html,body{background:#0f172a!important;color:#e2e8f0}"
"html,body{background:hsl(var(--background))!important;color:hsl(var(--foreground))}"
"#root>*{opacity:0;transition:opacity .15s ease}"
"</style>"
)
@@ -751,16 +760,26 @@ def _build_html(style: str) -> str:
except Exception:
pass
canonical_script = (
'<script id="aiui-canonical-url">'
"(function(){var p=location.pathname.replace(/\\/+$/, '')||'/';"
"if(p!==location.pathname){history.replaceState(null,'',"
"p+location.search+location.hash);}})();"
"</script>"
)
return (
'<!doctype html><html lang="en" style="background:#0f172a;color:#e2e8f0"><head>'
'<!doctype html><html lang="en"><head>'
'<meta charset="UTF-8">'
'<meta name="viewport" content="width=device-width,initial-scale=1.0">'
f"{canonical_script}"
f"{theme_bootstrap}"
f'<link rel="stylesheet" href="/assets/index.css?v={cache_bust}">'
f"{anti_flicker}"
f"{theme_vars_tag}"
f"{custom_css_tag}"
f"<title>{title}</title>"
'</head><body style="background:#0f172a;margin:0">'
'</head><body style="margin:0">'
'<div id="root"></div>'
f"{react_script}"
f'<script src="/plugins/plugin-loader.js?v={cache_bust}"></script>'
@@ -813,10 +832,8 @@ async def _plugins_config(request: Request) -> JSONResponse:
"syntax-highlight",
"code-copy",
"content-loader",
"toc",
"mermaid",
"nav-intercept",
"mkdocs-compat",
"homepage",
]
else:
@@ -3320,6 +3337,14 @@ def create_app(
"description": "Manage conversation sessions",
"order": 20,
},
{
"id": "runs",
"title": "Runs",
"icon": "⏱️",
"group": "Control",
"description": "Run flight recorder — timeline debugger",
"order": 22,
},
{
"id": "usage",
"title": "Usage",
@@ -3496,6 +3521,14 @@ def create_app(
"description": "Agent evaluation & accuracy",
"order": 40,
},
{
"id": "training",
"title": "Training",
"icon": "🧪",
"group": "Control",
"description": "Inspect praisonai-train sessions & apply profiles",
"order": 42,
},
{
"id": "code-studio",
"title": "Code Studio",
@@ -3548,6 +3581,7 @@ def create_app(
]
_page_api_overrides = {
"sessions": "/sessions",
"runs": "/api/sessions",
"cron": "/api/schedules",
"channels": "/api/channels",
"mcp": "/api/mcp/servers",
@@ -3587,6 +3621,8 @@ def create_app(
# Always mount built-in frontend plugins and assets BEFORE catch-all /
_frontend_dir = Path(__file__).parent / "templates" / "frontend"
_plugins_dir = _frontend_dir / "plugins"
if static_dir and (Path(static_dir) / "plugins").is_dir():
_plugins_dir = Path(static_dir) / "plugins"
_assets_dir = _frontend_dir / "assets"
# Dynamic plugins.json route — MUST come before static /plugins mount
@@ -3613,6 +3649,13 @@ def create_app(
routes.append(Route("/", _serve_index, methods=["GET"]))
_static_app = StaticFiles(directory=str(static_dir), html=True)
_static_root = Path(static_dir)
async def _serve_static_file(scope, receive, send, file_path: Path, media_type: str | None = None):
from starlette.responses import FileResponse
response = FileResponse(str(file_path), media_type=media_type)
await response(scope, receive, send)
async def _http_only_static(scope, receive, send):
if scope["type"] != "http":
@@ -3621,7 +3664,25 @@ def create_app(
await send({"type": "websocket.close", "code": 1008})
return
# Try StaticFiles first; on 404, fall back to SPA index
request_path = scope.get("path", "")
rel = request_path.lstrip("/")
if rel:
exact = _static_root / rel
if exact.is_file():
await _serve_static_file(scope, receive, send, exact)
return
if not request_path.endswith("/"):
html_path = _static_root / f"{rel}.html"
if html_path.is_file():
await _serve_static_file(scope, receive, send, html_path, media_type="text/html")
return
if exact.is_dir():
index = exact / "index.html"
if index.is_file():
await _serve_static_file(scope, receive, send, index, media_type="text/html")
return
# Try StaticFiles; on 404, fall back to SPA index
# (paths like /chat, /memory don't have static files but need
# the SPA shell so JS routing can take over).
response_started = False
@@ -0,0 +1 @@
import{g as p,r as u,d as a}from"./chunk-SVP7TREG.js";import{p as f}from"./chunk-JWPE2WC7.js";import{_ as n,l as o}from"./mermaid.core.js";import{M as c,b as d}from"./cynefin-OW5HDTMX.js";import"./index.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=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 i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
@@ -0,0 +1 @@
import{a0 as ln,a1 as an,a2 as H,a3 as q,a4 as B,a5 as un,a6 as y,a7 as tn,a8 as L,a9 as _,aa as rn,ab as o,ac as on,ad as sn,ae as fn}from"./mermaid.core.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,C,a){var O=I-l,i=D-h,n=C-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function W(l,h,I,D,v,A,C){var a=l-I,O=h-D,i=(C?A:-A)/L(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,F=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*L(on(0,T*T*R-P*P)),j=(P*g-m*S)/R,z=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=j-F,e=z-t,r=w-F,G=p-t;return x*x+e*e>r*r+G*G&&(j=w,z=p),{cx:j,cy:z,x01:-n,y01:-d,x11:j*(v/T-1),y11:z*(v/T-1)}}function hn(){var l=cn,h=yn,I=B(0),D=null,v=gn,A=dn,C=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,F=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(F>tn-y)a.moveTo(s*H(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*H(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=F,S=F,j=C.apply(this,arguments)/2,z=j>y&&(D?+D.apply(this,arguments):L(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if(z>y){var G=sn(z/u*q(j)),M=sn(z/s*q(j));(P-=G*2)>y?(G*=t?1:-1,R+=G,T-=G):(P=0,R=T=(f+c)/2),(S-=M*2)>y?(M*=t?1:-1,m+=M,g-=M):(S=0,m=g=(f+c)/2)}var J=s*H(m),K=s*q(m),N=u*H(T),Q=u*q(T);if(w>y){var U=s*H(g),V=s*q(g),X=u*H(R),Y=u*q(R),E;if(F<an)if(E=pn(J,K,X,Y,U,V,N,Q)){var Z=J-E[0],$=K-E[1],b=U-E[0],k=V-E[1],nn=1/q(fn((Z*b+$*k)/(L(Z*Z+$*$)*L(b*b+k*k)))/2),en=L(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=W(X,Y,J,K,s,x,t),r=W(U,V,N,Q,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(J,K),a.arc(0,0,s,m,g,!t)):a.moveTo(J,K),!(u>y)||!(P>y)?a.lineTo(N,Q):p>y?(e=W(N,Q,U,V,u,-p,t),r=W(J,K,X,Y,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[H(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:B(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:B(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:B(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:B(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:B(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:B(+n),i):A},i.padAngle=function(n){return arguments.length?(C=typeof n=="function"?n:B(+n),i):C},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
@@ -0,0 +1,36 @@
import{p as qe}from"./chunk-JWPE2WC7.js";import{_ as ct,D as Qe,Y as Je,l as Fe,b as Ke,a as je,n as _e,o as tr,g as er,s as rr,p as ir,A as ar,y as nr,B as or,c as Ee,b5 as Te,ak as pe,i as sr,j as hr,q as lr,al as fr,b6 as cr}from"./mermaid.core.js";import{p as gr}from"./cynefin-OW5HDTMX.js";import{c as be}from"./cytoscape.esm.js";import{g as ur}from"./index.js";var he={exports:{}},le={exports:{}},fe={exports:{}},dr=fe.exports,De;function vr(){return De||(De=1,(function(x,M){(function(R,T){x.exports=T()})(dr,function(){return(function(w){var R={};function T(v){if(R[v])return R[v].exports;var l=R[v]={i:v,l:!1,exports:{}};return w[v].call(l.exports,l,l.exports,T),l.l=!0,l.exports}return T.m=w,T.c=R,T.i=function(v){return v},T.d=function(v,l,i){T.o(v,l)||Object.defineProperty(v,l,{configurable:!1,enumerable:!0,get:i})},T.n=function(v){var l=v&&v.__esModule?function(){return v.default}:function(){return v};return T.d(l,"a",l),l},T.o=function(v,l){return Object.prototype.hasOwnProperty.call(v,l)},T.p="",T(T.s=28)})([(function(w,R,T){function v(){}v.QUALITY=1,v.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,v.DEFAULT_INCREMENTAL=!1,v.DEFAULT_ANIMATION_ON_LAYOUT=!0,v.DEFAULT_ANIMATION_DURING_LAYOUT=!1,v.DEFAULT_ANIMATION_PERIOD=50,v.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,v.DEFAULT_GRAPH_MARGIN=15,v.NODE_DIMENSIONS_INCLUDE_LABELS=!1,v.SIMPLE_NODE_SIZE=40,v.SIMPLE_NODE_HALF_SIZE=v.SIMPLE_NODE_SIZE/2,v.EMPTY_COMPOUND_NODE_SIZE=40,v.MIN_EDGE_LENGTH=1,v.WORLD_BOUNDARY=1e6,v.INITIAL_WORLD_BOUNDARY=v.WORLD_BOUNDARY/1e3,v.WORLD_CENTER_X=1200,v.WORLD_CENTER_Y=900,w.exports=v}),(function(w,R,T){var v=T(2),l=T(8),i=T(9);function r(f,e,d){v.call(this,d),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=d,this.bendpoints=[],this.source=f,this.target=e}r.prototype=Object.create(v.prototype);for(var a in v)r[a]=v[a];r.prototype.getSource=function(){return this.source},r.prototype.getTarget=function(){return this.target},r.prototype.isInterGraph=function(){return this.isInterGraph},r.prototype.getLength=function(){return this.length},r.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},r.prototype.getBendpoints=function(){return this.bendpoints},r.prototype.getLca=function(){return this.lca},r.prototype.getSourceInLca=function(){return this.sourceInLca},r.prototype.getTargetInLca=function(){return this.targetInLca},r.prototype.getOtherEnd=function(f){if(this.source===f)return this.target;if(this.target===f)return this.source;throw"Node is not incident with this edge"},r.prototype.getOtherEndInGraph=function(f,e){for(var d=this.getOtherEnd(f),t=e.getGraphManager().getRoot();;){if(d.getOwner()==e)return d;if(d.getOwner()==t)break;d=d.getOwner().getParent()}return null},r.prototype.updateLength=function(){var f=new Array(4);this.isOverlapingSourceAndTarget=l.getIntersection(this.target.getRect(),this.source.getRect(),f),this.isOverlapingSourceAndTarget||(this.lengthX=f[0]-f[2],this.lengthY=f[1]-f[3],Math.abs(this.lengthX)<1&&(this.lengthX=i.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=i.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},r.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=i.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=i.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},w.exports=r}),(function(w,R,T){function v(l){this.vGraphObject=l}w.exports=v}),(function(w,R,T){var v=T(2),l=T(10),i=T(13),r=T(0),a=T(16),f=T(5);function e(t,s,o,c){o==null&&c==null&&(c=s),v.call(this,c),t.graphManager!=null&&(t=t.graphManager),this.estimatedSize=l.MIN_VALUE,this.inclusionTreeDepth=l.MAX_VALUE,this.vGraphObject=c,this.edges=[],this.graphManager=t,o!=null&&s!=null?this.rect=new i(s.x,s.y,o.width,o.height):this.rect=new i}e.prototype=Object.create(v.prototype);for(var d in v)e[d]=v[d];e.prototype.getEdges=function(){return this.edges},e.prototype.getChild=function(){return this.child},e.prototype.getOwner=function(){return this.owner},e.prototype.getWidth=function(){return this.rect.width},e.prototype.setWidth=function(t){this.rect.width=t},e.prototype.getHeight=function(){return this.rect.height},e.prototype.setHeight=function(t){this.rect.height=t},e.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},e.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},e.prototype.getCenter=function(){return new f(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},e.prototype.getLocation=function(){return new f(this.rect.x,this.rect.y)},e.prototype.getRect=function(){return this.rect},e.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},e.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.reLine truncated
.edge {
stroke-width: ${x.archEdgeWidth};
stroke: ${x.archEdgeColor};
fill: none;
}
.arrow {
fill: ${x.archEdgeArrowColor};
}
.node-bkg {
fill: none;
stroke: ${x.archGroupBorderColor};
stroke-width: ${x.archGroupBorderWidth};
stroke-dasharray: 8;
}
.node-icon-text {
display: flex;
align-items: center;
}
.node-icon-text > div {
color: #fff;
margin: 1px;
height: fit-content;
text-align: center;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
}
`,"getStyles"),Fr=Sr;function me(x,M){if(x===0)return M();const w=Math.random;let R=x>>>0;Math.random=function(){R=R+1831565813>>>0;let T=R;return T=Math.imul(T^T>>>15,T|1),T^=T+Math.imul(T^T>>>7,T|61),((T^T>>>14)>>>0)/4294967296};try{return M()}finally{Math.random=w}}ct(me,"withSeededRandom");var re=ct(x=>`<g><rect width="80" height="80" style="fill: #087ebf; stroke-width: 0px;"/>${x}</g>`,"wrapIcon"),ne={prefix:"mermaid-architecture",height:80,width:80,icons:{database:{body:re('<path id="b" data-name="4" d="m20,57.86c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><path id="c" data-name="3" d="m20,45.95c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><path id="d" data-name="2" d="m20,34.05c0,3.94,8.95,7.14,20,7.14s20-3.2,20-7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse id="e" data-name="1" cx="40" cy="22.14" rx="20" ry="7.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><line x1="20" y1="57.86" x2="20" y2="22.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><line x1="60" y1="57.86" x2="60" y2="22.14" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/>')},server:{body:re('<rect x="17.5" y="17.5" width="45" height="45" rx="2" ry="2" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><line x1="17.5" y1="32.5" x2="62.5" y2="32.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><line x1="17.5" y1="47.5" x2="62.5" y2="47.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><g><path d="m56.25,25c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z" style="fill: #fff; stroke-width: 0px;"/><path d="m56.25,25c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z" style="fill: none; stroke: #fff; stroke-miterlimit: 10;"/></g><g><path d="m56.25,40c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z" style="fill: #fff; stroke-width: 0px;"/><path d="m56.25,40c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z" style="fill: none; stroke: #fff; stroke-miterlimit: 10;"/></g><g><path d="m56.25,55c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z" style="fill: #fff; stroke-width: 0px;"/><path d="m56.25,55c0,.27-.45.5-1,.5h-10.5c-.55,0-1-.23-1-.5s.45-.5,1-.5h10.5c.55,0,1,.23,1,.5Z" style="fill: none; stroke: #fff; stroke-miterlimit: 10;"/></g><g><circle cx="32.5" cy="25" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/><circle cx="27.5" cy="25" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/><circle cx="22.5" cy="25" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/></g><g><circle cx="32.5" cy="40" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/><circle cx="27.5" cy="40" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/><circle cx="22.5" cy="40" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/></g><g><circle cx="32.5" cy="55" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/><circle cx="27.5" cy="55" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/><circle cx="22.5" cy="55" r=".75" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10;"/></g>')},disk:{body:re('<rect x="20" y="15" width="40" height="50" rx="1" ry="1" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse cx="24" cy="19.17" rx=".8" ry=".83" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse cx="56" cy="19.17" rx=".8" ry=".83" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse cx="24" cy="60.83" rx=".8" ry=".83" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse cx="56" cy="60.83" rx=".8" ry=".83" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse cx="40" cy="33.75" rx="14" ry="14.58" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><ellipse cx="40" cy="33.75" rx="4" ry="4.17" style="fill: #fff; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><path d="m37.51,42.52l-4.83,13.22c-.26.71-1.1,1.02-1.76.64l-4.18-2.42c-.66-.38-.81-1.26-.33-1.84l9.01-10.8c.88-1.05,2.56-.08,2.09,1.2Z" style="fill: #fff; stroke-width: 0px;"/>')},internet:{body:re('<circle cx="40" cy="40" r="22.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><line x1="40" y1="17.5" x2="40" y2="62.5" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><line x1="17.5" y1="40" x2="62.5" y2="40" style="fill: none; stroke: #fff; stroke-miterlimit: 10; stroke-width: 2px;"/><path d="m39.99,17.51c-15.28,11.1-15.28,33.88,0,44.98" style="fill: none; sLine truncated
translate(${L}, ${F-E.height/2})
translate(${p*y.width/2}, ${m*y.height/2})
rotate(${-1*p*m*45}, 0, ${E.height/2})
`)}}}}}))},"drawEdges"),Pr=ct(async function(x,M,w,R){const v=w.getConfigField("padding")*.75,l=w.getConfigField("fontSize"),r=w.getConfigField("iconSize")/2;await Promise.all(M.nodes().map(async a=>{const f=ie(a);if(f.type==="group"){const{h:e,w:d,x1:t,y1:s}=a.boundingBox(),o=x.append("rect");o.attr("id",`${R}-group-${f.id}`).attr("x",t+r).attr("y",s+r).attr("width",d).attr("height",e).attr("class","node-bkg");const c=x.append("g");let h=t,N=s;if(f.icon){const g=c.append("g");g.html(`<g>${await pe(f.icon,{height:v,width:v,fallbackPrefix:ne.prefix})}</g>`),g.attr("transform","translate("+(h+r+1)+", "+(N+r+1)+")"),h+=v,N+=l/2-1-2}if(f.label){const g=c.append("g");await Te(g,f.label,{useHtmlLabels:!1,width:d,classes:"architecture-service-label"},Ee()),g.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","start").attr("text-anchor","start"),g.attr("transform","translate("+(h+r+4)+", "+(N+r+2)+")")}w.setElementForId(f.id,o)}}))},"drawGroups"),Gr=ct(async function(x,M,w,R){const T=Ee();for(const v of w){const l=M.append("g"),i=x.getConfigField("iconSize");if(v.title){const e=l.append("g");await Te(e,v.title,{useHtmlLabels:!1,width:i*1.5,classes:"architecture-service-label"},T),e.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle"),e.attr("transform","translate("+i/2+", "+i+")")}const r=l.append("g");if(v.icon)r.html(`<g>${await pe(v.icon,{height:i,width:i,fallbackPrefix:ne.prefix})}</g>`);else if(v.iconText){r.html(`<g>${await pe("blank",{height:i,width:i,fallbackPrefix:ne.prefix})}</g>`);const t=r.append("g").append("foreignObject").attr("width",i).attr("height",i).append("div").attr("class","node-icon-text").attr("style",`height: ${i}px;`).append("div").html(sr(v.iconText,T)),s=parseInt(window.getComputedStyle(t.node(),null).getPropertyValue("font-size").replace(/\D/g,""))??16;t.attr("style",`-webkit-line-clamp: ${Math.floor((i-2)/s)};`)}else r.append("path").attr("class","node-bkg").attr("id",`${R}-node-${v.id}`).attr("d",`M0,${i} V5 Q0,0 5,0 H${i-5} Q${i},0 ${i},5 V${i} Z`);l.attr("id",`${R}-service-${v.id}`).attr("class","architecture-service");const{width:a,height:f}=l.node().getBBox();v.width=a,v.height=f,x.setElementForId(v.id,l)}return 0},"drawServices"),Ur=ct(function(x,M,w,R){w.forEach(T=>{const v=M.append("g"),l=x.getConfigField("iconSize");v.append("g").append("rect").attr("id",`${R}-node-${T.id}`).attr("fill-opacity","0").attr("width",l).attr("height",l),v.attr("class","architecture-junction");const{width:r,height:a}=v._groups[0][0].getBBox();v.width=r,v.height=a,x.setElementForId(T.id,v)})},"drawJunctions");fr([{name:ne.prefix,icons:ne}]);be.use(Nr);function Xe(x,M,w){x.forEach(R=>{M.add({group:"nodes",data:{type:"service",id:R.id,icon:R.icon,label:R.title,parent:R.in,width:w.getConfigField("iconSize"),height:w.getConfigField("iconSize")},classes:"node-service"})})}ct(Xe,"addServices");function He(x,M,w){x.forEach(R=>{M.add({group:"nodes",data:{type:"junction",id:R.id,parent:R.in,width:w.getConfigField("iconSize"),height:w.getConfigField("iconSize")},classes:"node-junction"})})}ct(He,"addJunctions");function We(x,M){M.nodes().map(w=>{const R=ie(w);if(R.type==="group")return;R.x=w.position().x,R.y=w.position().y,x.getElementById(R.id).attr("transform","translate("+(R.x||0)+","+(R.y||0)+")")})}ct(We,"positionNodes");function Ve(x,M){x.forEach(w=>{M.add({group:"nodes",data:{type:"group",id:w.id,icon:w.icon,label:w.title,parent:w.in},classes:"node-group"})})}ct(Ve,"addGroups");function $e(x,M){x.forEach(w=>{const{lhsId:R,rhsId:T,lhsInto:v,lhsGroup:l,rhsInto:i,lhsDir:r,rhsDir:a,rhsGroup:f,title:e}=w,d=Ne(w.lhsDir,w.rhsDir)?"segments":"straight",t={id:`${R}-${T}`,label:e,source:R,sourceDir:r,sourceArrow:v,sourceGroup:l,sourceEndpoint:r==="L"?"0 50%":r==="R"?"100% 50%":r==="T"?"50% 0":"50% 100%",target:T,targetDir:a,targetArrow:i,targetGroup:f,targetEndpoint:a==="L"?"0 50%":a==="R"?"100% 50%":a==="T"?"50% 0":"50% 100%"};M.add({group:"edges",data:t,classes:d})})}ct($e,"addEdges");function ze(x,M,w,R=[]){const T=ct((d,t)=>{const s=new Map;for(const[o,c]of d.entries()){const h=`${o}`;let N=0;const g=[...c.entries()];if(g.length===1){s.set(h,g[0][1]);continue}for(let u=0;u<g.length-1;u++)for(let L=u+1;L<g.length;L++){const[F,C]=g[u],[G,V]=g[L];if(w.get(Pe(F,G))===t)s.set(h,[...s.get(h)??[],...C,...V]);else if(F==="default"||G==="default")s.set(h,[...s.get(h)??[],...C,...V]);else{const $=`${h}-${N++}`;s.set($,C);const A=`${h}-${N++}`;s.set(A,V)}}}return s},"flattenAlignments"),v=M.map(d=>{const t=new Map,s=new Map;return d.forEach(([o,c],h)=>{const N=x.getNode(h)?.in??"default",g=t.get(c)??new Map;t.has(c)||t.set(c,g);const u=s.get(o)??new Map;s.has(o)||s.set(o,u);for(const L of[g,u]){const F=L.get(N)??[];L.has(N)||L.set(N,F),F.push(h)}}),{horiz:[...T(t,"horizontal").values()].filter(o=>o.length>1),vert:[...T(s,"vertical").values()].filter(o=>o.length>1)}}),[l,i]=v.reduce(([d,t],{horiz:s,vert:o})=>[[...d,Line truncated
@@ -0,0 +1,129 @@
import{g as Pe}from"./chunk-5VM5RSS4.js";import{aD as Fe,aE as xe,aF as Me,aG as Ke,aH as Ye,aI as We,aJ as Ve,aK as Ue,aL as He,aM as Xe,aN as je,aO as Ge,aP as qe,aQ as Je,aR as Ze,aS as Qe,aT as $e,aU as et,aV as tt,aW as st,aX as rt,aY as it,aZ as at,a_ as nt,a$ as ot,_ as u,y as Y,j as X,b0 as ct,d as lt,l as m,p as ut,r as gt,c as Le,Q as ht,az as dt,ay as pt,aA as ft,k as bt,b1 as St,ag as ye,ah as xt}from"./mermaid.core.js";import{c as Lt}from"./channel.js";import"./index.js";function yt(e){return Array.isArray(e)}function mt(e){if(Fe(e))return e;const a=xe(e);if(!wt(e))return{};if(yt(e)){const r=Array.from(e);return e.length>0&&typeof e[0]=="string"&&Object.hasOwn(e,"index")&&(r.index=e.index,r.input=e.input),r}if(Me(e)){const r=e,l=r.constructor;return new l(r.buffer,r.byteOffset,r.length)}if(a==="[object ArrayBuffer]")return new ArrayBuffer(e.byteLength);if(a==="[object DataView]"){const r=e,l=r.buffer,d=r.byteOffset,s=r.byteLength,h=new ArrayBuffer(s),x=new Uint8Array(l,d,s);return new Uint8Array(h).set(x),new DataView(h)}if(a==="[object Boolean]"||a==="[object Number]"||a==="[object String]"){const r=e.constructor,l=new r(e.valueOf());return a==="[object String]"?_t(l,e):se(l,e),l}if(a==="[object Date]")return new Date(Number(e));if(a==="[object RegExp]"){const r=e,l=new RegExp(r.source,r.flags);return l.lastIndex=r.lastIndex,l}if(a==="[object Symbol]")return Object(Symbol.prototype.valueOf.call(e));if(a==="[object Map]"){const r=e,l=new Map;return r.forEach((d,s)=>{l.set(s,d)}),l}if(a==="[object Set]"){const r=e,l=new Set;return r.forEach(d=>{l.add(d)}),l}if(a==="[object Arguments]"){const r=e,l={};return se(l,r),l.length=r.length,l[Symbol.iterator]=r[Symbol.iterator],l}const o={};return kt(o,e),se(o,e),Et(o,e),o}function wt(e){switch(xe(e)){case ot:case nt:case at:case it:case rt:case st:case tt:case et:case $e:case Qe:case Ze:case Je:case qe:case Ge:case je:case Xe:case He:case Ue:case Ve:case We:case Ye:case Ke:return!0;default:return!1}}function se(e,a){for(const o in a)Object.hasOwn(a,o)&&(e[o]=a[o])}function Et(e,a){const o=Object.getOwnPropertySymbols(a);for(let r=0;r<o.length;r++){const l=o[r];Object.prototype.propertyIsEnumerable.call(a,l)&&(e[l]=a[l])}}function _t(e,a){const o=a.valueOf().length;for(const r in a)Object.hasOwn(a,r)&&(Number.isNaN(Number(r))||Number(r)>=o)&&(e[r]=a[r])}function kt(e,a){const o=Object.getPrototypeOf(a);o!==null&&typeof a.constructor=="function"&&Object.setPrototypeOf(e,o)}var ie=(function(){var e=u(function(v,g,i,c){for(i=i||{},c=v.length;c--;i[v[c]]=g);return i},"o"),a=[1,15],o=[1,7],r=[1,13],l=[1,14],d=[1,19],s=[1,16],h=[1,17],x=[1,18],y=[8,30],S=[8,10,21,28,29,30,31,39,43,46],f=[1,23],L=[1,24],w=[8,10,15,16,21,28,29,30,31,39,43,46],b=[8,10,15,16,21,27,28,29,30,31,39,43,46],k=[1,49],_={trace:u(function(){},"trace"),yy:{},symbols_:{error:2,spaceLines:3,SPACELINE:4,NL:5,separator:6,SPACE:7,EOF:8,start:9,BLOCK_DIAGRAM_KEY:10,document:11,stop:12,statement:13,link:14,LINK:15,START_LINK:16,LINK_LABEL:17,STR:18,nodeStatement:19,columnsStatement:20,SPACE_BLOCK:21,blockStatement:22,classDefStatement:23,cssClassStatement:24,styleStatement:25,node:26,SIZE:27,COLUMNS:28,"id-block":29,end:30,NODE_ID:31,nodeShapeNLabel:32,dirList:33,DIR:34,NODE_DSTART:35,NODE_DEND:36,BLOCK_ARROW_START:37,BLOCK_ARROW_END:38,classDef:39,CLASSDEF_ID:40,CLASSDEF_STYLEOPTS:41,DEFAULT:42,class:43,CLASSENTITY_IDS:44,STYLECLASS:45,style:46,STYLE_ENTITY_IDS:47,STYLE_DEFINITION_DATA:48,$accept:0,$end:1},terminals_:{2:"error",4:"SPACELINE",5:"NL",7:"SPACE",8:"EOF",10:"BLOCK_DIAGRAM_KEY",15:"LINK",16:"START_LINK",17:"LINK_LABEL",18:"STR",21:"SPACE_BLOCK",27:"SIZE",28:"COLUMNS",29:"id-block",30:"end",31:"NODE_ID",34:"DIR",35:"NODE_DSTART",36:"NODE_DEND",37:"BLOCK_ARROW_START",38:"BLOCK_ARROW_END",39:"classDef",40:"CLASSDEF_ID",41:"CLASSDEF_STYLEOPTS",42:"DEFAULT",43:"class",44:"CLASSENTITY_IDS",45:"STYLECLASS",46:"style",47:"STYLE_ENTITY_IDS",48:"STYLE_DEFINITION_DATA"},productions_:[0,[3,1],[3,2],[3,2],[6,1],[6,1],[6,1],[9,3],[12,1],[12,1],[12,2],[12,2],[11,1],[11,2],[14,1],[14,4],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[19,3],[19,2],[19,1],[20,1],[22,4],[22,3],[26,1],[26,2],[33,1],[33,2],[32,3],[32,4],[23,3],[23,3],[24,3],[25,3]],performAction:u(function(g,i,c,p,E,t,M){var n=t.length-1;switch(E){case 4:p.getLogger().debug("Rule: separator (NL) ");break;case 5:p.getLogger().debug("Rule: separator (Space) ");break;case 6:p.getLogger().debug("Rule: separator (EOF) ");break;case 7:p.getLogger().debug("Rule: hierarchy: ",t[n-1]),p.setHierarchy(t[n-1]);break;case 8:p.getLogger().debug("Stop NL ");break;case 9:p.getLogger().debug("Stop EOF ");break;case 10:p.getLogger().debug("Stop NL2 ");break;case 11:p.getLogger().debug("Stop EOF2 ");break;case 12:p.getLogger().debug("Rule: statement: ",t[n]),typeof t[n].length=="number"?this.$=t[n]:this.$=[t[n]];break;case 13:p.getLogger().debug("Rule: statement #2: ",t[n-1]),this.$=[t[n-1]].concat(t[n]);break;case 14:p.getLogger().debug("Rule: link: ",Line truncated
`+D.showPosition()+`
Expecting `+H.join(", ")+", got '"+(this.terminals_[N]||N)+"'":te="Parse error on line "+(P+1)+": Unexpected "+(N==V?"end of input":"'"+(this.terminals_[N]||N)+"'"),this.parseError(te,{text:D.match,token:this.terminals_[N]||N,line:D.yylineno,loc:$,expected:H})}if(C[0]instanceof Array&&C.length>1)throw new Error("Parse Error: multiple actions possible at state: "+R+", token: "+N);switch(C[0]){case 1:c.push(N),E.push(D.yytext),t.push(D.yylloc),c.push(C[1]),N=null,W=D.yyleng,n=D.yytext,P=D.yylineno,$=D.yylloc;break;case 2:if(B=this.productions_[C[1]][1],F.$=E[E.length-B],F._$={first_line:t[t.length-(B||1)].first_line,last_line:t[t.length-1].last_line,first_column:t[t.length-(B||1)].first_column,last_column:t[t.length-1].last_column},Be&&(F._$.range=[t[t.length-(B||1)].range[0],t[t.length-1].range[1]]),ee=this.performAction.apply(F,[n,W,P,A.yy,C[1],E,t].concat(Z)),typeof ee<"u")return ee;B&&(c=c.slice(0,-1*B*2),E=E.slice(0,-1*B),t=t.slice(0,-1*B)),c.push(this.productions_[C[1]][0]),E.push(F.$),t.push(F._$),pe=M[c[c.length-2]][c[c.length-1]],c.push(pe);break;case 3:return!0}}return!0},"parse")},T=(function(){var v={EOF:1,parseError:u(function(i,c){if(this.yy.parser)this.yy.parser.parseError(i,c);else throw new Error(i)},"parseError"),setInput:u(function(g,i){return this.yy=i||this.yy||{},this._input=g,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:u(function(){var g=this._input[0];this.yytext+=g,this.yyleng++,this.offset++,this.match+=g,this.matched+=g;var i=g.match(/(?:\r\n?|\n).*/g);return i?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),g},"input"),unput:u(function(g){var i=g.length,c=g.split(/(?:\r\n?|\n)/g);this._input=g+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-i),this.offset-=i;var p=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),c.length-1&&(this.yylineno-=c.length-1);var E=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:c?(c.length===p.length?this.yylloc.first_column:0)+p[p.length-c.length].length-c[0].length:this.yylloc.first_column-i},this.options.ranges&&(this.yylloc.range=[E[0],E[0]+this.yyleng-i]),this.yyleng=this.yytext.length,this},"unput"),more:u(function(){return this._more=!0,this},"more"),reject:u(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:u(function(g){this.unput(this.match.slice(g))},"less"),pastInput:u(function(){var g=this.matched.substr(0,this.matched.length-this.match.length);return(g.length>20?"...":"")+g.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:u(function(){var g=this.match;return g.length<20&&(g+=this._input.substr(0,20-g.length)),(g.substr(0,20)+(g.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:u(function(){var g=this.pastInput(),i=new Array(g.length+1).join("-");return g+this.upcomingInput()+`
`+i+"^"},"showPosition"),test_match:u(function(g,i){var c,p,E;if(this.options.backtrack_lexer&&(E={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(E.yylloc.range=this.yylloc.range.slice(0))),p=g[0].match(/(?:\r\n?|\n).*/g),p&&(this.yylineno+=p.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:p?p[p.length-1].length-p[p.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+g[0].length},this.yytext+=g[0],this.match+=g[0],this.matches=g,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(g[0].length),this.matched+=g[0],c=this.performAction.call(this,this.yy,this,i,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),c)return c;if(this._backtrack){for(var t in E)this[t]=E[t];return!1}return!1},"test_match"),next:u(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var g,i,c,p;this._more||(this.yytext="",this.match="");for(var E=this._currentRules(),t=0;t<E.length;t++)if(c=this._input.match(this.rules[E[t]]),c&&(!i||c[0].length>i[0].length)){if(i=c,p=t,this.options.backtrack_lexer){if(g=this.test_match(c,E[t]),g!==!1)return g;if(this._backtrack){i=!1;continue}else return!1}else if(!this.options.flex)break}return i?(g=this.test_match(i,E[p]),g!==!1?g:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text.
`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:u(function(){var i=this.next();return i||this.lex()},"lex"),begin:u(function(i){this.conditionStack.push(i)},"begin"),popState:u(function(){var i=this.conditionStack.length-1;return i>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:u(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:u(function(i){return i=this.conditionStack.length-1-Math.abs(i||0),i>=0?this.conditionStack[i]:"INITIAL"},"topState"),pushState:u(function(i){this.begin(i)},"pushState"),stateStackSize:u(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:u(function(i,c,p,E){switch(p){case 0:return i.getLogger().debug("Found block-beta"),10;case 1:return i.getLogger().debug("Found id-block"),29;case 2:return i.getLogger().debug("Found block"),10;case 3:i.getLogger().debug(".",c.yytext);break;case 4:i.getLogger().debug("_",c.yytext);break;case 5:return 5;case 6:return c.yytext=-1,28;case 7:return c.yytext=c.yytext.replace(/columns\s+/,""),i.getLogger().debug("COLUMNS (LEX)",c.yytext),28;case 8:this.pushState("md_string");break;case 9:return"MD_STR";case 10:this.popState();break;case 11:this.pushState("string");break;case 12:i.getLogger().debug("LEX: POPPING STR:",c.yytext),this.popState();break;case 13:return i.getLogger().debug("LEX: STR end:",c.yytext),"STR";case 14:return c.yytext=c.yytext.replace(/space\:/,""),i.getLogger().debug("SPACE NUM (LEX)",c.yytext),21;case 15:return c.yytext="1",i.getLogger().debug("COLUMNS (LEX)",c.yytext),21;case 16:return 42;case 17:return"LINKSTYLE";case 18:return"INTERPOLATE";case 19:return this.pushState("CLASSDEF"),39;case 20:return this.popState(),this.pushState("CLASSDEFID"),"DEFAULT_CLASSDEF_ID";case 21:return this.popState(),this.pushState("CLASSDEFID"),40;case 22:return this.popState(),41;case 23:return this.pushState("CLASS"),43;case 24:return this.popState(),this.pushState("CLASS_STYLE"),44;case 25:return this.popState(),45;case 26:return this.pushState("STYLE_STMNT"),46;case 27:return this.popState(),this.pushState("STYLE_DEFINITION"),47;case 28:return this.popState(),48;case 29:return this.pushState("acc_title"),"acc_title";case 30:return this.popState(),"acc_title_value";case 31:return this.pushState("acc_descr"),"acc_descr";case 32:return this.popState(),"acc_descr_value";case 33:this.pushState("acc_descr_multiline");break;case 34:this.popState();break;case 35:return"acc_descr_multiline_value";case 36:return 30;case 37:return this.popState(),i.getLogger().debug("Lex: (("),"NODE_DEND";case 38:return this.popState(),i.getLogger().debug("Lex: (("),"NODE_DEND";case 39:return this.popState(),i.getLogger().debug("Lex: ))"),"NODE_DEND";case 40:return this.popState(),i.getLogger().debug("Lex: (("),"NODE_DEND";case 41:return this.popState(),i.getLogger().debug("Lex: (("),"NODE_DEND";case 42:return this.popState(),i.getLogger().debug("Lex: (-"),"NODE_DEND";case 43:return this.popState(),i.getLogger().debug("Lex: -)"),"NODE_DEND";case 44:return this.popState(),i.getLogger().debug("Lex: (("),"NODE_DEND";case 45:return this.popState(),i.getLogger().debug("Lex: ]]"),"NODE_DEND";case 46:return this.popState(),i.getLogger().debug("Lex: ("),"NODE_DEND";case 47:return this.popState(),i.getLogger().debug("Lex: ])"),"NODE_DEND";case 48:return this.popState(),i.getLogger().debug("Lex: /]"),"NODE_DEND";case 49:return this.popState(),i.getLogger().debug("Lex: /]"),"NODE_DEND";case 50:return this.popState(),i.getLogger().debug("Lex: )]"),"NODE_DEND";case 51:return this.popState(),i.getLogger().debug("Lex: )"),"NODE_DEND";case 52:return this.popState(),i.getLogger().debug("Lex: ]>"),"NODE_DEND";case 53:return this.popState(),i.getLogger().debug("Lex: ]"),"NODE_DEND";case 54:return i.getLogger().debug("Lexa: -)"),this.pushState("NODE"),35;case 55:return i.getLogger().debug("Lexa: (-"),this.pushState("NODE"),35;case 56:return i.getLogger().debug("Lexa: ))"),this.pushState("NODE"),35;case 57:return i.getLogger().debug("Lexa: )"),this.pushState("NODE"),35;case 58:return i.getLogger().debug("Lex: ((("),this.pushState("NODE"),35;case 59:return i.getLogger().debug("Lexa: )"),this.pushState("NODE"),35;case 60:return i.getLogger().debug("Lexa: )"),this.pushState("NODE"),35;case 61:return i.getLogger().debug("Lexa: )"),this.pushState("NODE"),35;case 62:return i.getLogger().debug("Lexc: >"),this.pushState("NODE"),35;case 63:return i.getLogger().debug("Lexa: (["),this.pushState("NODE"),35;case 64:return i.getLogger().debug("Lexa: )"),this.pushState("NODE"),35;case 65:return this.pushState("NODE"),35;case 66:return this.pushState("NODE"),35;case 67:return this.pushState("NODE"),35;case 68:return this.pushState("NODE"),35;case 69:return this.pushState("NODE"),35;case 70:return this.pushState("NODE"),35;case 71:return this.p Line truncated
font-family: ${e.fontFamily};
color: ${e.nodeTextColor||e.textColor};
}
.cluster-label text {
fill: ${e.titleColor};
}
.cluster-label span {
color: ${e.titleColor};
}
.label text,span {
fill: ${e.nodeTextColor||e.textColor};
color: ${e.nodeTextColor||e.textColor};
}
.node rect,
.node circle,
.node ellipse,
.node polygon,
.node path {
fill: ${e.mainBkg};
stroke: ${e.nodeBorder};
stroke-width: 1px;
}
.flowchart-label text {
text-anchor: middle;
}
// .flowchart-label .text-outer-tspan {
// text-anchor: middle;
// }
// .flowchart-label .text-inner-tspan {
// text-anchor: start;
// }
.node .label {
text-align: center;
}
.node.clickable {
cursor: pointer;
}
.arrowheadPath {
fill: ${e.arrowheadColor};
}
.edgePaths .path {
stroke: ${e.lineColor};
stroke-width: 2.0px;
}
.flowchart-link {
stroke: ${e.lineColor};
fill: none;
}
.edgeLabel {
background-color: ${e.edgeLabelBackground};
/*
* This is for backward compatibility with existing code that didn't
* add a \`<p>\` around edge labels.
*
* TODO: We should probably remove this in a future release.
*/
p {
margin: 0;
padding: 0;
display: inline;
}
rect {
opacity: 0.5;
background-color: ${e.edgeLabelBackground};
fill: ${e.edgeLabelBackground};
}
text-align: center;
}
/* For html labels only */
.labelBkg {
background-color: ${e.edgeLabelBackground};
}
.node .cluster {
// fill: ${re(e.mainBkg,.5)};
fill: ${re(e.clusterBkg,.5)};
stroke: ${re(e.clusterBorder,.2)};
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
stroke-width: 1px;
}
.cluster text {
fill: ${e.titleColor};
}
.cluster span {
color: ${e.titleColor};
}
/* .cluster div {
color: ${e.titleColor};
} */
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: ${e.fontFamily};
font-size: 12px;
background: ${e.tertiaryColor};
border: 1px solid ${e.border2};
border-radius: 2px;
pointer-events: none;
z-index: 100;
}
.flowchartTitleText {
text-anchor: middle;
font-size: 18px;
fill: ${e.textColor};
}
${Pe()}
`,"getStyles"),Gt=jt;function ne(e,a){if(e===0||!Number.isInteger(e))throw new Error("Columns must be an integer !== 0.");if(a<0||!Number.isInteger(a))throw new Error("Position must be a non-negative integer."+a);if(e<0)return{px:a,py:0};if(e===1)return{px:0,py:a};const o=a%e,r=Math.floor(a/e);return{px:o,py:r}}u(ne,"calculateBlockPosition");var qt=u(e=>{let a=0,o=0;for(const r of e.children){const{width:l,height:d,x:s,y:h}=r.size??{width:0,height:0,x:0,y:0};if(m.debug("getMaxChildSize abc95 child:",r.id,"width:",l,"height:",d,"x:",s,"y:",h,r.type),r.type==="space")continue;const x=l/(r.widthInColumns??1);x>a&&(a=x),d>o&&(o=d)}return{width:a,height:o}},"getMaxChildSize");function G(e,a,o=0,r=0,l=8){m.debug("setBlockSizes abc95 (start)",e.id,e?.size?.x,"block width =",e?.size,"siblingWidth",o),e?.size?.width||(e.size={width:o,height:r,x:0,y:0});let d=0,s=0;if(e.children?.length>0){for(const b of e.children)G(b,a,0,0,l);const h=qt(e);d=h.width,s=h.height,m.debug("setBlockSizes abc95 maxWidth of",e.id,":s children is ",d,s);for(const b of e.children)b.size&&(m.debug(`abc95 Setting size of children of ${e.id} id=${b.id} ${d} ${s} ${JSON.stringify(b.size)}`),b.size.width=d*(b.widthInColumns??1)+l*((b.widthInColumns??1)-1),b.size.height=s,b.size.x=0,b.size.y=0,m.debug(`abc95 updating size of ${e.id} children child:${b.id} maxWidth:${d} maxHeight:${s}`));for(const b of e.children)G(b,a,d,s,l);const x=e.columns??-1;let y=0;for(const b of e.children)y+=b.widthInColumns??1;let S=e.children.length;x>0&&x<y&&(S=x);const f=Math.ceil(y/S);let L=S*(d+l)+l,w=f*(s+l)+l;if(L<o){m.debug(`Detected to small sibling: abc95 ${e.id} siblingWidth ${o} siblingHeight ${r} width ${L}`),L=o,w=r;const b=(o-S*l-l)/S,k=(r-f*l-l)/f;m.debug("Size indata abc88",e.id,"childWidth",b,"maxWidth",d),m.debug("Size indata abc88",e.id,"childHeight",k,"maxHeight",s),m.debug("Size indata abc88 xSize",S,"padding",l);for(const _ of e.children)_.size&&(_.size.width=b,_.size.height=k,_.size.x=0,_.size.y=0)}if(m.debug(`abc95 (finale calc) ${e.id} xSize ${S} ySize ${f} columns ${x}${e.children.length} width=${Math.max(L,e.size?.width||0)}`),L<(e?.size?.width||0)){L=e?.size?.width||0;const b=x>0?Math.min(e.children.length,x):e.children.length;if(b>0){const k=(L-b*l-l)/b;m.debug("abc95 (growing to fit) width",e.id,L,e.size?.width,k);for(const _ of e.children)_.size&&(_.size.width=k)}}e.size={width:L,height:w,x:0,y:0}}m.debug("setBlockSizes abc94 (done)",e.id,e?.size?.x,e?.size?.width,e?.size?.y,e?.size?.height)}u(G,"setBlockSizes");function ue(e,a,o=8){m.debug(`abc85 layout blocks (=>layoutBlocks) ${e.id} x: ${e?.size?.x} y: ${e?.size?.y} width: ${e?.size?.width}`);const r=e.columns??-1;if(m.debug("layoutBlocks columns abc95",e.id,"=>",r,e),e.children&&e.children.length>0){const l=e?.children[0]?.size?.width??0,d=e.children.length*l+(e.children.length-1)*o;m.debug("widthOfChildren 88",d,"posX");const s=new Map;{let f=0;for(const L of e.children){if(!L.size)continue;const{py:w}=ne(r,f),b=s.get(w)??0;L.size.height>b&&s.set(w,L.size.height);let k=L?.widthInColumns??1;r>0&&(k=Math.min(k,r-f%r)),f+=k}}const h=new Map;{let f=0;const L=[...s.keys()].sort((w,b)=>w-b);for(const w of L)h.set(w,f),f+=(s.get(w)??0)+o}let x=0;m.debug("abc91 block?.size?.x",e.id,e?.size?.x);let y=e?.size?.x?e?.size?.x+(-e?.size?.width/2||0):-o,S=0;for(const f of e.children){const L=e;if(!f.size)continue;const{width:w,height:b}=f.size,{px:k,py:_}=ne(r,x);if(_!=S&&(S=_,y=e?.size?.x?e?.size?.x+(-e?.size?.width/2||0):-o,m.debug("New row in layout for block",e.id," and child ",f.id,S)),m.debug(`abc89 layout blocks (child) id: ${f.id} Pos: ${x} (px, py) ${k},${_} (${L?.size?.x},${L?.size?.y}) parent: ${L.id} width: ${w}${o}`),L.size){const O=w/2;f.size.x=y+o+O,m.debug(`abc91 layout blocks (calc) px, pyid:${f.id} startingPos=X${y} new startingPosX${f.size.x} ${O} padding=${o} width=${w} halfWidth=${O} => x:${f.size.x} y:${f.size.y} ${f.widthInColumns} (width * (child?.w || 1)) / 2 ${w*(f?.widthInColumns??1)/2}`),y=f.size.x+O;const v=h.get(_)??0,g=s.get(_)??b;f.size.y=L.size.y-L.size.height/2+v+g/2+o,m.debug(`abc88 layout blocks (calc) px, pyid:${f.id}startingPosX${y}${o}${O}=>x:${f.size.x}y:${f.size.y}${f.widthInColumns}(width * (child?.w || 1)) / 2${w*(f?.widthInColumns??1)/2}`)}f.children&&ue(f,a,o);let T=f?.widthInColumns??1;r>0&&(T=Math.min(T,r-x%r)),x+=T,m.debug("abc88 columnsPos",f,x)}}m.debug(`layout blocks (<==layoutBlocks) ${e.id} x: ${e?.size?.x} y: ${e?.size?.y} width: ${e?.size?.width}`)}u(ue,"layoutBlocks");function ge(e,{minX:a,minY:o,maxX:r,maxY:l}={minX:0,minY:0,maxX:0,maxY:0}){if(e.size&&e.id!=="root"){const{x:d,y:s,width:h,height:x}=e.size;d-h/2<a&&(a=d-h/2),s-x/2<o&&(o=s-x/2),d+h/2>r&&(r=d+h/2),s+x/2>l&&(l=s+x/2)}if(e.children)for(const d of e.children)({minX:a,minY:o,maxX:r,maxY:l}=ge(d,{minX:a,minY:o,maxX:r,maxY:l}));return{minX:a,minY:o,maxX:r,maxY:l}}u(ge,"findBounds");function Ie(e){const a=e.getBlock("root");if(!a)return;const o=Le()?.block?.padding??8;G(a,e,0,0,o),ue(a, Line truncated
@@ -0,0 +1,38 @@
import{d as Le}from"./chunk-F27PBJKO.js";import{s as Ie,g as Me,a as Be,b as Ve,_ as d,c as wt,l as he,d as Ye,e as Fe,f as Dt,h as Ue,i as be,j as Jt,w as je,k as $t,m as de}from"./mermaid.core.js";import"./index.js";var Ut=(function(){var t=d(function(yt,m,x,E){for(x=x||{},E=yt.length;E--;x[yt[E]]=m);return x},"o"),e=[1,24],s=[1,25],a=[1,26],u=[1,27],i=[1,28],n=[1,63],l=[1,64],r=[1,65],h=[1,66],y=[1,67],f=[1,68],b=[1,69],v=[1,29],w=[1,30],N=[1,31],O=[1,32],P=[1,33],I=[1,34],W=[1,35],X=[1,36],q=[1,37],H=[1,38],Q=[1,39],K=[1,40],G=[1,41],J=[1,42],Z=[1,43],$=[1,44],tt=[1,45],et=[1,46],nt=[1,47],st=[1,48],rt=[1,50],at=[1,51],it=[1,52],ot=[1,53],lt=[1,54],ct=[1,55],ut=[1,56],ht=[1,57],dt=[1,58],pt=[1,59],ft=[1,60],kt=[14,42],Wt=[14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],Ot=[12,14,34,36,37,38,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],S=[1,82],k=[1,83],T=[1,84],C=[1,85],R=[12,14,42],ie=[12,14,33,42],Mt=[12,14,33,42,76,77,79,80],gt=[12,33],Xt=[34,36,37,38,39,40,41,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74],qt={trace:d(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,direction:5,direction_tb:6,direction_bt:7,direction_rl:8,direction_lr:9,graphConfig:10,C4_CONTEXT:11,NEWLINE:12,statements:13,EOF:14,C4_CONTAINER:15,C4_COMPONENT:16,C4_DYNAMIC:17,C4_DEPLOYMENT:18,otherStatements:19,diagramStatements:20,otherStatement:21,title:22,accDescription:23,acc_title:24,acc_title_value:25,acc_descr:26,acc_descr_value:27,acc_descr_multiline_value:28,boundaryStatement:29,boundaryStartStatement:30,boundaryStopStatement:31,boundaryStart:32,LBRACE:33,ENTERPRISE_BOUNDARY:34,attributes:35,SYSTEM_BOUNDARY:36,BOUNDARY:37,CONTAINER_BOUNDARY:38,NODE:39,NODE_L:40,NODE_R:41,RBRACE:42,diagramStatement:43,PERSON:44,PERSON_EXT:45,SYSTEM:46,SYSTEM_DB:47,SYSTEM_QUEUE:48,SYSTEM_EXT:49,SYSTEM_EXT_DB:50,SYSTEM_EXT_QUEUE:51,CONTAINER:52,CONTAINER_DB:53,CONTAINER_QUEUE:54,CONTAINER_EXT:55,CONTAINER_EXT_DB:56,CONTAINER_EXT_QUEUE:57,COMPONENT:58,COMPONENT_DB:59,COMPONENT_QUEUE:60,COMPONENT_EXT:61,COMPONENT_EXT_DB:62,COMPONENT_EXT_QUEUE:63,REL:64,BIREL:65,REL_U:66,REL_D:67,REL_L:68,REL_R:69,REL_B:70,REL_INDEX:71,UPDATE_EL_STYLE:72,UPDATE_REL_STYLE:73,UPDATE_LAYOUT_CONFIG:74,attribute:75,STR:76,STR_KEY:77,STR_VALUE:78,ATTRIBUTE:79,ATTRIBUTE_EMPTY:80,$accept:0,$end:1},terminals_:{2:"error",6:"direction_tb",7:"direction_bt",8:"direction_rl",9:"direction_lr",11:"C4_CONTEXT",12:"NEWLINE",14:"EOF",15:"C4_CONTAINER",16:"C4_COMPONENT",17:"C4_DYNAMIC",18:"C4_DEPLOYMENT",22:"title",23:"accDescription",24:"acc_title",25:"acc_title_value",26:"acc_descr",27:"acc_descr_value",28:"acc_descr_multiline_value",33:"LBRACE",34:"ENTERPRISE_BOUNDARY",36:"SYSTEM_BOUNDARY",37:"BOUNDARY",38:"CONTAINER_BOUNDARY",39:"NODE",40:"NODE_L",41:"NODE_R",42:"RBRACE",44:"PERSON",45:"PERSON_EXT",46:"SYSTEM",47:"SYSTEM_DB",48:"SYSTEM_QUEUE",49:"SYSTEM_EXT",50:"SYSTEM_EXT_DB",51:"SYSTEM_EXT_QUEUE",52:"CONTAINER",53:"CONTAINER_DB",54:"CONTAINER_QUEUE",55:"CONTAINER_EXT",56:"CONTAINER_EXT_DB",57:"CONTAINER_EXT_QUEUE",58:"COMPONENT",59:"COMPONENT_DB",60:"COMPONENT_QUEUE",61:"COMPONENT_EXT",62:"COMPONENT_EXT_DB",63:"COMPONENT_EXT_QUEUE",64:"REL",65:"BIREL",66:"REL_U",67:"REL_D",68:"REL_L",69:"REL_R",70:"REL_B",71:"REL_INDEX",72:"UPDATE_EL_STYLE",73:"UPDATE_REL_STYLE",74:"UPDATE_LAYOUT_CONFIG",76:"STR",77:"STR_KEY",78:"STR_VALUE",79:"ATTRIBUTE",80:"ATTRIBUTE_EMPTY"},productions_:[0,[3,1],[3,1],[5,1],[5,1],[5,1],[5,1],[4,1],[10,4],[10,4],[10,4],[10,4],[10,4],[13,1],[13,1],[13,2],[19,1],[19,2],[19,3],[21,1],[21,1],[21,2],[21,2],[21,1],[29,3],[30,3],[30,3],[30,4],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[32,2],[31,1],[20,1],[20,2],[20,3],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,1],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[43,2],[35,1],[35,2],[75,1],[75,2],[75,1],[75,1]],performAction:d(function(m,x,E,_,D,o,Pt){var p=o.length-1;switch(D){case 3:_.setDirection("TB");break;case 4:_.setDirection("BT");break;case 5:_.setDirection("RL");break;case 6:_.setDirection("LR");break;case 8:case 9:case 10:case 11:case 12:_.setC4Type(o[p-3]);break;case 19:_.setTitle(o[p].substring(6)),this.$=o[p].substring(6);break;case 20:_.setAccDescription(o[p].substring(15)),this.$=o[p].substring(15);break;case 21:this.$=o[p].trim(),_.setTitle(this.$);break;case 22:case 23:this.$=o[p].trim(),_.setAccDescription(this.$);break;case 28:o[p].splice(2,0,"ENTERPRISE"),_.addPersonOrSystemBoundary(...o[p]),this.$=o[p];break;case 29:o[p].splice(2,0,"SYSTEM"),_.addPersonOrSystemBoundary(...o[p]),this.$=o[p];break;case 30:_.addPersonOrSystemBoundary(...o[p]),this.$=o[p];break;case 31:o[p].splice(2,0,"CONTAINER"),_.addContainerBoundary(...o[p]),this.$=o[p];break;case 32:_.addDeploymentNode("node",...Line truncated
`+A.showPosition()+`
Expecting `+Yt.join(", ")+", got '"+(this.terminals_[M]||M)+"'":Gt="Parse error on line "+(xt+1)+": Unexpected "+(M==le?"end of input":"'"+(this.terminals_[M]||M)+"'"),this.parseError(Gt,{text:A.match,token:this.terminals_[M]||M,line:A.yylineno,loc:Qt,expected:Yt})}if(V[0]instanceof Array&&V.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Et+", token: "+M);switch(V[0]){case 1:E.push(M),D.push(A.yytext),o.push(A.yylloc),E.push(V[1]),M=null,oe=A.yyleng,p=A.yytext,xt=A.yylineno,Qt=A.yylloc;break;case 2:if(j=this.productions_[V[1]][1],Tt.$=D[D.length-j],Tt._$={first_line:o[o.length-(j||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(j||1)].first_column,last_column:o[o.length-1].last_column},Ne&&(Tt._$.range=[o[o.length-(j||1)].range[0],o[o.length-1].range[1]]),Kt=this.performAction.apply(Tt,[p,oe,xt,vt.yy,V[1],D,o].concat(De)),typeof Kt<"u")return Kt;j&&(E=E.slice(0,-1*j*2),D=D.slice(0,-1*j),o=o.slice(0,-1*j)),E.push(this.productions_[V[1]][0]),D.push(Tt.$),o.push(Tt._$),ue=Pt[E[E.length-2]][E[E.length-1]],E.push(ue);break;case 3:return!0}}return!0},"parse")},Oe=(function(){var yt={EOF:1,parseError:d(function(x,E){if(this.yy.parser)this.yy.parser.parseError(x,E);else throw new Error(x)},"parseError"),setInput:d(function(m,x){return this.yy=x||this.yy||{},this._input=m,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:d(function(){var m=this._input[0];this.yytext+=m,this.yyleng++,this.offset++,this.match+=m,this.matched+=m;var x=m.match(/(?:\r\n?|\n).*/g);return x?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),m},"input"),unput:d(function(m){var x=m.length,E=m.split(/(?:\r\n?|\n)/g);this._input=m+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-x),this.offset-=x;var _=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),E.length-1&&(this.yylineno-=E.length-1);var D=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:E?(E.length===_.length?this.yylloc.first_column:0)+_[_.length-E.length].length-E[0].length:this.yylloc.first_column-x},this.options.ranges&&(this.yylloc.range=[D[0],D[0]+this.yyleng-x]),this.yyleng=this.yytext.length,this},"unput"),more:d(function(){return this._more=!0,this},"more"),reject:d(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:d(function(m){this.unput(this.match.slice(m))},"less"),pastInput:d(function(){var m=this.matched.substr(0,this.matched.length-this.match.length);return(m.length>20?"...":"")+m.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:d(function(){var m=this.match;return m.length<20&&(m+=this._input.substr(0,20-m.length)),(m.substr(0,20)+(m.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:d(function(){var m=this.pastInput(),x=new Array(m.length+1).join("-");return m+this.upcomingInput()+`
`+x+"^"},"showPosition"),test_match:d(function(m,x){var E,_,D;if(this.options.backtrack_lexer&&(D={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(D.yylloc.range=this.yylloc.range.slice(0))),_=m[0].match(/(?:\r\n?|\n).*/g),_&&(this.yylineno+=_.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:_?_[_.length-1].length-_[_.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+m[0].length},this.yytext+=m[0],this.match+=m[0],this.matches=m,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(m[0].length),this.matched+=m[0],E=this.performAction.call(this,this.yy,this,x,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),E)return E;if(this._backtrack){for(var o in D)this[o]=D[o];return!1}return!1},"test_match"),next:d(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var m,x,E,_;this._more||(this.yytext="",this.match="");for(var D=this._currentRules(),o=0;o<D.length;o++)if(E=this._input.match(this.rules[D[o]]),E&&(!x||E[0].length>x[0].length)){if(x=E,_=o,this.options.backtrack_lexer){if(m=this.test_match(E,D[o]),m!==!1)return m;if(this._backtrack){x=!1;continue}else return!1}else if(!this.options.flex)break}return x?(m=this.test_match(x,D[_]),m!==!1?m:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text.
`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:d(function(){var x=this.next();return x||this.lex()},"lex"),begin:d(function(x){this.conditionStack.push(x)},"begin"),popState:d(function(){var x=this.conditionStack.length-1;return x>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:d(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:d(function(x){return x=this.conditionStack.length-1-Math.abs(x||0),x>=0?this.conditionStack[x]:"INITIAL"},"topState"),pushState:d(function(x){this.begin(x)},"pushState"),stateStackSize:d(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:d(function(x,E,_,D){switch(_){case 0:return 6;case 1:return 7;case 2:return 8;case 3:return 9;case 4:return 22;case 5:return 23;case 6:return this.begin("acc_title"),24;case 7:return this.popState(),"acc_title_value";case 8:return this.begin("acc_descr"),26;case 9:return this.popState(),"acc_descr_value";case 10:this.begin("acc_descr_multiline");break;case 11:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:break;case 14:c;break;case 15:return 12;case 16:break;case 17:return 11;case 18:return 15;case 19:return 16;case 20:return 17;case 21:return 18;case 22:return this.begin("person_ext"),45;case 23:return this.begin("person"),44;case 24:return this.begin("system_ext_queue"),51;case 25:return this.begin("system_ext_db"),50;case 26:return this.begin("system_ext"),49;case 27:return this.begin("system_queue"),48;case 28:return this.begin("system_db"),47;case 29:return this.begin("system"),46;case 30:return this.begin("boundary"),37;case 31:return this.begin("enterprise_boundary"),34;case 32:return this.begin("system_boundary"),36;case 33:return this.begin("container_ext_queue"),57;case 34:return this.begin("container_ext_db"),56;case 35:return this.begin("container_ext"),55;case 36:return this.begin("container_queue"),54;case 37:return this.begin("container_db"),53;case 38:return this.begin("container"),52;case 39:return this.begin("container_boundary"),38;case 40:return this.begin("component_ext_queue"),63;case 41:return this.begin("component_ext_db"),62;case 42:return this.begin("component_ext"),61;case 43:return this.begin("component_queue"),60;case 44:return this.begin("component_db"),59;case 45:return this.begin("component"),58;case 46:return this.begin("node"),39;case 47:return this.begin("node"),39;case 48:return this.begin("node_l"),40;case 49:return this.begin("node_r"),41;case 50:return this.begin("rel"),64;case 51:return this.begin("birel"),65;case 52:return this.begin("rel_u"),66;case 53:return this.begin("rel_u"),66;case 54:return this.begin("rel_d"),67;case 55:return this.begin("rel_d"),67;case 56:return this.begin("rel_l"),68;case 57:return this.begin("rel_l"),68;case 58:return this.begin("rel_r"),69;case 59:return this.begin("rel_r"),69;case 60:return this.begin("rel_b"),70;case 61:return this.begin("rel_index"),71;case 62:return this.begin("update_el_style"),72;case 63:return this.begin("update_rel_style"),73;case 64:return this.begin("update_layout_config"),74;case 65:return"EOF_IN_STRUCT";case 66:return this.begin("attribute"),"ATTRIBUTE_EMPTY";case 67:this.begin("attribute");break;case 68:this.popState(),this.popState();break;case 69:return 80;case 70:break;case 71:return 80;case 72:this.begin("string");break;case 73:this.popState();break;case 74:return"STR";case 75:this.begin("string_kv");break;case 76:return this.begin("string_kv_key"),"STR_KEY";case 77:this.popState(),this.begin("string_kv_value");break;case 78:return"STR_VALUE";case 79:this.popState(),this.popState();break;case 80:return"STR";case 81:return"LBRACE";case 82:return"RBRACE";case 83:return"SPACE";case 84:return"EOL";case 85:return 14}},"anonymous"),rules:[/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:title\s[^#\n;]+)/,/^(?:accDescription\s[^#\n;]+)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:C4Context\b)/,/^(?:C4Container\b)/,/^(?:C4Component\b)/,/^(?:C4Dynamic\b)/,/^(?:C4Deployment\b)/,/^(?:Person_Ext\b)/,/^(?:Person\b)/,/^(?:SystemQueue_Ext\b)/,/^(?:SystemDb_Ext\b)/,/^(?:System_Ext\b)/,/^(?:SystemQueue\b)/,/^(?:SystemDb\b)/,/^(?:System\b)/,/^(?:Boundary\b)/,/^(?:Enterprise_Boundary\b)/,/^(?:System_Boundary\b)/,/^(?:ContainerQueue_Ext\b)/,/^(?:ContainerDb_Ext\b)/,/^(?:Container_Ext\b)/,/^(?:ContainerQueue\b)/,/^(?:ContainerDb\b)/,/^(?:Container\b)/,/^(?:Container_Boundary\b)/,/^(?:ComponentQueue_Ext\b)/,/^(?:ComponentDb_Ext\b)/,/^(?:Component_Ext\b)/,/^(?:ComponentQueue\b)/,/^(?:ComponentDb\b)/,/^(?:Component\bLine truncated
`)},"elementFontStyles"),W0=d(t=>`.person {
stroke: ${t.personBorder};
fill: ${t.personBkg};
}
${z0()}
/* The element font colour is set inline per element (default white); the
label text takes it via currentColor. */
.c4-shape .label,
.c4-shape .label text {
color: inherit;
fill: currentColor;
}
/* Structurizr typography: bold name, smaller stereotype/type and description lines. */
.c4-shape .label .c4-name {
font-weight: bold;
}
.c4-shape .label .c4-type {
font-size: 0.75em;
}
.c4-shape .label .c4-descr {
font-size: 0.82em;
}
.c4-shape .basic,
.c4-shape rect,
.c4-shape path,
.c4-shape circle,
.c4-shape ellipse,
.c4-shape line {
stroke-width: 2px;
}
`,"getStyles"),X0=W0,K0={parser:ze,db:te,renderer:_e,styles:X0,init:d(({c4:t,wrap:e})=>{_e.setConf(t),te.setWrap(e)},"init")};export{K0 as diagram};
@@ -0,0 +1 @@
import{ai as o,aj as n}from"./mermaid.core.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
@@ -0,0 +1 @@
import{_ as s}from"./mermaid.core.js";var t,e=(t=class{constructor(i){this.init=i,this.records=this.init()}reset(){this.records=this.init()}},s(t,"ImperativeState"),t);export{e as I};
@@ -0,0 +1,15 @@
import{_ as e}from"./mermaid.core.js";var l=e(()=>`
/* Font Awesome icon styling - consolidated */
.label-icon {
display: inline-block;
height: 1em;
overflow: visible;
vertical-align: -0.125em;
}
.node .label-icon path {
fill: currentColor;
stroke: revert;
stroke-width: revert;
}
`,"getIconStyles");export{l as g};
@@ -0,0 +1 @@
import{_ as i,j as l,U as d,G as o}from"./mermaid.core.js";var x=i((r,t)=>{const e=r.append("rect");if(e.attr("x",t.x),e.attr("y",t.y),e.attr("fill",t.fill),e.attr("stroke",t.stroke),e.attr("width",t.width),e.attr("height",t.height),t.name&&e.attr("name",t.name),t.rx&&e.attr("rx",t.rx),t.ry&&e.attr("ry",t.ry),t.attrs!==void 0)for(const s in t.attrs)e.attr(s,t.attrs[s]);return t.class&&e.attr("class",t.class),e},"drawRect"),p=i((r,t)=>{const e={x:t.startx,y:t.starty,width:t.stopx-t.startx,height:t.stopy-t.starty,fill:t.fill,stroke:t.stroke,class:"rect"};x(r,e).lower()},"drawBackgroundRect"),y=i((r,t)=>{const e=t.text.replace(d," "),s=r.append("text");s.attr("x",t.x),s.attr("y",t.y),s.attr("class","legend"),s.style("text-anchor",t.anchor),t.class&&s.attr("class",t.class);const a=s.append("tspan");return a.attr("x",t.x+t.textMargin*2),a.text(e),s},"drawText"),m=i((r,t,e,s)=>{const a=r.append("image");a.attr("x",t),a.attr("y",e);const n=o.sanitizeUrl(s);a.attr("xlink:href",n)},"drawImage"),g=i((r,t,e,s)=>{const a=r.append("use");a.attr("x",t),a.attr("y",e);const n=o.sanitizeUrl(s);a.attr("xlink:href",`#${n}`)},"drawEmbeddedImage"),h=i(()=>({x:0,y:0,width:100,height:100,fill:"#EDF2AE",stroke:"#666",anchor:"start",rx:0,ry:0}),"getNoteRect"),f=i(()=>({x:0,y:0,width:100,height:100,"text-anchor":"start",style:"#666",textMargin:0,rx:0,ry:0,tspan:!0}),"getTextObj"),w=i(()=>{let r=l(".mermaidTooltip");return r.empty()&&(r=l("body").append("div").attr("class","mermaidTooltip").style("opacity",0).style("position","absolute").style("text-align","center").style("max-width","200px").style("padding","2px").style("font-size","12px").style("background","#ffffde").style("border","1px solid #333").style("border-radius","2px").style("pointer-events","none").style("z-index","100")),r},"createTooltip");export{p as a,h as b,g as c,x as d,m as e,w as f,f as g,y as h};
@@ -0,0 +1,231 @@
import{g as ee}from"./chunk-XXDRQBXY.js";import{s as se}from"./chunk-POPQ4Y6H.js";import{_ as p,l as b,c as $,v as ie,x as re,a as ae,b as ne,g as oe,s as le,n as ce,o as he,T as ue,k as j,p as de,j as kt,O as fe}from"./mermaid.core.js";import{f as pe}from"./chunk-F27PBJKO.js";var Ct=(function(){var t=p(function(V,o,h,a){for(h=h||{},a=V.length;a--;h[V[a]]=o);return h},"o"),e=[1,2],s=[1,3],n=[1,4],r=[2,4],c=[1,9],u=[1,11],S=[1,16],d=[1,17],T=[1,18],E=[1,19],m=[1,33],L=[1,20],D=[1,21],f=[1,22],I=[1,23],R=[1,24],C=[1,26],F=[1,27],A=[1,28],P=[1,29],w=[1,30],z=[1,31],rt=[1,32],at=[1,35],nt=[1,36],ot=[1,37],lt=[1,38],K=[1,34],y=[1,4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,41,45,48,51,52,53,54,57],ct=[1,4,5,14,15,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,39,40,41,45,48,51,52,53,54,57],Lt=[4,5,16,17,19,21,22,24,25,26,27,28,29,33,35,37,38,41,45,48,51,52,53,54,57],gt={trace:p(function(){},"trace"),yy:{},symbols_:{error:2,start:3,SPACE:4,NL:5,SD:6,document:7,line:8,statement:9,classDefStatement:10,styleStatement:11,cssClassStatement:12,idStatement:13,DESCR:14,"-->":15,HIDE_EMPTY:16,scale:17,WIDTH:18,COMPOSIT_STATE:19,STRUCT_START:20,STRUCT_STOP:21,STATE_DESCR:22,AS:23,ID:24,FORK:25,JOIN:26,CHOICE:27,CONCURRENT:28,note:29,notePosition:30,NOTE_TEXT:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,CLICK:38,STRING:39,HREF:40,classDef:41,CLASSDEF_ID:42,CLASSDEF_STYLEOPTS:43,DEFAULT:44,style:45,STYLE_IDS:46,STYLEDEF_STYLEOPTS:47,class:48,CLASSENTITY_IDS:49,STYLECLASS:50,direction_tb:51,direction_bt:52,direction_rl:53,direction_lr:54,eol:55,";":56,EDGE_STATE:57,STYLE_SEPARATOR:58,left_of:59,right_of:60,$accept:0,$end:1},terminals_:{2:"error",4:"SPACE",5:"NL",6:"SD",14:"DESCR",15:"-->",16:"HIDE_EMPTY",17:"scale",18:"WIDTH",19:"COMPOSIT_STATE",20:"STRUCT_START",21:"STRUCT_STOP",22:"STATE_DESCR",23:"AS",24:"ID",25:"FORK",26:"JOIN",27:"CHOICE",28:"CONCURRENT",29:"note",31:"NOTE_TEXT",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",38:"CLICK",39:"STRING",40:"HREF",41:"classDef",42:"CLASSDEF_ID",43:"CLASSDEF_STYLEOPTS",44:"DEFAULT",45:"style",46:"STYLE_IDS",47:"STYLEDEF_STYLEOPTS",48:"class",49:"CLASSENTITY_IDS",50:"STYLECLASS",51:"direction_tb",52:"direction_bt",53:"direction_rl",54:"direction_lr",56:";",57:"EDGE_STATE",58:"STYLE_SEPARATOR",59:"left_of",60:"right_of"},productions_:[0,[3,2],[3,2],[3,2],[7,0],[7,2],[8,2],[8,1],[8,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,3],[9,4],[9,1],[9,2],[9,1],[9,4],[9,3],[9,6],[9,1],[9,1],[9,1],[9,1],[9,4],[9,4],[9,1],[9,2],[9,2],[9,1],[9,5],[9,5],[10,3],[10,3],[11,3],[12,3],[32,1],[32,1],[32,1],[32,1],[55,1],[55,1],[13,1],[13,1],[13,3],[13,3],[30,1],[30,1]],performAction:p(function(o,h,a,g,_,i,B){var l=i.length-1;switch(_){case 3:return g.setRootDoc(i[l]),i[l];case 4:this.$=[];break;case 5:i[l]!="nl"&&(i[l-1].push(i[l]),this.$=i[l-1]);break;case 6:case 7:this.$=i[l];break;case 8:this.$="nl";break;case 12:this.$=i[l];break;case 13:const Z=i[l-1];Z.description=g.trimColon(i[l]),this.$=Z;break;case 14:this.$={stmt:"relation",state1:i[l-2],state2:i[l]};break;case 15:const Tt=g.trimColon(i[l]);this.$={stmt:"relation",state1:i[l-3],state2:i[l-1],description:Tt};break;case 19:this.$={stmt:"state",id:i[l-3],type:"default",description:"",doc:i[l-1]};break;case 20:var Y=i[l],X=i[l-2].trim();if(i[l].match(":")){var ut=i[l].split(":");Y=ut[0],X=[X,ut[1]]}this.$={stmt:"state",id:Y,type:"default",description:X};break;case 21:this.$={stmt:"state",id:i[l-3],type:"default",description:i[l-5],doc:i[l-1]};break;case 22:this.$={stmt:"state",id:i[l],type:"fork"};break;case 23:this.$={stmt:"state",id:i[l],type:"join"};break;case 24:this.$={stmt:"state",id:i[l],type:"choice"};break;case 25:this.$={stmt:"state",id:g.getDividerId(),type:"divider"};break;case 26:this.$={stmt:"state",id:i[l-1].trim(),note:{position:i[l-2].trim(),text:i[l].trim()}};break;case 29:this.$=i[l].trim(),g.setAccTitle(this.$);break;case 30:case 31:this.$=i[l].trim(),g.setAccDescription(this.$);break;case 32:this.$={stmt:"click",id:i[l-3],url:i[l-2],tooltip:i[l-1]};break;case 33:this.$={stmt:"click",id:i[l-3],url:i[l-1],tooltip:""};break;case 34:case 35:this.$={stmt:"classDef",id:i[l-1].trim(),classes:i[l].trim()};break;case 36:this.$={stmt:"style",id:i[l-1].trim(),styleClass:i[l].trim()};break;case 37:this.$={stmt:"applyClass",id:i[l-1].trim(),styleClass:i[l].trim()};break;case 38:g.setDirection("TB"),this.$={stmt:"dir",value:"TB"};break;case 39:g.setDirection("BT"),this.$={stmt:"dir",value:"BT"};break;case 40:g.setDirection("RL"),this.$={stmt:"dir",value:"RL"};break;case 41:g.setDirection("LR"),this.$={stmt:"dir",value:"LR"};break;case 44:case 45:this.$={stmt:"state",id:i[l].trim(),type:"default",description:""};break;case 46:this.$={stmt:"state",id:i[l-2].trim(),classes:[i[l].trim()],type:"default",description:""};break;case 47:this.$={stmt:"state",id:i[l-2].trim(),classes:[i[l].trim()],type:"default",description:""};break}Line truncated
`+k.showPosition()+`
Expecting `+ft.join(", ")+", got '"+(this.terminals_[x]||x)+"'":bt="Parse error on line "+(Y+1)+": Unexpected "+(x==Z?"end of input":"'"+(this.terminals_[x]||x)+"'"),this.parseError(bt,{text:k.match,token:this.terminals_[x]||x,line:k.yylineno,loc:_t,expected:ft})}if(N[0]instanceof Array&&N.length>1)throw new Error("Parse Error: multiple actions possible at state: "+W+", token: "+x);switch(N[0]){case 1:a.push(x),_.push(k.yytext),i.push(k.yylloc),a.push(N[1]),x=null,X=k.yyleng,l=k.yytext,Y=k.yylineno,_t=k.yylloc;break;case 2:if(G=this.productions_[N[1]][1],J.$=_[_.length-G],J._$={first_line:i[i.length-(G||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(G||1)].first_column,last_column:i[i.length-1].last_column},Zt&&(J._$.range=[i[i.length-(G||1)].range[0],i[i.length-1].range[1]]),mt=this.performAction.apply(J,[l,X,Y,U.yy,N[1],_,i].concat(Tt)),typeof mt<"u")return mt;G&&(a=a.slice(0,-1*G*2),_=_.slice(0,-1*G),i=i.slice(0,-1*G)),a.push(this.productions_[N[1]][0]),_.push(J.$),i.push(J._$),wt=B[a[a.length-2]][a[a.length-1]],a.push(wt);break;case 3:return!0}}return!0},"parse")},Qt=(function(){var V={EOF:1,parseError:p(function(h,a){if(this.yy.parser)this.yy.parser.parseError(h,a);else throw new Error(h)},"parseError"),setInput:p(function(o,h){return this.yy=h||this.yy||{},this._input=o,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:p(function(){var o=this._input[0];this.yytext+=o,this.yyleng++,this.offset++,this.match+=o,this.matched+=o;var h=o.match(/(?:\r\n?|\n).*/g);return h?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),o},"input"),unput:p(function(o){var h=o.length,a=o.split(/(?:\r\n?|\n)/g);this._input=o+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-h),this.offset-=h;var g=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),a.length-1&&(this.yylineno-=a.length-1);var _=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:a?(a.length===g.length?this.yylloc.first_column:0)+g[g.length-a.length].length-a[0].length:this.yylloc.first_column-h},this.options.ranges&&(this.yylloc.range=[_[0],_[0]+this.yyleng-h]),this.yyleng=this.yytext.length,this},"unput"),more:p(function(){return this._more=!0,this},"more"),reject:p(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:p(function(o){this.unput(this.match.slice(o))},"less"),pastInput:p(function(){var o=this.matched.substr(0,this.matched.length-this.match.length);return(o.length>20?"...":"")+o.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:p(function(){var o=this.match;return o.length<20&&(o+=this._input.substr(0,20-o.length)),(o.substr(0,20)+(o.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:p(function(){var o=this.pastInput(),h=new Array(o.length+1).join("-");return o+this.upcomingInput()+`
`+h+"^"},"showPosition"),test_match:p(function(o,h){var a,g,_;if(this.options.backtrack_lexer&&(_={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(_.yylloc.range=this.yylloc.range.slice(0))),g=o[0].match(/(?:\r\n?|\n).*/g),g&&(this.yylineno+=g.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:g?g[g.length-1].length-g[g.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+o[0].length},this.yytext+=o[0],this.match+=o[0],this.matches=o,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(o[0].length),this.matched+=o[0],a=this.performAction.call(this,this.yy,this,h,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),a)return a;if(this._backtrack){for(var i in _)this[i]=_[i];return!1}return!1},"test_match"),next:p(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var o,h,a,g;this._more||(this.yytext="",this.match="");for(var _=this._currentRules(),i=0;i<_.length;i++)if(a=this._input.match(this.rules[_[i]]),a&&(!h||a[0].length>h[0].length)){if(h=a,g=i,this.options.backtrack_lexer){if(o=this.test_match(a,_[i]),o!==!1)return o;if(this._backtrack){h=!1;continue}else return!1}else if(!this.options.flex)break}return h?(o=this.test_match(h,_[g]),o!==!1?o:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text.
`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:p(function(){var h=this.next();return h||this.lex()},"lex"),begin:p(function(h){this.conditionStack.push(h)},"begin"),popState:p(function(){var h=this.conditionStack.length-1;return h>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:p(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:p(function(h){return h=this.conditionStack.length-1-Math.abs(h||0),h>=0?this.conditionStack[h]:"INITIAL"},"topState"),pushState:p(function(h){this.begin(h)},"pushState"),stateStackSize:p(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:p(function(h,a,g,_){function i(){const B=a.yytext.indexOf("%%");if(B===0)return!1;if(B>0){const l=a.yytext.slice(0,B),Y=a.yytext.slice(B);Y&&h.lexer.unput(Y),a.yytext=l}return!0}switch(p(i,"processId"),g){case 0:return 38;case 1:return 40;case 2:return 39;case 3:return 44;case 4:return 51;case 5:return 52;case 6:return 53;case 7:return 54;case 8:return 5;case 9:break;case 10:break;case 11:break;case 12:break;case 13:return this.pushState("SCALE"),17;case 14:return 18;case 15:this.popState();break;case 16:return this.begin("acc_title"),33;case 17:return this.popState(),"acc_title_value";case 18:return this.begin("acc_descr"),35;case 19:return this.popState(),"acc_descr_value";case 20:this.begin("acc_descr_multiline");break;case 21:this.popState();break;case 22:return"acc_descr_multiline_value";case 23:return this.pushState("CLASSDEF"),41;case 24:return this.popState(),this.pushState("CLASSDEFID"),"DEFAULT_CLASSDEF_ID";case 25:return this.popState(),this.pushState("CLASSDEFID"),42;case 26:return this.popState(),43;case 27:return this.pushState("CLASS"),48;case 28:return this.popState(),this.pushState("CLASS_STYLE"),49;case 29:return this.popState(),50;case 30:return this.pushState("STYLE"),45;case 31:return this.popState(),this.pushState("STYLEDEF_STYLES"),46;case 32:return this.popState(),47;case 33:return this.pushState("SCALE"),17;case 34:return 18;case 35:this.popState();break;case 36:this.pushState("STATE");break;case 37:return this.popState(),a.yytext=a.yytext.slice(0,-8).trim(),25;case 38:return this.popState(),a.yytext=a.yytext.slice(0,-8).trim(),26;case 39:return this.popState(),a.yytext=a.yytext.slice(0,-10).trim(),27;case 40:return this.popState(),a.yytext=a.yytext.slice(0,-8).trim(),25;case 41:return this.popState(),a.yytext=a.yytext.slice(0,-8).trim(),26;case 42:return this.popState(),a.yytext=a.yytext.slice(0,-10).trim(),27;case 43:return 51;case 44:return 52;case 45:return 53;case 46:return 54;case 47:this.pushState("STATE_STRING");break;case 48:return this.pushState("STATE_ID"),"AS";case 49:return i()?(this.popState(),"ID"):void 0;case 50:this.popState();break;case 51:return"STATE_DESCR";case 52:throw new Error('Error: State name must be a single word. Found: "'+a.yytext.trim()+'"');case 53:return 19;case 54:this.popState();break;case 55:return this.popState(),this.pushState("struct"),20;case 56:return this.popState(),21;case 57:break;case 58:return this.begin("NOTE"),29;case 59:return this.popState(),this.pushState("NOTE_ID"),59;case 60:return this.popState(),this.pushState("NOTE_ID"),60;case 61:this.popState(),this.pushState("FLOATING_NOTE");break;case 62:return this.popState(),this.pushState("FLOATING_NOTE_ID"),"AS";case 63:break;case 64:return"NOTE_TEXT";case 65:return i()?(this.popState(),"ID"):void 0;case 66:return i()?(this.popState(),this.pushState("NOTE_TEXT"),24):void 0;case 67:return this.popState(),a.yytext=a.yytext.substr(2).trim(),31;case 68:return this.popState(),a.yytext=a.yytext.slice(0,-8).trim(),31;case 69:return 6;case 70:return 6;case 71:return 16;case 72:return 57;case 73:return i()?24:void 0;case 74:return a.yytext=a.yytext.trim(),14;case 75:return 15;case 76:return 28;case 77:return 58;case 78:return 5;case 79:return"INVALID"}},"anonymous"),rules:[/^(?:click\b)/i,/^(?:href\b)/i,/^(?:"[^"]*")/i,/^(?:default\b)/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*direction\s+BT[^\n]*)/i,/^(?:.*direction\s+RL[^\n]*)/i,/^(?:.*direction\s+LR[^\n]*)/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:((?!\n)\s)+)/i,/^(?:#[^\n]*)/i,/^(?:%%(?!\{)[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:classDef\s+)/i,/^(?:DEFAULT\s+)/i,/^(?:\w+\s+)/i,/^(?:[^\n]*)/i,/^(?:class\s+)/i,/^(?:(\w+)+((,\s*\w+)*))/i,/^(?:[^\n]*)/i,/^(?:style\s+)/i,/^(?:[\w,]+\s+)/i,/^(?:[^\n]*)/i,/^(?:scale\s+)/i,/^(?:\d+)/i,/^(?:\s+width\b)/i,/^(?:state\s+)/i,/^(?:.*<<fork>>)/i,/^(?:.*<<join>>)/i,/^(?:.*<<choice>>)/i,/^(?:.*\[\[fork\]\])/i,/^(?:.*\[\[join\]\])/i,/^(?:.*\[\[choice\]\])/i,/^(?:.*direction\s+TB[^\n]*)/i,/^(?:.*directio Line truncated
defs [id$="-barbEnd"] {
fill: ${t.transitionColor};
stroke: ${t.transitionColor};
}
g.stateGroup text {
fill: ${t.nodeBorder};
stroke: none;
font-size: 10px;
}
g.stateGroup text {
fill: ${t.textColor};
stroke: none;
font-size: 10px;
}
g.stateGroup .state-title {
font-weight: bolder;
fill: ${t.stateLabelColor};
}
g.stateGroup rect {
fill: ${t.mainBkg};
stroke: ${t.nodeBorder};
}
g.stateGroup line {
stroke: ${t.lineColor};
stroke-width: ${t.strokeWidth||1};
}
.transition {
stroke: ${t.transitionColor};
stroke-width: ${t.strokeWidth||1};
fill: none;
}
.stateGroup .composit {
fill: ${t.background};
border-bottom: 1px
}
.stateGroup .alt-composit {
fill: #e0e0e0;
border-bottom: 1px
}
.state-note {
stroke: ${t.noteBorderColor};
fill: ${t.noteBkgColor};
text {
fill: ${t.noteTextColor};
stroke: none;
font-size: 10px;
}
}
.stateLabel .box {
stroke: none;
stroke-width: 0;
fill: ${t.mainBkg};
opacity: 0.5;
}
.edgeLabel .label rect {
fill: ${t.labelBackgroundColor};
opacity: 0.5;
}
.edgeLabel {
background-color: ${t.edgeLabelBackground};
p {
background-color: ${t.edgeLabelBackground};
}
rect {
opacity: 0.5;
background-color: ${t.edgeLabelBackground};
fill: ${t.edgeLabelBackground};
}
text-align: center;
}
.edgeLabel .label text {
fill: ${t.transitionLabelColor||t.tertiaryTextColor};
}
.label div .edgeLabel {
color: ${t.transitionLabelColor||t.tertiaryTextColor};
}
.stateLabel text {
fill: ${t.stateLabelColor};
font-size: 10px;
font-weight: bold;
}
.node circle.state-start {
fill: ${t.specialStateColor};
stroke: ${t.specialStateColor};
}
.node .fork-join {
fill: ${t.specialStateColor};
stroke: ${t.specialStateColor};
}
.node circle.state-end {
fill: ${t.innerEndBackground};
stroke: ${t.background};
stroke-width: 1.5
}
.end-state-inner {
fill: ${t.compositeBackground||t.background};
// stroke: ${t.background};
stroke-width: 1.5
}
.node rect {
fill: ${t.stateBkg||t.mainBkg};
stroke: ${t.stateBorder||t.nodeBorder};
stroke-width: ${t.strokeWidth||1}px;
}
.node polygon {
fill: ${t.mainBkg};
stroke: ${t.stateBorder||t.nodeBorder};;
stroke-width: ${t.strokeWidth||1}px;
}
[id$="-barbEnd"] {
fill: ${t.lineColor};
}
.statediagram-cluster rect {
fill: ${t.compositeTitleBackground};
stroke: ${t.stateBorder||t.nodeBorder};
stroke-width: ${t.strokeWidth||1}px;
}
.cluster-label, .nodeLabel {
color: ${t.stateLabelColor};
// line-height: 1;
}
.statediagram-cluster rect.outer {
rx: 5px;
ry: 5px;
}
.statediagram-state .divider {
stroke: ${t.stateBorder||t.nodeBorder};
}
.statediagram-state .title-state {
rx: 5px;
ry: 5px;
}
.statediagram-cluster.statediagram-cluster .inner {
fill: ${t.compositeBackground||t.background};
}
.statediagram-cluster.statediagram-cluster-alt .inner {
fill: ${t.altBackground?t.altBackground:"#efefef"};
}
.statediagram-cluster .inner {
rx:0;
ry:0;
}
.statediagram-state rect.basic {
rx: 5px;
ry: 5px;
}
.statediagram-state rect.divider {
stroke-dasharray: 10,10;
fill: ${t.altBackground?t.altBackground:"#efefef"};
}
.note-edge {
stroke-dasharray: 5;
}
.statediagram-note rect {
fill: ${t.noteBkgColor};
stroke: ${t.noteBorderColor};
stroke-width: 1px;
rx: 0;
ry: 0;
}
.statediagram-note rect {
fill: ${t.noteBkgColor};
stroke: ${t.noteBorderColor};
stroke-width: 1px;
rx: 0;
ry: 0;
}
.statediagram-note text {
fill: ${t.noteTextColor};
}
.statediagram-note .nodeLabel {
color: ${t.noteTextColor};
}
.statediagram .edgeLabel {
color: red; // ${t.noteTextColor};
}
[id$="-dependencyStart"], [id$="-dependencyEnd"] {
fill: ${t.lineColor};
stroke: ${t.lineColor};
stroke-width: ${t.strokeWidth||1};
}
.statediagramTitleText {
text-anchor: middle;
font-size: 18px;
fill: ${t.textColor};
}
[data-look="neo"].statediagram-cluster rect {
fill: ${t.mainBkg};
stroke: ${t.useGradient?"url("+t.svgId+"-gradient)":t.stateBorder||t.nodeBorder};
stroke-width: ${t.strokeWidth??1};
}
[data-look="neo"].statediagram-cluster rect.outer {
rx: ${t.radius}px;
ry: ${t.radius}px;
filter: ${t.dropShadow?t.dropShadow.replace("url(#drop-shadow)",`url(${t.svgId}-drop-shadow)`):"none"}
}
`,"getStyles"),ze=Ye;export{He as S,We as a,je as b,ze as s};
@@ -0,0 +1 @@
import{_ as i}from"./mermaid.core.js";function t(c,e){c.accDescr&&e.setAccDescription?.(c.accDescr),c.accTitle&&e.setAccTitle?.(c.accTitle),c.title&&e.setDiagramTitle?.(c.title)}i(t,"populateCommonDb");export{t as p};
@@ -0,0 +1 @@
import{_ as a,d as w,l as x}from"./mermaid.core.js";var B=a((e,t,i,r)=>{e.attr("class",i);const{width:o,height:h,x:n,y:c}=u(e,t);w(e,h,o,r);const s=d(n,c,o,h,t);e.attr("viewBox",s),x.debug(`viewBox configured: ${s} with padding: ${t}`)},"setupViewPortForSVG"),u=a((e,t)=>{const i=e.node()?.getBBox()||{width:0,height:0,x:0,y:0};return{width:i.width+t*2,height:i.height+t*2,x:i.x,y:i.y}},"calculateDimensionsWithPadding"),d=a((e,t,i,r,o)=>`${e-o} ${t-o} ${i} ${r}`,"createViewBox");export{B as s};
@@ -0,0 +1,88 @@
import{_ as p,l as C,D as H,y as B,p as q,E as G,d as U,i as j,c as K}from"./mermaid.core.js";var A="",M="",O="",D=[],b=new Map,v=p(e=>j(e,K()),"sanitizeText"),y=p(e=>{switch(e.type){case"terminal":return{...e,value:v(e.value)};case"nonterminal":return{...e,name:v(e.name)};case"sequence":return{...e,elements:e.elements.map(y)};case"choice":return{...e,alternatives:e.alternatives.map(y)};case"optional":return{...e,element:y(e.element)};case"repetition":return{...e,element:y(e.element),separator:e.separator?y(e.separator):void 0};case"special":return{...e,text:v(e.text)}}},"sanitizeAstNode"),J=p(()=>{A="",M="",O="",D.length=0,b.clear(),q(),C.debug("[Railroad] Database cleared")},"clear"),Y=p(e=>{A=v(e),C.debug("[Railroad] Title set:",e)},"setTitle"),P=p(()=>A,"getTitle"),Q=p(e=>{const i={...e,name:v(e.name),definition:y(e.definition),comment:e.comment?v(e.comment):void 0};C.debug("[Railroad] Adding rule:",i.name),b.has(i.name)&&C.warn(`[Railroad] Rule '${i.name}' is already defined. Overwriting.`),D.push(i),b.set(i.name,i)},"addRule"),Z=p(()=>D,"getRules"),V=p(e=>b.get(e),"getRule"),ee=p(e=>{M=v(e).replace(/^\s+/g,""),C.debug("[Railroad] Accessibility title set:",e)},"setAccTitle"),te=p(()=>M,"getAccTitle"),re=p(e=>{O=v(e).replace(/\n\s+/g,`
`),C.debug("[Railroad] Accessibility description set:",e)},"setAccDescription"),ie=p(()=>O,"getAccDescription"),ne=Y,ae=P,oe={clear:J,setTitle:Y,getTitle:P,addRule:Q,getRules:Z,getRule:V,setAccTitle:ee,getAccTitle:te,setAccDescription:re,getAccDescription:ie,setDiagramTitle:ne,getDiagramTitle:ae},f={compactMode:!1,padding:10,verticalSeparation:8,horizontalSeparation:10,arcRadius:10,fontSize:14,fontFamily:"monospace",terminalFill:"#FFFFC0",terminalStroke:"#000000",terminalTextColor:"#000000",nonTerminalFill:"#FFFFFF",nonTerminalStroke:"#000000",nonTerminalTextColor:"#000000",lineColor:"#000000",strokeWidth:2,markerFill:"#000000",commentFill:"#E8E8E8",commentStroke:"#888888",commentTextColor:"#666666",specialFill:"#F0E0FF",specialStroke:"#8800CC",ruleNameColor:"#000066",showMarkers:!0,markerRadius:5},le=/^#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$|^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch)\([\d\s%+,./-]+\)$|^[a-z]+$/i,se=/^[\w "',.-]+$/,de=new Set(["compactMode","padding","verticalSeparation","horizontalSeparation","arcRadius","fontSize","fontFamily","terminalFill","terminalStroke","terminalTextColor","nonTerminalFill","nonTerminalStroke","nonTerminalTextColor","lineColor","strokeWidth","markerFill","commentFill","commentStroke","commentTextColor","specialFill","specialStroke","ruleNameColor","showMarkers","markerRadius"]),L=p(e=>e?Object.keys(e).every(i=>i==="railroad"||de.has(i)):!1,"isRailroadStyleOptions"),ce=p(e=>e?"railroad"in e&&e.railroad?e.railroad:L(e)?e:{}:{},"extractRailroadOverrides"),me=p(e=>{if(!e||L(e))return{};const{railroad:i,svgId:a,theme:n,look:t,...r}=e;return r},"extractThemeOverrides"),m=p((e,i)=>{if(typeof e!="string")return i;const a=e.trim();return le.test(a)?a:i},"sanitizeColorValue"),I=p((e,i)=>{if(typeof e!="string")return i;const a=e.trim();return se.test(a)?a:i},"sanitizeFontFamilyValue"),F=p((e,i)=>{const a=typeof e=="number"?e:typeof e=="string"?Number.parseFloat(e):Number.NaN;return Number.isFinite(a)&&a>=0?a:i},"sanitizeNumberValue"),he=p(e=>{const i=typeof e=="number"?e:typeof e=="string"?Number.parseFloat(e):Number.NaN;return Number.isFinite(i)&&i>0?i:void 0},"parseThemeFontSize"),pe=p(e=>{const i=I(e.fontFamily,f.fontFamily),a=he(e.fontSize)??f.fontSize;return{...f,fontFamily:i,fontSize:a,terminalFill:m(e.secondBkg??e.secondaryColor,f.terminalFill),terminalStroke:m(e.secondaryBorderColor??e.lineColor,f.terminalStroke),terminalTextColor:m(e.secondaryTextColor??e.textColor,f.terminalTextColor),nonTerminalFill:m(e.mainBkg??e.background,f.nonTerminalFill),nonTerminalStroke:m(e.primaryBorderColor??e.lineColor,f.nonTerminalStroke),nonTerminalTextColor:m(e.primaryTextColor??e.textColor,f.nonTerminalTextColor),lineColor:m(e.lineColor,f.lineColor),markerFill:m(e.lineColor,f.markerFill),commentFill:m(e.labelBackground??e.tertiaryColor,f.commentFill),commentStroke:m(e.tertiaryBorderColor??e.lineColor,f.commentStroke),commentTextColor:m(e.tertiaryTextColor??e.textColor,f.commentTextColor),specialFill:m(e.tertiaryColor??e.secondaryColor,f.specialFill),specialStroke:m(e.tertiaryBorderColor??e.secondaryBorderColor,f.specialStroke),ruleNameColor:m(e.titleColor??e.textColor,f.ruleNameColor)}},"buildThemeDefaults"),E=p(e=>{const i=B(),a={...G(),...i.themeVariables??{},...me(e)},n=pe(a),t={...i.railroad??{},...ce(e)};return{compactMode:t.compactMode??n.compactMode,padding:F(t.padding,n.padding),verticalSeparation:F(t.verticalSeparation,n.verticalSeparation),horizontalSeparation:F(t.horizontalSeparation,n.horizontalSeparation),arcRadius:F(t.arcRadius,n.arcRadius),fontSize:F(t.fontSize,n.fontSize),fontFamily:I(t.fontFamily,n.fontFamily),terminalFill:m(t.terminalFill,n.terminalFill),terminalStroke:m(t.terminalStroke,n.terminalStroke),terminalTextColor:m(t.terminalTextColor,n.terminalTextColor),nonTerminalFill:m(t.nonTerminalFill,n.nonTerminalFill),nonTerminalStroke:m(t.nonTerminalStroke,n.nonTerminalStroke),nonTerminalTextColor:m(t.nonTerminalTextColor,n.nonTerminalTextColor),lineColor:m(t.lineColor,n.lineColor),strokeWidth:F(t.strokeWidth,n.strokeWidth),markerFill:m(t.markerFill,n.markerFill),commentFill:m(t.commentFill,n.commentFill),commentStroke:m(t.commentStroke,n.commentStroke),commentTextColor:m(t.commentTextColor,n.commentTextColor),specialFill:m(t.specialFill,n.specialFill),specialStroke:m(t.specialStroke,n.specialStroke),ruleNameColor:m(t.ruleNameColor,n.ruleNameColor),showMarkers:t.showMarkers??n.showMarkers,markerRadius:F(t.markerRadius,n.markerRadius)}},"buildRailroadStyleOptions"),Te=p(e=>{const{fontFamily:i,fontSize:a,terminalFill:n,terminalStroke:t,terminalTextColor:r,nonTerminalFill:o,nonTerminalStroke:g,nonTerminalTextColor:l,lineColor:s,strokeWidth:h,markerFill:u,commentFill:c,commentStroke:w,commentTextColor:d,specialFill:T,specialStroke:z,ruleNameColor:S}=E(e);return`
.railroad-diagram {
font-family: ${i};
font-size: ${a}px;
}
.railroad-terminal rect {
fill: ${n};
stroke: ${t};
stroke-width: ${h}px;
}
.railroad-terminal text {
fill: ${r};
font-family: ${i};
font-size: ${a}px;
text-anchor: middle;
dominant-baseline: middle;
}
.railroad-nonterminal rect {
fill: ${o};
stroke: ${g};
stroke-width: ${h}px;
}
.railroad-nonterminal text {
fill: ${l};
font-family: ${i};
font-size: ${a}px;
text-anchor: middle;
dominant-baseline: middle;
}
.railroad-line {
stroke: ${s};
stroke-width: ${h}px;
fill: none;
}
.railroad-start circle,
.railroad-end circle {
fill: ${u};
}
.railroad-comment ellipse {
fill: ${c};
stroke: ${w};
stroke-width: ${h}px;
}
.railroad-comment text {
fill: ${d};
font-style: italic;
font-family: ${i};
font-size: ${a}px;
text-anchor: middle;
dominant-baseline: middle;
}
.railroad-special rect {
fill: ${T};
stroke: ${z};
stroke-width: ${h}px;
stroke-dasharray: 5,3;
}
.railroad-special text {
fill: ${l};
font-family: ${i};
font-size: ${a}px;
text-anchor: middle;
dominant-baseline: middle;
}
.railroad-rule-name {
font-weight: bold;
fill: ${S};
font-family: ${i};
font-size: ${a}px;
}
.railroad-group {
/* Grouping container, no specific styles */
}
`},"getStyles"),R,x=(R=class{constructor(){this.d=""}moveTo(i,a){return this.d+=`M ${i} ${a} `,this}lineTo(i,a){return this.d+=`L ${i} ${a} `,this}horizontalTo(i){return this.d+=`H ${i} `,this}verticalTo(i){return this.d+=`V ${i} `,this}arcTo(i,a,n,t,r,o,g){return this.d+=`A ${i} ${a} ${n} ${t?1:0} ${r?1:0} ${o} ${g} `,this}build(){return this.d.trim()}},p(R,"PathBuilder"),R),$,ue=($=class{constructor(i,a=E()){this.textCache=new Map,this.svg=i,this.config=a}measureText(i){if(this.textCache.has(i))return this.textCache.get(i);const a=this.svg.append("text").attr("font-family",this.config.fontFamily).attr("font-size",this.config.fontSize).text(i),n=a.node().getBBox(),t={width:n.width,height:n.height};return a.remove(),this.textCache.set(i,t),t}renderTerminal(i,a){const n=this.measureText(a),t=n.width+this.config.padding*2,r=n.height+this.config.padding*2,o=i.append("g").attr("class","railroad-terminal");return o.append("rect").attr("x",0).attr("y",0).attr("width",t).attr("height",r).attr("rx",10).attr("ry",10),o.append("text").attr("x",t/2).attr("y",r/2).text(a),{element:o.node(),dimensions:{width:t,height:r,up:r/2,down:r/2}}}renderNonTerminal(i,a){const n=this.measureText(a),t=n.width+this.config.padding*2,r=n.height+this.config.padding*2,o=i.append("g").attr("class","railroad-nonterminal");return o.append("rect").attr("x",0).attr("y",0).attr("width",t).attr("height",r),o.append("text").attr("x",t/2).attr("y",r/2).text(a),{element:o.node(),dimensions:{width:t,height:r,up:r/2,down:r/2}}}renderSequence(i,a){const n=a.map(s=>this.renderExpression(i,s));let t=0,r=0,o=0;for(const s of n)t+=s.dimensions.width,r=Math.max(r,s.dimensions.up),o=Math.max(o,s.dimensions.down);t+=(n.length-1)*this.config.horizontalSeparation;const g=i.append("g").attr("class","railroad-sequence");let l=0;for(let s=0;s<n.length;s++){const h=n[s],u=r-h.dimensions.up;if(g.node().appendChild(h.element).setAttribute("transform",`translate(${l}, ${u})`),s<n.length-1){const w=l+h.dimensions.width,d=w+this.config.horizontalSeparation,T=r;g.append("path").attr("class","railroad-line").attr("d",new x().moveTo(w,T).lineTo(d,T).build())}l+=h.dimensions.width+this.config.horizontalSeparation}return{element:g.node(),dimensions:{width:t,height:r+o,up:r,down:o}}}renderChoice(i,a){const n=a.map(c=>this.renderExpression(i,c));let t=0,r=0;for(const c of n)t=Math.max(t,c.dimensions.width),r+=c.dimensions.height;r+=(n.length-1)*this.config.verticalSeparation;const o=this.config.arcRadius,g=o*4,l=t+g,s=i.append("g").attr("class","railroad-choice");let h=0;const u=r/2;for(const c of n){const w=h,d=w+c.dimensions.up,T=o*2+(t-c.dimensions.width)/2;s.node().appendChild(c.element).setAttribute("transform",`translate(${T}, ${w})`);const S=new x,k=d>u;d===u?S.moveTo(0,u).lineTo(T,d):S.moveTo(0,u).arcTo(o,o,0,!1,k,o,u+(k?o:-o)).lineTo(o,d-(k?o:-o)).arcTo(o,o,0,!1,!k,o*2,d).lineTo(T,d),s.append("path").attr("class","railroad-line").attr("d",S.build());const N=new x,_=T+c.dimensions.width,X=l-o*2;d===u?N.moveTo(_,d).lineTo(l,u):N.moveTo(_,d).lineTo(X,d).arcTo(o,o,0,!1,!k,l-o,d+(k?-o:o)).lineTo(l-o,u+(k?o:-o)).arcTo(o,o,0,!1,k,l,u),s.append("path").attr("class","railroad-line").attr("d",N.build()),h+=c.dimensions.height+this.config.verticalSeparation}return{element:s.node(),dimensions:{width:l,height:r,up:u,down:r-u}}}renderOptional(i,a){const n=this.renderExpression(i,a),t=this.config.arcRadius,r=t*2,o=n.dimensions.width+t*4,g=n.dimensions.height+r,l=i.append("g").attr("class","railroad-optional"),s=t*2,h=r;l.node().appendChild(n.element).setAttribute("transform",`translate(${s}, ${h})`);const c=h+n.dimensions.up,w=new x().moveTo(0,c).lineTo(t*2,c);l.append("path").attr("class","railroad-line").attr("d",w.build());const d=new x().moveTo(s+n.dimensions.width,c).lineTo(o,c);l.append("path").attr("class","railroad-line").attr("d",d.build());const T=new x().moveTo(0,c).arcTo(t,t,0,!1,!1,t,c-t).lineTo(t,t).arcTo(t,t,0,!1,!0,t*2,0).lineTo(o-t*2,0).arcTo(t,t,0,!1,!0,o-t,t).lineTo(o-t,c-t).arcTo(t,t,0,!1,!1,o,c);return l.append("path").attr("class","railroad-line").attr("d",T.build()),{element:l.node(),dimensions:{width:o,height:g,up:c,down:g-c}}}renderRepetition(i,a,n){const t=this.renderExpression(i,a),r=this.config.arcRadius,o=r*2,g=t.dimensions.width+r*4,l=n===0,s=t.dimensions.height+o+(l?o:0),h=i.append("g").attr("class","railroad-repetition"),u=r*2,c=l?o:0;h.node().appendChild(t.element).setAttribute("transform",`translate(${u}, ${c})`);const d=c+t.dimensions.up;h.append("path").attr("class","railroad-line").attr("d",new x().moveTo(0,d).lineTo(r*2,d).build()),h.append("path").attr("class","railroad-line").attr("d",new x().moveTo(u+t.dimensions.width,d).lineTo(g,d).build());const T=c+t.dimensions.height+r,z=new x().moveTo(u+t.dimensions.width,d).arcTo(r,r,0,!1,!0,u+t.dimensions.width+r,d+r).lineTo(u+t.dimensions.width+r,T).arcTo(r,r,0,!1,!0,u+t.dimensions.width,T+r).lineTo(r*2,T+r).arcTo(r,r,0,!1,!0,r,T).lineTo(r,d+r).arcTo(r,r,0,!1,!0,r*2,d);if(h.append("path").attr("cl Line truncated
`+e);try{const n=H(i);n.attr("class","railroad-diagram");const r=B().railroad?.useMaxWidth??!0,o=oe.getRules();if(C.debug(`[Railroad] Rendering ${o.length} rules`),o.length===0){C.warn("[Railroad] No rules to render"),W(n,{height:100,width:200},r);return}const l=new ue(n,E()).renderDiagram(o);W(n,l,r),C.debug("[Railroad] Render complete")}catch(n){throw C.error("[Railroad] Render error:",n),n}},"draw"),xe={draw:ge};export{oe as d,Te as g,xe as r};
@@ -0,0 +1,206 @@
import{g as st}from"./chunk-5VM5RSS4.js";import{g as it}from"./chunk-XXDRQBXY.js";import{s as at}from"./chunk-POPQ4Y6H.js";import{_ as f,l as we,c as F,u as nt,v as rt,x as Ve,j as Ae,O as ut,b as lt,a as ct,s as ot,g as ht,n as dt,o as pt,k as I,p as At,q as ft,i as gt,P as U}from"./mermaid.core.js";import{f as mt}from"./chunk-F27PBJKO.js";var Pe=(function(){var s=f(function(O,o,h,p){for(h=h||{},p=O.length;p--;h[O[p]]=o);return h},"o"),i=[1,18],a=[1,19],n=[1,20],r=[1,41],c=[1,26],u=[1,42],d=[1,24],m=[1,25],g=[1,32],N=[1,33],ge=[1,34],b=[1,45],me=[1,35],Ce=[1,36],be=[1,37],ke=[1,38],Ee=[1,27],Te=[1,28],ye=[1,29],De=[1,30],Fe=[1,31],k=[1,44],E=[1,46],T=[1,43],y=[1,47],Be=[1,9],A=[1,8,9],ee=[1,58],te=[1,59],se=[1,60],ie=[1,61],ae=[1,62],_e=[1,63],Se=[1,64],_=[1,8,9,41],Me=[1,77],R=[1,8,9,12,13,22,39,41,44,46,68,69,70,71,72,73,74,79,81],ne=[1,8,9,12,13,18,20,22,39,41,44,46,47,60,68,69,70,71,72,73,74,79,81,86,100,102,103],re=[13,60,86,100,102,103],Y=[13,60,73,74,86,100,102,103],Re=[13,60,68,69,70,71,72,86,100,102,103],ue=[1,103],K=[1,121],W=[1,117],Q=[1,113],j=[1,119],X=[1,114],q=[1,115],H=[1,116],J=[1,118],Z=[1,120],Ge=[22,50,60,61,82,86,87,88,89,90],Ue=[1,128],le=[12,39],Ne=[1,8,9,39,41,44,46],ce=[1,8,9,22],ze=[1,153],Ye=[1,8,9,61],x=[1,8,9,22,50,60,61,82,86,87,88,89,90],Le={trace:f(function(){},"trace"),yy:{},symbols_:{error:2,start:3,mermaidDoc:4,statements:5,graphConfig:6,CLASS_DIAGRAM:7,NEWLINE:8,EOF:9,statement:10,classLabel:11,SQS:12,STR:13,SQE:14,namespaceName:15,alphaNumToken:16,classLiteralName:17,DOT:18,className:19,GENERICTYPE:20,relationStatement:21,LABEL:22,namespaceStatement:23,classStatement:24,memberStatement:25,annotationStatement:26,clickStatement:27,styleStatement:28,cssClassStatement:29,noteStatement:30,classDefStatement:31,direction:32,acc_title:33,acc_title_value:34,acc_descr:35,acc_descr_value:36,acc_descr_multiline_value:37,namespaceIdentifier:38,STRUCT_START:39,classStatements:40,STRUCT_STOP:41,NAMESPACE:42,classIdentifier:43,STYLE_SEPARATOR:44,members:45,ANNOTATION_START:46,ANNOTATION_END:47,CLASS:48,emptyBody:49,SPACE:50,MEMBER:51,SEPARATOR:52,relation:53,NOTE_FOR:54,noteText:55,NOTE:56,CLASSDEF:57,classList:58,stylesOpt:59,ALPHA:60,COMMA:61,direction_tb:62,direction_bt:63,direction_rl:64,direction_lr:65,relationType:66,lineType:67,AGGREGATION:68,EXTENSION:69,COMPOSITION:70,DEPENDENCY:71,LOLLIPOP:72,LINE:73,DOTTED_LINE:74,CALLBACK:75,LINK:76,LINK_TARGET:77,CLICK:78,CALLBACK_NAME:79,CALLBACK_ARGS:80,HREF:81,STYLE:82,CSSCLASS:83,style:84,styleComponent:85,NUM:86,COLON:87,UNIT:88,BRKT:89,PCT:90,commentToken:91,textToken:92,graphCodeTokens:93,textNoTagsToken:94,TAGSTART:95,TAGEND:96,"==":97,"--":98,DEFAULT:99,MINUS:100,keywords:101,UNICODE_TEXT:102,BQUOTE_STR:103,$accept:0,$end:1},terminals_:{2:"error",7:"CLASS_DIAGRAM",8:"NEWLINE",9:"EOF",12:"SQS",13:"STR",14:"SQE",18:"DOT",20:"GENERICTYPE",22:"LABEL",33:"acc_title",34:"acc_title_value",35:"acc_descr",36:"acc_descr_value",37:"acc_descr_multiline_value",39:"STRUCT_START",41:"STRUCT_STOP",42:"NAMESPACE",44:"STYLE_SEPARATOR",46:"ANNOTATION_START",47:"ANNOTATION_END",48:"CLASS",50:"SPACE",51:"MEMBER",52:"SEPARATOR",54:"NOTE_FOR",56:"NOTE",57:"CLASSDEF",60:"ALPHA",61:"COMMA",62:"direction_tb",63:"direction_bt",64:"direction_rl",65:"direction_lr",68:"AGGREGATION",69:"EXTENSION",70:"COMPOSITION",71:"DEPENDENCY",72:"LOLLIPOP",73:"LINE",74:"DOTTED_LINE",75:"CALLBACK",76:"LINK",77:"LINK_TARGET",78:"CLICK",79:"CALLBACK_NAME",80:"CALLBACK_ARGS",81:"HREF",82:"STYLE",83:"CSSCLASS",86:"NUM",87:"COLON",88:"UNIT",89:"BRKT",90:"PCT",93:"graphCodeTokens",95:"TAGSTART",96:"TAGEND",97:"==",98:"--",99:"DEFAULT",100:"MINUS",101:"keywords",102:"UNICODE_TEXT",103:"BQUOTE_STR"},productions_:[0,[3,1],[3,1],[4,1],[6,4],[5,1],[5,2],[5,3],[11,3],[15,1],[15,1],[15,3],[15,2],[19,1],[19,3],[19,1],[19,2],[19,2],[19,2],[10,1],[10,2],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,1],[10,2],[10,2],[10,1],[23,4],[23,5],[38,2],[38,3],[40,1],[40,2],[40,3],[40,1],[40,2],[40,3],[40,1],[40,2],[40,3],[24,1],[24,3],[24,4],[24,3],[24,6],[24,4],[24,7],[24,6],[43,2],[43,3],[49,0],[49,2],[49,2],[26,4],[45,1],[45,2],[25,1],[25,2],[25,1],[25,1],[21,3],[21,4],[21,4],[21,5],[30,3],[30,2],[31,3],[58,1],[58,3],[32,1],[32,1],[32,1],[32,1],[53,3],[53,2],[53,2],[53,1],[66,1],[66,1],[66,1],[66,1],[66,1],[67,1],[67,1],[27,3],[27,4],[27,3],[27,4],[27,4],[27,5],[27,3],[27,4],[27,4],[27,5],[27,4],[27,5],[27,5],[27,6],[28,3],[29,3],[59,1],[59,3],[84,1],[84,2],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[85,1],[91,1],[91,1],[92,1],[92,1],[92,1],[92,1],[92,1],[92,1],[92,1],[94,1],[94,1],[94,1],[94,1],[16,1],[16,1],[16,1],[16,1],[17,1],[55,1]],performAction:f(function(o,h,p,l,C,e,$){var t=e.length-1;switch(C){case 8:this.$=e[t-1];break;case 9:case 10:case 13:case 15:this.$=e[t];break;case 11:case 14:this.$=e[t-2]+"."+e[t];break;case 12:case 16:this.$=e[t-1]+e[t];break;case 17:case 18:this.$=e[t-1]+"~"+e[t]+"~";break;case 19:l.addRelation(e[t]);break;case 20:e[t-1].titlLine truncated
`+D.showPosition()+`
Expecting `+pe.join(", ")+", got '"+(this.terminals_[B]||B)+"'":Oe="Parse error on line "+(he+1)+": Unexpected "+(B==We?"end of input":"'"+(this.terminals_[B]||B)+"'"),this.parseError(Oe,{text:D.match,token:this.terminals_[B]||B,line:D.yylineno,loc:ve,expected:pe})}if(L[0]instanceof Array&&L.length>1)throw new Error("Parse Error: multiple actions possible at state: "+P+", token: "+B);switch(L[0]){case 1:p.push(B),C.push(D.yytext),e.push(D.yylloc),p.push(L[1]),B=null,Ke=D.yyleng,t=D.yytext,he=D.yylineno,ve=D.yylloc;break;case 2:if(v=this.productions_[L[1]][1],G.$=C[C.length-v],G._$={first_line:e[e.length-(v||1)].first_line,last_line:e[e.length-1].last_line,first_column:e[e.length-(v||1)].first_column,last_column:e[e.length-1].last_column},et&&(G._$.range=[e[e.length-(v||1)].range[0],e[e.length-1].range[1]]),Ie=this.performAction.apply(G,[t,Ke,he,V.yy,L[1],C,e].concat($e)),typeof Ie<"u")return Ie;v&&(p=p.slice(0,-1*v*2),C=C.slice(0,-1*v),e=e.slice(0,-1*v)),p.push(this.productions_[L[1]][0]),C.push(G.$),e.push(G._$),je=$[p[p.length-2]][p[p.length-1]],p.push(je);break;case 3:return!0}}return!0},"parse")},Je=(function(){var O={EOF:1,parseError:f(function(h,p){if(this.yy.parser)this.yy.parser.parseError(h,p);else throw new Error(h)},"parseError"),setInput:f(function(o,h){return this.yy=h||this.yy||{},this._input=o,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:f(function(){var o=this._input[0];this.yytext+=o,this.yyleng++,this.offset++,this.match+=o,this.matched+=o;var h=o.match(/(?:\r\n?|\n).*/g);return h?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),o},"input"),unput:f(function(o){var h=o.length,p=o.split(/(?:\r\n?|\n)/g);this._input=o+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-h),this.offset-=h;var l=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),p.length-1&&(this.yylineno-=p.length-1);var C=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:p?(p.length===l.length?this.yylloc.first_column:0)+l[l.length-p.length].length-p[0].length:this.yylloc.first_column-h},this.options.ranges&&(this.yylloc.range=[C[0],C[0]+this.yyleng-h]),this.yyleng=this.yytext.length,this},"unput"),more:f(function(){return this._more=!0,this},"more"),reject:f(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:f(function(o){this.unput(this.match.slice(o))},"less"),pastInput:f(function(){var o=this.matched.substr(0,this.matched.length-this.match.length);return(o.length>20?"...":"")+o.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:f(function(){var o=this.match;return o.length<20&&(o+=this._input.substr(0,20-o.length)),(o.substr(0,20)+(o.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:f(function(){var o=this.pastInput(),h=new Array(o.length+1).join("-");return o+this.upcomingInput()+`
`+h+"^"},"showPosition"),test_match:f(function(o,h){var p,l,C;if(this.options.backtrack_lexer&&(C={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(C.yylloc.range=this.yylloc.range.slice(0))),l=o[0].match(/(?:\r\n?|\n).*/g),l&&(this.yylineno+=l.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:l?l[l.length-1].length-l[l.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+o[0].length},this.yytext+=o[0],this.match+=o[0],this.matches=o,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(o[0].length),this.matched+=o[0],p=this.performAction.call(this,this.yy,this,h,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),p)return p;if(this._backtrack){for(var e in C)this[e]=C[e];return!1}return!1},"test_match"),next:f(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var o,h,p,l;this._more||(this.yytext="",this.match="");for(var C=this._currentRules(),e=0;e<C.length;e++)if(p=this._input.match(this.rules[C[e]]),p&&(!h||p[0].length>h[0].length)){if(h=p,l=e,this.options.backtrack_lexer){if(o=this.test_match(p,C[e]),o!==!1)return o;if(this._backtrack){h=!1;continue}else return!1}else if(!this.options.flex)break}return h?(o=this.test_match(h,C[l]),o!==!1?o:!1):this._input===""?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+`. Unrecognized text.
`+this.showPosition(),{text:"",token:null,line:this.yylineno})},"next"),lex:f(function(){var h=this.next();return h||this.lex()},"lex"),begin:f(function(h){this.conditionStack.push(h)},"begin"),popState:f(function(){var h=this.conditionStack.length-1;return h>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:f(function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},"_currentRules"),topState:f(function(h){return h=this.conditionStack.length-1-Math.abs(h||0),h>=0?this.conditionStack[h]:"INITIAL"},"topState"),pushState:f(function(h){this.begin(h)},"pushState"),stateStackSize:f(function(){return this.conditionStack.length},"stateStackSize"),options:{},performAction:f(function(h,p,l,C){switch(l){case 0:return 62;case 1:return 63;case 2:return 64;case 3:return 65;case 4:break;case 5:break;case 6:return this.begin("acc_title"),33;case 7:return this.popState(),"acc_title_value";case 8:return this.begin("acc_descr"),35;case 9:return this.popState(),"acc_descr_value";case 10:this.begin("acc_descr_multiline");break;case 11:this.popState();break;case 12:return"acc_descr_multiline_value";case 13:return 8;case 14:break;case 15:return 7;case 16:return 7;case 17:return"EDGE_STATE";case 18:this.begin("callback_name");break;case 19:this.popState();break;case 20:this.popState(),this.begin("callback_args");break;case 21:return 79;case 22:this.popState();break;case 23:return 80;case 24:this.popState();break;case 25:return"STR";case 26:this.begin("string");break;case 27:return 82;case 28:return 57;case 29:return this.begin("namespace"),42;case 30:return this.popState(),8;case 31:break;case 32:return this.begin("namespace-body"),39;case 33:this.popState(),this.less(0);break;case 34:return this.popState(),41;case 35:return"EOF_IN_STRUCT";case 36:return 8;case 37:break;case 38:return"EDGE_STATE";case 39:return this.begin("class"),48;case 40:return this.popState(),8;case 41:break;case 42:return this.popState(),this.popState(),41;case 43:return this.begin("class-body"),39;case 44:return this.popState(),41;case 45:return"EOF_IN_STRUCT";case 46:return"EDGE_STATE";case 47:return"OPEN_IN_STRUCT";case 48:break;case 49:return"MEMBER";case 50:return 83;case 51:return 75;case 52:return 76;case 53:return 78;case 54:return 54;case 55:return 56;case 56:return 46;case 57:return 47;case 58:return 81;case 59:this.popState();break;case 60:return"GENERICTYPE";case 61:this.begin("generic");break;case 62:this.popState();break;case 63:return"BQUOTE_STR";case 64:this.begin("bqstring");break;case 65:return 77;case 66:return 77;case 67:return 77;case 68:return 77;case 69:return 69;case 70:return 69;case 71:return 71;case 72:return 71;case 73:return 70;case 74:return 68;case 75:return 72;case 76:return 73;case 77:return 74;case 78:return 22;case 79:return 44;case 80:return 100;case 81:return 18;case 82:return"PLUS";case 83:return 87;case 84:return 61;case 85:return 89;case 86:return 89;case 87:return 90;case 88:return"EQUALS";case 89:return"EQUALS";case 90:return 60;case 91:return 12;case 92:return 14;case 93:return"PUNCTUATION";case 94:return 86;case 95:return 102;case 96:return 50;case 97:return 50;case 98:return 9}},"anonymous"),rules:[/^(?:.*direction\s+TB[^\n]*)/,/^(?:.*direction\s+BT[^\n]*)/,/^(?:.*direction\s+RL[^\n]*)/,/^(?:.*direction\s+LR[^\n]*)/,/^(?:%%(?!\{)*[^\n]*(\r?\n?)+)/,/^(?:%%[^\n]*(\r?\n)*)/,/^(?:accTitle\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*:\s*)/,/^(?:(?!\n||)*[^\n]*)/,/^(?:accDescr\s*\{\s*)/,/^(?:[\}])/,/^(?:[^\}]*)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:classDiagram-v2\b)/,/^(?:classDiagram\b)/,/^(?:\[\*\])/,/^(?:call[\s]+)/,/^(?:\([\s]*\))/,/^(?:\()/,/^(?:[^(]*)/,/^(?:\))/,/^(?:[^)]*)/,/^(?:["])/,/^(?:[^"]*)/,/^(?:["])/,/^(?:style\b)/,/^(?:classDef\b)/,/^(?:namespace\b)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:[{])/,/^(?:[}])/,/^(?:[}])/,/^(?:$)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:\[\*\])/,/^(?:class\b)/,/^(?:\s*(\r?\n)+)/,/^(?:\s+)/,/^(?:[}])/,/^(?:[{])/,/^(?:[}])/,/^(?:$)/,/^(?:\[\*\])/,/^(?:[{])/,/^(?:[\n])/,/^(?:[^{}\n]*)/,/^(?:cssClass\b)/,/^(?:callback\b)/,/^(?:link\b)/,/^(?:click\b)/,/^(?:note for\b)/,/^(?:note\b)/,/^(?:<<)/,/^(?:>>)/,/^(?:href\b)/,/^(?:[~])/,/^(?:[^~]*)/,/^(?:~)/,/^(?:[`])/,/^(?:[^`]+)/,/^(?:[`])/,/^(?:_self\b)/,/^(?:_blank\b)/,/^(?:_parent\b)/,/^(?:_top\b)/,/^(?:\s*<\|)/,/^(?:\s*\|>)/,/^(?:\s*>)/,/^(?:\s*<)/,/^(?:\s*\*)/,/^(?:\s*o\b)/,/^(?:\s*\(\))/,/^(?:--)/,/^(?:\.\.)/,/^(?::{1}[^:\n;]+)/,/^(?::{3})/,/^(?:-)/,/^(?:\.)/,/^(?:\+)/,/^(?::)/,/^(?:,)/,/^(?:#)/,/^(?:#)/,/^(?:%)/,/^(?:=)/,/^(?:=)/,/^(?:\w+)/,/^(?:\[)/,/^(?:\])/,/^(?:[!"#$%&'*+,-.`?\\/])/,/^(?:[0-9]+)/,/^(?:[\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]|[\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377]|[\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5]|[\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA]|[\uLine truncated
fill: ${s.nodeBorder||s.classText};
stroke: none;
font-family: ${s.fontFamily};
font-size: 10px;
.title {
font-weight: bolder;
}
}
.cluster-label text {
fill: ${s.titleColor};
}
.cluster-label span {
color: ${s.titleColor};
}
.cluster-label span p {
background-color: transparent;
}
.cluster rect {
fill: ${s.clusterBkg};
stroke: ${s.clusterBorder};
stroke-width: 1px;
}
.cluster text {
fill: ${s.titleColor};
}
.cluster span {
color: ${s.titleColor};
}
.nodeLabel, .edgeLabel {
color: ${s.classText};
}
.noteLabel .nodeLabel, .noteLabel .edgeLabel {
color: ${s.noteTextColor};
}
.edgeLabel .label rect {
fill: ${s.mainBkg};
}
.label text {
fill: ${s.classText};
}
.labelBkg {
background: ${s.mainBkg};
}
.edgeLabel .label span {
background: ${s.mainBkg};
}
.classTitle {
font-weight: bolder;
}
.node rect,
.node circle,
.node ellipse,
.node polygon,
.node path {
fill: ${s.mainBkg};
stroke: ${s.nodeBorder};
stroke-width: ${s.strokeWidth};
}
.divider {
stroke: ${s.nodeBorder};
stroke-width: 1;
}
g.clickable {
cursor: pointer;
}
g.classGroup rect {
fill: ${s.mainBkg};
stroke: ${s.nodeBorder};
}
g.classGroup line {
stroke: ${s.nodeBorder};
stroke-width: 1;
}
.classLabel .box {
stroke: none;
stroke-width: 0;
fill: ${s.mainBkg};
opacity: 0.5;
}
.classLabel .label {
fill: ${s.nodeBorder};
font-size: 10px;
}
.relation {
stroke: ${s.lineColor};
stroke-width: ${s.strokeWidth};
fill: none;
}
.dashed-line{
stroke-dasharray: 3;
}
.dotted-line{
stroke-dasharray: 1 2;
}
[id$="-compositionStart"], .composition {
fill: ${s.lineColor} !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-compositionEnd"], .composition {
fill: ${s.lineColor} !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-dependencyStart"], .dependency {
fill: ${s.lineColor} !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-dependencyEnd"], .dependency {
fill: ${s.lineColor} !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-extensionStart"], .extension {
fill: transparent !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-extensionEnd"], .extension {
fill: transparent !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-aggregationStart"], .aggregation {
fill: transparent !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-aggregationEnd"], .aggregation {
fill: transparent !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-lollipopStart"], .lollipop {
fill: ${s.mainBkg} !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
[id$="-lollipopEnd"], .lollipop {
fill: ${s.mainBkg} !important;
stroke: ${s.lineColor} !important;
stroke-width: 1;
}
.edgeTerminals {
font-size: 11px;
line-height: initial;
}
.classTitleText {
text-anchor: middle;
font-size: 18px;
fill: ${s.textColor};
}
.edgeLabel[data-look="neo"] {
background-color: ${s.edgeLabelBackground};
p {
background-color: ${s.edgeLabelBackground};
}
rect {
opacity: 0.5;
background-color: ${s.edgeLabelBackground};
fill: ${s.edgeLabelBackground};
}
text-align: center;
}
${st()}
`,"getStyles"),Nt=Ct,bt=f((s,i="TB")=>{if(!s.doc)return i;let a=i;for(const n of s.doc)n.stmt==="dir"&&(a=n.value);return a},"getDir"),kt=f(function(s,i){return i.db.getClasses()},"getClasses"),Et=f(async function(s,i,a,n){we.info("REF0:"),we.info("Drawing class diagram (v3)",i);const{securityLevel:r,state:c,layout:u}=F();n.db.setDiagramId(i);const d=n.db.getData(),m=it(i,r);d.type=n.type,d.layoutAlgorithm=nt(u),d.nodeSpacing=c?.nodeSpacing||50,d.rankSpacing=c?.rankSpacing||50,d.markers=["aggregation","extension","composition","dependency","lollipop"],d.diagramId=i,await rt(d,m);const g=8;Ve.insertTitle(m,"classDiagramTitleText",c?.titleTopMargin??25,n.db.getDiagramTitle()),at(m,g,"classDiagram",c?.useMaxWidth??!0)},"draw"),Lt={getClasses:kt,draw:Et,getDir:bt};export{St as C,_t as a,Lt as c,Nt as s};
@@ -0,0 +1 @@
import{_ as a,j as o}from"./mermaid.core.js";var g=a((t,e)=>{let n;return e==="sandbox"&&(n=o("#i"+t)),(e==="sandbox"?o(n.nodes()[0].contentDocument.body):o("body")).select(`[id="${t}"]`)},"getDiagramElement");export{g};
@@ -0,0 +1 @@
import{s as a,c as s,a as e,C as t}from"./chunk-TICWLB2K.js";import{_ as i}from"./mermaid.core.js";import"./chunk-5VM5RSS4.js";import"./chunk-XXDRQBXY.js";import"./chunk-POPQ4Y6H.js";import"./chunk-F27PBJKO.js";import"./index.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -0,0 +1 @@
import{s as a,c as s,a as e,C as t}from"./chunk-TICWLB2K.js";import{_ as i}from"./mermaid.core.js";import"./chunk-5VM5RSS4.js";import"./chunk-XXDRQBXY.js";import"./chunk-POPQ4Y6H.js";import"./chunk-F27PBJKO.js";import"./index.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
@@ -1 +1 @@
var b;(function(s){s.assertEqual=n=>{};function e(n){}s.assertIs=e;function t(n){throw new Error}s.assertNever=t,s.arrayToEnum=n=>{const i={};for(const a of n)i[a]=a;return i},s.getValidEnumValues=n=>{const i=s.objectKeys(n).filter(o=>typeof n[n[o]]!="number"),a={};for(const o of i)a[o]=n[o];return s.objectValues(a)},s.objectValues=n=>s.objectKeys(n).map(function(i){return n[i]}),s.objectKeys=typeof Object.keys=="function"?n=>Object.keys(n):n=>{const i=[];for(const a in n)Object.prototype.hasOwnProperty.call(n,a)&&i.push(a);return i},s.find=(n,i)=>{for(const a of n)if(i(a))return a},s.isInteger=typeof Number.isInteger=="function"?n=>Number.isInteger(n):n=>typeof n=="number"&&Number.isFinite(n)&&Math.floor(n)===n;function r(n,i=" | "){return n.map(a=>typeof a=="string"?`'${a}'`:a).join(i)}s.joinValues=r,s.jsonStringifyReplacer=(n,i)=>typeof i=="bigint"?i.toString():i})(b||(b={}));var Ie;(function(s){s.mergeShapes=(e,t)=>({...e,...t})})(Ie||(Ie={}));const f=b.arrayToEnum(["string","nan","number","integer","float","boolean","date","bigint","symbol","function","undefined","null","array","object","unknown","promise","void","never","map","set"]),I=s=>{switch(typeof s){case"undefined":return f.undefined;case"string":return f.string;case"number":return Number.isNaN(s)?f.nan:f.number;case"boolean":return f.boolean;case"function":return f.function;case"bigint":return f.bigint;case"symbol":return f.symbol;case"object":return Array.isArray(s)?f.array:s===null?f.null:s.then&&typeof s.then=="function"&&s.catch&&typeof s.catch=="function"?f.promise:typeof Map<"u"&&s instanceof Map?f.map:typeof Set<"u"&&s instanceof Set?f.set:typeof Date<"u"&&s instanceof Date?f.date:f.object;default:return f.unknown}},c=b.arrayToEnum(["invalid_type","invalid_literal","custom","invalid_union","invalid_union_discriminator","invalid_enum_value","unrecognized_keys","invalid_arguments","invalid_return_type","invalid_date","invalid_string","too_small","too_big","invalid_intersection_types","not_multiple_of","not_finite"]);class T extends Error{get errors(){return this.issues}constructor(e){super(),this.issues=[],this.addIssue=r=>{this.issues=[...this.issues,r]},this.addIssues=(r=[])=>{this.issues=[...this.issues,...r]};const t=new.target.prototype;Object.setPrototypeOf?Object.setPrototypeOf(this,t):this.__proto__=t,this.name="ZodError",this.issues=e}format(e){const t=e||function(i){return i.message},r={_errors:[]},n=i=>{for(const a of i.issues)if(a.code==="invalid_union")a.unionErrors.map(n);else if(a.code==="invalid_return_type")n(a.returnTypeError);else if(a.code==="invalid_arguments")n(a.argumentsError);else if(a.path.length===0)r._errors.push(t(a));else{let o=r,l=0;for(;l<a.path.length;){const d=a.path[l];l===a.path.length-1?(o[d]=o[d]||{_errors:[]},o[d]._errors.push(t(a))):o[d]=o[d]||{_errors:[]},o=o[d],l++}}};return n(this),r}static assert(e){if(!(e instanceof T))throw new Error(`Not a ZodError: ${e}`)}toString(){return this.message}get message(){return JSON.stringify(this.issues,b.jsonStringifyReplacer,2)}get isEmpty(){return this.issues.length===0}flatten(e=t=>t.message){const t={},r=[];for(const n of this.issues)if(n.path.length>0){const i=n.path[0];t[i]=t[i]||[],t[i].push(e(n))}else r.push(e(n));return{formErrors:r,fieldErrors:t}}get formErrors(){return this.flatten()}}T.create=s=>new T(s);const _e=(s,e)=>{let t;switch(s.code){case c.invalid_type:s.received===f.undefined?t="Required":t=`Expected ${s.expected}, received ${s.received}`;break;case c.invalid_literal:t=`Invalid literal value, expected ${JSON.stringify(s.expected,b.jsonStringifyReplacer)}`;break;case c.unrecognized_keys:t=`Unrecognized key(s) in object: ${b.joinValues(s.keys,", ")}`;break;case c.invalid_union:t="Invalid input";break;case c.invalid_union_discriminator:t=`Invalid discriminator value. Expected ${b.joinValues(s.options)}`;break;case c.invalid_enum_value:t=`Invalid enum value. Expected ${b.joinValues(s.options)}, received '${s.received}'`;break;case c.invalid_arguments:t="Invalid function arguments";break;case c.invalid_return_type:t="Invalid function return type";break;case c.invalid_date:t="Invalid date";break;case c.invalid_string:typeof s.validation=="object"?"includes"in s.validation?(t=`Invalid input: must include "${s.validation.includes}"`,typeof s.validation.position=="number"&&(t=`${t} at one or more positions greater than or equal to ${s.validation.position}`)):"startsWith"in s.validation?t=`Invalid input: must start with "${s.validation.startsWith}"`:"endsWith"in s.validation?t=`Invalid input: must end with "${s.validation.endsWith}"`:b.assertNever(s.validation):s.validation!=="regex"?t=`Invalid ${s.validation}`:t="Invalid";break;case c.too_small:s.type==="array"?t=`Array must contain ${s.exact?"exactly":s.inclusive?"at least":"more than"} ${s.minimum} element(s)`:s.type==="string"?t=`String must contain ${s.exact?"exactly":s.inclusive?"at least":"over"} ${s.minimum} character(s)`:s.type==="number"?t=`Number must be ${s.exact?"exactly equal to ":s.iLine truncated
var b;(function(s){s.assertEqual=n=>{};function e(n){}s.assertIs=e;function t(n){throw new Error}s.assertNever=t,s.arrayToEnum=n=>{const i={};for(const a of n)i[a]=a;return i},s.getValidEnumValues=n=>{const i=s.objectKeys(n).filter(o=>typeof n[n[o]]!="number"),a={};for(const o of i)a[o]=n[o];return s.objectValues(a)},s.objectValues=n=>s.objectKeys(n).map(function(i){return n[i]}),s.objectKeys=typeof Object.keys=="function"?n=>Object.keys(n):n=>{const i=[];for(const a in n)Object.prototype.hasOwnProperty.call(n,a)&&i.push(a);return i},s.find=(n,i)=>{for(const a of n)if(i(a))return a},s.isInteger=typeof Number.isInteger=="function"?n=>Number.isInteger(n):n=>typeof n=="number"&&Number.isFinite(n)&&Math.floor(n)===n;function r(n,i=" | "){return n.map(a=>typeof a=="string"?`'${a}'`:a).join(i)}s.joinValues=r,s.jsonStringifyReplacer=(n,i)=>typeof i=="bigint"?i.toString():i})(b||(b={}));var Ie;(function(s){s.mergeShapes=(e,t)=>({...e,...t})})(Ie||(Ie={}));const f=b.arrayToEnum(["string","nan","number","integer","float","boolean","date","bigint","symbol","function","undefined","null","array","object","unknown","promise","void","never","map","set"]),I=s=>{switch(typeof s){case"undefined":return f.undefined;case"string":return f.string;case"number":return Number.isNaN(s)?f.nan:f.number;case"boolean":return f.boolean;case"function":return f.function;case"bigint":return f.bigint;case"symbol":return f.symbol;case"object":return Array.isArray(s)?f.array:s===null?f.null:s.then&&typeof s.then=="function"&&s.catch&&typeof s.catch=="function"?f.promise:typeof Map<"u"&&s instanceof Map?f.map:typeof Set<"u"&&s instanceof Set?f.set:typeof Date<"u"&&s instanceof Date?f.date:f.object;default:return f.unknown}},c=b.arrayToEnum(["invalid_type","invalid_literal","custom","invalid_union","invalid_union_discriminator","invalid_enum_value","unrecognized_keys","invalid_arguments","invalid_return_type","invalid_date","invalid_string","too_small","too_big","invalid_intersection_types","not_multiple_of","not_finite"]);class T extends Error{get errors(){return this.issues}constructor(e){super(),this.issues=[],this.addIssue=r=>{this.issues=[...this.issues,r]},this.addIssues=(r=[])=>{this.issues=[...this.issues,...r]};const t=new.target.prototype;Object.setPrototypeOf?Object.setPrototypeOf(this,t):this.__proto__=t,this.name="ZodError",this.issues=e}format(e){const t=e||function(i){return i.message},r={_errors:[]},n=i=>{for(const a of i.issues)if(a.code==="invalid_union")a.unionErrors.map(n);else if(a.code==="invalid_return_type")n(a.returnTypeError);else if(a.code==="invalid_arguments")n(a.argumentsError);else if(a.path.length===0)r._errors.push(t(a));else{let o=r,l=0;for(;l<a.path.length;){const d=a.path[l];l===a.path.length-1?(o[d]=o[d]||{_errors:[]},o[d]._errors.push(t(a))):o[d]=o[d]||{_errors:[]},o=o[d],l++}}};return n(this),r}static assert(e){if(!(e instanceof T))throw new Error(`Not a ZodError: ${e}`)}toString(){return this.message}get message(){return JSON.stringify(this.issues,b.jsonStringifyReplacer,2)}get isEmpty(){return this.issues.length===0}flatten(e=t=>t.message){const t={},r=[];for(const n of this.issues)if(n.path.length>0){const i=n.path[0];t[i]=t[i]||[],t[i].push(e(n))}else r.push(e(n));return{formErrors:r,fieldErrors:t}}get formErrors(){return this.flatten()}}T.create=s=>new T(s);const _e=(s,e)=>{let t;switch(s.code){case c.invalid_type:s.received===f.undefined?t="Required":t=`Expected ${s.expected}, received ${s.received}`;break;case c.invalid_literal:t=`Invalid literal value, expected ${JSON.stringify(s.expected,b.jsonStringifyReplacer)}`;break;case c.unrecognized_keys:t=`Unrecognized key(s) in object: ${b.joinValues(s.keys,", ")}`;break;case c.invalid_union:t="Invalid input";break;case c.invalid_union_discriminator:t=`Invalid discriminator value. Expected ${b.joinValues(s.options)}`;break;case c.invalid_enum_value:t=`Invalid enum value. Expected ${b.joinValues(s.options)}, received '${s.received}'`;break;case c.invalid_arguments:t="Invalid function arguments";break;case c.invalid_return_type:t="Invalid function return type";break;case c.invalid_date:t="Invalid date";break;case c.invalid_string:typeof s.validation=="object"?"includes"in s.validation?(t=`Invalid input: must include "${s.validation.includes}"`,typeof s.validation.position=="number"&&(t=`${t} at one or more positions greater than or equal to ${s.validation.position}`)):"startsWith"in s.validation?t=`Invalid input: must start with "${s.validation.startsWith}"`:"endsWith"in s.validation?t=`Invalid input: must end with "${s.validation.endsWith}"`:b.assertNever(s.validation):s.validation!=="regex"?t=`Invalid ${s.validation}`:t="Invalid";break;case c.too_small:s.type==="array"?t=`Array must contain ${s.exact?"exactly":s.inclusive?"at least":"more than"} ${s.minimum} element(s)`:s.type==="string"?t=`String must contain ${s.exact?"exactly":s.inclusive?"at least":"over"} ${s.minimum} character(s)`:s.type==="number"?t=`Number must be ${s.exact?"exactly equal to ":s.iLine truncated
@@ -0,0 +1 @@
import{_ as V,l as $,j as lt}from"./mermaid.core.js";import{c as tt}from"./cytoscape.esm.js";import{g as gt}from"./index.js";var k={exports:{}},Z={exports:{}},Q={exports:{}},ut=Q.exports,q;function ft(){return q||(q=1,(function(G,b){(function(I,L){G.exports=L()})(ut,function(){return(function(N){var I={};function L(o){if(I[o])return I[o].exports;var e=I[o]={i:o,l:!1,exports:{}};return N[o].call(e.exports,e,e.exports,L),e.l=!0,e.exports}return L.m=N,L.c=I,L.i=function(o){return o},L.d=function(o,e,t){L.o(o,e)||Object.defineProperty(o,e,{configurable:!1,enumerable:!0,get:t})},L.n=function(o){var e=o&&o.__esModule?function(){return o.default}:function(){return o};return L.d(e,"a",e),e},L.o=function(o,e){return Object.prototype.hasOwnProperty.call(o,e)},L.p="",L(L.s=26)})([(function(N,I,L){function o(){}o.QUALITY=1,o.DEFAULT_CREATE_BENDS_AS_NEEDED=!1,o.DEFAULT_INCREMENTAL=!1,o.DEFAULT_ANIMATION_ON_LAYOUT=!0,o.DEFAULT_ANIMATION_DURING_LAYOUT=!1,o.DEFAULT_ANIMATION_PERIOD=50,o.DEFAULT_UNIFORM_LEAF_NODE_SIZES=!1,o.DEFAULT_GRAPH_MARGIN=15,o.NODE_DIMENSIONS_INCLUDE_LABELS=!1,o.SIMPLE_NODE_SIZE=40,o.SIMPLE_NODE_HALF_SIZE=o.SIMPLE_NODE_SIZE/2,o.EMPTY_COMPOUND_NODE_SIZE=40,o.MIN_EDGE_LENGTH=1,o.WORLD_BOUNDARY=1e6,o.INITIAL_WORLD_BOUNDARY=o.WORLD_BOUNDARY/1e3,o.WORLD_CENTER_X=1200,o.WORLD_CENTER_Y=900,N.exports=o}),(function(N,I,L){var o=L(2),e=L(8),t=L(9);function i(g,n,d){o.call(this,d),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=d,this.bendpoints=[],this.source=g,this.target=n}i.prototype=Object.create(o.prototype);for(var l in o)i[l]=o[l];i.prototype.getSource=function(){return this.source},i.prototype.getTarget=function(){return this.target},i.prototype.isInterGraph=function(){return this.isInterGraph},i.prototype.getLength=function(){return this.length},i.prototype.isOverlapingSourceAndTarget=function(){return this.isOverlapingSourceAndTarget},i.prototype.getBendpoints=function(){return this.bendpoints},i.prototype.getLca=function(){return this.lca},i.prototype.getSourceInLca=function(){return this.sourceInLca},i.prototype.getTargetInLca=function(){return this.targetInLca},i.prototype.getOtherEnd=function(g){if(this.source===g)return this.target;if(this.target===g)return this.source;throw"Node is not incident with this edge"},i.prototype.getOtherEndInGraph=function(g,n){for(var d=this.getOtherEnd(g),r=n.getGraphManager().getRoot();;){if(d.getOwner()==n)return d;if(d.getOwner()==r)break;d=d.getOwner().getParent()}return null},i.prototype.updateLength=function(){var g=new Array(4);this.isOverlapingSourceAndTarget=e.getIntersection(this.target.getRect(),this.source.getRect(),g),this.isOverlapingSourceAndTarget||(this.lengthX=g[0]-g[2],this.lengthY=g[1]-g[3],Math.abs(this.lengthX)<1&&(this.lengthX=t.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=t.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY))},i.prototype.updateLengthSimple=function(){this.lengthX=this.target.getCenterX()-this.source.getCenterX(),this.lengthY=this.target.getCenterY()-this.source.getCenterY(),Math.abs(this.lengthX)<1&&(this.lengthX=t.sign(this.lengthX)),Math.abs(this.lengthY)<1&&(this.lengthY=t.sign(this.lengthY)),this.length=Math.sqrt(this.lengthX*this.lengthX+this.lengthY*this.lengthY)},N.exports=i}),(function(N,I,L){function o(e){this.vGraphObject=e}N.exports=o}),(function(N,I,L){var o=L(2),e=L(10),t=L(13),i=L(0),l=L(16),g=L(4);function n(r,h,a,p){a==null&&p==null&&(p=h),o.call(this,p),r.graphManager!=null&&(r=r.graphManager),this.estimatedSize=e.MIN_VALUE,this.inclusionTreeDepth=e.MAX_VALUE,this.vGraphObject=p,this.edges=[],this.graphManager=r,a!=null&&h!=null?this.rect=new t(h.x,h.y,a.width,a.height):this.rect=new t}n.prototype=Object.create(o.prototype);for(var d in o)n[d]=o[d];n.prototype.getEdges=function(){return this.edges},n.prototype.getChild=function(){return this.child},n.prototype.getOwner=function(){return this.owner},n.prototype.getWidth=function(){return this.rect.width},n.prototype.setWidth=function(r){this.rect.width=r},n.prototype.getHeight=function(){return this.rect.height},n.prototype.setHeight=function(r){this.rect.height=r},n.prototype.getCenterX=function(){return this.rect.x+this.rect.width/2},n.prototype.getCenterY=function(){return this.rect.y+this.rect.height/2},n.prototype.getCenter=function(){return new g(this.rect.x+this.rect.width/2,this.rect.y+this.rect.height/2)},n.prototype.getLocation=function(){return new g(this.rect.x,this.rect.y)},n.prototype.getRect=function(){return this.rect},n.prototype.getDiagonal=function(){return Math.sqrt(this.rect.width*this.rect.width+this.rect.height*this.rect.height)},n.prototype.getHalfTheDiagonal=function(){return Math.sqrt(this.rect.height*this.rect.height+this.rect.width*this.rect.width)/2},n.prototype.setRect=function(r,h){this.rect.x=r.x,this.rect.y=r.y,this.rect.width=h.width,this.rect.height=h.height},n.prototype.setCenter=function(r,h){this.rect.x=r-this.rect.width/2,this.rect.y=h-this.rect.height/2},nLine truncated
@@ -0,0 +1,166 @@
import{_ as ut}from"./index.js";var fk=Object.create,Lu=Object.defineProperty,dk=Object.getOwnPropertyDescriptor,vh=Object.getOwnPropertyNames,pk=Object.getPrototypeOf,mk=Object.prototype.hasOwnProperty,s=(t,e)=>Lu(t,"name",{value:e,configurable:!0}),hk=(t,e)=>function(){return t&&(e=(0,t[vh(t)[0]])(t=0)),e},X=(t,e)=>function(){return e||(0,t[vh(t)[0]])((e={exports:{}}).exports,e),e.exports},en=(t,e)=>{for(var r in e)Lu(t,r,{get:e[r],enumerable:!0})},Th=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of vh(e))!mk.call(t,a)&&a!==r&&Lu(t,a,{get:()=>e[a],enumerable:!(n=dk(e,a))||n.enumerable});return t},kf=(t,e,r)=>(Th(t,e,"default"),r),$h=(t,e,r)=>(r=t!=null?fk(pk(t)):{},Th(Lu(r,"default",{value:t,enumerable:!0}),t)),Rh=t=>Th(Lu({},"__esModule",{value:!0}),t),Of={};en(Of,{AnnotatedTextEdit:()=>Ar,ChangeAnnotation:()=>pn,ChangeAnnotationIdentifier:()=>et,CodeAction:()=>Zp,CodeActionContext:()=>Jp,CodeActionKind:()=>Xp,CodeActionTriggerKind:()=>Yl,CodeDescription:()=>wp,CodeLens:()=>Qp,Color:()=>Ac,ColorInformation:()=>Ap,ColorPresentation:()=>Ep,Command:()=>dn,CompletionItem:()=>Gp,CompletionItemKind:()=>kp,CompletionItemLabelDetails:()=>Mp,CompletionItemTag:()=>Lp,CompletionList:()=>Fp,CreateFile:()=>ba,DeleteFile:()=>Sa,Diagnostic:()=>Wl,DiagnosticRelatedInformation:()=>Ec,DiagnosticSeverity:()=>_p,DiagnosticTag:()=>Sp,DocumentHighlight:()=>Kp,DocumentHighlightKind:()=>Up,DocumentLink:()=>tm,DocumentSymbol:()=>Yp,DocumentUri:()=>Tp,EOL:()=>x$,FoldingRange:()=>bp,FoldingRangeKind:()=>Cp,FormattingOptions:()=>em,Hover:()=>zp,InlayHint:()=>cm,InlayHintKind:()=>_c,InlayHintLabelPart:()=>Sc,InlineCompletionContext:()=>ym,InlineCompletionItem:()=>dm,InlineCompletionList:()=>pm,InlineCompletionTriggerKind:()=>mm,InlineValueContext:()=>um,InlineValueEvaluatableExpression:()=>lm,InlineValueText:()=>sm,InlineValueVariableLookup:()=>om,InsertReplaceEdit:()=>Dp,InsertTextFormat:()=>Op,InsertTextMode:()=>xp,Location:()=>Kl,LocationLink:()=>Rp,MarkedString:()=>Hl,MarkupContent:()=>wa,MarkupKind:()=>bc,OptionalVersionedTextDocumentIdentifier:()=>ql,ParameterInformation:()=>jp,Position:()=>oe,Range:()=>te,RenameFile:()=>_a,SelectedCompletionInfo:()=>hm,SelectionRange:()=>rm,SemanticTokenModifiers:()=>am,SemanticTokenTypes:()=>nm,SemanticTokens:()=>im,SignatureInformation:()=>Bp,StringValue:()=>fm,SymbolInformation:()=>qp,SymbolKind:()=>Wp,SymbolTag:()=>Vp,TextDocument:()=>vm,TextDocumentEdit:()=>Vl,TextDocumentIdentifier:()=>Ip,TextDocumentItem:()=>Pp,TextEdit:()=>ar,URI:()=>Rc,VersionedTextDocumentIdentifier:()=>Np,WorkspaceChange:()=>D$,WorkspaceEdit:()=>Cc,WorkspaceFolder:()=>gm,WorkspaceSymbol:()=>Hp,integer:()=>$p,uinteger:()=>Ul});var Tp,Rc,$p,Ul,oe,te,Kl,Rp,Ac,Ap,Ep,Cp,bp,Ec,_p,Sp,wp,Wl,dn,ar,pn,et,Ar,Vl,ba,_a,Sa,Cc,Pl,Bd,D$,Ip,Np,ql,Pp,bc,wa,kp,Op,Lp,Dp,xp,Mp,Gp,Fp,Hl,zp,jp,Bp,Up,Kp,Wp,Vp,qp,Hp,Yp,Xp,Yl,Jp,Zp,Qp,em,tm,rm,nm,am,im,sm,om,lm,um,_c,Sc,cm,fm,dm,pm,mm,hm,ym,gm,x$,vm,av,E,Du=hk({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-languageserver-types/lib/esm/main.js"(){var t,e,r,n;(function(a){function i(o){return typeof o=="string"}s(i,"is"),a.is=i})(Tp||(Tp={})),(function(a){function i(o){return typeof o=="string"}s(i,"is"),a.is=i})(Rc||(Rc={})),(function(a){a.MIN_VALUE=-2147483648,a.MAX_VALUE=2147483647;function i(o){return typeof o=="number"&&a.MIN_VALUE<=o&&o<=a.MAX_VALUE}s(i,"is"),a.is=i})($p||($p={})),(function(a){a.MIN_VALUE=0,a.MAX_VALUE=2147483647;function i(o){return typeof o=="number"&&a.MIN_VALUE<=o&&o<=a.MAX_VALUE}s(i,"is"),a.is=i})(Ul||(Ul={})),(function(a){function i(u,l){return u===Number.MAX_VALUE&&(u=Ul.MAX_VALUE),l===Number.MAX_VALUE&&(l=Ul.MAX_VALUE),{line:u,character:l}}s(i,"create"),a.create=i;function o(u){let l=u;return E.objectLiteral(l)&&E.uinteger(l.line)&&E.uinteger(l.character)}s(o,"is"),a.is=o})(oe||(oe={})),(function(a){function i(u,l,c,f){if(E.uinteger(u)&&E.uinteger(l)&&E.uinteger(c)&&E.uinteger(f))return{start:oe.create(u,l),end:oe.create(c,f)};if(oe.is(u)&&oe.is(l))return{start:u,end:l};throw new Error(`Range#create called with invalid arguments[${u}, ${l}, ${c}, ${f}]`)}s(i,"create"),a.create=i;function o(u){let l=u;return E.objectLiteral(l)&&oe.is(l.start)&&oe.is(l.end)}s(o,"is"),a.is=o})(te||(te={})),(function(a){function i(u,l){return{uri:u,range:l}}s(i,"create"),a.create=i;function o(u){let l=u;return E.objectLiteral(l)&&te.is(l.range)&&(E.string(l.uri)||E.undefined(l.uri))}s(o,"is"),a.is=o})(Kl||(Kl={})),(function(a){function i(u,l,c,f){return{targetUri:u,targetRange:l,targetSelectionRange:c,originSelectionRange:f}}s(i,"create"),a.create=i;function o(u){let l=u;return E.objectLiteral(l)&&te.is(l.targetRange)&&E.string(l.targetUri)&&te.is(l.targetSelectionRange)&&(te.is(l.originSelectionRange)||E.undefined(l.originSelectionRange))}s(o,"is"),a.is=o})(Rp||(Rp={})),(function(a){function i(u,l,c,f){return{red:u,green:l,blue:c,alpha:f}}s(i,"create"),a.create=i;function o(u){const l=u;return E.objectLiteral(l)&&E.numberRaLine truncated
`,`\r
`,"\r"],(function(a){function i(c,f,d,p){return new av(c,f,d,p)}s(i,"create"),a.create=i;function o(c){let f=c;return!!(E.defined(f)&&E.string(f.uri)&&(E.undefined(f.languageId)||E.string(f.languageId))&&E.uinteger(f.lineCount)&&E.func(f.getText)&&E.func(f.positionAt)&&E.func(f.offsetAt))}s(o,"is"),a.is=o;function u(c,f){let d=c.getText(),p=l(f,(h,T)=>{let C=h.range.start.line-T.range.start.line;return C===0?h.range.start.character-T.range.start.character:C}),y=d.length;for(let h=p.length-1;h>=0;h--){let T=p[h],C=c.offsetAt(T.range.start),v=c.offsetAt(T.range.end);if(v<=y)d=d.substring(0,C)+T.newText+d.substring(v,d.length);else throw new Error("Overlapping edit");y=C}return d}s(u,"applyEdits"),a.applyEdits=u;function l(c,f){if(c.length<=1)return c;const d=c.length/2|0,p=c.slice(0,d),y=c.slice(d);l(p,f),l(y,f);let h=0,T=0,C=0;for(;h<p.length&&T<y.length;)f(p[h],y[T])<=0?c[C++]=p[h++]:c[C++]=y[T++];for(;h<p.length;)c[C++]=p[h++];for(;T<y.length;)c[C++]=y[T++];return c}s(l,"mergeSort")})(vm||(vm={})),av=(n=class{constructor(i,o,u,l){this._uri=i,this._languageId=o,this._version=u,this._content=l,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(i){if(i){let o=this.offsetAt(i.start),u=this.offsetAt(i.end);return this._content.substring(o,u)}return this._content}update(i,o){this._content=i.text,this._version=o,this._lineOffsets=void 0}getLineOffsets(){if(this._lineOffsets===void 0){let i=[],o=this._content,u=!0;for(let l=0;l<o.length;l++){u&&(i.push(l),u=!1);let c=o.charAt(l);u=c==="\r"||c===`
`,c==="\r"&&l+1<o.length&&o.charAt(l+1)===`
`&&l++}u&&o.length>0&&i.push(o.length),this._lineOffsets=i}return this._lineOffsets}positionAt(i){i=Math.max(Math.min(i,this._content.length),0);let o=this.getLineOffsets(),u=0,l=o.length;if(l===0)return oe.create(0,i);for(;u<l;){let f=Math.floor((u+l)/2);o[f]>i?l=f:u=f+1}let c=u-1;return oe.create(c,i-o[c])}offsetAt(i){let o=this.getLineOffsets();if(i.line>=o.length)return this._content.length;if(i.line<0)return 0;let u=o[i.line],l=i.line+1<o.length?o[i.line+1]:this._content.length;return Math.max(Math.min(u+i.character,l),u)}get lineCount(){return this.getLineOffsets().length}},s(n,"FullTextDocument"),n),(function(a){const i=Object.prototype.toString;function o(v){return typeof v<"u"}s(o,"defined"),a.defined=o;function u(v){return typeof v>"u"}s(u,"undefined"),a.undefined=u;function l(v){return v===!0||v===!1}s(l,"boolean"),a.boolean=l;function c(v){return i.call(v)==="[object String]"}s(c,"string"),a.string=c;function f(v){return i.call(v)==="[object Number]"}s(f,"number"),a.number=f;function d(v,w,b){return i.call(v)==="[object Number]"&&w<=v&&v<=b}s(d,"numberRange"),a.numberRange=d;function p(v){return i.call(v)==="[object Number]"&&-2147483648<=v&&v<=2147483647}s(p,"integer"),a.integer=p;function y(v){return i.call(v)==="[object Number]"&&0<=v&&v<=2147483647}s(y,"uinteger"),a.uinteger=y;function h(v){return i.call(v)==="[object Function]"}s(h,"func"),a.func=h;function T(v){return v!==null&&typeof v=="object"}s(T,"objectLiteral"),a.objectLiteral=T;function C(v,w){return Array.isArray(v)&&v.every(w)}s(C,"typedArray"),a.typedArray=C})(E||(E={}))}}),Wn=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/ral.js"(t){Object.defineProperty(t,"__esModule",{value:!0});var e;function r(){if(e===void 0)throw new Error("No runtime abstraction layer installed");return e}s(r,"RAL"),(function(n){function a(i){if(i===void 0)throw new Error("No runtime abstraction layer provided");e=i}s(a,"install"),n.install=a})(r||(r={})),t.default=r}}),xu=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/is.js"(t){Object.defineProperty(t,"__esModule",{value:!0}),t.stringArray=t.array=t.func=t.error=t.number=t.string=t.boolean=void 0;function e(l){return l===!0||l===!1}s(e,"boolean"),t.boolean=e;function r(l){return typeof l=="string"||l instanceof String}s(r,"string"),t.string=r;function n(l){return typeof l=="number"||l instanceof Number}s(n,"number"),t.number=n;function a(l){return l instanceof Error}s(a,"error"),t.error=a;function i(l){return typeof l=="function"}s(i,"func"),t.func=i;function o(l){return Array.isArray(l)}s(o,"array"),t.array=o;function u(l){return o(l)&&l.every(c=>r(c))}s(u,"stringArray"),t.stringArray=u}}),nl=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/events.js"(t){var i,o;Object.defineProperty(t,"__esModule",{value:!0}),t.Emitter=t.Event=void 0;var e=Wn(),r;(function(u){const l={dispose(){}};u.None=function(){return l}})(r||(t.Event=r={}));var n=(i=class{add(l,c=null,f){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(l),this._contexts.push(c),Array.isArray(f)&&f.push({dispose:s(()=>this.remove(l,c),"dispose")})}remove(l,c=null){if(!this._callbacks)return;let f=!1;for(let d=0,p=this._callbacks.length;d<p;d++)if(this._callbacks[d]===l)if(this._contexts[d]===c){this._callbacks.splice(d,1),this._contexts.splice(d,1);return}else f=!0;if(f)throw new Error("When adding a listener with a context, you should remove it with the same context")}invoke(...l){if(!this._callbacks)return[];const c=[],f=this._callbacks.slice(0),d=this._contexts.slice(0);for(let p=0,y=f.length;p<y;p++)try{c.push(f[p].apply(d[p],l))}catch(h){(0,e.default)().console.error(h)}return c}isEmpty(){return!this._callbacks||this._callbacks.length===0}dispose(){this._callbacks=void 0,this._contexts=void 0}},s(i,"CallbackList"),i),a=(o=class{constructor(l){this._options=l}get event(){return this._event||(this._event=(l,c,f)=>{this._callbacks||(this._callbacks=new n),this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(l,c);const d={dispose:s(()=>{this._callbacks&&(this._callbacks.remove(l,c),d.dispose=o._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))},"dispose")};return Array.isArray(f)&&f.push(d),d}),this._event}fire(l){this._callbacks&&this._callbacks.invoke.call(this._callbacks,l)}dispose(){this._callbacks&&(this._callbacks.dispose(),this._callbacks=void 0)}},s(o,"Emitter"),o);t.Emitter=a,a._noop=function(){}}}),Lf=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/cancellation.js"(t){var l,c;Object.defineProperty(t,"__esModule",{value:!0}),t.CancellationTokenSource=t.CancellationToken=void 0;var e=Wn(),r=xu(),n=nl(),a;(function(f){f.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:n.Even Line truncated
${JSON.stringify(Object.fromEntries(h))}`));return}const C=parseInt(T);if(isNaN(C)){this.fireError(new Error(`Content-Length value must be a number. Got ${T}`));return}this.nextMessageLength=C}const y=this.buffer.tryReadBody(this.nextMessageLength);if(y===void 0){this.setPartialMessageTimer();return}this.clearPartialMessageTimer(),this.nextMessageLength=-1,this.readSemaphore.lock(async()=>{const h=this.options.contentDecoder!==void 0?await this.options.contentDecoder.decode(y):y,T=await this.options.contentTypeDecoder.decode(h,this.options);this.callback(T)}).catch(h=>{this.fireError(h)})}}catch(y){this.fireError(y)}}clearPartialMessageTimer(){this.partialMessageTimer&&(this.partialMessageTimer.dispose(),this.partialMessageTimer=void 0)}setPartialMessageTimer(){this.clearPartialMessageTimer(),!(this._partialMessageTimeout<=0)&&(this.partialMessageTimer=(0,e.default)().timer.setTimeout((p,y)=>{this.partialMessageTimer=void 0,p===this.messageToken&&(this.firePartialMessage({messageToken:p,waitingTime:y}),this.setPartialMessageTimer())},this._partialMessageTimeout,this.messageToken,this._partialMessageTimeout))}},s(f,"ReadableStreamMessageReader"),f);t.ReadableStreamMessageReader=l}}),Tk=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/messageWriter.js"(t){var d,p;Object.defineProperty(t,"__esModule",{value:!0}),t.WriteableStreamMessageWriter=t.AbstractMessageWriter=t.MessageWriter=void 0;var e=Wn(),r=xu(),n=F$(),a=nl(),i="Content-Length: ",o=`\r
`,u;(function(y){function h(T){let C=T;return C&&r.func(C.dispose)&&r.func(C.onClose)&&r.func(C.onError)&&r.func(C.write)}s(h,"is"),y.is=h})(u||(t.MessageWriter=u={}));var l=(d=class{constructor(){this.errorEmitter=new a.Emitter,this.closeEmitter=new a.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(h,T,C){this.errorEmitter.fire([this.asError(h),T,C])}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}asError(h){return h instanceof Error?h:new Error(`Writer received error. Reason: ${r.string(h.message)?h.message:"unknown"}`)}},s(d,"AbstractMessageWriter"),d);t.AbstractMessageWriter=l;var c;(function(y){function h(T){return T===void 0||typeof T=="string"?{charset:T??"utf-8",contentTypeEncoder:(0,e.default)().applicationJson.encoder}:{charset:T.charset??"utf-8",contentEncoder:T.contentEncoder,contentTypeEncoder:T.contentTypeEncoder??(0,e.default)().applicationJson.encoder}}s(h,"fromOptions"),y.fromOptions=h})(c||(c={}));var f=(p=class extends l{constructor(h,T){super(),this.writable=h,this.options=c.fromOptions(T),this.errorCount=0,this.writeSemaphore=new n.Semaphore(1),this.writable.onError(C=>this.fireError(C)),this.writable.onClose(()=>this.fireClose())}async write(h){return this.writeSemaphore.lock(async()=>this.options.contentTypeEncoder.encode(h,this.options).then(C=>this.options.contentEncoder!==void 0?this.options.contentEncoder.encode(C):C).then(C=>{const v=[];return v.push(i,C.byteLength.toString(),o),v.push(o),this.doWrite(h,v,C)},C=>{throw this.fireError(C),C}))}async doWrite(h,T,C){try{return await this.writable.write(T.join(""),"ascii"),this.writable.write(C)}catch(v){return this.handleError(v,h),Promise.reject(v)}}handleError(h,T){this.errorCount++,this.fireError(h,T,this.errorCount)}end(){this.writable.end()}},s(p,"WriteableStreamMessageWriter"),p);t.WriteableStreamMessageWriter=f}}),$k=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/messageBuffer.js"(t){var i;Object.defineProperty(t,"__esModule",{value:!0}),t.AbstractMessageBuffer=void 0;var e=13,r=10,n=`\r
`,a=(i=class{constructor(u="utf-8"){this._encoding=u,this._chunks=[],this._totalLength=0}get encoding(){return this._encoding}append(u){const l=typeof u=="string"?this.fromString(u,this._encoding):u;this._chunks.push(l),this._totalLength+=l.byteLength}tryReadHeaders(u=!1){if(this._chunks.length===0)return;let l=0,c=0,f=0,d=0;e:for(;c<this._chunks.length;){const T=this._chunks[c];for(f=0;f<T.length;){switch(T[f]){case e:switch(l){case 0:l=1;break;case 2:l=3;break;default:l=0}break;case r:switch(l){case 1:l=2;break;case 3:l=4,f++;break e;default:l=0}break;default:l=0}f++}d+=T.byteLength,c++}if(l!==4)return;const p=this._read(d+f),y=new Map,h=this.toString(p,"ascii").split(n);if(h.length<2)return y;for(let T=0;T<h.length-2;T++){const C=h[T],v=C.indexOf(":");if(v===-1)throw new Error(`Message header must separate key and value using ':'
${C}`);const w=C.substr(0,v),b=C.substr(v+1).trim();y.set(u?w.toLowerCase():w,b)}return y}tryReadBody(u){if(!(this._totalLength<u))return this._read(u)}get numberOfBytes(){return this._totalLength}_read(u){if(u===0)return this.emptyBuffer();if(u>this._totalLength)throw new Error("Cannot read so many bytes!");if(this._chunks[0].byteLength===u){const d=this._chunks[0];return this._chunks.shift(),this._totalLength-=u,this.asNative(d)}if(this._chunks[0].byteLength>u){const d=this._chunks[0],p=this.asNative(d,u);return this._chunks[0]=d.slice(u),this._totalLength-=u,p}const l=this.allocNative(u);let c=0,f=0;for(;u>0;){const d=this._chunks[f];if(d.byteLength>u){const p=d.slice(0,u);l.set(p,c),c+=u,this._chunks[f]=d.slice(u),this._totalLength-=u,u-=u}else l.set(d,c),c+=d.byteLength,this._chunks.shift(),this._totalLength-=d.byteLength,u-=d.byteLength}return l}},s(i,"AbstractMessageBuffer"),i);t.AbstractMessageBuffer=a}}),Rk=X({"../../node_modules/.pnpm/[email protected]/node_modules/vscode-jsonrpc/lib/common/connection.js"(t){var k,_;Object.defineProperty(t,"__esModule",{value:!0}),t.createMessageConnection=t.ConnectionOptions=t.MessageStrategy=t.CancellationStrategy=t.CancellationSenderStrategy=t.CancellationReceiverStrategy=t.RequestCancellationReceiverStrategy=t.IdCancellationReceiverStrategy=t.ConnectionStrategy=t.ConnectionError=t.ConnectionErrors=t.LogTraceNotification=t.SetTraceNotification=t.TraceFormat=t.TraceValues=t.Trace=t.NullLogger=t.ProgressType=t.ProgressToken=void 0;var e=Wn(),r=xu(),n=M$(),a=G$(),i=nl(),o=Lf(),u;(function($){$.type=new n.NotificationType("$/cancelRequest")})(u||(u={}));var l;(function($){function I(R){return typeof R=="string"||typeof R=="number"}s(I,"is"),$.is=I})(l||(t.ProgressToken=l={}));var c;(function($){$.type=new n.NotificationType("$/progress")})(c||(c={}));var f=(k=class{constructor(){}},s(k,"ProgressType"),k);t.ProgressType=f;var d;(function($){function I(R){return r.func(R)}s(I,"is"),$.is=I})(d||(d={})),t.NullLogger=Object.freeze({error:s(()=>{},"error"),warn:s(()=>{},"warn"),info:s(()=>{},"info"),log:s(()=>{},"log")});var p;(function($){$[$.Off=0]="Off",$[$.Messages=1]="Messages",$[$.Compact=2]="Compact",$[$.Verbose=3]="Verbose"})(p||(t.Trace=p={}));var y;(function($){$.Off="off",$.Messages="messages",$.Compact="compact",$.Verbose="verbose"})(y||(t.TraceValues=y={})),(function($){function I(A){if(!r.string(A))return $.Off;switch(A=A.toLowerCase(),A){case"off":return $.Off;case"messages":return $.Messages;case"compact":return $.Compact;case"verbose":return $.Verbose;default:return $.Off}}s(I,"fromString"),$.fromString=I;function R(A){switch(A){case $.Off:return"off";case $.Messages:return"messages";case $.Compact:return"compact";case $.Verbose:return"verbose";default:return"off"}}s(R,"toString"),$.toString=R})(p||(t.Trace=p={}));var h;(function($){$.Text="text",$.JSON="json"})(h||(t.TraceFormat=h={})),(function($){function I(R){return r.string(R)?(R=R.toLowerCase(),R==="json"?$.JSON:$.Text):$.Text}s(I,"fromString"),$.fromString=I})(h||(t.TraceFormat=h={}));var T;(function($){$.type=new n.NotificationType("$/setTrace")})(T||(t.SetTraceNotification=T={}));var C;(function($){$.type=new n.NotificationType("$/logTrace")})(C||(t.LogTraceNotification=C={}));var v;(function($){$[$.Closed=1]="Closed",$[$.Disposed=2]="Disposed",$[$.AlreadyListening=3]="AlreadyListening"})(v||(t.ConnectionErrors=v={}));var w=(_=class extends Error{constructor(I,R){super(R),this.code=I,Object.setPrototypeOf(this,_.prototype)}},s(_,"ConnectionError"),_);t.ConnectionError=w;var b;(function($){function I(R){const A=R;return A&&r.func(A.cancelUndispatched)}s(I,"is"),$.is=I})(b||(t.ConnectionStrategy=b={}));var N;(function($){function I(R){const A=R;return A&&(A.kind===void 0||A.kind==="id")&&r.func(A.createCancellationTokenSource)&&(A.dispose===void 0||r.func(A.dispose))}s(I,"is"),$.is=I})(N||(t.IdCancellationReceiverStrategy=N={}));var B;(function($){function I(R){const A=R;return A&&A.kind==="request"&&r.func(A.createCancellationTokenSource)&&(A.dispose===void 0||r.func(A.dispose))}s(I,"is"),$.is=I})(B||(t.RequestCancellationReceiverStrategy=B={}));var ne;(function($){$.Message=Object.freeze({createCancellationTokenSource(R){return new o.CancellationTokenSource}});function I(R){return N.is(R)||B.is(R)}s(I,"is"),$.is=I})(ne||(t.CancellationReceiverStrategy=ne={}));var J;(function($){$.Message=Object.freeze({sendCancellation(R,A){return R.sendNotification(u.type,{id:A})},cleanup(R){}});function I(R){const A=R;return A&&r.func(A.sendCancellation)&&r.func(A.cleanup)}s(I,"is"),$.is=I})(J||(t.CancellationSenderStrategy=J={}));var he;(function($){$.Message=Object.freeze({receiver:ne.Message,sender:J.Message});function I(R){const A=R;return A&&ne.is(A.receiver)&&J.is(A.sender)}s(I,"is"),$.is=I})(he||(t.CancellationStrategy=he={}));var Ae;(function($){function I(R){const A=R;return A&&r.func(A.handleMessage)}s(I,"is"),$.is=I})(Ae||(t.MessageStrategy=Ae={}));var ye;(function($){function I(R){const A=R;ret Line truncated
${JSON.stringify(g.error,void 0,4)}`):S.error("Received response message without id. No further error information provided.");else{const P=g.id,D=Ee.get(P);if(wl(g,D),D!==void 0){Ee.delete(P);try{if(g.error){const F=g.error;D.reject(new n.ResponseError(F.code,F.message,F.data))}else if(g.result!==void 0)D.resolve(g.result);else throw new Error("Should never happen.")}catch(F){F.message?S.error(`Response handler '${D.method}' failed with message: ${F.message}`):S.error(`Response handler '${D.method}' failed unexpectedly.`)}}}}s(Al,"handleResponse");function El(g){if(er())return;let P,D;if(g.method===u.type.method){const F=g.params.id;Ve.delete(F),sn(g);return}else{const F=Z.get(g.method);F&&(D=F.handler,P=F.type)}if(D||q)try{if(sn(g),D)if(g.params===void 0)P!==void 0&&P.numberOfParams!==0&&P.parameterStructures!==n.ParameterStructures.byName&&S.error(`Notification ${g.method} defines ${P.numberOfParams} params but received none.`),D();else if(Array.isArray(g.params)){const F=g.params;g.method===c.type.method&&F.length===2&&l.is(F[0])?D({token:F[0],value:F[1]}):(P!==void 0&&(P.parameterStructures===n.ParameterStructures.byName&&S.error(`Notification ${g.method} defines parameters by name but received parameters by position`),P.numberOfParams!==g.params.length&&S.error(`Notification ${g.method} defines ${P.numberOfParams} params but received ${F.length} arguments`)),D(...F))}else P!==void 0&&P.parameterStructures===n.ParameterStructures.byPosition&&S.error(`Notification ${g.method} defines parameters by position but received parameters by name`),D(g.params);else q&&q(g.method,g.params)}catch(F){F.message?S.error(`Notification handler '${g.method}' failed with message: ${F.message}`):S.error(`Notification handler '${g.method}' failed unexpectedly.`)}else je.fire(g)}s(El,"handleNotification");function Cl(g){if(!g){S.error("Received empty message.");return}S.error(`Received message which is neither a response nor a notification message:
${JSON.stringify(g,null,4)}`);const P=g;if(r.string(P.id)||r.number(P.id)){const D=P.id,F=Ee.get(D);F&&F.reject(new Error("The received response has neither a result nor an error property."))}}s(Cl,"handleInvalidMessage");function xt(g){if(g!=null)switch(ee){case p.Verbose:return JSON.stringify(g,null,4);case p.Compact:return JSON.stringify(g);default:return}}s(xt,"stringifyTrace");function bl(g){if(!(ee===p.Off||!ce))if(Qe===h.Text){let P;(ee===p.Verbose||ee===p.Compact)&&g.params&&(P=`Params: ${xt(g.params)}
`),ce.log(`Sending request '${g.method} - (${g.id})'.`,P)}else tr("send-request",g)}s(bl,"traceSendingRequest");function _l(g){if(!(ee===p.Off||!ce))if(Qe===h.Text){let P;(ee===p.Verbose||ee===p.Compact)&&(g.params?P=`Params: ${xt(g.params)}
`:P=`No parameters provided.
`),ce.log(`Sending notification '${g.method}'.`,P)}else tr("send-notification",g)}s(_l,"traceSendingNotification");function jr(g,P,D){if(!(ee===p.Off||!ce))if(Qe===h.Text){let F;(ee===p.Verbose||ee===p.Compact)&&(g.error&&g.error.data?F=`Error data: ${xt(g.error.data)}
`:g.result?F=`Result: ${xt(g.result)}
`:g.error===void 0&&(F=`No result returned.
`)),ce.log(`Sending response '${P} - (${g.id})'. Processing request took ${Date.now()-D}ms`,F)}else tr("send-response",g)}s(jr,"traceSendingResponse");function Sl(g){if(!(ee===p.Off||!ce))if(Qe===h.Text){let P;(ee===p.Verbose||ee===p.Compact)&&g.params&&(P=`Params: ${xt(g.params)}
`),ce.log(`Received request '${g.method} - (${g.id})'.`,P)}else tr("receive-request",g)}s(Sl,"traceReceivedRequest");function sn(g){if(!(ee===p.Off||!ce||g.method===C.type.method))if(Qe===h.Text){let P;(ee===p.Verbose||ee===p.Compact)&&(g.params?P=`Params: ${xt(g.params)}
`:P=`No parameters provided.
`),ce.log(`Received notification '${g.method}'.`,P)}else tr("receive-notification",g)}s(sn,"traceReceivedNotification");function wl(g,P){if(!(ee===p.Off||!ce))if(Qe===h.Text){let D;if((ee===p.Verbose||ee===p.Compact)&&(g.error&&g.error.data?D=`Error data: ${xt(g.error.data)}
`:g.result?D=`Result: ${xt(g.result)}
`:g.error===void 0&&(D=`No result returned.
`)),P){const F=g.error?` Request failed: ${g.error.message} (${g.error.code}).`:"";ce.log(`Received response '${P.method} - (${g.id})' in ${Date.now()-P.timerStart}ms.${F}`,D)}else ce.log(`Received response ${g.id} without active response promise.`,D)}else tr("receive-response",g)}s(wl,"traceReceivedResponse");function tr(g,P){if(!ce||ee===p.Off)return;const D={isLSPMessage:!0,type:g,message:P,timestamp:Date.now()};ce.log(D)}s(tr,"logLSPMessage");function Tr(){if(ma())throw new w(v.Closed,"Connection is closed.");if(er())throw new w(v.Disposed,"Connection is disposed.")}s(Tr,"throwIfClosedOrDisposed");function Il(){if(pa())throw new w(v.AlreadyListening,"Connection is already listening")}s(Il,"throwIfListening");function Nl(){if(!pa())throw new Error("Call listen() first.")}s(Nl,"throwIfNotListening");function m(g){return g===void 0?null:g}s(m,"undefinedToNull");function le(g){if(g!==null)return g}s(le,"nullToUndefined");function we(g){return g!=null&&!Array.isArray(g)&&typeof g=="object"}s(we,"isNamedParam");function H(g,P){switch(g){case n.ParameterStructures.auto:return we(P)?le(P):[m(P)];case n.ParameterStructures.byName:if(!we(P))throw new Error("Received parameters by name but param is not an object literal.");return le(P);case n.ParameterStructures.byPosition:return[m(P)];default:throw new Error(`Unknown parameter structure ${g.toString()}`)}}s(H,"computeSingleParam");function Ie(g,P){let D;const F=g.numberOfParams;switch(F){case 0:D=void 0;break;case 1:D=H(g.parameterStructures,P[0]);break;default:D=[];for(let Ce=0;Ce<P.length&&Ce<F;Ce++)D.push(m(P[Ce]));if(P.length<F)for(let Ce=P.length;Ce<F;Ce++)D.push(null);break}return D}s(Ie,"computeMessageParams");const va={sendNotification:s((g,...P)=>{Tr();let D,F;if(r.string(g)){D=g;const me=P[0];let De=0,Ge=n.ParameterStructures.auto;n.ParameterStructures.is(me)&&(De=1,Ge=me);let ie=P.length;const Ne=ie-De;switch(Ne){case 0:F=void 0;break;case 1:F=H(Ge,P[De]);break;default:if(Ge===n.ParameterStructures.byName)throw new Error(`Received ${Ne} parameters for 'by Name' notification parameter structure.`);F=P.slice(De,ie).map(fe=>m(fe));break}}else{const me=P;D=g.method,F=Ie(g,me)}const Ce={jsonrpc:z,method:D,params:F};return _l(Ce),I.write(Ce).catch(me=>{throw S.error("Sending notification failed."),me})},"sendNotification"),onNotification:s((g,P)=>{Tr();let D;return r.func(g)?q=g:P&&(r.string(g)?(D=g,Z.set(g,{type:void 0,handler:P})):(D=g.method,Z.set(g.method,{type:g,handler:P}))),{dispose:s(()=>{D!==void 0?Z.delete(D):q=void 0},"dispose")}},"onNotification"),onProgress:s((g,P,D)=>{if(ae.has(P))throw new Error(`Progress handler for token ${P} already registered`);return ae.set(P,D),{dispose:s(()=>{ae.delete(P)},"dispose")}},"onProgress"),sendProgress:s((g,P,D)=>va.sendNotification(c.type,{token:P,value:D}),"sendProgress"),onUnhandledProgress:Qt.event,sendRequest:s((g,...P)=>{Tr(),Nl();let D,F,Ce;if(r.string(g)){D=g;const ie=P[0],Ne=P[P.length-1];let fe=0,Ue=n.ParameterStructures.auto;n.ParameterStructures.is(ie)&&(fe=1,Ue=ie);let lt=P.length;o.CancellationToken.is(Ne)&&(lt=lt-1,Ce=Ne);const rr=lt-fe;switch(rr){case 0:F=void 0;break;case 1:F=H(Ue,P[fe]);break;default:if(Ue===n.ParameterStructures.byName)throw new Error(`Received ${rr} parameters for 'by Name' request parameter structure.`);F=P.slice(fe,lt).map(ck=>m(ck));break}}else{const ie=P;D=g.method,F=Ie(g,ie);const Ne=g.numberOfParams;Ce=o.CancellationToken.is(ie[Ne])?ie[Ne]:void 0}const me=L++;let De;Ce&&(De=Ce.onCancellationRequested(()=>{const ie=ve.sender.sendCancellation(va,me);return ie===void 0?(S.log(`Received no promise from cancellation strategy when cancelling id ${me}`),Promise.resolve()):ie.catch(()=>{S.log(`Sending cancellation messages for id ${me} failed`)})}));const Ge={jsonrpc:z,id:me,method:D,params:F};return bl(Ge),typeof ve.sender.enableCancellation=="function"&&ve.sender.enableCancellation(Ge),new Promise(async(ie,Ne)=>{const fe=s(rr=>{ie(rr),ve.sender.cleanup(me),De?.dispose()},"resolveWithCleanup"),Ue=s(rr=>{Ne(rr),ve.sender.cleanup(me),De?.dispose()},"rejectWithCleanup"),lt={method:D,timerStart:Date.now(),resolve:fe,reject:Ue};try{await I.write(Ge),Ee.set(me,lt)}catch(rr){throw S.error("Sending request failed."),lt.reject(new n.ResponseError(n.ErrorCodes.MessageWriteError,rr.message?rr.message:"Unknown reason")),rr}})},"sendRequest"),onRequest:s((g,P)=>{Tr();let D=null;return d.is(g)?(D=void 0,M=g):r.string(g)?(D=null,P!==void 0&&(D=g,Y.set(g,{handler:P,type:void 0}))):P!==void 0&&(D=g.method,Y.set(g.method,{type:g,handler:P})),{dispose:s(()=>{D!==null&&(D!==void 0?Y.delete(D):M=void 0)},"dispose")}},"onRequest"),hasPendingResponse:s(()=>Ee.size>0,"hasPendingResponse"),trace:s(async(g,P,D)=>{let F=!1,Ce=h.Text;D!==void 0&&(r.boolean(D)?F=D:(F=D.sendNotification||!1,Ce=D.traceFormat||h.Text)),ee=g,Qe=Ce,ee===p.Off?ce=void 0:ce=P,F&&!ma()&&!er()&&await va.sendNotification(T.type,{value:p.toString(g)})},"trace"),onError:ge.event,onClose:G.event,onUnhandledNotification:je.event,onD Line truncated
`),W("\r"),W(" "),W("\v"),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W(" "),W("\u2028"),W("\u2029"),W(" "),W(" "),W(" "),W("\uFEFF")],Yk=/[0-9a-fA-F]/,nc=/[0-9]/,Xk=/[1-9]/,ri,mR=(ri=class{constructor(){this.idx=0,this.input="",this.groupIdx=0}saveState(){return{idx:this.idx,input:this.input,groupIdx:this.groupIdx}}restoreState(e){this.idx=e.idx,this.input=e.input,this.groupIdx=e.groupIdx}pattern(e){this.idx=0,this.input=e,this.groupIdx=0,this.consumeChar("/");const r=this.disjunction();this.consumeChar("/");const n={type:"Flags",loc:{begin:this.idx,end:e.length},global:!1,ignoreCase:!1,multiLine:!1,unicode:!1,sticky:!1};for(;this.isRegExpFlag();)switch(this.popChar()){case"g":Ia(n,"global");break;case"i":Ia(n,"ignoreCase");break;case"m":Ia(n,"multiLine");break;case"u":Ia(n,"unicode");break;case"y":Ia(n,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:n,value:r,loc:this.loc(0)}}disjunction(){const e=[],r=this.idx;for(e.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),e.push(this.alternative());return{type:"Disjunction",value:e,loc:this.loc(r)}}alternative(){const e=[],r=this.idx;for(;this.isTerm();)e.push(this.term());return{type:"Alternative",value:e,loc:this.loc(r)}}term(){return this.isAssertion()?this.assertion():this.atom()}assertion(){const e=this.idx;switch(this.popChar()){case"^":return{type:"StartAnchor",loc:this.loc(e)};case"$":return{type:"EndAnchor",loc:this.loc(e)};case"\\":switch(this.popChar()){case"b":return{type:"WordBoundary",loc:this.loc(e)};case"B":return{type:"NonWordBoundary",loc:this.loc(e)}}throw Error("Invalid Assertion Escape");case"(":this.consumeChar("?");let r;switch(this.popChar()){case"=":r="Lookahead";break;case"!":r="NegativeLookahead";break;case"<":{switch(this.popChar()){case"=":r="Lookbehind";break;case"!":r="NegativeLookbehind"}break}}mn(r);const n=this.disjunction();return this.consumeChar(")"),{type:r,value:n,loc:this.loc(e)}}return pR()}quantifier(e=!1){let r;const n=this.idx;switch(this.popChar()){case"*":r={atLeast:0,atMost:1/0};break;case"+":r={atLeast:1,atMost:1/0};break;case"?":r={atLeast:0,atMost:1};break;case"{":const a=this.integerIncludingZero();switch(this.popChar()){case"}":r={atLeast:a,atMost:a};break;case",":let i;this.isDigit()?(i=this.integerIncludingZero(),r={atLeast:a,atMost:i}):r={atLeast:a,atMost:1/0},this.consumeChar("}");break}if(e===!0&&r===void 0)return;mn(r);break}if(!(e===!0&&r===void 0)&&mn(r))return this.peekChar(0)==="?"?(this.consumeChar("?"),r.greedy=!1):r.greedy=!0,r.type="Quantifier",r.loc=this.loc(n),r}atom(){let e;const r=this.idx;switch(this.peekChar()){case".":e=this.dotAll();break;case"\\":e=this.atomEscape();break;case"[":e=this.characterClass();break;case"(":e=this.group();break}if(e===void 0&&this.isPatternCharacter()&&(e=this.patternCharacter()),mn(e))return e.loc=this.loc(r),this.isQuantifier()&&(e.quantifier=this.quantifier()),e}dotAll(){return this.consumeChar("."),{type:"Set",complement:!0,value:[W(`
`),W("\r"),W("\u2028"),W("\u2029")]}}atomEscape(){switch(this.consumeChar("\\"),this.peekChar()){case"1":case"2":case"3":case"4":case"5":case"6":case"7":case"8":case"9":return this.decimalEscapeAtom();case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}}decimalEscapeAtom(){return{type:"GroupBackReference",value:this.positiveInteger()}}characterClassEscape(){let e,r=!1;switch(this.popChar()){case"d":e=lf;break;case"D":e=lf,r=!0;break;case"s":e=sv;break;case"S":e=sv,r=!0;break;case"w":e=uf;break;case"W":e=uf,r=!0;break}if(mn(e))return{type:"Set",value:e,complement:r}}controlEscapeAtom(){let e;switch(this.popChar()){case"f":e=W("\f");break;case"n":e=W(`
`);break;case"r":e=W("\r");break;case"t":e=W(" ");break;case"v":e=W("\v");break}if(mn(e))return{type:"Character",value:e}}controlLetterEscapeAtom(){this.consumeChar("c");const e=this.popChar();if(/[a-zA-Z]/.test(e)===!1)throw Error("Invalid ");return{type:"Character",value:e.toUpperCase().charCodeAt(0)-64}}nulCharacterAtom(){return this.consumeChar("0"),{type:"Character",value:W("\0")}}hexEscapeSequenceAtom(){return this.consumeChar("x"),this.parseHexDigits(2)}regExpUnicodeEscapeSequenceAtom(){return this.consumeChar("u"),this.parseHexDigits(4)}identityEscapeAtom(){const e=this.popChar();return{type:"Character",value:W(e)}}classPatternCharacterAtom(){switch(this.peekChar()){case`
`:case"\r":case"\u2028":case"\u2029":case"\\":case"]":throw Error("TBD");default:const e=this.popChar();return{type:"Character",value:W(e)}}}characterClass(){const e=[];let r=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),r=!0);this.isClassAtom();){const n=this.classAtom();if(n.type,Rm(n)&&this.isRangeDash()){this.consumeChar("-");const a=this.classAtom();if(a.type,Rm(a)){if(a.value<n.value)throw Error("Range out of order in character class");e.push({from:n.value,to:a.value})}else wc(n.value,e),e.push(W("-")),wc(a.value,e)}else wc(n.value,e)}return this.consumeChar("]"),{type:"Set",complement:r,value:e}}classAtom(){switch(this.peekChar()){case"]":case`
`:case"\r":case"\u2028":case"\u2029":throw Error("TBD");case"\\":return this.classEscape();default:return this.classPatternCharacterAtom()}}classEscape(){switch(this.consumeChar("\\"),this.peekChar()){case"b":return this.consumeChar("b"),{type:"Character",value:W("\b")};case"d":case"D":case"s":case"S":case"w":case"W":return this.characterClassEscape();case"f":case"n":case"r":case"t":case"v":return this.controlEscapeAtom();case"c":return this.controlLetterEscapeAtom();case"0":return this.nulCharacterAtom();case"x":return this.hexEscapeSequenceAtom();case"u":return this.regExpUnicodeEscapeSequenceAtom();default:return this.identityEscapeAtom()}}group(){let e=!0;this.consumeChar("("),this.peekChar(0)==="?"?(this.consumeChar("?"),this.consumeChar(":"),e=!1):this.groupIdx++;const r=this.disjunction();this.consumeChar(")");const n={type:"Group",capturing:e,value:r};return e&&(n.idx=this.groupIdx),n}positiveInteger(){let e=this.popChar();if(Xk.test(e)===!1)throw Error("Expecting a positive integer");for(;nc.test(this.peekChar(0));)e+=this.popChar();return parseInt(e,10)}integerIncludingZero(){let e=this.popChar();if(nc.test(e)===!1)throw Error("Expecting an integer");for(;nc.test(this.peekChar(0));)e+=this.popChar();return parseInt(e,10)}patternCharacter(){const e=this.popChar();switch(e){case`
`:case"\r":case"\u2028":case"\u2029":case"^":case"$":case"\\":case".":case"*":case"+":case"?":case"(":case")":case"[":case"|":throw Error("TBD");default:return{type:"Character",value:W(e)}}}isRegExpFlag(){switch(this.peekChar(0)){case"g":case"i":case"m":case"u":case"y":return!0;default:return!1}}isRangeDash(){return this.peekChar()==="-"&&this.isClassAtom(1)}isDigit(){return nc.test(this.peekChar(0))}isClassAtom(e=0){switch(this.peekChar(e)){case"]":case`
`:case"\r":case"\u2028":case"\u2029":return!1;default:return!0}}isTerm(){return this.isAtom()||this.isAssertion()}isAtom(){if(this.isPatternCharacter())return!0;switch(this.peekChar(0)){case".":case"\\":case"[":case"(":return!0;default:return!1}}isAssertion(){switch(this.peekChar(0)){case"^":case"$":return!0;case"\\":switch(this.peekChar(1)){case"b":case"B":return!0;default:return!1}case"(":return this.peekChar(1)==="?"&&(this.peekChar(2)==="="||this.peekChar(2)==="!"||this.peekChar(2)==="<"&&(this.peekChar(3)==="="||this.peekChar(3)==="!"));default:return!1}}isQuantifier(){const e=this.saveState();try{return this.quantifier(!0)!==void 0}catch{return!1}finally{this.restoreState(e)}}isPatternCharacter(){switch(this.peekChar()){case"^":case"$":case"\\":case".":case"*":case"+":case"?":case"(":case")":case"[":case"|":case"/":case`
`:case"\r":case"\u2028":case"\u2029":return!1;default:return!0}}parseHexDigits(e){let r="";for(let a=0;a<e;a++){const i=this.popChar();if(Yk.test(i)===!1)throw Error("Expecting a HexDecimal digits");r+=i}return{type:"Character",value:parseInt(r,16)}}peekChar(e=0){return this.input[this.idx+e]}popChar(){const e=this.peekChar(0);return this.consumeChar(void 0),e}consumeChar(e){if(e!==void 0&&this.input[this.idx]!==e)throw Error("Expected: '"+e+"' but found: '"+this.input[this.idx]+"' at offset: "+this.idx);if(this.idx>=this.input.length)throw Error("Unexpected end of input");this.idx++}loc(e){return{begin:e,end:this.idx}}},s(ri,"RegExpParser"),ri),ni,Kf=(ni=class{visitChildren(e){for(const r in e){const n=e[r];e.hasOwnProperty(r)&&(n.type!==void 0?this.visit(n):Array.isArray(n)&&n.forEach(a=>{this.visit(a)},this))}}visit(e){switch(e.type){case"Pattern":this.visitPattern(e);break;case"Flags":this.visitFlags(e);break;case"Disjunction":this.visitDisjunction(e);break;case"Alternative":this.visitAlternative(e);break;case"StartAnchor":this.visitStartAnchor(e);break;case"EndAnchor":this.visitEndAnchor(e);break;case"WordBoundary":this.visitWordBoundary(e);break;case"NonWordBoundary":this.visitNonWordBoundary(e);break;case"Lookahead":this.visitLookahead(e);break;case"NegativeLookahead":this.visitNegativeLookahead(e);break;case"Lookbehind":this.visitLookbehind(e);break;case"NegativeLookbehind":this.visitNegativeLookbehind(e);break;case"Character":this.visitCharacter(e);break;case"Set":this.visitSet(e);break;case"Group":this.visitGroup(e);break;case"GroupBackReference":this.visitGroupBackReference(e);break;case"Quantifier":this.visitQuantifier(e);break}this.visitChildren(e)}visitPattern(e){}visitFlags(e){}visitDisjunction(e){}visitAlternative(e){}visitStartAnchor(e){}visitEndAnchor(e){}visitWordBoundary(e){}visitNonWordBoundary(e){}visitLookahead(e){}visitNegativeLookahead(e){}visitLookbehind(e){}visitNegativeLookbehind(e){}visitCharacter(e){}visitSet(e){}visitGroup(e){}visitGroupBackReference(e){}visitQuantifier(e){}},s(ni,"BaseRegExpVisitor"),ni),hR=/\r?\n/gm,yR=new mR,ai,Jk=(ai=class extends Kf{constructor(){super(...arguments),this.isStarting=!0,this.endRegexpStack=[],this.multiline=!1}get endRegex(){return this.endRegexpStack.join("")}reset(e){this.multiline=!1,this.regex=e,this.startRegexp="",this.isStarting=!0,this.endRegexpStack=[]}visitGroup(e){e.quantifier&&(this.isStarting=!1,this.endRegexpStack=[])}visitCharacter(e){const r=String.fromCharCode(e.value);if(!this.multiline&&r===`
`&&(this.multiline=!0),e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const n=il(r);this.endRegexpStack.push(n),this.isStarting&&(this.startRegexp+=n)}}visitSet(e){if(!this.multiline){const r=this.regex.substring(e.loc.begin,e.loc.end),n=new RegExp(r);this.multiline=!!`
`.match(n)}if(e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const r=this.regex.substring(e.loc.begin,e.loc.end);this.endRegexpStack.push(r),this.isStarting&&(this.startRegexp+=r)}}visitChildren(e){e.type==="Group"&&e.quantifier||super.visitChildren(e)}},s(ai,"TerminalRegExpVisitor"),ai),On=new Jk;function gR(t){try{typeof t!="string"&&(t=t.source),t=`/${t}/`;const e=yR.pattern(t),r=[];for(const n of e.value.value)On.reset(t),On.visit(n),r.push({start:On.startRegexp,end:On.endRegex});return r}catch{return[]}}s(gR,"getTerminalParts");function iy(t){try{return typeof t=="string"&&(t=new RegExp(t)),t=t.toString(),On.reset(t),On.visit(yR.pattern(t)),On.multiline}catch{return!1}}s(iy,"isMultilineComment");var vR=`\f
\r \v              \u2028\u2029   \uFEFF`.split("");function Wf(t){const e=typeof t=="string"?new RegExp(t):t;return vR.some(r=>e.test(r))}s(Wf,"isWhitespace");function il(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}s(il,"escapeRegExp");function sy(t,e){const r=oy(t),n=e.match(r);return!!n&&n[0].length>0}s(sy,"partialMatches");function oy(t){typeof t=="string"&&(t=new RegExp(t));const e=t,r=t.source;let n=0;function a(){let i="",o;function u(c){i+=r.substr(n,c),n+=c}s(u,"appendRaw");function l(c){i+="(?:"+r.substr(n,c)+"|$)",n+=c}for(s(l,"appendOptional");n<r.length;)switch(r[n]){case"\\":switch(r[n+1]){case"c":l(3);break;case"x":l(4);break;case"u":e.unicode?r[n+2]==="{"?l(r.indexOf("}",n)-n+1):l(6):l(2);break;case"p":case"P":e.unicode?l(r.indexOf("}",n)-n+1):l(2);break;case"k":l(r.indexOf(">",n)-n+1);break;default:l(2);break}break;case"[":o=/\[(?:\\.|.)*?\]/g,o.lastIndex=n,o=o.exec(r)||[],l(o[0].length);break;case"|":case"^":case"$":case"*":case"+":case"?":u(1);break;case"{":o=/\{\d+,?\d*\}/g,o.lastIndex=n,o=o.exec(r),o?u(o[0].length):l(1);break;case"(":if(r[n+1]==="?")switch(r[n+2]){case":":i+="(?:",n+=3,i+=a()+"|$)";break;case"=":i+="(?=",n+=3,i+=a()+")";break;case"!":o=n,n+=3,a(),i+=r.substr(o,n-o);break;case"<":switch(r[n+3]){case"=":case"!":o=n,n+=4,a(),i+=r.substr(o,n-o);break;default:u(r.indexOf(">",n)-n+1),i+=a()+"|$)";break}break}else u(1),i+=a()+"|$)";break;case")":return++n,i;default:l(1);break}return i}return s(a,"process"),new RegExp(a(),t.flags)}s(oy,"partialRegExp");function ly(t){return t.rules.find(e=>mt(e)&&e.entry)}s(ly,"getEntryRule");function uy(t){return t.rules.filter(e=>jt(e)&&e.hidden)}s(uy,"getHiddenRules");function Vf(t,e){const r=new Set,n=ly(t);if(!n)return new Set(t.rules);const a=[n].concat(uy(t));for(const o of a)cy(o,r,e);const i=new Set;for(const o of t.rules)(r.has(o.name)||jt(o)&&o.hidden)&&i.add(o);return i}s(Vf,"getAllReachableRules");function cy(t,e,r){e.add(t.name),Mr(t).forEach(n=>{if(Nr(n)||r&&Ff(n)){const a=n.rule.ref;a&&!e.has(a.name)&&cy(a,e,r)}})}s(cy,"ruleDfs");function TR(t){const e=new Set;return Mr(t).forEach(r=>{Yn(r)&&(mt(r.type.ref)&&e.add(r.type.ref),Gu(r.type.ref)&&mt(r.type.ref.$container)&&e.add(r.type.ref.$container))}),e}s(TR,"getAllRulesUsedForCrossReferences");function fy(t){if(t.terminal)return t.terminal;if(t.type.ref)return Xf(t.type.ref)?.terminal}s(fy,"getCrossReferenceTerminal");function dy(t){return t.hidden&&!Wf(ju(t))}s(dy,"isCommentTerminal");function py(t,e){return!t||!e?[]:Hf(t,e,t.astNode,!0)}s(py,"findNodesForProperty");function qf(t,e,r){if(!t||!e)return;const n=Hf(t,e,t.astNode,!0);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}s(qf,"findNodeForProperty");function Hf(t,e,r,n){if(!n){const a=qn(t.grammarSource,wr);if(a&&a.feature===e)return[t]}return Sr(t)&&t.astNode===r?t.content.flatMap(a=>Hf(a,e,r,!1)):[]}s(Hf,"findNodesForPropertyInternal");function $R(t,e){return t?Yf(t,e,t?.astNode):[]}s($R,"findNodesForKeyword");function my(t,e,r){if(!t)return;const n=Yf(t,e,t?.astNode);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}s(my,"findNodeForKeyword");function Yf(t,e,r){if(t.astNode!==r)return[];if(Ir(t.grammarSource)&&t.grammarSource.value===e)return[t];const n=Jo(t).iterator();let a;const i=[];do if(a=n.next(),!a.done){const o=a.value;o.astNode===r?Ir(o.grammarSource)&&o.grammarSource.value===e&&i.push(o):n.prune()}while(!a.done);return i}s(Yf,"findNodesForKeywordInternal");function hy(t){const e=t.astNode;for(;e===t.container?.astNode;){const r=qn(t.grammarSource,wr);if(r)return r;t=t.container}}s(hy,"findAssignment");function Xf(t){let e=t;return Gu(e)&&(Yr(e.$container)?e=e.$container.$container:Hn(e.$container)?e=e.$container:tn(e.$container)),yy(t,e,new Map)}s(Xf,"findNameAssignment");function yy(t,e,r){function n(a,i){let o;return qn(a,wr)||(o=yy(i,i,r)),r.set(t,o),o}if(s(n,"go"),r.has(t))return r.get(t);r.set(t,void 0);for(const a of Mr(e)){if(wr(a)&&a.feature.toLowerCase()==="name")return r.set(t,a),a;if(Nr(a)&&mt(a.rule.ref))return n(a,a.rule.ref);if(Gf(a)&&a.typeRef?.ref)return n(a,a.typeRef.ref)}}s(yy,"findNameAssignmentInternal");function gy(t){const e=t.$container;if(Xn(e)){const r=e.elements,n=r.indexOf(t);for(let a=n-1;a>=0;a--){const i=r[a];if(Yr(i))return i;{const o=Mr(r[a]).find(Yr);if(o)return o}}}if(xf(e))return gy(e)}s(gy,"getActionAtElement");function RR(t,e){return t==="?"||t==="*"||Xn(e)&&!!e.guardCondition}s(RR,"isOptionalCardinality");function AR(t){return t==="*"||t==="+"}s(AR,"isArrayCardinality");function ER(t){return t==="+="}s(ER,"isArrayOperator");function Fu(t){return vy(t,new Set)}s(Fu,"isDataTypeRule");function vy(t,e){if(e.has(t))return!0;e.add(t);for(const r of Mr(t))if(Nr(r)){if(!r.rule.ref||mt(r.rule.ref)&&!vy(r.rule.ref,e)||Xo(r.rule.ref))return!1}else{if(wr(r))return!1;if(Yr(r))return!1}return!!t.definition}s(vy,"isDataTypeRuleInternal");function CR(t){return cf(t.type,new Set)}s(CR,"isDat Line truncated
`;function Fb(t,e=!1){try{const r=Ju(t);return hf(r.value,{},r.flags.ignoreCase)}catch(r){if(r.message===Gb)e&&Uy(`${mf} Unable to optimize: < ${t.toString()} >
Complement Sets cannot be automatically optimized.
This will disable the lexer's first char optimizations.
See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#COMPLEMENT for details.`);else{let n="";e&&(n=`
This will disable the lexer's first char optimizations.
See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),pf(`${mf}
Failed parsing: < ${t.toString()} >
Using the @chevrotain/regexp-to-ast library
Please open an issue at: https://github.com/chevrotain/chevrotain/issues`+n)}}return[]}s(Fb,"getOptimizedStartCodesIndices");function hf(t,e,r){switch(t.type){case"Disjunction":for(let a=0;a<t.value.length;a++)hf(t.value[a],e,r);break;case"Alternative":const n=t.value;for(let a=0;a<n.length;a++){const i=n[a];switch(i.type){case"EndAnchor":case"GroupBackReference":case"Lookahead":case"NegativeLookahead":case"Lookbehind":case"NegativeLookbehind":case"StartAnchor":case"WordBoundary":case"NonWordBoundary":continue}const o=i;switch(o.type){case"Character":Xl(o.value,e,r);break;case"Set":if(o.complement===!0)throw Error(Gb);V(o.value,l=>{if(typeof l=="number")Xl(l,e,r);else{const c=l;if(r===!0)for(let f=c.from;f<=c.to;f++)Xl(f,e,r);else{for(let f=c.from;f<=c.to&&f<Zl;f++)Xl(f,e,r);if(c.to>=Zl){const f=c.from>=Zl?c.from:Zl,d=c.to,p=Or(f),y=Or(d);for(let h=p;h<=y;h++)e[h]=h}}}});break;case"Group":hf(o.value,e,r);break;default:throw Error("Non Exhaustive Match")}const u=o.quantifier!==void 0&&o.quantifier.atLeast===0;if(o.type==="Group"&&yf(o)===!1||o.type!=="Group"&&u===!1)break}break;default:throw Error("non exhaustive match!")}return Ke(e)}s(hf,"firstCharOptimizedIndices");function Xl(t,e,r){const n=Or(t);e[n]=n,r===!0&&zb(t,e)}s(Xl,"addOptimizedIdxToResult");function zb(t,e){const r=String.fromCharCode(t),n=r.toUpperCase();if(n!==r){const a=Or(n.charCodeAt(0));e[a]=a}else{const a=r.toLowerCase();if(a!==r){const i=Or(a.charCodeAt(0));e[i]=i}}}s(zb,"handleIgnoreCase");function Sm(t,e){return el(t.value,r=>{if(typeof r=="number")return vt(e,r);{const n=r;return el(e,a=>n.from<=a&&a<=n.to)!==void 0}})}s(Sm,"findCode");function yf(t){const e=t.quantifier;return e&&e.atLeast===0?!0:t.value?se(t.value)?Yt(t.value,yf):yf(t.value):!1}s(yf,"isWholeOptional");var Ti,v1=(Ti=class extends Kf{constructor(e){super(),this.targetCharCodes=e,this.found=!1}visitChildren(e){if(this.found!==!0){switch(e.type){case"Lookahead":this.visitLookahead(e);return;case"NegativeLookahead":this.visitNegativeLookahead(e);return;case"Lookbehind":this.visitLookbehind(e);return;case"NegativeLookbehind":this.visitNegativeLookbehind(e);return}super.visitChildren(e)}}visitCharacter(e){vt(this.targetCharCodes,e.value)&&(this.found=!0)}visitSet(e){e.complement?Sm(e,this.targetCharCodes)===void 0&&(this.found=!0):Sm(e,this.targetCharCodes)!==void 0&&(this.found=!0)}},s(Ti,"CharCodeFinder"),Ti);function dd(t,e){if(e instanceof RegExp){const r=Ju(e),n=new v1(t);return n.visit(r),n.found}else return el(e,r=>vt(t,r.charCodeAt(0)))!==void 0}s(dd,"canMatchCharCode");var Un="PATTERN",Jl="defaultMode",ic="modes";function jb(t,e){e=jy(e,{debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",`
`],tracer:s((w,b)=>b(),"tracer")});const r=e.tracer;r("initCharCodeToOptimizedIndexMap",()=>{l_()});let n;r("Reject Lexer.NA",()=>{n=cd(t,w=>w[Un]===pt.NA)});let a=!1,i;r("Transform Patterns",()=>{a=!1,i=j(n,w=>{const b=w[Un];if(Pr(b)){const N=b.source;return N.length===1&&N!=="^"&&N!=="$"&&N!=="."&&!b.ignoreCase?N:N.length===2&&N[0]==="\\"&&!vt(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],N[1])?N[1]:wm(b)}else{if(Gr(b))return a=!0,{exec:b};if(typeof b=="object")return a=!0,b;if(typeof b=="string"){if(b.length===1)return b;{const N=b.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),B=new RegExp(N);return wm(B)}}else throw Error("non exhaustive match")}})});let o,u,l,c,f;r("misc mapping",()=>{o=j(n,w=>w.tokenTypeIdx),u=j(n,w=>{const b=w.GROUP;if(b!==pt.SKIPPED){if(Ct(b))return b;if(kr(b))return!1;throw Error("non exhaustive match")}}),l=j(n,w=>{const b=w.LONGER_ALT;if(b)return se(b)?j(b,B=>Fv(n,B)):[Fv(n,b)]}),c=j(n,w=>w.PUSH_MODE),f=j(n,w=>K(w,"POP_MODE"))});let d;r("Line Terminator Handling",()=>{const w=Hy(e.lineTerminatorCharacters);d=j(n,b=>!1),e.positionTracking!=="onlyOffset"&&(d=j(n,b=>K(b,"LINE_BREAKS")?!!b.LINE_BREAKS:qy(b,w)===!1&&dd(w,b.PATTERN)))});let p,y,h,T;r("Misc Mapping #2",()=>{p=j(n,Vy),y=j(i,s_),h=kt(n,(w,b)=>{const N=b.GROUP;return Ct(N)&&N!==pt.SKIPPED&&(w[N]=[]),w},{}),T=j(i,(w,b)=>({pattern:i[b],longerAlt:l[b],canLineTerminator:d[b],isCustom:p[b],short:y[b],group:u[b],push:c[b],pop:f[b],tokenTypeIdx:o[b],tokenType:n[b]}))});let C=!0,v=[];return e.safeMode||r("First Char Optimization",()=>{v=kt(n,(w,b,N)=>{if(typeof b.PATTERN=="string"){const B=b.PATTERN.charCodeAt(0),ne=Or(B);Pc(w,ne,T[N])}else if(se(b.START_CHARS_HINT)){let B;V(b.START_CHARS_HINT,ne=>{const J=typeof ne=="string"?ne.charCodeAt(0):ne,he=Or(J);B!==he&&(B=he,Pc(w,he,T[N]))})}else if(Pr(b.PATTERN))if(b.PATTERN.unicode)C=!1,e.ensureOptimizations&&pf(`${mf} Unable to analyze < ${b.PATTERN.toString()} > pattern.
The regexp unicode flag is not currently supported by the regexp-to-ast library.
This will disable the lexer's first char optimizations.
For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNICODE_OPTIMIZE`);else{const B=Fb(b.PATTERN,e.ensureOptimizations);Re(B)&&(C=!1),V(B,ne=>{Pc(w,ne,T[N])})}else e.ensureOptimizations&&pf(`${mf} TokenType: <${b.name}> is using a custom token pattern without providing <start_chars_hint> parameter.
This will disable the lexer's first char optimizations.
For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),C=!1;return w},[])}),{emptyGroups:h,patternIdxToConfig:T,charCodeToPatternIdxToConfig:v,hasCustom:a,canBeOptimized:C}}s(jb,"analyzeTokenTypes");function Bb(t,e){let r=[];const n=Kb(t);r=r.concat(n.errors);const a=Wb(n.valid),i=a.valid;return r=r.concat(a.errors),r=r.concat(Ub(i)),r=r.concat(Jb(i)),r=r.concat(Zb(i,e)),r=r.concat(Qb(i)),r}s(Bb,"validatePatterns");function Ub(t){let e=[];const r=Bt(t,n=>Pr(n[Un]));return e=e.concat(Vb(r)),e=e.concat(Hb(r)),e=e.concat(Yb(r)),e=e.concat(Xb(r)),e=e.concat(qb(r)),e}s(Ub,"validateRegExpPattern");function Kb(t){const e=Bt(t,a=>!K(a,Un)),r=j(e,a=>({message:"Token Type: ->"+a.name+"<- missing static 'PATTERN' property",type:Me.MISSING_PATTERN,tokenTypes:[a]})),n=ud(t,e);return{errors:r,valid:n}}s(Kb,"findMissingPatterns");function Wb(t){const e=Bt(t,a=>{const i=a[Un];return!Pr(i)&&!Gr(i)&&!K(i,"exec")&&!Ct(i)}),r=j(e,a=>({message:"Token Type: ->"+a.name+"<- static 'PATTERN' can only be a RegExp, a Function matching the {CustomPatternMatcherFunc} type or an Object matching the {ICustomPattern} interface.",type:Me.INVALID_PATTERN,tokenTypes:[a]})),n=ud(t,e);return{errors:r,valid:n}}s(Wb,"findInvalidPatterns");var T1=/[^\\][$]/;function Vb(t){const a=class a extends Kf{constructor(){super(...arguments),this.found=!1}visitEndAnchor(o){this.found=!0}};s(a,"EndAnchorFinder");let e=a;const r=Bt(t,i=>{const o=i.PATTERN;try{const u=Ju(o),l=new e;return l.visit(u),l.found}catch{return T1.test(o.source)}});return j(r,i=>({message:`Unexpected RegExp Anchor Error:
Token Type: ->`+i.name+`<- static 'PATTERN' cannot contain end of input anchor '$'
See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:Me.EOI_ANCHOR_FOUND,tokenTypes:[i]}))}s(Vb,"findEndOfInputAnchor");function qb(t){const e=Bt(t,n=>n.PATTERN.test(""));return j(e,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' must not match an empty string",type:Me.EMPTY_MATCH_PATTERN,tokenTypes:[n]}))}s(qb,"findEmptyMatchRegExps");var $1=/[^\\[][\^]|^\^/;function Hb(t){const a=class a extends Kf{constructor(){super(...arguments),this.found=!1}visitStartAnchor(o){this.found=!0}};s(a,"StartAnchorFinder");let e=a;const r=Bt(t,i=>{const o=i.PATTERN;try{const u=Ju(o),l=new e;return l.visit(u),l.found}catch{return $1.test(o.source)}});return j(r,i=>({message:`Unexpected RegExp Anchor Error:
Token Type: ->`+i.name+`<- static 'PATTERN' cannot contain start of input anchor '^'
See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:Me.SOI_ANCHOR_FOUND,tokenTypes:[i]}))}s(Hb,"findStartOfInputAnchor");function Yb(t){const e=Bt(t,n=>{const a=n[Un];return a instanceof RegExp&&(a.multiline||a.global)});return j(e,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:Me.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[n]}))}s(Yb,"findUnsupportedFlags");function Xb(t){const e=[];let r=j(t,i=>kt(t,(o,u)=>(i.PATTERN.source===u.PATTERN.source&&!vt(e,u)&&u.PATTERN!==pt.NA&&(e.push(u),o.push(u)),o),[]));r=Xu(r);const n=Bt(r,i=>i.length>1);return j(n,i=>{const o=j(i,l=>l.name);return{message:`The same RegExp pattern ->${Jt(i).PATTERN}<-has been used in all of the following Token Types: ${o.join(", ")} <-`,type:Me.DUPLICATE_PATTERNS_FOUND,tokenTypes:i}})}s(Xb,"findDuplicatePatterns");function Jb(t){const e=Bt(t,n=>{if(!K(n,"GROUP"))return!1;const a=n.GROUP;return a!==pt.SKIPPED&&a!==pt.NA&&!Ct(a)});return j(e,n=>({message:"Token Type: ->"+n.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:Me.INVALID_GROUP_TYPE_FOUND,tokenTypes:[n]}))}s(Jb,"findInvalidGroupType");function Zb(t,e){const r=Bt(t,a=>a.PUSH_MODE!==void 0&&!vt(e,a.PUSH_MODE));return j(r,a=>({message:`Token Type: ->${a.name}<- static 'PUSH_MODE' value cannot refer to a Lexer Mode ->${a.PUSH_MODE}<-which does not exist`,type:Me.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[a]}))}s(Zb,"findModesThatDoNotExist");function Qb(t){const e=[],r=kt(t,(n,a,i)=>{const o=a.PATTERN;return o===pt.NA||(Ct(o)?n.push({str:o,idx:i,tokenType:a}):Pr(o)&&t_(o)&&n.push({str:o.source,idx:i,tokenType:a})),n},[]);return V(t,(n,a)=>{V(r,({str:i,idx:o,tokenType:u})=>{if(a<o&&e_(i,n.PATTERN)){const l=`Token: ->${u.name}<- can never be matched.
Because it appears AFTER the Token Type ->${n.name}<-in the lexer's definition.
See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#UNREACHABLE`;e.push({message:l,type:Me.UNREACHABLE_PATTERN,tokenTypes:[n,u]})}})}),e}s(Qb,"findUnreachablePatterns");function e_(t,e){if(Pr(e)){if(r_(e))return!1;const r=e.exec(t);return r!==null&&r.index===0}else{if(Gr(e))return e(t,0,[],{});if(K(e,"exec"))return e.exec(t,0,[],{});if(typeof e=="string")return e===t;throw Error("non exhaustive match")}}s(e_,"tryToMatchStrToPattern");function t_(t){return el([".","\\","[","]","|","^","$","(",")","?","*","+","{"],r=>t.source.indexOf(r)!==-1)===void 0}s(t_,"noMetaChar");function r_(t){return/(\(\?=)|(\(\?!)|(\(\?<=)|(\(\?<!)/.test(t.source)}s(r_,"usesLookAheadOrBehind");function wm(t){const e=t.ignoreCase?"iy":"y";return new RegExp(`${t.source}`,e)}s(wm,"addStickyFlag");function n_(t,e,r){const n=[];return K(t,Jl)||n.push({message:"A MultiMode Lexer cannot be initialized without a <"+Jl+`> property in its definition
`,type:Me.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),K(t,ic)||n.push({message:"A MultiMode Lexer cannot be initialized without a <"+ic+`> property in its definition
`,type:Me.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),K(t,ic)&&K(t,Jl)&&!K(t.modes,t.defaultMode)&&n.push({message:`A MultiMode Lexer cannot be initialized with a ${Jl}: <${t.defaultMode}>which does not exist
`,type:Me.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),K(t,ic)&&V(t.modes,(a,i)=>{V(a,(o,u)=>{if(kr(o))n.push({message:`A Lexer cannot be initialized using an undefined Token Type. Mode:<${i}> at index: <${u}>
`,type:Me.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED});else if(K(o,"LONGER_ALT")){const l=se(o.LONGER_ALT)?o.LONGER_ALT:[o.LONGER_ALT];V(l,c=>{!kr(c)&&!vt(a,c)&&n.push({message:`A MultiMode Lexer cannot be initialized with a longer_alt <${c.name}> on token <${o.name}> outside of mode <${i}>
`,type:Me.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE})})}})}),n}s(n_,"performRuntimeChecks");function a_(t,e,r){const n=[];let a=!1;const i=Xu(Ht(Ke(t.modes))),o=cd(i,l=>l[Un]===pt.NA),u=Hy(r);return e&&V(o,l=>{const c=qy(l,u);if(c!==!1){const d={message:o_(l,c),type:c.issue,tokenType:l};n.push(d)}else K(l,"LINE_BREAKS")?l.LINE_BREAKS===!0&&(a=!0):dd(u,l.PATTERN)&&(a=!0)}),e&&!a&&n.push({message:`Warning: No LINE_BREAKS Found.
This Lexer has been defined to track line and column information,
But none of the Token Types can be identified as matching a line terminator.
See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#LINE_BREAKS
for details.`,type:Me.NO_LINE_BREAKS_FLAGS}),n}s(a_,"performWarningRuntimeChecks");function i_(t){const e={},r=Nt(t);return V(r,n=>{const a=t[n];if(se(a))e[n]=[];else throw Error("non exhaustive match")}),e}s(i_,"cloneEmptyGroups");function Vy(t){const e=t.PATTERN;if(Pr(e))return!1;if(Gr(e))return!0;if(K(e,"exec"))return!0;if(Ct(e))return!1;throw Error("non exhaustive match")}s(Vy,"isCustomPattern");function s_(t){return Ct(t)&&t.length===1?t.charCodeAt(0):!1}s(s_,"isShortPattern");var R1={test:s(function(t){const e=t.length;for(let r=this.lastIndex;r<e;r++){const n=t.charCodeAt(r);if(n===10)return this.lastIndex=r+1,!0;if(n===13)return t.charCodeAt(r+1)===10?this.lastIndex=r+2:this.lastIndex=r+1,!0}return!1},"test"),lastIndex:0};function qy(t,e){if(K(t,"LINE_BREAKS"))return!1;if(Pr(t.PATTERN)){try{dd(e,t.PATTERN)}catch(r){return{issue:Me.IDENTIFY_TERMINATOR,errMsg:r.message}}return!1}else{if(Ct(t.PATTERN))return!1;if(Vy(t))return{issue:Me.CUSTOM_LINE_BREAK};throw Error("non exhaustive match")}}s(qy,"checkLineBreaksIssues");function o_(t,e){if(e.issue===Me.IDENTIFY_TERMINATOR)return`Warning: unable to identify line terminator usage in pattern.
The problem is in the <${t.name}> Token Type
Root cause: ${e.errMsg}.
For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR`;if(e.issue===Me.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the <line_breaks> option.
The problem is in the <${t.name}> Token Type
For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK`;throw Error("non exhaustive match")}s(o_,"buildLineBreakIssueMessage");function Hy(t){return j(t,r=>Ct(r)?r.charCodeAt(0):r)}s(Hy,"getCharCodes");function Pc(t,e,r){t[e]===void 0?t[e]=[r]:t[e].push(r)}s(Pc,"addToMapOfArrays");var Zl=256,kc=[];function Or(t){return t<Zl?t:kc[t]}s(Or,"charCodeToOptimizedIndex");function l_(){if(Re(kc)){kc=new Array(65536);for(let t=0;t<65536;t++)kc[t]=t>255?255+~~(t/255):t}}s(l_,"initCharCodeToOptimizedIndexMap");function ul(t,e){const r=t.tokenTypeIdx;return r===e.tokenTypeIdx?!0:e.isParent===!0&&e.categoryMatchesMap[r]===!0}s(ul,"tokenStructuredMatcher");function _u(t,e){return t.tokenTypeIdx===e.tokenTypeIdx}s(_u,"tokenStructuredMatcherNoCategories");var jv=1,u_={};function cl(t){const e=c_(t);f_(e),p_(e),d_(e),V(e,r=>{r.isParent=r.categoryMatches.length>0})}s(cl,"augmentTokenTypes");function c_(t){let e=it(t),r=t,n=!0;for(;n;){r=Xu(Ht(j(r,i=>i.CATEGORIES)));const a=ud(r,e);e=e.concat(a),Re(a)?n=!1:r=a}return e}s(c_,"expandCategories");function f_(t){V(t,e=>{Xy(e)||(u_[jv]=e,e.tokenTypeIdx=jv++),Im(e)&&!se(e.CATEGORIES)&&(e.CATEGORIES=[e.CATEGORIES]),Im(e)||(e.CATEGORIES=[]),m_(e)||(e.categoryMatches=[]),h_(e)||(e.categoryMatchesMap={})})}s(f_,"assignTokenDefaultProps");function d_(t){V(t,e=>{e.categoryMatches=[],V(e.categoryMatchesMap,(r,n)=>{e.categoryMatches.push(u_[n].tokenTypeIdx)})})}s(d_,"assignCategoriesTokensProp");function p_(t){V(t,e=>{Yy([],e)})}s(p_,"assignCategoriesMapProp");function Yy(t,e){V(t,r=>{e.categoryMatchesMap[r.tokenTypeIdx]=!0}),V(e.CATEGORIES,r=>{const n=t.concat(e);vt(n,r)||Yy(n,r)})}s(Yy,"singleAssignCategoriesToksMap");function Xy(t){return K(t,"tokenTypeIdx")}s(Xy,"hasShortKeyProperty");function Im(t){return K(t,"CATEGORIES")}s(Im,"hasCategoriesProperty");function m_(t){return K(t,"categoryMatches")}s(m_,"hasExtendingTokensTypesProperty");function h_(t){return K(t,"categoryMatchesMap")}s(h_,"hasExtendingTokensTypesMapProperty");function y_(t){return K(t,"tokenTypeIdx")}s(y_,"isTokenType");var Nm={buildUnableToPopLexerModeMessage(t){return`Unable to pop Lexer Mode after encountering Token ->${t.image}<- The Mode Stack is empty`},buildUnexpectedCharactersMessage(t,e,r,n,a,i){return`unexpected character: ->${t.charAt(e)}<- at offset: ${e}, skipped ${r} characters.`}},Me;(function(t){t[t.MISSING_PATTERN=0]="MISSING_PATTERN",t[t.INVALID_PATTERN=1]="INVALID_PATTERN",t[t.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",t[t.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",t[t.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",t[t.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",t[t.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",t[t.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",t[t.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",t[t.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",t[t.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",t[t.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",t[t.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",t[t.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",t[t.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",t[t.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",t[t.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK",t[t.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE=17]="MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE"})(Me||(Me={}));var Ql={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[`
`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:Nm,traceInitPerf:!1,skipValidations:!1,recoveryEnabled:!0};Object.freeze(Ql);var $i,pt=($i=class{constructor(e,r=Ql){if(this.lexerDefinition=e,this.lexerDefinitionErrors=[],this.lexerDefinitionWarning=[],this.patternIdxToConfig={},this.charCodeToPatternIdxToConfig={},this.modes=[],this.emptyGroups={},this.trackStartLines=!0,this.trackEndLines=!0,this.hasCustom=!1,this.canModeBeOptimized={},this.TRACE_INIT=(a,i)=>{if(this.traceInitPerf===!0){this.traceInitIndent++;const o=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent<this.traceInitMaxIdent&&console.log(`${o}--> <${a}>`);const{time:u,value:l}=Ky(i),c=u>10?console.warn:console.log;return this.traceInitIndent<this.traceInitMaxIdent&&c(`${o}<-- <${a}> time: ${u}ms`),this.traceInitIndent--,l}else return i()},typeof r=="boolean")throw Error(`The second argument to the Lexer constructor is now an ILexerConfig Object.
a boolean 2nd argument is no longer supported`);this.config=Pt({},Ql,r);const n=this.config.traceInitPerf;n===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof n=="number"&&(this.traceInitMaxIdent=n,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",()=>{let a,i=!0;this.TRACE_INIT("Lexer Config handling",()=>{if(this.config.lineTerminatorsPattern===Ql.lineTerminatorsPattern)this.config.lineTerminatorsPattern=R1;else if(this.config.lineTerminatorCharacters===Ql.lineTerminatorCharacters)throw Error(`Error: Missing <lineTerminatorCharacters> property on the Lexer config.
For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(r.safeMode&&r.ensureOptimizations)throw Error('"safeMode" and "ensureOptimizations" flags are mutually exclusive.');this.trackStartLines=/full|onlyStart/i.test(this.config.positionTracking),this.trackEndLines=/full/i.test(this.config.positionTracking),se(e)?a={modes:{defaultMode:it(e)},defaultMode:Jl}:(i=!1,a=it(e))}),this.config.skipValidations===!1&&(this.TRACE_INIT("performRuntimeChecks",()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(n_(a,this.trackStartLines,this.config.lineTerminatorCharacters))}),this.TRACE_INIT("performWarningRuntimeChecks",()=>{this.lexerDefinitionWarning=this.lexerDefinitionWarning.concat(a_(a,this.trackStartLines,this.config.lineTerminatorCharacters))})),a.modes=a.modes?a.modes:{},V(a.modes,(u,l)=>{a.modes[l]=cd(u,c=>kr(c))});const o=Nt(a.modes);if(V(a.modes,(u,l)=>{this.TRACE_INIT(`Mode: <${l}> processing`,()=>{if(this.modes.push(l),this.config.skipValidations===!1&&this.TRACE_INIT("validatePatterns",()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(Bb(u,o))}),Re(this.lexerDefinitionErrors)){cl(u);let c;this.TRACE_INIT("analyzeTokenTypes",()=>{c=jb(u,{lineTerminatorCharacters:this.config.lineTerminatorCharacters,positionTracking:r.positionTracking,ensureOptimizations:r.ensureOptimizations,safeMode:r.safeMode,tracer:this.TRACE_INIT})}),this.patternIdxToConfig[l]=c.patternIdxToConfig,this.charCodeToPatternIdxToConfig[l]=c.charCodeToPatternIdxToConfig,this.emptyGroups=Pt({},this.emptyGroups,c.emptyGroups),this.hasCustom=c.hasCustom||this.hasCustom,this.canModeBeOptimized[l]=c.canBeOptimized}})}),this.defaultMode=a.defaultMode,!Re(this.lexerDefinitionErrors)&&!this.config.deferDefinitionErrorsHandling){const l=j(this.lexerDefinitionErrors,c=>c.message).join(`-----------------------
`);throw new Error(`Errors detected in definition of Lexer:
`+l)}V(this.lexerDefinitionWarning,u=>{Uy(u.message)}),this.TRACE_INIT("Choosing sub-methods implementations",()=>{if(i&&(this.handleModes=He),this.trackStartLines===!1&&(this.computeNewColumn=Ku),this.trackEndLines===!1&&(this.updateTokenEndLineColumnLocation=He),/full/i.test(this.config.positionTracking))this.createTokenInstance=this.createFullToken;else if(/onlyStart/i.test(this.config.positionTracking))this.createTokenInstance=this.createStartOnlyToken;else if(/onlyOffset/i.test(this.config.positionTracking))this.createTokenInstance=this.createOffsetOnlyToken;else throw Error(`Invalid <positionTracking> config option: "${this.config.positionTracking}"`);this.hasCustom?(this.addToken=this.addTokenUsingPush,this.handlePayload=this.handlePayloadWithCustom):(this.addToken=this.addTokenUsingMemberAccess,this.handlePayload=this.handlePayloadNoCustom)}),this.TRACE_INIT("Failed Optimization Warnings",()=>{const u=kt(this.canModeBeOptimized,(l,c,f)=>(c===!1&&l.push(f),l),[]);if(r.ensureOptimizations&&!Re(u))throw Error(`Lexer Modes: < ${u.join(", ")} > cannot be optimized.
Disable the "ensureOptimizations" lexer config flag to silently ignore this and run the lexer in an un-optimized mode.
Or inspect the console log for details on how to resolve these issues.`)}),this.TRACE_INIT("clearRegExpParserCache",()=>{Mb()}),this.TRACE_INIT("toFastProperties",()=>{Wy(this)})})}tokenize(e,r=this.defaultMode){if(!Re(this.lexerDefinitionErrors)){const a=j(this.lexerDefinitionErrors,i=>i.message).join(`-----------------------
`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer:
`+a)}return this.tokenizeInternal(e,r)}tokenizeInternal(e,r){let n,a,i,o,u,l,c,f,d,p,y,h,T,C,v;const w=e,b=w.length;let N=0,B=0;const ne=this.hasCustom?0:Math.floor(e.length/10),J=new Array(ne),he=[];let Ae=this.trackStartLines?1:void 0,ye=this.trackStartLines?1:void 0;const ue=i_(this.emptyGroups),ot=this.trackStartLines,k=this.config.lineTerminatorsPattern;let _=0,$=[],I=[];const R=[],A=[];Object.freeze(A);let S=!1;const L=s(M=>{if(R.length===1&&M.tokenType.PUSH_MODE===void 0){const Y=this.config.errorMessageProvider.buildUnableToPopLexerModeMessage(M);he.push({offset:M.startOffset,line:M.startLine,column:M.startColumn,length:M.image.length,message:Y})}else{R.pop();const Y=Bn(R);$=this.patternIdxToConfig[Y],I=this.charCodeToPatternIdxToConfig[Y],_=$.length;const q=this.canModeBeOptimized[Y]&&this.config.safeMode===!1;I&&q?S=!0:S=!1}},"pop_mode");function x(M){R.push(M),I=this.charCodeToPatternIdxToConfig[M],$=this.patternIdxToConfig[M],_=$.length,_=$.length;const Y=this.canModeBeOptimized[M]&&this.config.safeMode===!1;I&&Y?S=!0:S=!1}s(x,"push_mode"),x.call(this,r);let O;const z=this.config.recoveryEnabled;for(;N<b;){l=null,d=-1;const M=w.charCodeAt(N);let Y;if(S){const Z=Or(M),ae=I[Z];Y=ae!==void 0?ae:A}else Y=$;const q=Y.length;for(n=0;n<q;n++){O=Y[n];const Z=O.pattern;c=null;const ae=O.short;if(ae!==!1?M===ae&&(d=1,l=Z):O.isCustom===!0?(v=Z.exec(w,N,J,ue),v!==null?(l=v[0],d=l.length,v.payload!==void 0&&(c=v.payload)):l=null):(Z.lastIndex=N,d=this.matchLength(Z,e,N)),d!==-1){if(u=O.longerAlt,u!==void 0){l=e.substring(N,N+d);const Oe=u.length;for(i=0;i<Oe;i++){const pe=$[u[i]],Ee=pe.pattern;if(f=null,pe.isCustom===!0?(v=Ee.exec(w,N,J,ue),v!==null?(o=v[0],v.payload!==void 0&&(f=v.payload)):o=null):(Ee.lastIndex=N,o=this.match(Ee,e,N)),o&&o.length>l.length){l=o,d=o.length,c=f,O=pe;break}}}break}}if(d!==-1){if(p=O.group,p!==void 0&&(l=l!==null?l:e.substring(N,N+d),y=O.tokenTypeIdx,h=this.createTokenInstance(l,N,y,O.tokenType,Ae,ye,d),this.handlePayload(h,c),p===!1?B=this.addToken(J,B,h):ue[p].push(h)),ot===!0&&O.canLineTerminator===!0){let Z=0,ae,Oe;k.lastIndex=0;do l=l!==null?l:e.substring(N,N+d),ae=k.test(l),ae===!0&&(Oe=k.lastIndex-1,Z++);while(ae===!0);Z!==0?(Ae=Ae+Z,ye=d-Oe,this.updateTokenEndLineColumnLocation(h,p,Oe,Z,Ae,ye,d)):ye=this.computeNewColumn(ye,d)}else ye=this.computeNewColumn(ye,d);N=N+d,this.handleModes(O,L,x,h)}else{const Z=N,ae=Ae,Oe=ye;let pe=z===!1;for(;pe===!1&&N<b;)for(N++,a=0;a<_;a++){const Ee=$[a],Ve=Ee.pattern,Le=Ee.short;if(Le!==!1?w.charCodeAt(N)===Le&&(pe=!0):Ee.isCustom===!0?pe=Ve.exec(w,N,J,ue)!==null:(Ve.lastIndex=N,pe=Ve.exec(e)!==null),pe===!0)break}if(T=N-Z,ye=this.computeNewColumn(ye,T),C=this.config.errorMessageProvider.buildUnexpectedCharactersMessage(w,Z,T,ae,Oe,Bn(R)),he.push({offset:Z,line:ae,column:Oe,length:T,message:C}),z===!1)break}}return this.hasCustom||(J.length=B),{tokens:J,groups:ue,errors:he}}handleModes(e,r,n,a){if(e.pop===!0){const i=e.push;r(a),i!==void 0&&n.call(this,i)}else e.push!==void 0&&n.call(this,e.push)}updateTokenEndLineColumnLocation(e,r,n,a,i,o,u){let l,c;r!==void 0&&(l=n===u-1,c=l?-1:0,a===1&&l===!0||(e.endLine=i+c,e.endColumn=o-1+-c))}computeNewColumn(e,r){return e+r}createOffsetOnlyToken(e,r,n,a){return{image:e,startOffset:r,tokenTypeIdx:n,tokenType:a}}createStartOnlyToken(e,r,n,a,i,o){return{image:e,startOffset:r,startLine:i,startColumn:o,tokenTypeIdx:n,tokenType:a}}createFullToken(e,r,n,a,i,o,u){return{image:e,startOffset:r,endOffset:r+u-1,startLine:i,endLine:i,startColumn:o,endColumn:o+u-1,tokenTypeIdx:n,tokenType:a}}addTokenUsingPush(e,r,n){return e.push(n),r}addTokenUsingMemberAccess(e,r,n){return e[r]=n,r++,r}handlePayloadNoCustom(e,r){}handlePayloadWithCustom(e,r){r!==null&&(e.payload=r)}match(e,r,n){return e.test(r)===!0?r.substring(n,e.lastIndex):null}matchLength(e,r,n){return e.test(r)===!0?e.lastIndex-n:-1}},s($i,"Lexer"),$i);pt.SKIPPED="This marks a skipped Token pattern, this means each token identified by it will be consumed and then thrown into oblivion, this can be used to for example to completely ignore whitespace.";pt.NA=/NOT_APPLICABLE/;function Mn(t){return Jy(t)?t.LABEL:t.name}s(Mn,"tokenLabel");function Jy(t){return Ct(t.LABEL)&&t.LABEL!==""}s(Jy,"hasTokenLabel");var A1="parent",Bv="categories",Uv="label",Kv="group",Wv="push_mode",Vv="pop_mode",qv="longer_alt",Hv="line_breaks",Yv="start_chars_hint";function Xa(t){return g_(t)}s(Xa,"createToken");function g_(t){const e=t.pattern,r={};if(r.name=t.name,kr(e)||(r.PATTERN=e),K(t,A1))throw`The parent property is no longer supported.
See: https://github.com/chevrotain/chevrotain/issues/564#issuecomment-349062346 for details.`;return K(t,Bv)&&(r.CATEGORIES=t[Bv]),cl([r]),K(t,Uv)&&(r.LABEL=t[Uv]),K(t,Kv)&&(r.GROUP=t[Kv]),K(t,Vv)&&(r.POP_MODE=t[Vv]),K(t,Wv)&&(r.PUSH_MODE=t[Wv]),K(t,qv)&&(r.LONGER_ALT=t[qv]),K(t,Hv)&&(r.LINE_BREAKS=t[Hv]),K(t,Yv)&&(r.START_CHARS_HINT=t[Yv]),r}s(g_,"createTokenInternal");var Jr=Xa({name:"EOF",pattern:pt.NA});cl([Jr]);function Zu(t,e,r,n,a,i,o,u){return{image:e,startOffset:r,endOffset:n,startLine:a,endLine:i,startColumn:o,endColumn:u,tokenTypeIdx:t.tokenTypeIdx,tokenType:t}}s(Zu,"createTokenInstance");function Zy(t,e){return ul(t,e)}s(Zy,"tokenMatcher");var qa={buildMismatchTokenMessage({expected:t,actual:e,previous:r,ruleName:n}){return`Expecting ${Jy(t)?`--> ${Mn(t)} <--`:`token of type --> ${t.name} <--`} but found --> '${e.image}' <--`},buildNotAllInputParsedMessage({firstRedundant:t,ruleName:e}){return"Redundant input, expecting EOF but found: "+t.image},buildNoViableAltMessage({expectedPathsPerAlt:t,actual:e,previous:r,customUserDescription:n,ruleName:a}){const i="Expecting: ",u=`
but found: '`+Jt(e).image+"'";if(n)return i+n+u;{const l=kt(t,(p,y)=>p.concat(y),[]),c=j(l,p=>`[${j(p,y=>Mn(y)).join(", ")}]`),d=`one of these possible Token sequences:
${j(c,(p,y)=>` ${y+1}. ${p}`).join(`
`)}`;return i+d+u}},buildEarlyExitMessage({expectedIterationPaths:t,actual:e,customUserDescription:r,ruleName:n}){const a="Expecting: ",o=`
but found: '`+Jt(e).image+"'";if(r)return a+r+o;{const l=`expecting at least one iteration which starts with one of these possible Token sequences::
<${j(t,c=>`[${j(c,f=>Mn(f)).join(",")}]`).join(" ,")}>`;return a+l+o}}};Object.freeze(qa);var E1={buildRuleNotFoundError(t,e){return"Invalid grammar, reference to a rule which is not defined: ->"+e.nonTerminalName+`<-
inside top level rule: ->`+t.name+"<-"}},Ln={buildDuplicateFoundError(t,e){function r(f){return f instanceof Se?f.terminalType.name:f instanceof ht?f.nonTerminalName:""}s(r,"getExtraProductionArgument");const n=t.name,a=Jt(e),i=a.idx,o=Kt(a),u=r(a),l=i>0;let c=`->${o}${l?i:""}<- ${u?`with argument: ->${u}<-`:""}
appears more than once (${e.length} times) in the top level rule: ->${n}<-.
For further details see: https://chevrotain.io/docs/FAQ.html#NUMERICAL_SUFFIXES
`;return c=c.replace(/[ \t]+/g," "),c=c.replace(/\s\s+/g,`
`),c},buildNamespaceConflictError(t){return`Namespace conflict found in grammar.
The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <${t.name}>.
To resolve this make sure each Terminal and Non-Terminal names are unique
This is easy to accomplish by using the convention that Terminal names start with an uppercase letter
and Non-Terminal names start with a lower case letter.`},buildAlternationPrefixAmbiguityError(t){const e=j(t.prefixPath,a=>Mn(a)).join(", "),r=t.alternation.idx===0?"":t.alternation.idx;return`Ambiguous alternatives: <${t.ambiguityIndices.join(" ,")}> due to common lookahead prefix
in <OR${r}> inside <${t.topLevelRule.name}> Rule,
<${e}> may appears as a prefix path in all these alternatives.
See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#COMMON_PREFIX
For Further details.`},buildAlternationAmbiguityError(t){const e=t.alternation.idx===0?"":t.alternation.idx,r=t.prefixPath.length===0;let n=`Ambiguous Alternatives Detected: <${t.ambiguityIndices.join(" ,")}> in <OR${e}> inside <${t.topLevelRule.name}> Rule,
`;if(r)n+=`These alternatives are all empty (match no tokens), making them indistinguishable.
Only the last alternative may be empty.
`;else{const a=j(t.prefixPath,i=>Mn(i)).join(", ");n+=`<${a}> may appears as a prefix path in all these alternatives.
`}return n+=`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES
For Further details.`,n},buildEmptyRepetitionError(t){let e=Kt(t.repetition);return t.repetition.idx!==0&&(e+=t.repetition.idx),`The repetition <${e}> within Rule <${t.topLevelRule.name}> can never consume any tokens.
This could lead to an infinite loop.`},buildTokenNameError(t){return"deprecated"},buildEmptyAlternationError(t){return`Ambiguous empty alternative: <${t.emptyChoiceIdx+1}> in <OR${t.alternation.idx}> inside <${t.topLevelRule.name}> Rule.
Only the last alternative may be an empty alternative.`},buildTooManyAlternativesError(t){return`An Alternation cannot have more than 256 alternatives:
<OR${t.alternation.idx}> inside <${t.topLevelRule.name}> Rule.
has ${t.alternation.definition.length+1} alternatives.`},buildLeftRecursionError(t){const e=t.topLevelRule.name,r=j(t.leftRecursionPath,i=>i.name),n=`${e} --> ${r.concat([e]).join(" --> ")}`;return`Left Recursion found in grammar.
rule: <${e}> can be invoked from itself (directly or indirectly)
without consuming any Tokens. The grammar path that causes this is:
${n}
To fix this refactor your grammar to remove the left recursion.
see: https://en.wikipedia.org/wiki/LL_parser#Left_factoring.`},buildInvalidRuleNameError(t){return"deprecated"},buildDuplicateRuleNameError(t){let e;return t.topLevelRule instanceof sl?e=t.topLevelRule.name:e=t.topLevelRule,`Duplicate definition, rule: ->${e}<- is already defined in the grammar: ->${t.grammarName}<-`}};function v_(t,e){const r=new C1(t,e);return r.resolveRefs(),r.errors}s(v_,"resolveGrammar");var Ri,C1=(Ri=class extends ol{constructor(e,r){super(),this.nameToTopRule=e,this.errMsgProvider=r,this.errors=[]}resolveRefs(){V(Ke(this.nameToTopRule),e=>{this.currTopLevel=e,e.accept(this)})}visitNonTerminal(e){const r=this.nameToTopRule[e.nonTerminalName];if(r)e.referencedRule=r;else{const n=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,e);this.errors.push({message:n,type:yt.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:e.nonTerminalName})}}},s(Ri,"GastRefResolverVisitor"),Ri),Ai,b1=(Ai=class extends fd{constructor(e,r){super(),this.topProd=e,this.path=r,this.possibleTokTypes=[],this.nextProductionName="",this.nextProductionOccurrence=0,this.found=!1,this.isAtEndOfPath=!1}startWalking(){if(this.found=!1,this.path.ruleStack[0]!==this.topProd.name)throw Error("The path does not start with the walker's top Rule!");return this.ruleStack=it(this.path.ruleStack).reverse(),this.occurrenceStack=it(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes}walk(e,r=[]){this.found||super.walk(e,r)}walkProdRef(e,r,n){if(e.referencedRule.name===this.nextProductionName&&e.idx===this.nextProductionOccurrence){const a=r.concat(n);this.updateExpectedNext(),this.walk(e.referencedRule,a)}}updateExpectedNext(){Re(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())}},s(Ai,"AbstractNextPossibleTokensWalker"),Ai),Ei,_1=(Ei=class extends b1{constructor(e,r){super(e,r),this.path=r,this.nextTerminalName="",this.nextTerminalOccurrence=0,this.nextTerminalName=this.path.lastTok.name,this.nextTerminalOccurrence=this.path.lastTokOccurrence}walkTerminal(e,r,n){if(this.isAtEndOfPath&&e.terminalType.name===this.nextTerminalName&&e.idx===this.nextTerminalOccurrence&&!this.found){const a=r.concat(n),i=new bt({definition:a});this.possibleTokTypes=ll(i),this.found=!0}}},s(Ei,"NextAfterTokenWalker"),Ei),Ci,pd=(Ci=class extends fd{constructor(e,r){super(),this.topRule=e,this.occurrence=r,this.result={token:void 0,occurrence:void 0,isEndOfRule:void 0}}startWalking(){return this.walk(this.topRule),this.result}},s(Ci,"AbstractNextTerminalAfterProductionWalker"),Ci),bi,S1=(bi=class extends pd{walkMany(e,r,n){if(e.idx===this.occurrence){const a=Jt(r.concat(n));this.result.isEndOfRule=a===void 0,a instanceof Se&&(this.result.token=a.terminalType,this.result.occurrence=a.idx)}else super.walkMany(e,r,n)}},s(bi,"NextTerminalAfterManyWalker"),bi),_i,Xv=(_i=class extends pd{walkManySep(e,r,n){if(e.idx===this.occurrence){const a=Jt(r.concat(n));this.result.isEndOfRule=a===void 0,a instanceof Se&&(this.result.token=a.terminalType,this.result.occurrence=a.idx)}else super.walkManySep(e,r,n)}},s(_i,"NextTerminalAfterManySepWalker"),_i),Si,w1=(Si=class extends pd{walkAtLeastOne(e,r,n){if(e.idx===this.occurrence){const a=Jt(r.concat(n));this.result.isEndOfRule=a===void 0,a instanceof Se&&(this.result.token=a.terminalType,this.result.occurrence=a.idx)}else super.walkAtLeastOne(e,r,n)}},s(Si,"NextTerminalAfterAtLeastOneWalker"),Si),wi,Jv=(wi=class extends pd{walkAtLeastOneSep(e,r,n){if(e.idx===this.occurrence){const a=Jt(r.concat(n));this.result.isEndOfRule=a===void 0,a instanceof Se&&(this.result.token=a.terminalType,this.result.occurrence=a.idx)}else super.walkAtLeastOneSep(e,r,n)}},s(wi,"NextTerminalAfterAtLeastOneSepWalker"),wi);function gf(t,e,r=[]){r=it(r);let n=[],a=0;function i(u){return u.concat(nt(t,a+1))}s(i,"remainingPathWith");function o(u){const l=gf(i(u),e,r);return n.concat(l)}for(s(o,"getAlternativesForProd");r.length<e&&a<t.length;){const u=t[a];if(u instanceof bt)return o(u.definition);if(u instanceof ht)return o(u.definition);if(u instanceof at)n=o(u.definition);else if(u instanceof Ot){const l=u.definition.concat([new xe({definition:u.definition})]);return o(l)}else if(u instanceof Lt){const l=[new bt({definition:u.definition}),new xe({definition:[new Se({terminalType:u.separator})].concat(u.definition)})];return o(l)}else if(u instanceof _t){const l=u.definition.concat([new xe({definition:[new Se({terminalType:u.separator})].concat(u.definition)})]);n=o(l)}else if(u instanceof xe){const l=u.definition.concat([new xe({definition:u.definition})]);n=o(l)}else{if(u instanceof St)return V(u.definition,l=>{Re(l.definition)===!1&&(n=o(l.definition))}),n;if(u instanceof Se)r.push(u.terminalType);else throw Error("non exhaustive match")}a++}return n.push({p Line truncated
${i.join(`
`).replace(/\n/g,`
`)}`)}},"validateVisitor")};return r.prototype=n,r.prototype.constructor=r,r._RULE_NAMES=e,r}s(rS,"createBaseSemanticVisitorConstructor");function nS(t,e,r){const n=s(function(){},"derivedConstructor");sg(n,t+"BaseSemanticsWithDefaults");const a=Object.create(r.prototype);return V(e,i=>{a[i]=tS}),n.prototype=a,n.prototype.constructor=n,n}s(nS,"createBaseVisitorConstructorWithDefaults");var Gm;(function(t){t[t.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",t[t.MISSING_METHOD=1]="MISSING_METHOD"})(Gm||(Gm={}));function aS(t,e){return iS(t,e)}s(aS,"validateVisitor");function iS(t,e){const r=Bt(e,a=>Gr(t[a])===!1),n=j(r,a=>({msg:`Missing visitor method: <${a}> on ${t.constructor.name} CST Visitor.`,type:Gm.MISSING_METHOD,methodName:a}));return Xu(n)}s(iS,"validateMissingCstMethods");var Ki,j1=(Ki=class{initTreeBuilder(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=K(e,"nodeLocationTracking")?e.nodeLocationTracking:Lr.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=He,this.cstFinallyStateUpdate=He,this.cstPostTerminal=He,this.cstPostNonTerminal=He,this.cstPostRule=He;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=Mm,this.setNodeLocationFromNode=Mm,this.cstPostRule=He,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=He,this.setNodeLocationFromNode=He,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=xm,this.setNodeLocationFromNode=xm,this.cstPostRule=He,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=He,this.setNodeLocationFromNode=He,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=He,this.setNodeLocationFromNode=He,this.cstPostRule=He,this.setInitialNodeLocation=He;else throw Error(`Invalid <nodeLocationTracking> config option: "${e.nodeLocationTracking}"`)}setInitialNodeLocationOnlyOffsetRecovery(e){e.location={startOffset:NaN,endOffset:NaN}}setInitialNodeLocationOnlyOffsetRegular(e){e.location={startOffset:this.LA(1).startOffset,endOffset:NaN}}setInitialNodeLocationFullRecovery(e){e.location={startOffset:NaN,startLine:NaN,startColumn:NaN,endOffset:NaN,endLine:NaN,endColumn:NaN}}setInitialNodeLocationFullRegular(e){const r=this.LA(1);e.location={startOffset:r.startOffset,startLine:r.startLine,startColumn:r.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}}cstInvocationStateUpdate(e){const r={name:e,children:Object.create(null)};this.setInitialNodeLocation(r),this.CST_STACK.push(r)}cstFinallyStateUpdate(){this.CST_STACK.pop()}cstPostRuleFull(e){const r=this.LA(0),n=e.location;n.startOffset<=r.startOffset?(n.endOffset=r.endOffset,n.endLine=r.endLine,n.endColumn=r.endColumn):(n.startOffset=NaN,n.startLine=NaN,n.startColumn=NaN)}cstPostRuleOnlyOffset(e){const r=this.LA(0),n=e.location;n.startOffset<=r.startOffset?n.endOffset=r.endOffset:n.startOffset=NaN}cstPostTerminal(e,r){const n=this.CST_STACK[this.CST_STACK.length-1];Q_(n,r,e),this.setNodeLocationFromToken(n.location,r)}cstPostNonTerminal(e,r){const n=this.CST_STACK[this.CST_STACK.length-1];eS(n,r,e),this.setNodeLocationFromNode(n.location,e.location)}getBaseCstVisitorConstructor(){if(kr(this.baseCstVisitorConstructor)){const e=rS(this.className,Nt(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor}getBaseCstVisitorConstructorWithDefaults(){if(kr(this.baseCstVisitorWithDefaultsConstructor)){const e=nS(this.className,Nt(this.gastProductionsCache),this.getBaseCstVisitorConstructor());return this.baseCstVisitorWithDefaultsConstructor=e,e}return this.baseCstVisitorWithDefaultsConstructor}getLastExplicitRuleShortName(){const e=this.RULE_STACK;return e[e.length-1]}getPreviousExplicitRuleShortName(){const e=this.RULE_STACK;return e[e.length-2]}getLastExplicitRuleOccurrenceIndex(){const e=this.RULE_OCCURRENCE_STACK;return e[e.length-1]}},s(Ki,"TreeBuilder"),Ki),Wi,B1=(Wi=class{initLexerAdapter(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1}set input(e){if(this.selfAnalysisDone!==!0)throw Error("Missing <performSelfAnalysis> invocation at the end of the Parser's constructor.");this.reset(),this.tokVector=e,this.tokVectorLength=e.length}get input(){return this.tokVector}SKIP_TOKEN(){return this.currIdx<=this.tokVector.length-2?(this.consumeToken(),this.LA(1)):Tf}LA(e){const r=this.currIdx+e;return r<0||this.tokVectorLength<=r?Tf:this.tokVector[r]}consumeToken(){this.currIdx++}exportLexerState(){return this.currIdx}importLexerState(e){this.currIdx=e}resetLexerState(){this.currIdx=-1}moveToTerminatedState(){this.currIdx=this.tokVector.length-1}getLexerPosition(){return this.exportLexerState()}},sLine truncated
See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0
For Further details.`);if(se(e)){if(Re(e))throw Error(`A Token Vocabulary cannot be empty.
Note that the first argument for the parser constructor
is no longer a Token vector (since v4.0).`);if(typeof e[0].startOffset=="number")throw Error(`The Parser constructor no longer accepts a token vector as the first argument.
See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_4-0-0
For Further details.`)}if(se(e))this.tokensMap=kt(e,(i,o)=>(i[o.name]=o,i),{});else if(K(e,"modes")&&Yt(Ht(Ke(e.modes)),y_)){const i=Ht(Ke(e.modes)),o=By(i);this.tokensMap=kt(o,(u,l)=>(u[l.name]=l,u),{})}else if(zt(e))this.tokensMap=it(e);else throw new Error("<tokensDictionary> argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=Jr;const n=K(e,"modes")?Ht(Ke(e.modes)):Ke(e),a=Yt(n,i=>Re(i.categoryMatches));this.tokenMatcher=a?_u:ul,cl(Ke(this.tokensMap))}defineRule(e,r,n){if(this.selfAnalysisDone)throw Error(`Grammar rule <${e}> may not be defined after the 'performSelfAnalysis' method has been called'
Make sure that all grammar rule definitions are done before 'performSelfAnalysis' is called.`);const a=K(n,"resyncEnabled")?n.resyncEnabled:$f.resyncEnabled,i=K(n,"recoveryValueFunc")?n.recoveryValueFunc:$f.recoveryValueFunc,o=this.ruleShortNameIdx<<M1+nn;this.ruleShortNameIdx++,this.shortRuleNameToFull[o]=e,this.fullRuleNameToShort[e]=o;let u;return this.outputCst===!0?u=s(function(...f){try{this.ruleInvocationStateUpdate(o,e,this.subruleIdx),r.apply(this,f);const d=this.CST_STACK[this.CST_STACK.length-1];return this.cstPostRule(d),d}catch(d){return this.invokeRuleCatch(d,a,i)}finally{this.ruleFinallyStateUpdate()}},"invokeRuleWithTry"):u=s(function(...f){try{return this.ruleInvocationStateUpdate(o,e,this.subruleIdx),r.apply(this,f)}catch(d){return this.invokeRuleCatch(d,a,i)}finally{this.ruleFinallyStateUpdate()}},"invokeRuleWithTryCst"),Object.assign(u,{ruleName:e,originalGrammarAction:r})}invokeRuleCatch(e,r,n){const a=this.RULE_STACK.length===1,i=r&&!this.isBackTracking()&&this.recoveryEnabled;if(Su(e)){const o=e;if(i){const u=this.findReSyncTokenType();if(this.isInCurrentRuleReSyncSet(u))if(o.resyncedTokens=this.reSyncTo(u),this.outputCst){const l=this.CST_STACK[this.CST_STACK.length-1];return l.recoveredNode=!0,l}else return n(e);else{if(this.outputCst){const l=this.CST_STACK[this.CST_STACK.length-1];l.recoveredNode=!0,o.partialCstResult=l}throw o}}else{if(a)return this.moveToTerminatedState(),n(e);throw o}}else throw e}optionInternal(e,r){const n=this.getKeyForAutomaticLookahead(J_,r);return this.optionInternalLogic(e,r,n)}optionInternalLogic(e,r,n){let a=this.getLaFuncFromCache(n),i;if(typeof e!="function"){i=e.DEF;const o=e.GATE;if(o!==void 0){const u=a;a=s(()=>o.call(this)&&u.call(this),"lookAheadFunc")}}else i=e;if(a.call(this)===!0)return i.call(this)}atLeastOneInternal(e,r){const n=this.getKeyForAutomaticLookahead(Lm,e);return this.atLeastOneInternalLogic(e,r,n)}atLeastOneInternalLogic(e,r,n){let a=this.getLaFuncFromCache(n),i;if(typeof r!="function"){i=r.DEF;const o=r.GATE;if(o!==void 0){const u=a;a=s(()=>o.call(this)&&u.call(this),"lookAheadFunc")}}else i=r;if(a.call(this)===!0){let o=this.doSingleRepetition(i);for(;a.call(this)===!0&&o===!0;)o=this.doSingleRepetition(i)}else throw this.raiseEarlyExitException(e,Pe.REPETITION_MANDATORY,r.ERR_MSG);this.attemptInRepetitionRecovery(this.atLeastOneInternal,[e,r],a,Lm,e,w1)}atLeastOneSepFirstInternal(e,r){const n=this.getKeyForAutomaticLookahead(Lc,e);this.atLeastOneSepFirstInternalLogic(e,r,n)}atLeastOneSepFirstInternalLogic(e,r,n){const a=r.DEF,i=r.SEP;if(this.getLaFuncFromCache(n).call(this)===!0){a.call(this);const u=s(()=>this.tokenMatcher(this.LA(1),i),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),i)===!0;)this.CONSUME(i),a.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,i,u,a,Jv],u,Lc,e,Jv)}else throw this.raiseEarlyExitException(e,Pe.REPETITION_MANDATORY_WITH_SEPARATOR,r.ERR_MSG)}manyInternal(e,r){const n=this.getKeyForAutomaticLookahead(Om,e);return this.manyInternalLogic(e,r,n)}manyInternalLogic(e,r,n){let a=this.getLaFuncFromCache(n),i;if(typeof r!="function"){i=r.DEF;const u=r.GATE;if(u!==void 0){const l=a;a=s(()=>u.call(this)&&l.call(this),"lookaheadFunction")}}else i=r;let o=!0;for(;a.call(this)===!0&&o===!0;)o=this.doSingleRepetition(i);this.attemptInRepetitionRecovery(this.manyInternal,[e,r],a,Om,e,S1,o)}manySepFirstInternal(e,r){const n=this.getKeyForAutomaticLookahead(Dm,e);this.manySepFirstInternalLogic(e,r,n)}manySepFirstInternalLogic(e,r,n){const a=r.DEF,i=r.SEP;if(this.getLaFuncFromCache(n).call(this)===!0){a.call(this);const u=s(()=>this.tokenMatcher(this.LA(1),i),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),i)===!0;)this.CONSUME(i),a.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,i,u,a,Xv],u,Dm,e,Xv)}}repetitionSepSecondInternal(e,r,n,a,i){for(;n();)this.CONSUME(r),a.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,r,n,a,i],n,Lc,e,i)}doSingleRepetition(e){const r=this.getLexerPosition();return e.call(this),this.getLexerPosition()>r}orInternal(e,r){const n=this.getKeyForAutomaticLookahead(X_,r),a=se(e)?e:e.DEF,o=this.getLaFuncFromCache(n).call(this,a);if(o!==void 0)return a[o].ALT.call(this);this.raiseNoAltException(r,e.ERR_MSG)}ruleFinallyStateUpdate(){if(this.RULE_STACK.pop(),this.RULE_OCCURRENCE_STACK.pop(),this.cstFinallyStateUpdate(),this.RULE_STACK.length===0&&this.isAtEndOfInput()===!1){const e=this.LA(1),r=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new O1(r,e))}}subruleInternal(e,r,n){let a;try{const i=n!==void 0?n.ARGS:void 0;return this.subruleIdx=r,a=e.apply(this,i),this.cstPostNonTerminal(a,n!==void 0&&n.LABEL!==void 0?n.LABEL:e.ruleName),a}catch(i){throw this.subruleInternalError(i,n,e.ruleName)}}subruleInternalError(e,r,n){throw Su(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstRe Line truncated
See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze(oS);var q1={name:`This CSTNode indicates the Parser is in Recording Phase
See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},Xi,H1=(Xi=class{initGastRecorder(e){this.recordingProdStack=[],this.RECORDING_PHASE=!1}enableRecording(){this.RECORDING_PHASE=!0,this.TRACE_INIT("Enable Recording",()=>{for(let e=0;e<10;e++){const r=e>0?e:"";this[`CONSUME${r}`]=function(n,a){return this.consumeInternalRecord(n,e,a)},this[`SUBRULE${r}`]=function(n,a){return this.subruleInternalRecord(n,e,a)},this[`OPTION${r}`]=function(n){return this.optionInternalRecord(n,e)},this[`OR${r}`]=function(n){return this.orInternalRecord(n,e)},this[`MANY${r}`]=function(n){this.manyInternalRecord(e,n)},this[`MANY_SEP${r}`]=function(n){this.manySepFirstInternalRecord(e,n)},this[`AT_LEAST_ONE${r}`]=function(n){this.atLeastOneInternalRecord(e,n)},this[`AT_LEAST_ONE_SEP${r}`]=function(n){this.atLeastOneSepFirstInternalRecord(e,n)}}this.consume=function(e,r,n){return this.consumeInternalRecord(r,e,n)},this.subrule=function(e,r,n){return this.subruleInternalRecord(r,e,n)},this.option=function(e,r){return this.optionInternalRecord(r,e)},this.or=function(e,r){return this.orInternalRecord(r,e)},this.many=function(e,r){this.manyInternalRecord(e,r)},this.atLeastOne=function(e,r){this.atLeastOneInternalRecord(e,r)},this.ACTION=this.ACTION_RECORD,this.BACKTRACK=this.BACKTRACK_RECORD,this.LA=this.LA_RECORD})}disableRecording(){this.RECORDING_PHASE=!1,this.TRACE_INIT("Deleting Recording methods",()=>{const e=this;for(let r=0;r<10;r++){const n=r>0?r:"";delete e[`CONSUME${n}`],delete e[`SUBRULE${n}`],delete e[`OPTION${n}`],delete e[`OR${n}`],delete e[`MANY${n}`],delete e[`MANY_SEP${n}`],delete e[`AT_LEAST_ONE${n}`],delete e[`AT_LEAST_ONE_SEP${n}`]}delete e.consume,delete e.subrule,delete e.option,delete e.or,delete e.many,delete e.atLeastOne,delete e.ACTION,delete e.BACKTRACK,delete e.LA})}ACTION_RECORD(e){}BACKTRACK_RECORD(e,r){return()=>!0}LA_RECORD(e){return Tf}topLevelRuleRecord(e,r){try{const n=new sl({definition:[],name:e});return n.name=e,this.recordingProdStack.push(n),r.call(this),this.recordingProdStack.pop(),n}catch(n){if(n.KNOWN_RECORDER_ERROR!==!0)try{n.message=n.message+`
This error was thrown during the "grammar recording phase" For more info see:
https://chevrotain.io/docs/guide/internals.html#grammar-recording`}catch{throw n}throw n}}optionInternalRecord(e,r){return Na.call(this,at,e,r)}atLeastOneInternalRecord(e,r){Na.call(this,Ot,r,e)}atLeastOneSepFirstInternalRecord(e,r){Na.call(this,Lt,r,e,Zv)}manyInternalRecord(e,r){Na.call(this,xe,r,e)}manySepFirstInternalRecord(e,r){Na.call(this,_t,r,e,Zv)}orInternalRecord(e,r){return lS.call(this,e,r)}subruleInternalRecord(e,r,n){if(wu(r),!e||K(e,"ruleName")===!1){const u=new Error(`<SUBRULE${Fm(r)}> argument is invalid expecting a Parser method reference but got: <${JSON.stringify(e)}>
inside top level rule: <${this.recordingProdStack[0].name}>`);throw u.KNOWN_RECORDER_ERROR=!0,u}const a=Bn(this.recordingProdStack),i=e.ruleName,o=new ht({idx:r,nonTerminalName:i,label:n?.LABEL,referencedRule:void 0});return a.definition.push(o),this.outputCst?q1:yd}consumeInternalRecord(e,r,n){if(wu(r),!Xy(e)){const o=new Error(`<CONSUME${Fm(r)}> argument is invalid expecting a TokenType reference but got: <${JSON.stringify(e)}>
inside top level rule: <${this.recordingProdStack[0].name}>`);throw o.KNOWN_RECORDER_ERROR=!0,o}const a=Bn(this.recordingProdStack),i=new Se({idx:r,terminalType:e,label:n?.LABEL});return a.definition.push(i),oS}},s(Xi,"GastRecorder"),Xi);function Na(t,e,r,n=!1){wu(r);const a=Bn(this.recordingProdStack),i=Gr(e)?e:e.DEF,o=new t({definition:[],idx:r});return n&&(o.separator=e.SEP),K(e,"MAX_LOOKAHEAD")&&(o.maxLookahead=e.MAX_LOOKAHEAD),this.recordingProdStack.push(o),i.call(this),a.definition.push(o),this.recordingProdStack.pop(),yd}s(Na,"recordProd");function lS(t,e){wu(e);const r=Bn(this.recordingProdStack),n=se(t)===!1,a=n===!1?t:t.DEF,i=new St({definition:[],idx:e,ignoreAmbiguities:n&&t.IGNORE_AMBIGUITIES===!0});K(t,"MAX_LOOKAHEAD")&&(i.maxLookahead=t.MAX_LOOKAHEAD);const o=Eb(a,u=>Gr(u.GATE));return i.hasPredicates=o,r.definition.push(i),V(a,u=>{const l=new bt({definition:[]});i.definition.push(l),K(u,"IGNORE_AMBIGUITIES")?l.ignoreAmbiguities=u.IGNORE_AMBIGUITIES:K(u,"GATE")&&(l.ignoreAmbiguities=!0),this.recordingProdStack.push(l),u.ALT.call(this),this.recordingProdStack.pop()}),yd}s(lS,"recordOrProd");function Fm(t){return t===0?"":`${t}`}s(Fm,"getIdxSuffix");function wu(t){if(t<0||t>Qv){const e=new Error(`Invalid DSL Method idx value: <${t}>
Idx value must be a none negative value smaller than ${Qv+1}`);throw e.KNOWN_RECORDER_ERROR=!0,e}}s(wu,"assertMethodIdxIsValid");var Ji,Y1=(Ji=class{initPerformanceTracer(e){if(K(e,"traceInitPerf")){const r=e.traceInitPerf,n=typeof r=="number";this.traceInitMaxIdent=n?r:1/0,this.traceInitPerf=n?r>0:r}else this.traceInitMaxIdent=0,this.traceInitPerf=Lr.traceInitPerf;this.traceInitIndent=-1}TRACE_INIT(e,r){if(this.traceInitPerf===!0){this.traceInitIndent++;const n=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent<this.traceInitMaxIdent&&console.log(`${n}--> <${e}>`);const{time:a,value:i}=Ky(r),o=a>10?console.warn:console.log;return this.traceInitIndent<this.traceInitMaxIdent&&o(`${n}<-- <${e}> time: ${a}ms`),this.traceInitIndent--,i}else return r()}},s(Ji,"PerformanceTracer"),Ji);function uS(t,e){e.forEach(r=>{const n=r.prototype;Object.getOwnPropertyNames(n).forEach(a=>{if(a==="constructor")return;const i=Object.getOwnPropertyDescriptor(n,a);i&&(i.get||i.set)?Object.defineProperty(t.prototype,a,i):t.prototype[a]=r.prototype[a]})})}s(uS,"applyMixins");var Tf=Zu(Jr,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(Tf);var Lr=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:qa,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1}),$f=Object.freeze({recoveryValueFunc:s(()=>{},"recoveryValueFunc"),resyncEnabled:!0}),yt;(function(t){t[t.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",t[t.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",t[t.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",t[t.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",t[t.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",t[t.LEFT_RECURSION=5]="LEFT_RECURSION",t[t.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",t[t.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",t[t.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",t[t.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",t[t.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",t[t.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",t[t.TOO_MANY_ALTS=12]="TOO_MANY_ALTS",t[t.CUSTOM_LOOKAHEAD_VALIDATION=13]="CUSTOM_LOOKAHEAD_VALIDATION"})(yt||(yt={}));function zm(t=void 0){return function(){return t}}s(zm,"EMPTY_ALT");var Fn,og=(Fn=class{static performSelfAnalysis(e){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")}performSelfAnalysis(){this.TRACE_INIT("performSelfAnalysis",()=>{let e;this.selfAnalysisDone=!0;const r=this.className;this.TRACE_INIT("toFastProps",()=>{Wy(this)}),this.TRACE_INIT("Grammar Recording",()=>{try{this.enableRecording(),V(this.definedRulesNames,a=>{const o=this[a].originalGrammarAction;let u;this.TRACE_INIT(`${a} Rule`,()=>{u=this.topLevelRuleRecord(a,o)}),this.gastProductionsCache[a]=u})}finally{this.disableRecording()}});let n=[];if(this.TRACE_INIT("Grammar Resolving",()=>{n=z_({rules:Ke(this.gastProductionsCache)}),this.definitionErrors=this.definitionErrors.concat(n)}),this.TRACE_INIT("Grammar Validations",()=>{if(Re(n)&&this.skipValidations===!1){const a=j_({rules:Ke(this.gastProductionsCache),tokenTypes:Ke(this.tokensMap),errMsgProvider:Ln,grammarName:r}),i=S_({lookaheadStrategy:this.lookaheadStrategy,rules:Ke(this.gastProductionsCache),tokenTypes:Ke(this.tokensMap),grammarName:r});this.definitionErrors=this.definitionErrors.concat(a,i)}}),Re(this.definitionErrors)&&(this.recoveryEnabled&&this.TRACE_INIT("computeAllProdsFollows",()=>{const a=Db(Ke(this.gastProductionsCache));this.resyncFollows=a}),this.TRACE_INIT("ComputeLookaheadFunctions",()=>{var a,i;(i=(a=this.lookaheadStrategy).initialize)===null||i===void 0||i.call(a,{rules:Ke(this.gastProductionsCache)}),this.preComputeLookaheadFunctions(Ke(this.gastProductionsCache))})),!Fn.DEFER_DEFINITION_ERRORS_HANDLING&&!Re(this.definitionErrors))throw e=j(this.definitionErrors,a=>a.message),new Error(`Parser Definition Errors detected:
${e.join(`
-------------------------------
`)}`)})}constructor(e,r){this.definitionErrors=[],this.selfAnalysisDone=!1;const n=this;if(n.initErrorHandler(r),n.initLexerAdapter(),n.initLooksAhead(r),n.initRecognizerEngine(e,r),n.initRecoverable(r),n.initTreeBuilder(r),n.initContentAssist(),n.initGastRecorder(r),n.initPerformanceTracer(r),K(r,"ignoredIssues"))throw new Error(`The <ignoredIssues> IParserConfig property has been deprecated.
Please use the <IGNORE_AMBIGUITIES> flag on the relevant DSL method instead.
See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES
For further details.`);this.skipValidations=K(r,"skipValidations")?r.skipValidations:Lr.skipValidations}},s(Fn,"Parser"),Fn);og.DEFER_DEFINITION_ERRORS_HANDLING=!1;uS(og,[x1,G1,j1,B1,K1,U1,W1,V1,H1,Y1]);var Zi,X1=(Zi=class extends og{constructor(e,r=Lr){const n=it(r);n.outputCst=!1,super(e,n)}},s(Zi,"EmbeddedActionsParser"),Zi);function cS(t,e){for(var r=-1,n=t==null?0:t.length,a=Array(n);++r<n;)a[r]=e(t[r],r,t);return a}s(cS,"arrayMap");var fS=cS;function dS(){this.__data__=[],this.size=0}s(dS,"listCacheClear");var J1=dS;function pS(t,e){return t===e||t!==t&&e!==e}s(pS,"eq");var mS=pS;function hS(t,e){for(var r=t.length;r--;)if(mS(t[r][0],e))return r;return-1}s(hS,"assocIndexOf");var gd=hS,Z1=Array.prototype,Q1=Z1.splice;function yS(t){var e=this.__data__,r=gd(e,t);if(r<0)return!1;var n=e.length-1;return r==n?e.pop():Q1.call(e,r,1),--this.size,!0}s(yS,"listCacheDelete");var eG=yS;function gS(t){var e=this.__data__,r=gd(e,t);return r<0?void 0:e[r][1]}s(gS,"listCacheGet");var tG=gS;function vS(t){return gd(this.__data__,t)>-1}s(vS,"listCacheHas");var rG=vS;function TS(t,e){var r=this.__data__,n=gd(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this}s(TS,"listCacheSet");var nG=TS;function ia(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}s(ia,"ListCache");ia.prototype.clear=J1;ia.prototype.delete=eG;ia.prototype.get=tG;ia.prototype.has=rG;ia.prototype.set=nG;var vd=ia;function $S(){this.__data__=new vd,this.size=0}s($S,"stackClear");var aG=$S;function RS(t){var e=this.__data__,r=e.delete(t);return this.size=e.size,r}s(RS,"stackDelete");var iG=RS;function AS(t){return this.__data__.get(t)}s(AS,"stackGet");var sG=AS;function ES(t){return this.__data__.has(t)}s(ES,"stackHas");var oG=ES,lG=typeof global=="object"&&global&&global.Object===Object&&global,CS=lG,uG=typeof self=="object"&&self&&self.Object===Object&&self,cG=CS||uG||Function("return this")(),Fr=cG,fG=Fr.Symbol,pr=fG,bS=Object.prototype,dG=bS.hasOwnProperty,pG=bS.toString,Ol=pr?pr.toStringTag:void 0;function _S(t){var e=dG.call(t,Ol),r=t[Ol];try{t[Ol]=void 0;var n=!0}catch{}var a=pG.call(t);return n&&(e?t[Ol]=r:delete t[Ol]),a}s(_S,"getRawTag");var mG=_S,hG=Object.prototype,yG=hG.toString;function SS(t){return yG.call(t)}s(SS,"objectToString");var gG=SS,vG="[object Null]",TG="[object Undefined]",eT=pr?pr.toStringTag:void 0;function wS(t){return t==null?t===void 0?TG:vG:eT&&eT in Object(t)?mG(t):gG(t)}s(wS,"baseGetTag");var fl=wS;function IS(t){var e=typeof t;return t!=null&&(e=="object"||e=="function")}s(IS,"isObject");var lg=IS,$G="[object AsyncFunction]",RG="[object Function]",AG="[object GeneratorFunction]",EG="[object Proxy]";function NS(t){if(!lg(t))return!1;var e=fl(t);return e==RG||e==AG||e==$G||e==EG}s(NS,"isFunction");var PS=NS,CG=Fr["__core-js_shared__"],qd=CG,tT=(function(){var t=/[^.]+$/.exec(qd&&qd.keys&&qd.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""})();function kS(t){return!!tT&&tT in t}s(kS,"isMasked");var bG=kS,_G=Function.prototype,SG=_G.toString;function OS(t){if(t!=null){try{return SG.call(t)}catch{}try{return t+""}catch{}}return""}s(OS,"toSource");var sa=OS,wG=/[\\^$.*+?()[\]{}|]/g,IG=/^\[object .+?Constructor\]$/,NG=Function.prototype,PG=Object.prototype,kG=NG.toString,OG=PG.hasOwnProperty,LG=RegExp("^"+kG.call(OG).replace(wG,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");function LS(t){if(!lg(t)||bG(t))return!1;var e=PS(t)?LG:IG;return e.test(sa(t))}s(LS,"baseIsNative");var DG=LS;function DS(t,e){return t?.[e]}s(DS,"getValue");var xG=DS;function xS(t,e){var r=xG(t,e);return DG(r)?r:void 0}s(xS,"getNative");var dl=xS,MG=dl(Fr,"Map"),Iu=MG,GG=dl(Object,"create"),Nu=GG;function MS(){this.__data__=Nu?Nu(null):{},this.size=0}s(MS,"hashClear");var FG=MS;function GS(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}s(GS,"hashDelete");var zG=GS,jG="__lodash_hash_undefined__",BG=Object.prototype,UG=BG.hasOwnProperty;function FS(t){var e=this.__data__;if(Nu){var r=e[t];return r===jG?void 0:r}return UG.call(e,t)?e[t]:void 0}s(FS,"hashGet");var KG=FS,WG=Object.prototype,VG=WG.hasOwnProperty;function zS(t){var e=this.__data__;return Nu?e[t]!==void 0:VG.call(e,t)}s(zS,"hashHas");var qG=zS,HG="__lodash_hash_undefined__";function jS(t,e){var r=this.__data__;return this.size+=this.has(t)?0:1,r[t]=Nu&&e===void 0?HG:e,this}s(jS,"hashSet");var YG=jS;function oa(t){var e=-1,r=t==null?0:t.length;for(this.clear();++e<r;){var n=t[e];this.set(n[0],n[1])}}s(oa,"Hash");oa.prototype.clear=FG;oa.prototype.delete=zG;oa.prototype.get=KG;oa.prototype.has=qG;oa.prototype.set=YG;var rT=oa;function BS(){this.size=0,this.__data__={hash:new rT,map:new(Iu||vd),string:new rT}}s(BS,"mapCacheClear");var XG=BS;function US(t){var e=typeof t;return e=="string"||e=="number"||e=="symbol"||e=="boolean"?t!=="__proto__":t===null}s(US,"isKeyable");var JG=US;function KS(t,e){var r=t.__data__;return JG(e)?r[typeof e=="string"?"string":"hash"]:r.map}s(KS,"getMapDat Line truncated
<${e}> may appears as a prefix path in all these alternatives.
`;return n=n+`See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#AMBIGUOUS_ALTERNATIVES
For Further details.`,n}s(uN,"buildAmbiguityError");function cN(t){if(t instanceof ht)return"SUBRULE";if(t instanceof at)return"OPTION";if(t instanceof St)return"OR";if(t instanceof Ot)return"AT_LEAST_ONE";if(t instanceof Lt)return"AT_LEAST_ONE_SEP";if(t instanceof _t)return"MANY_SEP";if(t instanceof xe)return"MANY";if(t instanceof Se)return"CONSUME";throw Error("non exhaustive match")}s(cN,"getProductionDslName");function fN(t,e,r){const n=Gj(e.configs.elements,i=>i.state.transitions),a=Jj(n.filter(i=>i instanceof vg).map(i=>i.tokenType),i=>i.tokenTypeIdx);return{actualToken:r,possibleTokenTypes:a,tokenPath:t}}s(fN,"buildAdaptivePredictError");function dN(t,e){return t.edges[e.tokenTypeIdx]}s(dN,"getExistingTargetState");function pN(t,e,r){const n=new Wm,a=[];for(const o of t.elements){if(r.is(o.alt)===!1)continue;if(o.state.type===tc){a.push(o);continue}const u=o.state.transitions.length;for(let l=0;l<u;l++){const c=o.state.transitions[l],f=mN(c,e);f!==void 0&&n.add({state:f,alt:o.alt,stack:o.stack})}}let i;if(a.length===0&&n.size===1&&(i=n),i===void 0){i=new Wm;for(const o of n.elements)ku(o,i)}if(a.length>0&&!vN(i))for(const o of a)i.add(o);return i}s(pN,"computeReachSet");function mN(t,e){if(t instanceof vg&&Zy(e,t.tokenType))return t.target}s(mN,"getReachableTarget");function hN(t,e){let r;for(const n of t.elements)if(e.is(n.alt)===!0){if(r===void 0)r=n.alt;else if(r!==n.alt)return}return r}s(hN,"getUniqueAlt");function bg(t){return{configs:t,edges:{},isAcceptState:!1,prediction:-1}}s(bg,"newDFAState");function qm(t,e,r,n){return n=_g(t,n),e.edges[r.tokenTypeIdx]=n,n}s(qm,"addDFAEdge");function _g(t,e){if(e===Af)return e;const r=e.configs.key,n=t.states[r];return n!==void 0?n:(e.configs.finalize(),t.states[r]=e,e)}s(_g,"addDFAState");function yN(t){const e=new Wm,r=t.transitions.length;for(let n=0;n<r;n++){const i={state:t.transitions[n].target,alt:n,stack:[]};ku(i,e)}return e}s(yN,"computeStartState");function ku(t,e){const r=t.state;if(r.type===tc){if(t.stack.length>0){const a=[...t.stack],o={state:a.pop(),alt:t.alt,stack:a};ku(o,e)}else e.add(t);return}r.epsilonOnlyTransitions||e.add(t);const n=r.transitions.length;for(let a=0;a<n;a++){const i=r.transitions[a],o=gN(t,i);o!==void 0&&ku(o,e)}}s(ku,"closure");function gN(t,e){if(e instanceof TI)return{state:e.target,alt:t.alt,stack:t.stack};if(e instanceof Tg){const r=[...t.stack,e.followState];return{state:e.target,alt:t.alt,stack:r}}}s(gN,"getEpsilonTarget");function vN(t){for(const e of t.elements)if(e.state.type===tc)return!0;return!1}s(vN,"hasConfigInRuleStopState");function TN(t){for(const e of t.elements)if(e.state.type!==tc)return!1;return!0}s(TN,"allConfigsInRuleStopStates");function $N(t){if(TN(t))return!0;const e=RN(t.elements);return AN(e)&&!EN(e)}s($N,"hasConflictTerminatingPrediction");function RN(t){const e=new Map;for(const r of t){const n=Eg(r,!1);let a=e.get(n);a===void 0&&(a={},e.set(n,a)),a[r.alt]=!0}return e}s(RN,"getConflictingAltSets");function AN(t){for(const e of Array.from(t.values()))if(Object.keys(e).length>1)return!0;return!1}s(AN,"hasConflictingAltSet");function EN(t){for(const e of Array.from(t.values()))if(Object.keys(e).length===1)return!0;return!1}s(EN,"hasStateAssociatedWithOneAlt");Du();var ss,CN=(ss=class{constructor(){this.nodeStack=[]}get current(){return this.nodeStack[this.nodeStack.length-1]??this.rootNode}buildRootNode(e){return this.rootNode=new wg(e),this.rootNode.root=this.rootNode,this.nodeStack=[this.rootNode],this.rootNode}buildCompositeNode(e){const r=new Nd;return r.grammarSource=e,r.root=this.rootNode,this.current.content.push(r),this.nodeStack.push(r),r}buildLeafNode(e,r){const n=new Ef(e.startOffset,e.image.length,Tu(e),e.tokenType,!r);return n.grammarSource=r,n.root=this.rootNode,this.current.content.push(n),n}removeNode(e){const r=e.container;if(r){const n=r.content.indexOf(e);n>=0&&r.content.splice(n,1)}}addHiddenNodes(e){const r=[];for(const i of e){const o=new Ef(i.startOffset,i.image.length,Tu(i),i.tokenType,!0);o.root=this.rootNode,r.push(o)}let n=this.current,a=!1;if(n.content.length>0){n.content.push(...r);return}for(;n.container;){const i=n.container.content.indexOf(n);if(i>0){n.container.content.splice(i,0,...r),a=!0;break}n=n.container}a||this.rootNode.content.unshift(...r)}construct(e){const r=this.current;typeof e.$type=="string"&&!e.$infixName&&(this.current.astNode=e),e.$cstNode=r;const n=this.nodeStack.pop();n?.content.length===0&&this.removeNode(n)}},s(ss,"CstNodeBuilder"),ss),os,Sg=(os=class{get hidden(){return!1}get astNode(){const e=typeof this._astNode?.$type=="string"?this._astNode:this.container?.astNode;if(!e)throw new Error("This node has no associated AST element");return e}set astNode(e){this._astNode=e}get text(){return this.root.fullText.substring(this.offset,this.end)}},s(os,"AbstractCstNode"),os),ls,Ef=(ls=class extends Sg{get offset(){return this._offset}get length(){return this._length}get end(){return this._offset+this._length}get hidden(){return this._hidden}get Line truncated
`;case"r":return"\r";case"t":return" ";case"v":return"\v";case"0":return"\0";default:return c}}s(r,"convertEscapeCharacter");function n(c){return c.charAt(0)==="^"?c.substring(1):c}s(n,"convertID"),t.convertID=n;function a(c){return parseInt(c)}s(a,"convertInt"),t.convertInt=a;function i(c){return BigInt(c)}s(i,"convertBigint"),t.convertBigint=i;function o(c){return new Date(c)}s(o,"convertDate"),t.convertDate=o;function u(c){return Number(c)}s(u,"convertNumber"),t.convertNumber=u;function l(c){return c.toLowerCase()==="true"}s(l,"convertBoolean"),t.convertBoolean=l})(or||(or={}));var $e={};kf($e,$h(Lf()));function Ld(){return new Promise(t=>{typeof setImmediate>"u"?setTimeout(t,0):setImmediate(t)})}s(Ld,"delayNextTick");var Fc=0,zN=10;function Dd(){return Fc=performance.now(),new $e.CancellationTokenSource}s(Dd,"startCancelableOperation");function Mg(t){zN=t}s(Mg,"setInterruptionPeriod");var cr=Symbol("OperationCancelled");function fa(t){return t===cr}s(fa,"isOperationCancelled");async function Ye(t){if(t===$e.CancellationToken.None)return;const e=performance.now();if(e-Fc>=zN&&(Fc=e,await Ld(),Fc=performance.now()),t.isCancellationRequested)throw cr}s(Ye,"interruptAndCheck");var $s,Dr=($s=class{constructor(){this.promise=new Promise((e,r)=>{this.resolve=n=>(e(n),this),this.reject=n=>(r(n),this)})}},s($s,"Deferred"),$s),Hr,_T=(Hr=class{constructor(e,r,n,a){this._uri=e,this._languageId=r,this._version=n,this._content=a,this._lineOffsets=void 0}get uri(){return this._uri}get languageId(){return this._languageId}get version(){return this._version}getText(e){if(e){const r=this.offsetAt(e.start),n=this.offsetAt(e.end);return this._content.substring(r,n)}return this._content}update(e,r){for(const n of e)if(Hr.isIncremental(n)){const a=Fg(n.range),i=this.offsetAt(a.start),o=this.offsetAt(a.end);this._content=this._content.substring(0,i)+n.text+this._content.substring(o,this._content.length);const u=Math.max(a.start.line,0),l=Math.max(a.end.line,0);let c=this._lineOffsets;const f=Hm(n.text,!1,i);if(l-u===f.length)for(let p=0,y=f.length;p<y;p++)c[p+u+1]=f[p];else f.length<1e4?c.splice(u+1,l-u,...f):this._lineOffsets=c=c.slice(0,u+1).concat(f,c.slice(l+1));const d=n.text.length-(o-i);if(d!==0)for(let p=u+1+f.length,y=c.length;p<y;p++)c[p]=c[p]+d}else if(Hr.isFull(n))this._content=n.text,this._lineOffsets=void 0;else throw new Error("Unknown change event received");this._version=r}getLineOffsets(){return this._lineOffsets===void 0&&(this._lineOffsets=Hm(this._content,!0)),this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);const r=this.getLineOffsets();let n=0,a=r.length;if(a===0)return{line:0,character:e};for(;n<a;){const o=Math.floor((n+a)/2);r[o]>e?a=o:n=o+1}const i=n-1;return e=this.ensureBeforeEOL(e,r[i]),{line:i,character:e-r[i]}}offsetAt(e){const r=this.getLineOffsets();if(e.line>=r.length)return this._content.length;if(e.line<0)return 0;const n=r[e.line];if(e.character<=0)return n;const a=e.line+1<r.length?r[e.line+1]:this._content.length,i=Math.min(n+e.character,a);return this.ensureBeforeEOL(i,n)}ensureBeforeEOL(e,r){for(;e>r&&Gg(this._content.charCodeAt(e-1));)e--;return e}get lineCount(){return this.getLineOffsets().length}static isIncremental(e){const r=e;return r!=null&&typeof r.text=="string"&&r.range!==void 0&&(r.rangeLength===void 0||typeof r.rangeLength=="number")}static isFull(e){const r=e;return r!=null&&typeof r.text=="string"&&r.range===void 0&&r.rangeLength===void 0}},s(Hr,"FullTextDocument"),Hr),_f;(function(t){function e(a,i,o,u){return new _T(a,i,o,u)}s(e,"create"),t.create=e;function r(a,i,o){if(a instanceof _T)return a.update(i,o),a;throw new Error("TextDocument.update: document must be created by TextDocument.create")}s(r,"update"),t.update=r;function n(a,i){const o=a.getText(),u=Sf(i.map(jN),(f,d)=>{const p=f.range.start.line-d.range.start.line;return p===0?f.range.start.character-d.range.start.character:p});let l=0;const c=[];for(const f of u){const d=a.offsetAt(f.range.start);if(d<l)throw new Error("Overlapping edit");d>l&&c.push(o.substring(l,d)),f.newText.length&&c.push(f.newText),l=a.offsetAt(f.range.end)}return c.push(o.substr(l)),c.join("")}s(n,"applyEdits"),t.applyEdits=n})(_f||(_f={}));function Sf(t,e){if(t.length<=1)return t;const r=t.length/2|0,n=t.slice(0,r),a=t.slice(r);Sf(n,e),Sf(a,e);let i=0,o=0,u=0;for(;i<n.length&&o<a.length;)e(n[i],a[o])<=0?t[u++]=n[i++]:t[u++]=a[o++];for(;i<n.length;)t[u++]=n[i++];for(;o<a.length;)t[u++]=a[o++];return t}s(Sf,"mergeSort");function Hm(t,e,r=0){const n=e?[r]:[];for(let a=0;a<t.length;a++){const i=t.charCodeAt(a);Gg(i)&&(i===13&&a+1<t.length&&t.charCodeAt(a+1)===10&&a++,n.push(r+a+1))}return n}s(Hm,"computeLineOffsets");function Gg(t){return t===13||t===10}s(Gg,"isEOL");function Fg(t){const e=t.start,r=t.end;return e.line>r.line||e.line===r.line&&e.character>r.character?{start:r,end:e}:t}s(Fg,"getWellformedRange");function jN(t){const e=Fg(t.range);return e!==t.range?{newText:t.newText,range:e}:t}s(jN,"getWellfo Line truncated
${r}`),this.inline?`{${e}}`:e}toMarkdown(e){return e?.renderTag?.(this)??this.toMarkdownDefault(e)}toMarkdownDefault(e){const r=this.content.toMarkdown(e);if(this.inline){const i=vP(this.name,r,e??{});if(typeof i=="string")return i}let n="";e?.tag==="italic"||e?.tag===void 0?n="*":e?.tag==="bold"?n="**":e?.tag==="bold-italic"&&(n="***");let a=`${n}@${this.name}${n}`;return this.content.inlines.length===1?a=`${a} — ${r}`:this.content.inlines.length>1&&(a=`${a}
${r}`),this.inline?`{${a}}`:a}},s(Qs,"JSDocTagImpl"),Qs);function vP(t,e,r){if(t==="linkplain"||t==="linkcode"||t==="link"){const n=e.indexOf(" ");let a=e;if(n>0){const o=Pf(e,n);a=e.substring(o),e=e.substring(0,n)}return(t==="linkcode"||t==="link"&&r.link==="code")&&(a=`\`${a}\``),r.renderLink?.(e,a)??TP(e,a)}}s(vP,"renderInlineTag");function TP(t,e){try{return It.parse(t,!0),`[${e}](${t})`}catch{return t}}s(TP,"renderLinkDefault");var eo,Jm=(eo=class{constructor(e,r){this.inlines=e,this.range=r}toString(){let e="";for(let r=0;r<this.inlines.length;r++){const n=this.inlines[r],a=this.inlines[r+1];e+=n.toString(),a&&a.range.start.line>n.range.start.line&&(e+=`
`)}return e}toMarkdown(e){let r="";for(let n=0;n<this.inlines.length;n++){const a=this.inlines[n],i=this.inlines[n+1];r+=a.toMarkdown(e),i&&i.range.start.line>a.range.start.line&&(r+=`
`)}return r}},s(eo,"JSDocTextImpl"),eo),to,$P=(to=class{constructor(e,r){this.text=e,this.range=r}toString(){return this.text}toMarkdown(){return this.text}},s(to,"JSDocLineImpl"),to);function Zm(t){return t.endsWith(`
`)?`
`:`
`}s(Zm,"fillNewlines");var ro,RP=(ro=class{constructor(e){this.indexManager=e.shared.workspace.IndexManager,this.commentProvider=e.documentation.CommentProvider}getDocumentation(e){const r=this.commentProvider.getComment(e);if(r&&Xg(r))return Yg(r).toMarkdown({renderLink:s((a,i)=>this.documentationLinkRenderer(e,a,i),"renderLink"),renderTag:s(a=>this.documentationTagRenderer(e,a),"renderTag")})}documentationLinkRenderer(e,r,n){const a=this.findNameInLocalSymbols(e,r)??this.findNameInGlobalScope(e,r);if(a&&a.nameSegment){const i=a.nameSegment.range.start.line+1,o=a.nameSegment.range.start.character+1,u=a.documentUri.with({fragment:`L${i},${o}`});return`[${n}](${u.toString()})`}else return}documentationTagRenderer(e,r){}findNameInLocalSymbols(e,r){const a=Vt(e).localSymbols;if(!a)return;let i=e;do{const u=a.getStream(i).find(l=>l.name===r);if(u)return u;i=i.$container}while(i)}findNameInGlobalScope(e,r){return this.indexManager.allElements().find(a=>a.name===r)}},s(ro,"JSDocDocumentationProvider"),ro),no,AP=(no=class{constructor(e){this.grammarConfig=()=>e.parser.GrammarConfig}getComment(e){return Kg(e)?e.$comment:Zh(e.$cstNode,this.grammarConfig().multilineCommentRules)?.text}},s(no,"DefaultCommentProvider"),no),ao,EP=(ao=class{constructor(e){this.syncParser=e.parser.LangiumParser}parse(e,r){return Promise.resolve(this.syncParser.parse(e))}},s(ao,"DefaultAsyncParser"),ao),io,gB=(io=class{constructor(e){this.threadCount=8,this.terminationDelay=200,this.workerPool=[],this.queue=[],this.hydrator=e.serializer.Hydrator}initializeWorkers(){for(;this.workerPool.length<this.threadCount;){const e=this.createWorker();e.onReady(()=>{if(this.queue.length>0){const r=this.queue.shift();r&&(e.lock(),r.resolve(e))}}),this.workerPool.push(e)}}async parse(e,r){const n=await this.acquireParserWorker(r),a=new Dr;let i;const o=r.onCancellationRequested(()=>{i=setTimeout(()=>{this.terminateWorker(n)},this.terminationDelay)});return n.parse(e).then(u=>{const l=this.hydrator.hydrate(u);a.resolve(l)}).catch(u=>{a.reject(u)}).finally(()=>{o.dispose(),clearTimeout(i)}),a.promise}terminateWorker(e){e.terminate();const r=this.workerPool.indexOf(e);r>=0&&this.workerPool.splice(r,1)}async acquireParserWorker(e){this.initializeWorkers();for(const n of this.workerPool)if(n.ready)return n.lock(),n;const r=new Dr;return e.onCancellationRequested(()=>{const n=this.queue.indexOf(r);n>=0&&this.queue.splice(n,1),r.reject(cr)}),this.queue.push(r),r.promise}},s(io,"AbstractThreadedAsyncParser"),io),so,vB=(so=class{get ready(){return this._ready}get onReady(){return this.onReadyEmitter.event}constructor(e,r,n,a){this.onReadyEmitter=new Gd.Emitter,this.deferred=new Dr,this._ready=!0,this._parsing=!1,this.sendMessage=e,this._terminate=a,r(i=>{const o=i;this.deferred.resolve(o),this.unlock()}),n(i=>{this.deferred.reject(i),this.unlock()})}terminate(){this.deferred.reject(cr),this._terminate()}lock(){this._ready=!1}unlock(){this._parsing=!1,this._ready=!0,this.onReadyEmitter.fire()}parse(e){if(this._parsing)throw new Error("Parser worker is busy");return this._parsing=!0,this.deferred=new Dr,this.sendMessage(e),this.deferred.promise}},s(so,"ParserWorker"),so),oo,CP=(oo=class{constructor(){this.previousTokenSource=new $e.CancellationTokenSource,this.writeQueue=[],this.readQueue=[],this.done=!0}write(e){this.cancelWrite();const r=Dd();return this.previousTokenSource=r,this.enqueue(this.writeQueue,e,r.token)}read(e){return this.enqueue(this.readQueue,e)}enqueue(e,r,n=$e.CancellationToken.None){const a=new Dr,i={action:r,deferred:a,cancellationToken:n};return e.push(i),this.performNextOperation(),a.promise}async performNextOperation(){if(!this.done)return;const e=[];if(this.writeQueue.length>0)e.push(this.writeQueue.shift());else if(this.readQueue.length>0)e.push(...this.readQueue.splice(0,this.readQueue.length));else return;this.done=!1,await Promise.all(e.map(async({action:r,deferred:n,cancellationToken:a})=>{try{const i=await Promise.resolve().then(()=>r(a));n.resolve(i)}catch(i){fa(i)?n.resolve(void 0):n.reject(i)}})),this.done=!0,this.performNextOperation()}cancelWrite(){this.previousTokenSource.cancel()}},s(oo,"DefaultWorkspaceLock"),oo),lo,bP=(lo=class{constructor(e){this.grammarElementIdMap=new wf,this.tokenTypeIdMap=new wf,this.grammar=e.Grammar,this.lexer=e.parser.Lexer,this.linker=e.references.Linker}dehydrate(e){return{lexerErrors:e.lexerErrors,lexerReport:e.lexerReport?this.dehydrateLexerReport(e.lexerReport):void 0,parserErrors:e.parserErrors.map(r=>({...r,message:r.message})),value:this.dehydrateAstNode(e.value,this.createDehyrationContext(e.value))}}dehydrateLexerReport(e){return e}createDehyrationContext(e){const r=new Map,n=new Map;for(const a of qt(e))r.set(a,{});if(e.$cstNode)for(const a of Jo(e.$cstNode))n.set(a,{});return{astNodes:r,cstNodes:n}}dehydrateAstNode(e,r){const n=r.astNodes.get(e);n.$type=e.$type,n.$containerIndex=e.$containerIndex,n.$containerProperty=e.$containerProperty,e.$cstNode!==void 0&&(n.$cstNode=this.dehydrateCstN Line truncated
`.includes(e[r-1])}matchWhitespace(e,r,n,a){this.whitespaceRegExp.lastIndex=r;const i=this.whitespaceRegExp.exec(e);return{currIndentLevel:i?.[0].length??0,prevIndentLevel:this.indentationStack.at(-1),match:i}}createIndentationTokenInstance(e,r,n,a){const i=this.getLineNumber(r,a);return Zu(e,n,a,a+n.length,i,i,1,n.length)}getLineNumber(e,r){return e.substring(0,r).split(/\r\n|\r|\n/).length}indentMatcher(e,r,n,a){if(!this.isStartOfLine(e,r))return null;const{currIndentLevel:i,prevIndentLevel:o,match:u}=this.matchWhitespace(e,r,n,a);return i<=o?null:(this.indentationStack.push(i),u)}dedentMatcher(e,r,n,a){if(!this.isStartOfLine(e,r))return null;const{currIndentLevel:i,prevIndentLevel:o,match:u}=this.matchWhitespace(e,r,n,a);if(i>=o)return null;const l=this.indentationStack.lastIndexOf(i);if(l===-1)return this.diagnostics.push({severity:"error",message:`Invalid dedent level ${i} at offset: ${r}. Current indentation stack: ${this.indentationStack}`,offset:r,length:u?.[0]?.length??0,line:this.getLineNumber(e,r),column:1}),null;const c=this.indentationStack.length-l-1,f=e.substring(0,r).match(/[\r\n]+$/)?.[0].length??1;for(let d=0;d<c;d++){const p=this.createIndentationTokenInstance(this.dedentTokenType,e,"",r-(f-1));n.push(p),this.indentationStack.pop()}return null}buildTerminalToken(e){const r=super.buildTerminalToken(e),{indentTokenName:n,dedentTokenName:a,whitespaceTokenName:i}=this.options;return r.name===n?this.indentTokenType:r.name===a?this.dedentTokenType:r.name===i?Xa({name:i,pattern:this.whitespaceRegExp,group:pt.SKIPPED}):r}flushRemainingDedents(e){const r=[];for(;this.indentationStack.length>1;)r.push(this.createIndentationTokenInstance(this.dedentTokenType,e,"",e.length)),this.indentationStack.pop();return this.indentationStack=[0],r}},s(uo,"IndentationAwareTokenBuilder"),uo),co,TB=(co=class extends Hg{constructor(e){if(super(e),e.parser.TokenBuilder instanceof SP)this.indentationTokenBuilder=e.parser.TokenBuilder;else throw new Error("IndentationAwareLexer requires an accompanying IndentationAwareTokenBuilder")}tokenize(e,r=qg){const n=super.tokenize(e),a=n.report;r?.mode==="full"&&n.tokens.push(...a.remainingDedents),a.remainingDedents=[];const{indentTokenType:i,dedentTokenType:o}=this.indentationTokenBuilder,u=i.tokenTypeIdx,l=o.tokenTypeIdx,c=[],f=n.tokens.length-1;for(let d=0;d<f;d++){const p=n.tokens[d],y=n.tokens[d+1];if(p.tokenTypeIdx===u&&y.tokenTypeIdx===l){d++;continue}c.push(p)}return f>=0&&c.push(n.tokens[f]),n.tokens=c,n}},s(co,"IndentationAwareLexer"),co),nv={};en(nv,{AstUtils:()=>_h,BiMap:()=>wf,Cancellation:()=>$e,ContextCache:()=>Md,CstUtils:()=>Eh,DONE_RESULT:()=>ct,Deferred:()=>Dr,Disposable:()=>Gn,DisposableCache:()=>xd,DocumentCache:()=>XN,EMPTY_STREAM:()=>Vo,ErrorWithLocation:()=>Uf,GrammarUtils:()=>ry,MultiMap:()=>xr,OperationCancelled:()=>cr,Reduction:()=>vu,RegExpUtils:()=>ay,SimpleCache:()=>Bg,StreamImpl:()=>ur,TreeStreamImpl:()=>qo,URI:()=>It,UriTrie:()=>zg,UriUtils:()=>dt,WorkspaceCache:()=>Ug,assertCondition:()=>ny,assertUnreachable:()=>tn,delayNextTick:()=>Ld,interruptAndCheck:()=>Ye,isOperationCancelled:()=>fa,loadGrammarFromJson:()=>Ze,setInterruptionPeriod:()=>Mg,startCancelableOperation:()=>Dd,stream:()=>de});kf(nv,Gd);var fo,wP=(fo=class{stat(e){throw new Error("No file system is available.")}statSync(e){throw new Error("No file system is available.")}async exists(){return!1}existsSync(){return!1}readBinary(){throw new Error("No file system is available.")}readBinarySync(){throw new Error("No file system is available.")}readFile(){throw new Error("No file system is available.")}readFileSync(){throw new Error("No file system is available.")}async readDirectory(){return[]}readDirectorySync(){return[]}},s(fo,"EmptyFileSystemProvider"),fo),st={fileSystemProvider:s(()=>new wP,"fileSystemProvider")},$B={Grammar:s(()=>{},"Grammar"),LanguageMetaData:s(()=>({caseInsensitive:!1,fileExtensions:[".langium"],languageId:"langium"}),"LanguageMetaData")},RB={AstReflection:s(()=>new qh,"AstReflection")};function IP(){const t=re(Je(st),RB),e=re(Xe({shared:t}),$B);return t.ServiceRegistry.register(e),e}s(IP,"createMinimalGrammarServices");function Ze(t){const e=IP(),r=e.serializer.JsonSerializer.deserialize(t);return e.shared.workspace.LangiumDocumentFactory.fromModel(r,It.parse(`memory:/${r.name??"grammar"}.langium`)),r}s(Ze,"loadGrammarFromJson");kf(z$,nv);var po,AB=(po=class{constructor(e){this.activeCategories=new Set,this.allCategories=new Set(["validating","parsing","linking"]),this.activeCategories=e??new Set(this.allCategories),this.records=new xr}isActive(e){return this.activeCategories.has(e)}start(...e){e?e.forEach(r=>this.activeCategories.add(r)):this.activeCategories=new Set(this.allCategories)}stop(...e){e?e.forEach(r=>this.activeCategories.delete(r)):this.activeCategories.clear()}createTask(e,r){if(!this.isActive(e))throw new Error(`Category "${e}" is not active.`);return console.log(`Creating profiling task for '${e}.${r}'.`),new NP(n=>this.records.add(e,this.dumpLine truncated
`)}}},s(yo,"AbstractMermaidValueConverter"),yo),go,pl=(go=class extends vr{runCustomConverter(e,r,n){}},s(go,"CommonValueConverter"),go),vo,$t=(vo=class extends Od{constructor(e){super(),this.keywords=new Set(e)}buildKeywordTokens(e,r,n){const a=super.buildKeywordTokens(e,r,n);return a.forEach(i=>{this.keywords.has(i.name)&&i.PATTERN!==void 0&&(i.PATTERN=new RegExp(i.PATTERN.toString()+"(?:(?=%%)|(?!\\S))"))}),a}},s(vo,"AbstractMermaidTokenBuilder"),vo),To;To=class extends $t{},s(To,"CommonTokenBuilder");var $o,zU=($o=class extends $t{constructor(){super(["radar-beta"])}},s($o,"RadarTokenBuilder"),$o),kP={parser:{TokenBuilder:s(()=>new zU,"TokenBuilder"),ValueConverter:s(()=>new pl,"ValueConverter")}};function OP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),wU,kP);return e.ServiceRegistry.register(r),{shared:e,Radar:r}}s(OP,"createRadarServices");var Ro,jU=(Ro=class extends $t{constructor(){super(["railroad-beta"])}},s(Ro,"RailroadTokenBuilder"),Ro),w$=s(t=>{const e=t.slice(1,-1);let r="";for(let n=0;n<e.length;n++){const a=e[n];if(a==="\\"&&n+1<e.length){n++;const i=e[n];switch(i){case"n":r+=`
`;break;case"r":r+="\r";break;case"t":r+=" ";break;default:r+=i}continue}r+=a}return r},"decodeEscapedString"),Ao,BU=(Ao=class extends vr{runConverter(e,r,n){const a=super.runConverter(e,r,n);if(e.name==="TITLE"&&typeof a=="string"){const i=a.trim();if(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))return w$(i)}return a}runCustomConverter(e,r,n){if(e.name==="RR_STRING")return w$(r)}},s(Ao,"RailroadValueConverter"),Ao),LP={parser:{TokenBuilder:s(()=>new jU,"TokenBuilder"),ValueConverter:s(()=>new BU,"ValueConverter")}};function DP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),PU,LP);return e.ServiceRegistry.register(r),{shared:e,Railroad:r}}s(DP,"createRailroadServices");var Eo,UU=(Eo=class extends $t{constructor(){super(["railroad-ebnf-beta"])}},s(Eo,"RailroadEbnfTokenBuilder"),Eo),I$=s(t=>{const e=t.slice(1,-1);let r="";for(let n=0;n<e.length;n++){const a=e[n];if(a==="\\"&&n+1<e.length){n++;const i=e[n];switch(i){case"n":r+=`
`;break;case"r":r+="\r";break;case"t":r+=" ";break;default:r+=i}continue}r+=a}return r},"decodeEscapedString"),Co,KU=(Co=class extends vr{runConverter(e,r,n){const a=super.runConverter(e,r,n);if(e.name==="TITLE"&&typeof a=="string"){const i=a.trim();if(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))return I$(i)}return a}runCustomConverter(e,r,n){if(e.name==="EBNF_STRING")return I$(r);if(e.name==="EBNF_SPECIAL_SEQUENCE")return r.slice(1,-1).trim()}},s(Co,"RailroadEbnfValueConverter"),Co),xP={parser:{TokenBuilder:s(()=>new UU,"TokenBuilder"),ValueConverter:s(()=>new KU,"ValueConverter")}};function MP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),NU,xP);return e.ServiceRegistry.register(r),{shared:e,RailroadEbnf:r}}s(MP,"createRailroadEbnfServices");var bo,WU=(bo=class extends $t{constructor(){super(["railroad-abnf-beta"])}},s(bo,"RailroadAbnfTokenBuilder"),bo),_o,VU=(_o=class extends vr{runConverter(e,r,n){const a=super.runConverter(e,r,n);if(e.name==="TITLE"&&typeof a=="string"){const i=a.trim();if(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))return i.slice(1,-1)}return a}runCustomConverter(e,r,n){if(e.name==="ABNF_STRING")return r.slice(1,-1)}},s(_o,"RailroadAbnfValueConverter"),_o),GP={parser:{TokenBuilder:s(()=>new WU,"TokenBuilder"),ValueConverter:s(()=>new VU,"ValueConverter")}};function FP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),IU,GP);return e.ServiceRegistry.register(r),{shared:e,RailroadAbnf:r}}s(FP,"createRailroadAbnfServices");var So,qU=(So=class extends $t{constructor(){super(["railroad-peg-beta"])}},s(So,"RailroadPegTokenBuilder"),So),N$=s(t=>{const e=t.slice(1,-1);let r="";for(let n=0;n<e.length;n++){const a=e[n];if(a==="\\"&&n+1<e.length){n++;const i=e[n];switch(i){case"n":r+=`
`;break;case"r":r+="\r";break;case"t":r+=" ";break;default:r+=i}continue}r+=a}return r},"decodeEscapedString"),wo,HU=(wo=class extends vr{runConverter(e,r,n){const a=super.runConverter(e,r,n);if(e.name==="TITLE"&&typeof a=="string"){const i=a.trim();if(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))return N$(i)}return a}runCustomConverter(e,r,n){if(e.name==="PEG_STRING")return N$(r)}},s(wo,"RailroadPegValueConverter"),wo),zP={parser:{TokenBuilder:s(()=>new qU,"TokenBuilder"),ValueConverter:s(()=>new HU,"ValueConverter")}};function jP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),kU,zP);return e.ServiceRegistry.register(r),{shared:e,RailroadPeg:r}}s(jP,"createRailroadPegServices");var Io,YU=(Io=class extends $t{constructor(){super(["treemap"])}},s(Io,"TreemapTokenBuilder"),Io),XU=/classDef\s+([A-Z_a-z]\w+)(?:\s+([^\n\r;]*))?;?/,No,JU=(No=class extends vr{runCustomConverter(e,r,n){if(e.name==="NUMBER2")return parseFloat(r.replace(/,/g,""));if(e.name==="SEPARATOR")return r.substring(1,r.length-1);if(e.name==="STRING2")return r.substring(1,r.length-1);if(e.name==="INDENTATION")return r.length;if(e.name==="ClassDef"){if(typeof r!="string")return r;const a=XU.exec(r);if(a)return{$type:"ClassDefStatement",className:a[1],styleText:a[2]||void 0}}}},s(No,"TreemapValueConverter"),No);function BP(t){const e=t.validation.TreemapValidator,r=t.validation.ValidationRegistry;if(r){const n={Treemap:e.checkSingleRoot.bind(e)};r.register(n,e)}}s(BP,"registerValidationChecks");var Po,ZU=(Po=class{checkSingleRoot(e,r){let n;for(const a of e.TreemapRows)a.item&&(n===void 0&&a.indent===void 0?n=0:a.indent===void 0?r("error","Multiple root nodes are not allowed in a treemap.",{node:a,property:"item"}):n!==void 0&&n>=parseInt(a.indent,10)&&r("error","Multiple root nodes are not allowed in a treemap.",{node:a,property:"item"}))}},s(Po,"TreemapValidator"),Po),UP={parser:{TokenBuilder:s(()=>new YU,"TokenBuilder"),ValueConverter:s(()=>new JU,"ValueConverter")},validation:{TreemapValidator:s(()=>new ZU,"TreemapValidator")}};function KP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),OU,UP);return e.ServiceRegistry.register(r),BP(r),{shared:e,Treemap:r}}s(KP,"createTreemapServices");var ko,QU=(ko=class extends vr{runCustomConverter(e,r,n){if(e.name.toUpperCase()==="LINK_LABEL")return r.substring(1).trim()}},s(ko,"WardleyValueConverter"),ko),WP={parser:{ValueConverter:s(()=>new QU,"ValueConverter")}};function VP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),DU,WP);return e.ServiceRegistry.register(r),{shared:e,Wardley:r}}s(VP,"createWardleyServices");var Oo,eK=(Oo=class extends $t{constructor(){super(["cynefin-beta"])}},s(Oo,"CynefinTokenBuilder"),Oo),qP={parser:{TokenBuilder:s(()=>new eK,"TokenBuilder"),ValueConverter:s(()=>new pl,"ValueConverter")}};function HP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),AU,qP);return e.ServiceRegistry.register(r),{shared:e,Cynefin:r}}s(HP,"createCynefinServices");var Lo,tK=(Lo=class extends $t{constructor(){super(["gitGraph"])}},s(Lo,"GitGraphTokenBuilder"),Lo),YP={parser:{TokenBuilder:s(()=>new tK,"TokenBuilder"),ValueConverter:s(()=>new pl,"ValueConverter")}};function XP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),CU,YP);return e.ServiceRegistry.register(r),{shared:e,GitGraph:r}}s(XP,"createGitGraphServices");var Do,rK=(Do=class extends $t{constructor(){super(["info","showInfo"])}},s(Do,"InfoTokenBuilder"),Do),JP={parser:{TokenBuilder:s(()=>new rK,"TokenBuilder"),ValueConverter:s(()=>new pl,"ValueConverter")}};function ZP(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),bU,JP);return e.ServiceRegistry.register(r),{shared:e,Info:r}}s(ZP,"createInfoServices");var xo,nK=(xo=class extends $t{constructor(){super(["packet"])}},s(xo,"PacketTokenBuilder"),xo),QP={parser:{TokenBuilder:s(()=>new nK,"TokenBuilder"),ValueConverter:s(()=>new pl,"ValueConverter")}};function ek(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),_U,QP);return e.ServiceRegistry.register(r),{shared:e,Packet:r}}s(ek,"createPacketServices");var Mo,aK=(Mo=class extends $t{constructor(){super(["pie","showData"])}},s(Mo,"PieTokenBuilder"),Mo),Go,iK=(Go=class extends vr{runCustomConverter(e,r,n){if(e.name==="PIE_SECTION_LABEL")return r.replace(/"/g,"").trim()}},s(Go,"PieValueConverter"),Go),tk={parser:{TokenBuilder:s(()=>new aK,"TokenBuilder"),ValueConverter:s(()=>new iK,"ValueConverter")}};function rk(t=st){const e=re(Je(t),Tt),r=re(Xe({shared:e}),SU,tk);return e.ServiceRegistry.register(r),{shared:e,Pie:r}}s(rk,"createPieServices");var Fo,sK=(Fo=class extends vr{runCustomConverter(e,r,n){if(e.name==="INDENTATION")return r?.length||0;if(e.name==="QUOTED_NAME")return r.substring(1,r.length-1);if(e.name==="BARE_NAME")return r.replace(/[\t ]+$/,"");if(e.name==="CLASS_ANNOTATION")return r.trim().substring(3).trim();if(e.name==="ICON_ANNOTATION"){const a=r.trim();return a.substring(5,a.length-1)}if(e.name==="DESC_ANNOTATION")return r.trim().substring(2).trim()}},s(Fo,"TreeViewValueConverter"),Fo),zo,oK=(zo=class extends Line truncated
`),n=e.parserErrors.map(a=>{const i=a.token.startLine!==void 0&&!isNaN(a.token.startLine)?a.token.startLine:"?",o=a.token.startColumn!==void 0&&!isNaN(a.token.startColumn)?a.token.startColumn:"?";return`Parse error on line ${i}, column ${o}: ${a.message}`}).join(`
`);super(`Parsing failed: ${r} ${n}`),this.result=e}},s(Wo,"MermaidParseError"),Wo);const hK=Object.freeze(Object.defineProperty({__proto__:null,InfoModule:JP,createInfoServices:ZP},Symbol.toStringTag,{value:"Module"})),yK=Object.freeze(Object.defineProperty({__proto__:null,PacketModule:QP,createPacketServices:ek},Symbol.toStringTag,{value:"Module"})),gK=Object.freeze(Object.defineProperty({__proto__:null,PieModule:tk,createPieServices:rk},Symbol.toStringTag,{value:"Module"})),vK=Object.freeze(Object.defineProperty({__proto__:null,TreeViewModule:nk,createTreeViewServices:ak},Symbol.toStringTag,{value:"Module"})),TK=Object.freeze(Object.defineProperty({__proto__:null,ArchitectureModule:ik,createArchitectureServices:sk},Symbol.toStringTag,{value:"Module"})),$K=Object.freeze(Object.defineProperty({__proto__:null,GitGraphModule:YP,createGitGraphServices:XP},Symbol.toStringTag,{value:"Module"})),RK=Object.freeze(Object.defineProperty({__proto__:null,EventModelingModule:lk,createEventModelingServices:uk},Symbol.toStringTag,{value:"Module"})),AK=Object.freeze(Object.defineProperty({__proto__:null,RadarModule:kP,createRadarServices:OP},Symbol.toStringTag,{value:"Module"})),EK=Object.freeze(Object.defineProperty({__proto__:null,RailroadModule:LP,createRailroadServices:DP},Symbol.toStringTag,{value:"Module"})),CK=Object.freeze(Object.defineProperty({__proto__:null,RailroadEbnfModule:xP,createRailroadEbnfServices:MP},Symbol.toStringTag,{value:"Module"})),bK=Object.freeze(Object.defineProperty({__proto__:null,RailroadAbnfModule:GP,createRailroadAbnfServices:FP},Symbol.toStringTag,{value:"Module"})),_K=Object.freeze(Object.defineProperty({__proto__:null,RailroadPegModule:zP,createRailroadPegServices:jP},Symbol.toStringTag,{value:"Module"})),SK=Object.freeze(Object.defineProperty({__proto__:null,TreemapModule:UP,createTreemapServices:KP},Symbol.toStringTag,{value:"Module"})),wK=Object.freeze(Object.defineProperty({__proto__:null,WardleyModule:WP,createWardleyServices:VP},Symbol.toStringTag,{value:"Module"})),IK=Object.freeze(Object.defineProperty({__proto__:null,CynefinModule:qP,createCynefinServices:HP},Symbol.toStringTag,{value:"Module"}));export{mK as M,MP as a,FP as b,DP as c,jP as d,NB as i,pK as p};
@@ -0,0 +1,62 @@
import{p as xt}from"./chunk-JWPE2WC7.js";import{s as gt,g as $t,o as bt,n as wt,a as Ct,b as vt,_ as s,l as O,D as Dt,d as kt,p as At,A as U,y as Q,B as Tt,E as ot}from"./mermaid.core.js";import{p as Bt}from"./cynefin-OW5HDTMX.js";import"./index.js";var rt=s(()=>({domains:new Map,transitions:[]}),"createDefaultData"),H=rt(),St=s(()=>H.domains,"getDomains"),Mt=s(()=>H.transitions,"getTransitions"),zt=s(t=>{if(t)for(const e of t){const n=e.domain,a=(e.items??[]).map(c=>({label:c.label}));H.domains.set(n,{name:n,items:a})}},"setDomains"),Lt=s(t=>{t&&(H.transitions=t.filter(e=>e.from===e.to?(O.warn(`Cynefin: self-loop transition on domain "${e.from}" is not meaningful and will be skipped.`),!1):!0).map(e=>({from:e.from,to:e.to,label:e.label||void 0})))},"setTransitions"),Nt=s(()=>U({...Tt.cynefin,...Q().cynefin}),"getConfig"),Pt=s(()=>{At(),H=rt()},"clear"),Y={getDomains:St,getTransitions:Mt,setDomains:zt,setTransitions:Lt,getConfig:Nt,clear:Pt,setAccTitle:vt,getAccTitle:Ct,setDiagramTitle:wt,getDiagramTitle:bt,getAccDescription:$t,setAccDescription:gt},It=s(t=>{xt(t,Y),Y.setDomains(t.domains),Y.setTransitions(t.transitions)},"populate"),Wt={parse:s(async t=>{const e=await Bt("cynefin",t);O.debug(e),It(e)},"parse")};function V(t){let e=t+1831565813|0;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}s(V,"seededRandom");function st(t){let e=0;for(let n=0;n<t.length;n++){const a=t.charCodeAt(n);e=(e<<5)-e+a,e|=0}return e}s(st,"hashString");function it(t,e){return typeof t=="number"&&Number.isFinite(t)&&t!==0?t:st(e)}s(it,"resolveSeed");function ct(t,e,n,a){const c=t/2,m=a??t*.015,v=7,W=e/v,d=[];for(let o=0;o<=v;o++){const p=V(n+o*17)*m*2-m;d.push({x:c+p,y:o*W})}let D=`M${d[0].x},${d[0].y}`;for(let o=0;o<d.length-1;o++){const p=d[o],i=d[o+1],f=(p.y+i.y)/2,b=o%2===0?1:-1,h=m*1.5*b*V(n+o*31+7),R=p.x+h,_=f,E=i.x-h;D+=` C${R},${_} ${E},${f} ${i.x},${i.y}`}return D}s(ct,"generateFoldPath");function lt(t,e,n,a){const c=e/2,m=a??e*.015,v=7,W=t/v,d=[];for(let o=0;o<=v;o++){const p=V(n+o*23)*m*2-m;d.push({x:o*W,y:c+p})}let D=`M${d[0].x},${d[0].y}`;for(let o=0;o<d.length-1;o++){const p=d[o],i=d[o+1],f=(p.x+i.x)/2,b=o%2===0?1:-1,h=m*1.5*b*V(n+o*37+11),R=f,_=p.y+h,E=f,z=i.y-h;D+=` C${R},${_} ${E},${z} ${i.x},${i.y}`}return D}s(lt,"generateHorizontalBoundary");function dt(t,e){const n=t/2,a=e*.5,c=e,m=t*.03;return[`M${n},${a}`,`C${n+m},${a+(c-a)*.2}`,`${n-m*1.5},${a+(c-a)*.55}`,`${n+m*.5},${a+(c-a)*.75}`,`C${n-m},${a+(c-a)*.85}`,`${n+m*.3},${a+(c-a)*.95}`,`${n},${c}`].join(" ")}s(dt,"generateCliffPath");function ft(t,e,n,a){return[`M${t-n},${e}`,`A${n},${a} 0 1,1 ${t+n},${e}`,`A${n},${a} 0 1,1 ${t-n},${e}`,"Z"].join(" ")}s(ft,"generateConfusionPath");var at={complex:{model:"Probe → Sense → Respond",practice:"Emergent Practices"},complicated:{model:"Sense → Analyse → Respond",practice:"Good Practices"},clear:{model:"Sense → Categorise → Respond",practice:"Best Practices"},chaotic:{model:"Act → Sense → Respond",practice:"Novel Practices"},confusion:{model:"",practice:"Disorder"}},Rt=s((t,e)=>{const n=t/2,a=e/2;return{complex:{cx:n/2,cy:a/2,x:0,y:0,w:n,h:a},complicated:{cx:n+n/2,cy:a/2,x:n,y:0,w:n,h:a},chaotic:{cx:n/2,cy:a+a/2,x:0,y:a,w:n,h:a},clear:{cx:n+n/2,cy:a+a/2,x:n,y:a,w:n,h:a},confusion:{cx:n,cy:a,x:n*.7,y:a*.7,w:n*.6,h:a*.6}}},"getDomainLayouts"),_t=s(()=>{const t=ot(),e=Q();return U(t,e.themeVariables).cynefin},"getCynefinDomainColors"),q=3,Et=s((t,e,n,a)=>{const c=a.db,m=c.getDomains(),v=c.getTransitions(),W=c.getDiagramTitle(),d=c.getAccTitle(),D=c.getAccDescription(),o=c.getConfig(),p=_t();O.debug("Rendering Cynefin diagram");const i=o.width,f=o.height,b=o.padding,h=o.showDomainDescriptions,R=o.boundaryAmplitude,_=i+b*2,E=f+b*2,z={complex:p.complexBg,complicated:p.complicatedBg,clear:p.clearBg,chaotic:p.chaoticBg,confusion:p.confusionBg},k=Dt(e);kt(k,E,_,o.useMaxWidth??!0),k.attr("viewBox",`0 0 ${_} ${E}`),d&&k.append("title").text(d),D&&k.append("desc").text(D);const A=k.append("g").attr("transform",`translate(${b}, ${b})`),F=Rt(i,f),Z=it(o.seed,e),mt=A.append("g").attr("class","cynefin-backgrounds"),X=["complex","complicated","chaotic","clear"];for(const l of X){const r=F[l];mt.append("rect").attr("class","cynefinDomain").attr("x",r.x).attr("y",r.y).attr("width",r.w).attr("height",r.h).attr("fill",z[l]).attr("fill-opacity",.4).attr("stroke","none")}const j=A.append("g").attr("class","cynefin-boundaries");j.append("path").attr("class","cynefinBoundary").attr("d",ct(i,f,Z,R)).attr("fill","none"),j.append("path").attr("class","cynefinBoundary").attr("d",lt(i,f,Z+100,R)).attr("fill","none"),j.append("path").attr("class","cynefinCliff").attr("d",dt(i,f)).attr("fill","none");const pt=i*.15,yt=f*.15;A.append("path").attr("class","cynefinConfusion").attr("d",ft(i/2,f/2,pt,yt)).attr("fill",z.confusion).attr("fill-opacity",.5);const J=A.append("g").attr("class","cynefin-labels");for(const l of X){const r=F[l];J.append("text").attr("class","cynefinDomainLabel").attr("x"Line truncated
.cynefinDomain {
stroke: none;
}
.cynefinDomainLabel {
font-size: ${t.domainFontSize}px;
font-weight: bold;
fill: ${t.labelColor};
}
.cynefinSubtitle {
font-size: ${t.itemFontSize-1}px;
fill: ${t.textColor};
font-style: italic;
}
.cynefinItem {
fill-opacity: 0.95;
stroke: ${t.boundaryColor};
stroke-width: 1;
}
.cynefinItemText {
font-size: ${t.itemFontSize}px;
fill: ${t.textColor};
}
.cynefinItemOverflow {
fill-opacity: 0.6;
stroke: ${t.boundaryColor};
stroke-width: 1;
stroke-dasharray: 3 2;
}
.cynefinBoundary {
stroke: ${t.boundaryColor};
stroke-width: ${t.boundaryWidth};
stroke-dasharray: 6 3;
}
.cynefinCliff {
stroke: ${t.cliffColor};
stroke-width: ${t.cliffWidth};
}
.cynefinConfusion {
stroke: ${t.boundaryColor};
stroke-width: 1.5;
stroke-dasharray: 4 2;
}
.cynefinArrowLine {
stroke: ${t.arrowColor};
stroke-width: ${t.arrowWidth};
fill: none;
}
.cynefinArrowHead {
fill: ${t.arrowColor};
stroke: none;
}
.cynefinArrowLabel {
font-size: ${t.itemFontSize-1}px;
fill: ${t.textColor};
}
.cynefinTitle {
font-size: ${t.domainFontSize+2}px;
font-weight: bold;
fill: ${t.labelColor};
}
`},"styles"),Gt=Ht,qt={parser:Wt,db:Y,renderer:Ft,styles:Gt};export{qt as diagram};
@@ -0,0 +1,321 @@
function Ds(r,e){(e==null||e>r.length)&&(e=r.length);for(var t=0,a=Array(e);t<e;t++)a[t]=r[t];return a}function tc(r){if(Array.isArray(r))return r}function ac(r){if(Array.isArray(r))return Ds(r)}function ct(r,e){if(!(r instanceof e))throw new TypeError("Cannot call a class as a function")}function nc(r,e){for(var t=0;t<e.length;t++){var a=e[t];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(r,Jl(a.key),a)}}function dt(r,e,t){return e&&nc(r.prototype,e),Object.defineProperty(r,"prototype",{writable:!1}),r}function Cr(r,e){var t=typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(!t){if(Array.isArray(r)||(t=Ks(r))||e){t&&(r=t);var a=0,n=function(){};return{s:n,n:function(){return a>=r.length?{done:!0}:{done:!1,value:r[a++]}},e:function(u){throw u},f:n}}throw new TypeError(`Invalid attempt to iterate non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var i,s=!0,o=!1;return{s:function(){t=t.call(r)},n:function(){var u=t.next();return s=u.done,u},e:function(u){o=!0,i=u},f:function(){try{s||t.return==null||t.return()}finally{if(o)throw i}}}}function Ql(r,e,t){return(e=Jl(e))in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r}function ic(r){if(typeof Symbol<"u"&&r[Symbol.iterator]!=null||r["@@iterator"]!=null)return Array.from(r)}function sc(r,e){var t=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(t!=null){var a,n,i,s,o=[],u=!0,l=!1;try{if(i=(t=t.call(r)).next,e===0){if(Object(t)!==t)return;u=!1}else for(;!(u=(a=i.call(t)).done)&&(o.push(a.value),o.length!==e);u=!0);}catch(v){l=!0,n=v}finally{try{if(!u&&t.return!=null&&(s=t.return(),Object(s)!==s))return}finally{if(l)throw n}}return o}}function oc(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function uc(){throw new TypeError(`Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function Xe(r,e){return tc(r)||sc(r,e)||Ks(r,e)||oc()}function yn(r){return ac(r)||ic(r)||Ks(r)||uc()}function lc(r,e){if(typeof r!="object"||!r)return r;var t=r[Symbol.toPrimitive];if(t!==void 0){var a=t.call(r,e);if(typeof a!="object")return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function Jl(r){var e=lc(r,"string");return typeof e=="symbol"?e:e+""}function je(r){"@babel/helpers - typeof";return je=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},je(r)}function Ks(r,e){if(r){if(typeof r=="string")return Ds(r,e);var t={}.toString.call(r).slice(8,-1);return t==="Object"&&r.constructor&&(t=r.constructor.name),t==="Map"||t==="Set"?Array.from(r):t==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?Ds(r,e):void 0}}var Qe=typeof window>"u"?null:window,Co=Qe?Qe.navigator:null;Qe&&Qe.document;var vc=je(""),jl=je({}),fc=je(function(){}),cc=typeof HTMLElement>"u"?"undefined":je(HTMLElement),La=function(e){return e&&e.instanceString&&He(e.instanceString)?e.instanceString():null},he=function(e){return e!=null&&je(e)==vc},He=function(e){return e!=null&&je(e)===fc},Fe=function(e){return!Tr(e)&&(Array.isArray?Array.isArray(e):e!=null&&e instanceof Array)},Me=function(e){return e!=null&&je(e)===jl&&!Fe(e)&&e.constructor===Object},dc=function(e){return e!=null&&je(e)===jl},ae=function(e){return e!=null&&je(e)===je(1)&&!isNaN(e)},ev=function(e){return ae(e)&&Math.floor(e)===e},mn=function(e){if(cc!=="undefined")return e!=null&&e instanceof HTMLElement},Tr=function(e){return Ia(e)||rv(e)},Ia=function(e){return La(e)==="collection"&&e._private.single},rv=function(e){return La(e)==="collection"&&!e._private.single},Xs=function(e){return La(e)==="core"},tv=function(e){return La(e)==="stylesheet"},hc=function(e){return La(e)==="event"},st=function(e){return e==null?!0:!!(e===""||e.match(/^\s+$/))},gc=function(e){return typeof HTMLElement>"u"?!1:e instanceof HTMLElement},pc=function(e){return Me(e)&&ae(e.x1)&&ae(e.x2)&&ae(e.y1)&&ae(e.y2)},yc=function(e){return dc(e)&&He(e.then)},mc=function(){return Co&&Co.userAgent.match(/msie|trident|edge/i)},Yt=function(e,t){t||(t=function(){if(arguments.length===1)return arguments[0];if(arguments.length===0)return"undefined";for(var i=[],s=0;s<arguments.length;s++)i.push(arguments[s]);return i.join("$")});var a=function(){var i=this,s=arguments,o,u=t.apply(i,s),l=a.cache;return(o=l[u])||(o=l[u]=e.apply(i,s)),o};return a.cache={},a},Ys=Yt(function(r){return r.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),Rn=Yt(function(r){return r.replace(/(-\w)/g,function(e){return e[1].toUpperCase()})}),av=Yt(function(r,e){return r+e[0].toUpperCase()+e.substring(1)},function(r,e){return r+"$"+e}),To=function(e){return st(e)?e:e.charAt(0).toUpperCase()+e.substring(1)},rt=function(e,t){return e.slice(-1*t.length)===t},Je="(?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))",bc="rgb[a]?\\(("+Je+"[%]?)\\s*,\\s*("+Je+"[%]?)\\s*,\\s*("+Je+"[%]?)(?:\\s*,\\s*("+Je+"))?\\)",wc="rgb[a]?\\((?:"+Je+"[%]?)\\s*,\\s*(?:"+Je+"[%]?)\\s*,\\s*(?:"+Je+"[%]?)(?:\\s*,\\s*(?:"+Je+"))?\\)",xc="hsl[a]?\\(("+Je+")\\s*,\\s*("+Je+"[%])\\s*,\\s*("+Je+"[%])(?:\\s*,\\s*("+Je+"))?\\)",Ec="hsl[a]?\\((?:"+Je+")\\s*,\\s*(?:"+Je+"[%])\\s*,\\s*(?:"+Je+"[%])(?:\\s*,\\s*(?:"+Je+"))?\\)",Cc="\\#[0-9a-fA-F]{3}",Tc="\\#[0-9a-fA-F]{6}",nv=function(e,t){return e<t?-1:e>t?1:0},Sc=function(e,t){return-1*nv(e,t)},me=Object.assign!=null?Object.assign.bind(Object):function(r){for(var e=arguments,t=1;t<e.length;t++){var a=e[t];if(a!=null)for(var n=Object.keys(a),i=0;i<n.length;i++){var s=n[i];r[s]=a[s]}}return r},kc=function(e){if(!(!(e.length===4||e.length===7)||e[0]!=="#")){var t=e.length===4,a,n,i,s=16;return t?(a=parseInt(e[1]+e[1],s),n=parseInt(e[2]+e[2],s),i=parseInt(e[3]+e[3],s)):(a=parseInt(e[1]+e[2],s),n=parseInt(e[3]+e[4],s),i=parseInt(e[5]+e[6],s)),[a,n,i]}},Dc=function(e){var t,a,n,i,s,o,u,l;function v(d,y,g){return g<0&&(g+=1),g>1&&(g-=1),g<1/6?d+(y-d)*6*g:g<1/2?y:g<2/3?d+(y-d)*(2/3-g)*6:d}var f=new RegExp("^"+xc+"$").exec(e);if(f){if(a=parseInt(f[1]),a<0?a=(360- -1*a%360)%360:a>360&&(a=a%360),a/=360,n=parseFloat(f[2]),n<0||n>100||(n=n/100,i=parseFloat(f[3]),i<0||i>100)||(i=i/100,s=f[4],s!==void 0&&(s=parseFloat(s),s<0||s>1)))return;if(n===0)o=u=l=Math.round(i*255);else{var c=i<.5?i*(1+n):i+n-i*n,h=2*i-c;o=Math.round(255*v(h,c,a+1/3)),u=Math.round(255*v(h,c,a)),l=Math.round(255*v(h,c,a-1/3))}t=[o,u,l,s]}return t},Bc=function(e){var t,a=new RegExp("^"+bc+"$").exec(e);if(a){t=[];for(var n=[],i=1;i<=3;i++){var s=a[i];if(s[s.length-1]==="%"&&(n[i]=!0),s=parseFloat(s),n[i]&&(s=s/100*255),s<0||s>255)return;t.push(Math.floor(s))}var o=n[1]||n[2]||n[3],u=n[1]&&n[2]&&n[3];if(o&&!u)return;var l=a[4];if(l!==void 0){if(l=parseFloat(l),l<0||l>1)re Line truncated
`),f=r.pstyle("text-max-width").pfValue,c=r.pstyle("text-overflow-wrap").value,h=c==="anywhere",d=[],y=/[\s\u200b]+|$/g,g=0;g<v.length;g++){var p=v[g],m=this.calculateLabelDimensions(r,p),b=m.width;if(h){var w=p.split("").join(l);p=w}if(b>f){var E=p.matchAll(y),C="",x=0,T=Cr(E),k;try{for(T.s();!(k=T.n()).done;){var B=k.value,D=B[0],P=p.substring(x,B.index);x=B.index+D.length;var A=C.length===0?P:C+P+D,R=this.calculateLabelDimensions(r,A),L=R.width;L<=f?C+=P+D:(C&&d.push(C),C=P+D)}}catch(q){T.e(q)}finally{T.f()}C.match(/^[\s\u200b]+$/)||d.push(C)}else d.push(p)}s("labelWrapCachedLines",d),n=s("labelWrapCachedText",d.join(`
`)),s("labelWrapKey",u)}else if(o==="ellipsis"){var I=r.pstyle("text-max-width").pfValue,M="",N="…",F=!1;if(this.calculateLabelDimensions(r,n).width<I)return n;for(var _=0;_<n.length;_++){var z=this.calculateLabelDimensions(r,M+n[_]+N).width;if(z>I)break;M+=n[_],_===n.length-1&&(F=!0)}return F||(M+=N),M}return n};Hr.getLabelJustification=function(r){var e=r.pstyle("text-justification").strValue,t=r.pstyle("text-halign").strValue;return e==="auto"?r.isNode()?Ug(t):"center":e};Hr.calculateLabelDimensions=function(r,e){var t=this,a=t.cy.window(),n=a.document,i=0,s=r.pstyle("font-style").strValue,o=r.pstyle("font-size").pfValue,u=r.pstyle("font-family").strValue,l=r.pstyle("font-weight").strValue,v=r.pstyle("text-metrics").strValue||"font",f=this.labelCalcCanvas,c=this.labelCalcCanvasContext;if(!f){f=this.labelCalcCanvas=n.createElement("canvas"),c=this.labelCalcCanvasContext=f.getContext("2d");var h=f.style;h.position="absolute",h.left="-9999px",h.top="-9999px",h.zIndex="-1",h.visibility="hidden",h.pointerEvents="none"}c.font="".concat(s," ").concat(l," ").concat(o,"px ").concat(u);for(var d=0,y=0,g=e.split(`
`),p=g.length,m=0,b=0,w=0;w<p;w++){var E=g[w],C=c.measureText(E),x=Math.ceil(C.width),T=o;v==="glyph"&&(w===0&&(b=C.actualBoundingBoxAscent),w===p-1&&(m=C.actualBoundingBoxDescent)),d=Math.max(x,d),y+=T}return v==="glyph"&&(y-=o-b-m),d+=i,y+=i,{width:d,height:y,labelActualAscent:b,labelActualDescent:m}};Hr.calculateLabelAngle=function(r,e){var t=r._private,a=t.rscratch,n=r.isEdge(),i=e?e+"-":"",s=r.pstyle(i+"text-rotation"),o=s.strValue;return o==="none"?0:n&&o==="autorotate"?a.labelAutoAngle:o==="autorotate"?0:s.pfValue};Hr.calculateLabelAngles=function(r){var e=this,t=r.isEdge(),a=r._private,n=a.rscratch;n.labelAngle=e.calculateLabelAngle(r),t&&(n.sourceLabelAngle=e.calculateLabelAngle(r,"source"),n.targetLabelAngle=e.calculateLabelAngle(r,"target"))};var xf={},Ml=28,Ll=!1;xf.getNodeShape=function(r){var e=this,t=r.pstyle("shape").value;if(t==="cutrectangle"&&(r.width()<Ml||r.height()<Ml))return Ll||(Ne("The `cutrectangle` node shape can not be used at small sizes so `rectangle` is used instead"),Ll=!0),"rectangle";if(r.isParent())return t==="rectangle"||t==="roundrectangle"||t==="round-rectangle"||t==="cutrectangle"||t==="cut-rectangle"||t==="barrel"?t:"rectangle";if(t==="polygon"){var a=r.pstyle("shape-polygon-points").value;return e.nodeShapes.makePolygon(a).name}return t};var Kn={};Kn.registerCalculationListeners=function(){var r=this.cy,e=r.collection(),t=this,a=function(s){var o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;if(e.merge(s),o)for(var u=0;u<s.length;u++){var l=s[u],v=l._private,f=v.rstyle;f.clean=!1,f.cleanConnected=!1}};t.binder(r).on("bounds.* dirty.*",function(s){var o=s.target;a(o)}).on("style.* background.*",function(s){var o=s.target;a(o,!1)});var n=function(s){if(s){var o=t.onUpdateEleCalcsFns;e.cleanStyle();for(var u=0;u<e.length;u++){var l=e[u],v=l._private.rstyle;l.isNode()&&!v.cleanConnected&&(a(l.connectedEdges()),v.cleanConnected=!0)}if(o)for(var f=0;f<o.length;f++){var c=o[f];c(s,e)}t.recalculateRenderedStyle(e),e=r.collection()}};t.flushRenderedStyleQueue=function(){n(!0)},t.beforeRender(n,t.beforeRenderPriorities.eleCalcs)};Kn.onUpdateEleCalcs=function(r){var e=this.onUpdateEleCalcsFns=this.onUpdateEleCalcsFns||[];e.push(r)};Kn.recalculateRenderedStyle=function(r,e){var t=function(w){return w._private.rstyle.cleanConnected};if(r.length!==0){var a=[],n=[];if(!this.destroyed){e===void 0&&(e=!0);for(var i=0;i<r.length;i++){var s=r[i],o=s._private,u=o.rstyle;s.isEdge()&&(!t(s.source())||!t(s.target()))&&(u.clean=!1),s.isEdge()&&s.isBundledBezier()&&s.parallelEdges().some(function(b){return!b._private.rstyle.clean&&b.isBundledBezier()})&&(u.clean=!1),!(e&&u.clean||s.removed())&&s.pstyle("display").value!=="none"&&(o.group==="nodes"?n.push(s):a.push(s),u.clean=!0)}for(var l=0;l<n.length;l++){var v=n[l],f=v._private,c=f.rstyle,h=v.position();this.recalculateNodeLabelProjection(v),c.nodeX=h.x,c.nodeY=h.y,c.nodeW=v.pstyle("width").pfValue,c.nodeH=v.pstyle("height").pfValue}this.recalculateEdgeProjections(a);for(var d=0;d<a.length;d++){var y=a[d],g=y._private,p=g.rstyle,m=g.rscratch;p.srcX=m.arrowStartX,p.srcY=m.arrowStartY,p.tgtX=m.arrowEndX,p.tgtY=m.arrowEndY,p.midX=m.midX,p.midY=m.midY,p.labelAngle=m.labelAngle,p.sourceLabelAngle=m.sourceLabelAngle,p.targetLabelAngle=m.targetLabelAngle}}}};var Xn={};Xn.updateCachedGrabbedEles=function(){var r=this.cachedZSortedEles;if(r){r.drag=[],r.nondrag=[];for(var e=[],t=0;t<r.length;t++){var a=r[t],n=a._private.rscratch;a.grabbed()&&!a.isParent()?e.push(a):n.inDragLayer?r.drag.push(a):r.nondrag.push(a)}for(var t=0;t<e.length;t++){var a=e[t];r.drag.push(a)}}};Xn.invalidateCachedZSortedEles=function(){this.cachedZSortedEles=null};Xn.getCachedZSortedEles=function(r){if(r||!this.cachedZSortedEles){var e=this.cy.mutableElements().toArray();e.sort(rf),e.interactive=e.filter(function(t){return t.interactive()}),this.cachedZSortedEles=e,this.updateCachedGrabbedEles()}else e=this.cachedZSortedEles;return e};var Ef={};[At,Dn,hr,Ga,po,Hr,xf,Kn,Xn].forEach(function(r){me(Ef,r)});var Cf={};Cf.getCachedImage=function(r,e,t){var a=this,n=a.imageCache=a.imageCache||{},i=n[r];if(i)return i.image.complete||i.image.addEventListener("load",t),i.image;i=n[r]=n[r]||{};var s=i.image=new Image;s.addEventListener("load",t),s.addEventListener("error",function(){s.error=!0});var o="data:",u=r.substring(0,o.length).toLowerCase()===o;return u||(e=e==="null"?null:e,s.crossOrigin=e),s.src=r,s};var Tf=function(e,t){var a=e[0];!a||a._private.grabbed===t||(a._private.grabbed=t,e.updateStyle(!1))},sy=function(e){Tf(e,!0)},oy=function(e){Tf(e,!1)},ia={};ia.registerBinding=function(r,e,t,a){var n=Array.prototype.slice.apply(arguments,[1]);if(Array.isArray(r)){for(var i=[],s=0;s<r.length;s++){var o=r[s];if(o!==void 0){var u=this.binder(o);i.push(u.on.apply(u,n))}}return i}var u=this.binder(r);return u.on.apply(u,n)};ia.binder=function(r){var e=this,t=e.cy.window(),a=r===t||r===t.document||r===t.document.body||gc(r);if(e.supportsPassiveEvents==null){var n=!1;try{va Line truncated
float circleSD(vec2 p, float r) {
return distance(vec2(0), p) - r; // signed distance
}
`,dm=`
float rectangleSD(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return distance(vec2(0),max(d,0.0)) + min(max(d.x,d.y),0.0);
}
`,hm=`
float roundRectangleSD(vec2 p, vec2 b, vec4 cr) {
cr.xy = (p.x > 0.0) ? cr.xy : cr.zw;
cr.x = (p.y > 0.0) ? cr.x : cr.y;
vec2 q = abs(p) - b + cr.x;
return min(max(q.x, q.y), 0.0) + distance(vec2(0), max(q, 0.0)) - cr.x;
}
`,gm=`
float ellipseSD(vec2 p, vec2 ab) {
p = abs( p ); // symmetry
// find root with Newton solver
vec2 q = ab*(p-ab);
float w = (q.x<q.y)? 1.570796327 : 0.0;
for( int i=0; i<5; i++ ) {
vec2 cs = vec2(cos(w),sin(w));
vec2 u = ab*vec2( cs.x,cs.y);
vec2 v = ab*vec2(-cs.y,cs.x);
w = w + dot(p-u,v)/(dot(p-u,u)+dot(v,v));
}
// compute final point and distance
float d = length(p-ab*vec2(cos(w),sin(w)));
// return signed distance
return (dot(p/ab,p/ab)>1.0) ? d : -d;
}
`,Ea={SCREEN:{name:"screen",screen:!0},PICKING:{name:"picking",picking:!0}},Pn={IGNORE:1,USE_BB:2},Es=0,Ul=1,Kl=2,Cs=3,Vt=4,nn=5,ga=6,pa=7,pm=(function(){function r(e,t,a){ct(this,r),this.r=e,this.gl=t,this.maxInstances=a.webglBatchSize,this.atlasSize=a.webglTexSize,this.bgColor=a.bgColor,this.debug=a.webglDebug,this.batchDebugInfo=[],a.enableWrapping=!0,a.createTextureCanvas=Xy,this.atlasManager=new vm(e,a),this.batchManager=new fm(a),this.simpleShapeOptions=new Map,this.program=this._createShaderProgram(Ea.SCREEN),this.pickingProgram=this._createShaderProgram(Ea.PICKING),this.vao=this._createVAO()}return dt(r,[{key:"addAtlasCollection",value:function(t,a){this.atlasManager.addAtlasCollection(t,a)}},{key:"addTextureAtlasRenderType",value:function(t,a){this.atlasManager.addRenderType(t,a)}},{key:"addSimpleShapeRenderType",value:function(t,a){this.simpleShapeOptions.set(t,a)}},{key:"invalidate",value:function(t){var a=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=a.type,i=this.atlasManager;return n?i.invalidate(t,{filterType:function(o){return o===n},forceRedraw:!0}):i.invalidate(t)}},{key:"gc",value:function(){this.atlasManager.gc()}},{key:"_createShaderProgram",value:function(t){var a=this.gl,n=`#version 300 es
precision highp float;
uniform mat3 uPanZoomMatrix;
uniform int uAtlasSize;
// instanced
in vec2 aPosition; // a vertex from the unit square
in mat3 aTransform; // used to transform verticies, eg into a bounding box
in int aVertType; // the type of thing we are rendering
// the z-index that is output when using picking mode
in vec4 aIndex;
// For textures
in int aAtlasId; // which shader unit/atlas to use
in vec4 aTex; // x/y/w/h of texture in atlas
// for edges
in vec4 aPointAPointB;
in vec4 aPointCPointD;
in vec2 aLineWidth; // also used for node border width
// simple shapes
in vec4 aCornerRadius; // for round-rectangle [top-right, bottom-right, top-left, bottom-left]
in vec4 aColor; // also used for edges
in vec4 aBorderColor; // aLineWidth is used for border width
// output values passed to the fragment shader
out vec2 vTexCoord;
out vec4 vColor;
out vec2 vPosition;
// flat values are not interpolated
flat out int vAtlasId;
flat out int vVertType;
flat out vec2 vTopRight;
flat out vec2 vBotLeft;
flat out vec4 vCornerRadius;
flat out vec4 vBorderColor;
flat out vec2 vBorderWidth;
flat out vec4 vIndex;
void main(void) {
int vid = gl_VertexID;
vec2 position = aPosition; // TODO make this a vec3, simplifies some code below
if(aVertType == `.concat(Es,`) {
float texX = aTex.x; // texture coordinates
float texY = aTex.y;
float texW = aTex.z;
float texH = aTex.w;
if(vid == 1 || vid == 2 || vid == 4) {
texX += texW;
}
if(vid == 2 || vid == 4 || vid == 5) {
texY += texH;
}
float d = float(uAtlasSize);
vTexCoord = vec2(texX / d, texY / d); // tex coords must be between 0 and 1
gl_Position = vec4(uPanZoomMatrix * aTransform * vec3(position, 1.0), 1.0);
}
else if(aVertType == `).concat(Vt," || aVertType == ").concat(pa,`
|| aVertType == `).concat(nn," || aVertType == ").concat(ga,`) { // simple shapes
// the bounding box is needed by the fragment shader
vBotLeft = (aTransform * vec3(0, 0, 1)).xy; // flat
vTopRight = (aTransform * vec3(1, 1, 1)).xy; // flat
vPosition = (aTransform * vec3(position, 1)).xy; // will be interpolated
// calculations are done in the fragment shader, just pass these along
vColor = aColor;
vCornerRadius = aCornerRadius;
vBorderColor = aBorderColor;
vBorderWidth = aLineWidth;
gl_Position = vec4(uPanZoomMatrix * aTransform * vec3(position, 1.0), 1.0);
}
else if(aVertType == `).concat(Ul,`) {
vec2 source = aPointAPointB.xy;
vec2 target = aPointAPointB.zw;
// adjust the geometry so that the line is centered on the edge
position.y = position.y - 0.5;
// stretch the unit square into a long skinny rectangle
vec2 xBasis = target - source;
vec2 yBasis = normalize(vec2(-xBasis.y, xBasis.x));
vec2 point = source + xBasis * position.x + yBasis * aLineWidth[0] * position.y;
gl_Position = vec4(uPanZoomMatrix * vec3(point, 1.0), 1.0);
vColor = aColor;
}
else if(aVertType == `).concat(Kl,`) {
vec2 pointA = aPointAPointB.xy;
vec2 pointB = aPointAPointB.zw;
vec2 pointC = aPointCPointD.xy;
vec2 pointD = aPointCPointD.zw;
// adjust the geometry so that the line is centered on the edge
position.y = position.y - 0.5;
vec2 p0, p1, p2, pos;
if(position.x == 0.0) { // The left side of the unit square
p0 = pointA;
p1 = pointB;
p2 = pointC;
pos = position;
} else { // The right side of the unit square, use same approach but flip the geometry upside down
p0 = pointD;
p1 = pointC;
p2 = pointB;
pos = vec2(0.0, -position.y);
}
vec2 p01 = p1 - p0;
vec2 p12 = p2 - p1;
vec2 p21 = p1 - p2;
// Find the normal vector.
vec2 tangent = normalize(normalize(p12) + normalize(p01));
vec2 normal = vec2(-tangent.y, tangent.x);
// Find the vector perpendicular to p0 -> p1.
vec2 p01Norm = normalize(vec2(-p01.y, p01.x));
// Determine the bend direction.
float sigma = sign(dot(p01 + p21, normal));
float width = aLineWidth[0];
if(sign(pos.y) == -sigma) {
// This is an intersecting vertex. Adjust the position so that there's no overlap.
vec2 point = 0.5 * width * normal * -sigma / dot(normal, p01Norm);
gl_Position = vec4(uPanZoomMatrix * vec3(p1 + point, 1.0), 1.0);
} else {
// This is a non-intersecting vertex. Treat it like a mitre join.
vec2 point = 0.5 * width * normal * sigma * dot(normal, p01Norm);
gl_Position = vec4(uPanZoomMatrix * vec3(p1 + point, 1.0), 1.0);
}
vColor = aColor;
}
else if(aVertType == `).concat(Cs,` && vid < 3) {
// massage the first triangle into an edge arrow
if(vid == 0)
position = vec2(-0.15, -0.3);
if(vid == 1)
position = vec2( 0.0, 0.0);
if(vid == 2)
position = vec2( 0.15, -0.3);
gl_Position = vec4(uPanZoomMatrix * aTransform * vec3(position, 1.0), 1.0);
vColor = aColor;
}
else {
gl_Position = vec4(2.0, 0.0, 0.0, 1.0); // discard vertex by putting it outside webgl clip space
}
vAtlasId = aAtlasId;
vVertType = aVertType;
vIndex = aIndex;
}
`),i=this.batchManager.getIndexArray(),s=`#version 300 es
precision highp float;
// declare texture unit for each texture atlas in the batch
`.concat(i.map(function(l){return"uniform sampler2D uTexture".concat(l,";")}).join(`
`),`
uniform vec4 uBGColor;
uniform float uZoom;
in vec2 vTexCoord;
in vec4 vColor;
in vec2 vPosition; // model coordinates
flat in int vAtlasId;
flat in vec4 vIndex;
flat in int vVertType;
flat in vec2 vTopRight;
flat in vec2 vBotLeft;
flat in vec4 vCornerRadius;
flat in vec4 vBorderColor;
flat in vec2 vBorderWidth;
out vec4 outColor;
`).concat(cm,`
`).concat(dm,`
`).concat(hm,`
`).concat(gm,`
vec4 blend(vec4 top, vec4 bot) { // blend colors with premultiplied alpha
return vec4(
top.rgb + (bot.rgb * (1.0 - top.a)),
top.a + (bot.a * (1.0 - top.a))
);
}
vec4 distInterp(vec4 cA, vec4 cB, float d) { // interpolate color using Signed Distance
// scale to the zoom level so that borders don't look blurry when zoomed in
// note 1.5 is an aribitrary value chosen because it looks good
return mix(cA, cB, 1.0 - smoothstep(0.0, 1.5 / uZoom, abs(d)));
}
void main(void) {
if(vVertType == `).concat(Es,`) {
// look up the texel from the texture unit
`).concat(i.map(function(l){return"if(vAtlasId == ".concat(l,") outColor = texture(uTexture").concat(l,", vTexCoord);")}).join(`
else `),`
}
else if(vVertType == `).concat(Cs,`) {
// mimics how canvas renderer uses context.globalCompositeOperation = 'destination-out';
outColor = blend(vColor, uBGColor);
outColor.a = 1.0; // make opaque, masks out line under arrow
}
else if(vVertType == `).concat(Vt,` && vBorderWidth == vec2(0.0)) { // simple rectangle with no border
outColor = vColor; // unit square is already transformed to the rectangle, nothing else needs to be done
}
else if(vVertType == `).concat(Vt," || vVertType == ").concat(pa,`
|| vVertType == `).concat(nn," || vVertType == ").concat(ga,`) { // use SDF
float outerBorder = vBorderWidth[0];
float innerBorder = vBorderWidth[1];
float borderPadding = outerBorder * 2.0;
float w = vTopRight.x - vBotLeft.x - borderPadding;
float h = vTopRight.y - vBotLeft.y - borderPadding;
vec2 b = vec2(w/2.0, h/2.0); // half width, half height
vec2 p = vPosition - vec2(vTopRight.x - b[0] - outerBorder, vTopRight.y - b[1] - outerBorder); // translate to center
float d; // signed distance
if(vVertType == `).concat(Vt,`) {
d = rectangleSD(p, b);
} else if(vVertType == `).concat(pa,` && w == h) {
d = circleSD(p, b.x); // faster than ellipse
} else if(vVertType == `).concat(pa,`) {
d = ellipseSD(p, b);
} else {
d = roundRectangleSD(p, b, vCornerRadius.wzyx);
}
// use the distance to interpolate a color to smooth the edges of the shape, doesn't need multisampling
// we must smooth colors inwards, because we can't change pixels outside the shape's bounding box
if(d > 0.0) {
if(d > outerBorder) {
discard;
} else {
outColor = distInterp(vBorderColor, vec4(0), d - outerBorder);
}
} else {
if(d > innerBorder) {
vec4 outerColor = outerBorder == 0.0 ? vec4(0) : vBorderColor;
vec4 innerBorderColor = blend(vBorderColor, vColor);
outColor = distInterp(innerBorderColor, outerColor, d);
}
else {
vec4 outerColor;
if(innerBorder == 0.0 && outerBorder == 0.0) {
outerColor = vec4(0);
} else if(innerBorder == 0.0) {
outerColor = vBorderColor;
} else {
outerColor = blend(vBorderColor, vColor);
}
outColor = distInterp(vColor, outerColor, d - innerBorder);
}
}
}
else {
outColor = vColor;
}
`).concat(t.picking?`if(outColor.a == 0.0) discard;
else outColor = vIndex;`:"",`
}
`),o=Ky(a,n,s);o.aPosition=a.getAttribLocation(o,"aPosition"),o.aIndex=a.getAttribLocation(o,"aIndex"),o.aVertType=a.getAttribLocation(o,"aVertType"),o.aTransform=a.getAttribLocation(o,"aTransform"),o.aAtlasId=a.getAttribLocation(o,"aAtlasId"),o.aTex=a.getAttribLocation(o,"aTex"),o.aPointAPointB=a.getAttribLocation(o,"aPointAPointB"),o.aPointCPointD=a.getAttribLocation(o,"aPointCPointD"),o.aLineWidth=a.getAttribLocation(o,"aLineWidth"),o.aColor=a.getAttribLocation(o,"aColor"),o.aCornerRadius=a.getAttribLocation(o,"aCornerRadius"),o.aBorderColor=a.getAttribLocation(o,"aBorderColor"),o.uPanZoomMatrix=a.getUniformLocation(o,"uPanZoomMatrix"),o.uAtlasSize=a.getUniformLocation(o,"uAtlasSize"),o.uBGColor=a.getUniformLocation(o,"uBGColor"),o.uZoom=a.getUniformLocation(o,"uZoom"),o.uTextures=[];for(var u=0;u<this.batchManager.getMaxAtlasesPerBatch();u++)o.uTextures.push(a.getUniformLocation(o,"uTexture".concat(u)));return o}},{key:"_createVAO",value:function(){var t=[0,0,1,0,1,1,0,0,1,1,0,1];this.vertexCount=t.length/2;var a=this.maxInstances,n=this.gl,i=this.program,s=n.createVertexArray();return n.bindVertexArray(s),tm(n,"vec2",i.aPosition,t),this.transformBuffer=am(n,a,i.aTransform),this.indexBuffer=Fr(n,a,"vec4",i.aIndex),this.vertTypeBuffer=Fr(n,a,"int",i.aVertType),this.atlasIdBuffer=Fr(n,a,"int",i.aAtlasId),this.texBuffer=Fr(n,a,"vec4",i.aTex),this.pointAPointBBuffer=Fr(n,a,"vec4",i.aPointAPointB),this.pointCPointDBuffer=Fr(n,a,"vec4",i.aPointCPointD),this.lineWidthBuffer=Fr(n,a,"vec2",i.aLineWidth),this.colorBuffer=Fr(n,a,"vec4",i.aColor),this.cornerRadiusBuffer=Fr(n,a,"vec4",i.aCornerRadius),this.borderColorBuffer=Fr(n,a,"vec4",i.aBorderColor),n.bindVertexArray(null),s}},{key:"buffers",get:function(){var t=this;return this._buffers||(this._buffers=Object.keys(this).filter(function(a){return rt(a,"Buffer")}).map(function(a){return t[a]})),this._buffers}},{key:"startFrame",value:function(t){var a=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Ea.SCREEN;this.panZoomMatrix=t,this.renderTarget=a,this.batchDebugInfo=[],this.wrappedCount=0,this.simpleCount=0,this.startBatch()}},{key:"startBatch",value:function(){this.instanceCount=0,this.batchManager.startBatch()}},{key:"endFrame",value:function(){this.endBatch()}},{key:"_isVisible",value:function(t,a){return t.visible()?a&&a.isVisible?a.isVisible(t):!0:!1}},{key:"drawTexture",value:function(t,a,n){var i=this.atlasManager,s=this.batchManager,o=i.getRenderTypeOpts(n);if(this._isVisible(t,o)&&!(t.isEdge()&&!this._isValidEdge(t))){if(this.renderTarget.picking&&o.getTexPickingMode){var u=o.getTexPickingMode(t);if(u===Pn.IGNORE)return;if(u==Pn.USE_BB){this.drawPickingRectangle(t,a,n);return}}var l=i.getAtlasInfo(t,n),v=Cr(l),f;try{for(v.s();!(f=v.n()).done;){var c=f.value,h=c.atlas,d=c.tex1,y=c.tex2;s.canAddToCurrentBatch(h)||this.endBatch();for(var g=s.getAtlasIndexForBatch(h),p=0,m=[[d,!0],[y,!1]];p<m.length;p++){var b=Xe(m[p],2),w=b[0],E=b[1];if(w.w!=0){var C=this.instanceCount;this.vertTypeBuffer.getView(C)[0]=Es;var x=this.indexBuffer.getView(C);Ft(a,x);var T=this.atlasIdBuffer.getView(C);T[0]=g;var k=this.texBuffer.getView(C);k[0]=w.x,k[1]=w.y,k[2]=w.w,k[3]=w.h;var B=this.transformBuffer.getMatrixView(C);this.setTransformMatrix(t,B,o,c,E),this.instanceCount++,E||this.wrappedCount++,this.instanceCount>=this.maxInstances&&this.endBatch()}}}}catch(D){v.e(D)}finally{v.f()}}}},{key:"setTransformMatrix",value:function(t,a,n,i){var s=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,o=0;if(n.shapeProps&&n.shapeProps.padding&&(o=t.pstyle(n.shapeProps.padding).pfValue),i){var u=i.bb,l=i.tex1,v=i.tex2,f=l.w/(l.w+v.w);s||(f=1-f);var c=this._getAdjustedBB(u,o,s,f);this._applyTransformMatrix(a,c,n,t)}else{var h=n.getBoundingBox(t),d=this._getAdjustedBB(h,o,!0,1);this._applyTransformMatrix(a,d,n,t)}}},{key:"_applyTransformMatrix",value:function(t,a,n,i){var s,o;Wl(t);var u=n.getRotation?n.getRotation(i):0;if(u!==0){var l=n.getRotationPoint(i),v=l.x,f=l.y;pn(t,t,[v,f]),$l(t,t,u);var c=n.getRotationOffset(i);s=c.x+(a.xOffset||0),o=c.y+(a.yOffset||0)}else s=a.x1,o=a.y1;pn(t,t,[s,o]),Hs(t,t,[a.w,a.h])}},{key:"_getAdjustedBB",value:function(t,a,n,i){var s=t.x1,o=t.y1,u=t.w,l=t.h,v=t.yOffset;a&&(s-=a,o-=a,u+=2*a,l+=2*a);var f=0,c=u*i;return n&&i<1?u=c:!n&&i<1&&(f=u-c,s+=f,u=c),{x1:s,y1:o,w:u,h:l,xOffset:f,yOffset:v}}},{key:"drawPickingRectangle",value:function(t,a,n){var i=this.atlasManager.getRenderTypeOpts(n),s=this.instanceCount;this.vertTypeBuffer.getView(s)[0]=Vt;var o=this.indexBuffer.getView(s);Ft(a,o);var u=this.colorBuffer.getView(s);bt([0,0,0],1,u);var l=this.transformBuffer.getMatrixView(s);this.setTransformMatrix(t,l,i),this.simpleCount++,this.instanceCount++,this.instanceCount>=this.maxInstances&&this.endBatch()}},{key:"drawNode",value:function(t,a,n){var i=this.simpleShapeOptions.get(n);if(this._isVisible(t,i)){var s=i.shapeProps,o=this._getVertTypeForShape(t,s.shape);if(o===void 0||i.isSimple&&!i.isSimple(t,this.renderTarget)){this.drawTexture(t, Line truncated
@@ -0,0 +1,4 @@
import{_ as m,ao as x,c as k,Q as O,l as p,ap as A,aq as Y,ar as b,as as _,at as z,au as H,av as D,aw as J,ax as T,ay as X,ah as R,af as F,az as q,aA as W}from"./mermaid.core.js";import{l as j}from"./layout.js";import"./index.js";var C=m((t,e,r)=>Math.max(e,Math.min(r,t)),"clamp"),P=m((t="TB")=>{switch(t){case"BT":return"bottom";case"LR":return"right";case"RL":return"left";default:return"top"}},"getDefaultSelfLoopSide"),Q=m(t=>t==="flowchart"||t==="flowchart-v2"||t==="stateDiagram"||t==="er"||t==="classDiagram","shouldMergeSelfLoopSegments"),U=["x","y","width","height","labelBBox","intersect","calcIntersect","diff","clusterNode"],K=m((t,e,r,d,a)=>{const f=[],h=new Set;if(r.forEach(({start:i,end:o})=>{i!==d&&h.add(i),o!==d&&h.add(o)}),h.forEach(i=>{const o=t.node(i);typeof o?.x=="number"&&typeof o?.y=="number"&&f.push(o)}),f.length===0&&r.forEach(({edge:i})=>{(i.points??[]).forEach(o=>{typeof o?.x=="number"&&typeof o?.y=="number"&&f.push(o)})}),f.length===0)return P(a);const c=f.reduce((i,o)=>({x:i.x+o.x/f.length,y:i.y+o.y/f.length}),{x:0,y:0}),l=c.x-e.x,s=c.y-e.y;return Math.abs(l)>Math.abs(s)?l>0?"right":"left":Math.abs(s)>0?s>0?"bottom":"top":P(a)},"getSelfLoopSide"),V=m((t,e="top",r=0,d=0)=>{const a=t.x,f=t.y-r,h=t.width/2,c=t.height/2,l=Math.max(36,Math.min(100,t.width*.8)),s=C(Math.max(d,t.width*.35),36,l),i=C(Math.min(t.width,t.height)*.45,24,48);switch(e){case"bottom":{const o=f+c;return[{x:a-s/2,y:o},{x:a-s/2,y:o+i},{x:a+s/2,y:o+i},{x:a+s/2,y:o}]}case"right":{const o=a+h;return[{x:o,y:f-s/2},{x:o+i,y:f-s/2},{x:o+i,y:f+s/2},{x:o,y:f+s/2}]}case"left":{const o=a-h;return[{x:o,y:f-s/2},{x:o-i,y:f-s/2},{x:o-i,y:f+s/2},{x:o,y:f+s/2}]}default:{const o=f-c;return[{x:a-s/2,y:o},{x:a-s/2,y:o-i},{x:a+s/2,y:o-i},{x:a+s/2,y:o}]}}},"getSelfLoopPoints"),Z=m((t,e,r="top",d=0,a={})=>{const h=t.x,c=t.y-d,l=a.width??0,s=a.height??0;switch(r){case"bottom":return{x:h,y:Math.max(...e.map(i=>i.y))+s/2+4};case"right":return{x:Math.max(...e.map(i=>i.x))+l/2+4,y:c};case"left":return{x:Math.min(...e.map(i=>i.x))-l/2-4,y:c};default:return{x:h,y:Math.min(...e.map(i=>i.y))-s/2-4}}},"getSelfLoopLabelPosition"),B=m((t,e=0,{mergeSelfLoops:r=!0}={})=>{const d=new Map,a=[],f=t.graph()?.rankdir;return t.edges().forEach(h=>{const c=t.edge(h);if(r&&c.selfLoop){const l=c.selfLoop.id;d.has(l)||d.set(l,[]),d.get(l).push({edge:c,start:h.v,end:h.w})}else a.push({edge:c,start:h.v,end:h.w})}),d.forEach(h=>{if(h.length!==3){h.forEach(u=>a.push(u));return}h.sort((u,E)=>u.edge.selfLoop.order-E.edge.selfLoop.order);const[c,l,s]=h,i=c.edge.originalEdge??l.edge.originalEdge??s.edge.originalEdge??l.edge,o=t.node(i.start);if(!o){h.forEach(u=>a.push(u));return}const n={width:l.edge.width,height:l.edge.height},L=K(t,o,h,i.start,f),w=V(o,L,e,n.width??0),y=Z(o,w,L,e,n),g={...l.edge,...i,id:i.id,points:w,start:i.start,end:i.end,x:y.x,y:y.y,width:n.width,height:n.height,labelStyle:l.edge.labelStyle,fromCluster:c.edge.fromCluster??l.edge.fromCluster??s.edge.fromCluster,toCluster:c.edge.toCluster??l.edge.toCluster??s.edge.toCluster};delete g.selfLoop,delete g.originalEdge,a.push({edge:g,start:g.start,end:g.end})}),a},"getEdgesToRender"),I=m(async({element:t,graph:e,diagramType:r,id:d,parentCluster:a,siteConfig:f})=>{const h=e.graph().rankdir;p.trace("Dir in recursive render - dir:",h);const{clusters:c,edgePaths:l,edgeLabels:s,nodes:i,rootGroups:o}=_(t,{edgePathsClass:"edgePaths"});e.nodes()?p.info("Recursive render XXX",e.nodes()):p.info("No nodes found for",e),e.edges().length>0&&p.info("Recursive edges",e.edge(e.edges()[0]));const n=Q(r);await Promise.all(e.nodes().map(async function(y){const g=e.node(y);if(a!==void 0){const u=JSON.parse(JSON.stringify(a.clusterData));p.trace(`Setting data for parent cluster XXX
Node.id = `,y,`
data=`,u.height,`
Parent cluster`,a.height),e.setNode(a.id,u),e.parent(y)||(p.trace("Setting parent",y,a.id),e.setParent(y,a.id,u))}if(p.info("(Insert) Node XXX"+y+": "+JSON.stringify(e.node(y))),g?.clusterNode){p.info("Cluster identified XBX",y,g.width,e.node(y));const{ranksep:u,nodesep:E}=e.graph();g.graph.setGraph({...g.graph.graph(),ranksep:u+25,nodesep:E});const S=await oe({element:i,graph:g.graph,diagramType:r,id:d,parentCluster:e.node(y),siteConfig:f}),N=S.elem;z(g,N),g.diff=S.diff||0,p.info("New compound node after recursive render XAX",y,"width",g.width,"height",g.height),H(N,g)}else e.children(y).length>0?(p.trace("Cluster - the non recursive path XBX",y,g.id,g,g.width,"Graph:",e),p.trace(D(g.id,e)),b.set(g.id,{id:D(g.id,e),node:g})):(p.trace("Node - the non recursive path XAX",y,i,e.node(y),h),await J(i,e.node(y),{config:f,dir:h}))})),await m(async()=>{const y=e.edges().map(async function(g){const u=e.edge(g.v,g.w,g.name);if(p.info("Edge "+g.v+" -> "+g.w+": "+JSON.stringify(g)),p.info("Edge "+g.v+" -> "+g.w+": ",g," ",JSON.stringify(e.edge(g))),p.info("Fix",b,"ids:",g.v,g.w,"Translating: ",b.get(g.v),b.get(g.w)),n&&u.selfLoop){if(u.selfLoop.order!==1)return;const E={...u.originalEdge,...u,id:u.selfLoop.id,startLabelLeft:u.originalEdge?.startLabelLeft??u.startLabelLeft,startLabelRight:u.originalEdge?.startLabelRight??u.startLabelRight,endLabelLeft:u.originalEdge?.endLabelLeft??u.endLabelLeft,endLabelRight:u.originalEdge?.endLabelRight??u.endLabelRight};await X(s,E),u.width=E.width,u.height=E.height,u.labelStyle=E.labelStyle;return}await X(s,u)});await Promise.all(y)},"processEdges")();const{subGraphTitleTotalMargin:w}=T(f);return{elem:o,graph:e,groups:{clusters:c,edgePaths:l,edgeLabels:s,nodes:i,rootGroups:o},diagramType:r,id:d,mergeSelfLoops:n,subGraphTitleTotalMargin:w}},"measureDagreGraph"),M=m(t=>{p.info("############################################# XXX"),p.info("### Layout ### XXX"),p.info("############################################# XXX"),j(t)},"runDagreGraphLayout"),$=m((t,e,r)=>{const d=t.node(e);if(!d)return;const a={...d};return d?.clusterNode?a.y=(d.y??0)+r:t.children(e).length>0?a.height=(d.height??0)+r:a.y=(d.y??0)+r/2,a},"normalizeDagreNode"),v=m((t,e)=>{U.forEach(r=>{e[r]!==void 0&&(t[r]=e[r])})},"applyDagreNodeLayout"),ee=m((t,e,r,d)=>({...t,start:t.start??e,end:t.end??r,points:(t.points??[]).map(a=>({...a,y:typeof a.y=="number"?a.y+d:a.y}))}),"normalizeDagreEdge"),te=m((t,e)=>{const{graph:r,mergeSelfLoops:d,subGraphTitleTotalMargin:a=0}=e,f=new Map(t.nodes.map(c=>[c.id,c]));x(r).forEach(c=>{const l=$(r,c,a);if(!l)return;v(r.node(c),l);const s=f.get(c);s&&v(s,l)});const h=a/2;return t.edges=B(r,h,{mergeSelfLoops:d}).map(({edge:c,start:l,end:s})=>ee(c,l,s,h)),t},"applyDagreLayoutResult"),re=m(async({elem:t,graph:e,groups:{clusters:r,edgePaths:d},diagramType:a,id:f,mergeSelfLoops:h,subGraphTitleTotalMargin:c})=>{let l=0;await Promise.all(x(e).map(async function(o){const n=e.node(o);if(p.info("Position XBX => "+o+": ("+n.x,","+n.y,") width: ",n.width," height: ",n.height),n?.clusterNode)n.y+=c,p.info("A tainted cluster node XBX1",o,n.id,n.width,n.height,n.x,n.y,e.parent(o)),b.get(n.id).node=n,R(n);else if(e.children(o).length>0){p.info("A pure cluster node XBX1",o,n.id,n.x,n.y,n.width,n.height,e.parent(o)),n.height+=c,e.node(n.parentId);const L=n?.padding/2||0,w=n?.labelBBox?.height||0,y=w-L||0;p.debug("OffsetY",y,"labelHeight",w,"halfPadding",L),await F(r,n),b.get(n.id).node=n}else{const L=e.node(n.parentId);n.y+=c/2,p.info("A regular node XBX1 - using the padding",n.id,"parent",n.parentId,n.width,n.height,n.x,n.y,"offsetY",n.offsetY,"parent",L,L?.offsetY,n),R(n)}}));const s=c/2;return B(e,s,{mergeSelfLoops:h}).forEach(function({edge:o,start:n,end:L}){p.info("Edge "+n+" -> "+L+": "+JSON.stringify(o),o),o.points.forEach(u=>u.y+=s);const w=e.node(n),y=e.node(L),g=q(d,o,b,a,w,y,f);W(o,g)}),e.nodes().forEach(function(o){const n=e.node(o);p.info(o,n.type,n.diff),n.isGroup&&(l=n.diff)}),p.warn("Returning from recursive render XAX",t,l),{elem:t,diff:l}},"paintDagreLayoutCore"),oe=m(async t=>{const e=await I(t);return M(e.graph),await re(e)},"renderDagreSubgraph"),G=m(t=>{const e=new O({multigraph:!0,compound:!0}).setGraph({rankdir:t.direction,nodesep:t.config?.nodeSpacing||t.nodeSpacing||t.config?.flowchart?.nodeSpacing,ranksep:t.config?.rankSpacing||t.rankSpacing||t.config?.flowchart?.rankSpacing,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}});return t.nodes.forEach(r=>{e.setNode(r.id,{...r}),r.parentId&&e.setParent(r.id,r.parentId)}),p.debug("Edges:",t.edges),t.edges.forEach(r=>{if(r.start===r.end){const d=r.start,a=d+"---"+d+"---1",f=d+"---"+d+"---2",h=e.node(d);e.setNode(a,{domId:a,id:a,parentId:h.parentId,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),e.setParent(a,h.parentId),e.setNode(f,{domId:f,id:f,parentId:h.parentId,labelStyle:"",padding:0,shape:"labelRect",label:"",style:"",width:10,height:10}),e.setParent(f,h.pa Line truncated
@@ -0,0 +1 @@
function J(n){return Math.abs(n=Math.round(n))>=1e21?n.toLocaleString("en").replace(/,/g,""):n.toString(10)}function j(n,t){if(!isFinite(n)||n===0)return null;var e=(n=t?n.toExponential(t-1):n.toExponential()).indexOf("e"),i=n.slice(0,e);return[i.length>1?i[0]+i.slice(2):i,+n.slice(e+1)]}function K(n){return n=j(Math.abs(n)),n?n[1]:NaN}function Q(n,t){return function(e,i){for(var o=e.length,a=[],c=0,h=n[0],M=0;o>0&&h>0&&(M+h+1>i&&(h=Math.max(1,i-M)),a.push(e.substring(o-=h,o+h)),!((M+=h+1)>i));)h=n[c=(c+1)%n.length];return a.reverse().join(t)}}function V(n){return function(t){return t.replace(/[0-9]/g,function(e){return n[+e]})}}var W=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function $(n){if(!(t=W.exec(n)))throw new Error("invalid format: "+n);var t;return new L({fill:t[1],align:t[2],sign:t[3],symbol:t[4],zero:t[5],width:t[6],comma:t[7],precision:t[8]&&t[8].slice(1),trim:t[9],type:t[10]})}$.prototype=L.prototype;function L(n){this.fill=n.fill===void 0?" ":n.fill+"",this.align=n.align===void 0?">":n.align+"",this.sign=n.sign===void 0?"-":n.sign+"",this.symbol=n.symbol===void 0?"":n.symbol+"",this.zero=!!n.zero,this.width=n.width===void 0?void 0:+n.width,this.comma=!!n.comma,this.precision=n.precision===void 0?void 0:+n.precision,this.trim=!!n.trim,this.type=n.type===void 0?"":n.type+""}L.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(this.width===void 0?"":Math.max(1,this.width|0))+(this.comma?",":"")+(this.precision===void 0?"":"."+Math.max(0,this.precision|0))+(this.trim?"~":"")+this.type};function _(n){n:for(var t=n.length,e=1,i=-1,o;e<t;++e)switch(n[e]){case".":i=o=e;break;case"0":i===0&&(i=e),o=e;break;default:if(!+n[e])break n;i>0&&(i=0);break}return i>0?n.slice(0,i)+n.slice(o+1):n}var N;function v(n,t){var e=j(n,t);if(!e)return N=void 0,n.toPrecision(t);var i=e[0],o=e[1],a=o-(N=Math.max(-8,Math.min(8,Math.floor(o/3)))*3)+1,c=i.length;return a===c?i:a>c?i+new Array(a-c+1).join("0"):a>0?i.slice(0,a)+"."+i.slice(a):"0."+new Array(1-a).join("0")+j(n,Math.max(0,t+a-1))[0]}function X(n,t){var e=j(n,t);if(!e)return n+"";var i=e[0],o=e[1];return o<0?"0."+new Array(-o).join("0")+i:i.length>o+1?i.slice(0,o+1)+"."+i.slice(o+1):i+new Array(o-i.length+2).join("0")}const O={"%":(n,t)=>(n*100).toFixed(t),b:n=>Math.round(n).toString(2),c:n=>n+"",d:J,e:(n,t)=>n.toExponential(t),f:(n,t)=>n.toFixed(t),g:(n,t)=>n.toPrecision(t),o:n=>Math.round(n).toString(8),p:(n,t)=>X(n*100,t),r:X,s:v,X:n=>Math.round(n).toString(16).toUpperCase(),x:n=>Math.round(n).toString(16)};function R(n){return n}var U=Array.prototype.map,Y=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function nn(n){var t=n.grouping===void 0||n.thousands===void 0?R:Q(U.call(n.grouping,Number),n.thousands+""),e=n.currency===void 0?"":n.currency[0]+"",i=n.currency===void 0?"":n.currency[1]+"",o=n.decimal===void 0?".":n.decimal+"",a=n.numerals===void 0?R:V(U.call(n.numerals,String)),c=n.percent===void 0?"%":n.percent+"",h=n.minus===void 0?"−":n.minus+"",M=n.nan===void 0?"NaN":n.nan+"";function T(f,g){f=$(f);var b=f.fill,p=f.align,m=f.sign,w=f.symbol,S=f.zero,E=f.width,F=f.comma,y=f.precision,C=f.trim,d=f.type;d==="n"?(F=!0,d="g"):O[d]||(y===void 0&&(y=12),C=!0,d="g"),(S||b==="0"&&p==="=")&&(S=!0,b="0",p="=");var q=(g&&g.prefix!==void 0?g.prefix:"")+(w==="$"?e:w==="#"&&/[boxX]/.test(d)?"0"+d.toLowerCase():""),B=(w==="$"?i:/[%p]/.test(d)?c:"")+(g&&g.suffix!==void 0?g.suffix:""),D=O[d],H=/[defgprs%]/.test(d);y=y===void 0?6:/[gprs]/.test(d)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y));function G(r){var l=q,u=B,x,I,k;if(d==="c")u=D(r)+u,r="";else{r=+r;var P=r<0||1/r<0;if(r=isNaN(r)?M:D(Math.abs(r),y),C&&(r=_(r)),P&&+r==0&&m!=="+"&&(P=!1),l=(P?m==="("?m:h:m==="-"||m==="("?"":m)+l,u=(d==="s"&&!isNaN(r)&&N!==void 0?Y[8+N/3]:"")+u+(P&&m==="("?")":""),H){for(x=-1,I=r.length;++x<I;)if(k=r.charCodeAt(x),48>k||k>57){u=(k===46?o+r.slice(x+1):r.slice(x))+u,r=r.slice(0,x);break}}}F&&!S&&(r=t(r,1/0));var z=l.length+r.length+u.length,s=z<E?new Array(E-z+1).join(b):"";switch(F&&S&&(r=t(s+r,s.length?E-u.length:1/0),s=""),p){case"<":r=l+r+u+s;break;case"=":r=l+s+r+u;break;case"^":r=s.slice(0,z=s.length>>1)+l+r+u+s.slice(z);break;default:r=s+l+r+u;break}return a(r)}return G.toString=function(){return f+""},G}function Z(f,g){var b=Math.max(-8,Math.min(8,Math.floor(K(g)/3)))*3,p=Math.pow(10,-b),m=T((f=$(f),f.type="f",f),{suffix:Y[8+b/3]});return function(w){return m(p*w)}}return{format:T,formatPrefix:Z}}var A,tn,rn;en({thousands:",",grouping:[3],currency:["$",""]});function en(n){return A=nn(n),tn=A.format,rn=A.formatPrefix,A}export{rn as a,tn as b,K as e,$ as f};
@@ -0,0 +1,30 @@
import{I as X}from"./chunk-2Q5K7J3B.js";import{p as z}from"./chunk-JWPE2WC7.js";import{n as O,b as G,s as Y,o as P,g as F,a as Z,_ as g,A as N,l as A,D as q,d as U,y as E,p as j,i as J,ak as K,B as Q,al as ee}from"./mermaid.core.js";import{p as te}from"./cynefin-OW5HDTMX.js";import"./index.js";var D=/[─━│┃└┗├┣]/,L=/[└┗├┣]/,ne=/[─━]/,k=/^[\s│┃]+$/,T=/^\s*(title[\t ]|accTitle[\t ]*:|accDescr[\t ]*[:{])/,V=/^\s*%%/,re=" ";function _(n){return n.some(t=>D.test(t))}g(_,"isBoxDrawingFormat");function M(n){for(const t of n){const e=L.exec(t);if(e?.index&&e.index>0)return e.index}return 4}g(M,"inferSegmentWidth");function S(n,t){return n.replace(/\bline\s+(\d+)\b/gi,(e,r)=>{const s=parseInt(r,10),i=t.get(s);return i?`line ${i}`:e})}g(S,"remapErrorLines");function R(n){const t=n.split(`
`),e=new Map;let r=-1;for(const[p,c]of t.entries())if(c.trim()==="treeView-beta"){r=p;break}if(r===-1)return{text:n,lineMap:e};const s=[];for(let p=r+1;p<t.length;p++){const c=t[p];c.trim()===""||V.test(c)||T.test(c)||k.test(c)||s.push(c.replace(/\t/g," "))}if(!_(s))return{text:n,lineMap:e};const i=M(s),o=[];let a=0;for(let p=0;p<=r;p++)o.push(t[p]),a++,e.set(a,p+1);for(let p=r+1;p<t.length;p++){const c=t[p],d=c.trim(),h=p+1;if(d===""){o.push(c),a++,e.set(a,h);continue}if(V.test(c)){o.push(c),a++,e.set(a,h);continue}if(T.test(c)){o.push(c),a++,e.set(a,h);continue}if(k.test(c))continue;const l=c.replace(/\t/g," "),w=L.exec(l);if(w?.index!==void 0){const f=w.index,m=Math.round(f/i)+1;let u=f+1;for(;u<l.length&&ne.test(l[u]);)u++;for(;u<l.length&&l[u]===" ";)u++;const v=l.slice(u).trimEnd();if(!v)throw new Error(`Line ${h}: Empty node — expected a filename or directory name after the box-drawing prefix`);const W=re.repeat(m);o.push(W+v),a++,e.set(a,h)}else{if(/^[\s─━│┃└┗├┣]+$/.test(l))continue;if(D.test(l))o.push(c),a++,e.set(a,h);else{if(/^\s+/.test(l))throw new Error(`Line ${h}: Unexpected indentation without box-drawing characters. In box-drawing format, use ├── or └── prefixes for indented nodes.`);o.push(c),a++,e.set(a,h)}}}return{text:o.join(`
`),lineMap:e}}g(R,"preprocessBoxDrawing");var x=new X(()=>({cnt:1,stack:[{id:0,level:-1,name:"/",nodeType:"directory",children:[]}]})),ie=g(()=>{x.reset(),j()},"clear"),oe=g(()=>x.records.stack[0],"getRoot"),se=g(()=>x.records.cnt,"getCount"),ae=Q.treeView,ce=g(()=>N(ae,E().treeView),"getConfig"),le=g((n,t,e,r,s,i)=>{for(;n<=x.records.stack[x.records.stack.length-1].level;)x.records.stack.pop();const o={id:x.records.cnt++,level:n,name:t,nodeType:e,icon:s,cssClass:r,description:i,children:[]};x.records.stack[x.records.stack.length-1].children.push(o),x.records.stack.push(o)},"addNode"),de={clear:ie,addNode:le,getRoot:oe,getCount:se,getConfig:ce,getAccTitle:Z,getAccDescription:F,getDiagramTitle:P,setAccDescription:Y,setAccTitle:G,setDiagramTitle:O},I=de,he=g(n=>{z(n,I);for(const t of n.nodes){const e=typeof t.indent=="number"?t.indent:0;let r=t.name;const s=r.endsWith("/");s&&(r=r.slice(0,-1));const i=s?"directory":"file",o=t.classAnnotation||void 0,a=t.iconAnnotation,p=a!==void 0?a||"none":void 0,c=t.descAnnotation||void 0,d=c?J(c,E()):void 0;I.addNode(e,r,i,o,p,d)}},"populate"),pe={parse:g(async n=>{const{text:t,lineMap:e}=R(n);try{const r=await te("treeView",t);A.debug(r),he(r)}catch(r){throw e.size>0&&r instanceof Error&&(r.message=S(r.message,e)),r}},"parse")},b={prefix:"mermaid-treeview",height:24,width:24,icons:{folder:{body:'<path fill="currentColor" d="M10.59 4.59A2 2 0 0 0 9.17 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.17z"/>'},file:{body:'<path fill="currentColor" fill-rule="evenodd" d="M6 2a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8.83a2 2 0 0 0-.59-1.42l-4.82-4.82A2 2 0 0 0 13.17 2H6Zm7.5 1.9l4.6 4.6h-3.6a1 1 0 0 1-1-1V3.9Z" clip-rule="evenodd"/>'}}};function H(n,t){const e=t?.filenameIcons?.[n];if(e)return e;const r=n.lastIndexOf(".");if(r>0){const s=n.substring(r).toLowerCase(),i=t?.extensionIcons;return i?.[s]??i?.[s.slice(1)]}}g(H,"detectIcon");function C(n,t){return n.includes(":")?n:n in b.icons||!t?`${b.prefix}:${n}`:`${t}:${n}`}g(C,"qualifyIcon");function B(n,t){if(n.icon!=="none"){if(n.icon)return C(n.icon,t.defaultIconPack);if(t.showIcons){if(n.nodeType==="file"){const e=H(n.name,t);if(e==="none")return;if(e)return C(e,t.defaultIconPack)}return`${b.prefix}:${n.nodeType==="directory"?"folder":"file"}`}}}g(B,"getNodeIcon");ee([{name:b.prefix,icons:b}]);var y=14,ge=4,fe=16,ue=g(async(n,t)=>{const e=[],r=g(i=>{const o=B(i,t);o&&e.push({icon:o,node:i}),i.children.forEach(r)},"collect");r(n);const s=await Promise.all(e.map(async({icon:i,node:o})=>({id:o.id,svg:await K(i,{height:y,width:y})})));return new Map(s.map(({id:i,svg:o})=>[i,o]))},"resolveNodeIcons"),we=g((n,t,e,r,s,i)=>{const o=r.append("g");let a="treeView-node-label";e.nodeType==="directory"&&(a+=" treeView-node-dir"),e.cssClass&&(a+=` ${e.cssClass}`);const p=y+ge,c=B(e,s),d=c!==void 0;c&&o.append("g").attr("class","treeView-node-icon").attr("transform",`translate(${n+s.paddingX}, ${t+s.paddingY})`).html(i.get(e.id)??"");const h=o.append("text").text(e.name).attr("dominant-baseline","middle").attr("class",a),{height:l,width:w}=h.node().getBBox(),f=l+s.paddingY*2,m=n+s.paddingX+(d?p:0);h.attr("x",m),h.attr("y",t+f/2);const u=m+w,v=w+s.paddingX*2+(d?p:0);return e.BBox={x:n,y:t,width:v,height:f},e.cssClass?.split(/\s+/).includes("highlight")&&o.insert("rect",":first-child").attr("x",n).attr("y",t+1).attr("width",0).attr("height",f-2).attr("rx",3).attr("class","treeView-highlight-bg"),{node:e,nodeGroup:o,labelRightEdge:u,centerY:t+f/2}},"positionLabel"),$=g((n,t,e,r,s,i)=>n.append("line").attr("x1",t).attr("y1",e).attr("x2",r).attr("y2",s).attr("stroke-width",i).attr("class","treeView-node-line"),"positionLine"),me=g((n,t,e,r)=>{let s=0,i=0;const o=[],a=g((d,h,l,w)=>{const f=w*(l.rowIndent+l.paddingX),m=we(f,s,h,d,l,r);o.push(m);const{height:u,width:v}=h.BBox;$(d,f-l.rowIndent,s+u/2,f,s+u/2,l.lineThickness),i=Math.max(i,f+v),s+=u},"drawNode"),p=g((d,h=0)=>{a(n,d,e,h),d.children.forEach(m=>{p(m,h+1)});const{x:l,y:w,height:f}=d.BBox;if(d.children.length){const{y:m,height:u}=d.children[d.children.length-1].BBox;$(n,l+e.paddingX,w+f,l+e.paddingX,m+u/2+e.lineThickness/2,e.lineThickness)}},"processNode");p(t);const c=o.filter(d=>d.node.description);if(c.length>0){const h=Math.max(...o.map(l=>l.labelRightEdge))+fe;for(const l of c){const f=l.nodeGroup.append("text").text(l.node.description).attr("dominant-baseline","middle").attr("class","treeView-node-description").attr("x",h).attr("y",l.centerY).node().getBBox();i=Math.max(i,h+f.width+e.paddingX)}}for(const d of o)if(d.node.cssClass?.split(/\s+/).includes("highlight")){const h=d.nodeGroup.select(".treeView-highlight-bg");if(!h.empty()){const l=i-d.node.BBox.x+8;h.attr("width",l),i=Math.max(i,d.node.BBox.x+l+2)}}return{totalHeight:s,totalWidth:i}},"drawTree"),xe=g(async(n,t,e,r)=>{A.debug(`Rendering treeView diagram
`+n);const s=r.db,i=s.getRoot(),o=s.getConfig(),a=q(t),p=a.append("g");p.attr("class","tree-view");const c=await ue(i,o),{totalHeight:d,totalWidth:h}=me(p,i,o,c);a.attr("viewBox",`-${o.lineThickness/2} 0 ${h} ${d}`),U(a,d,h,o.useMaxWidth)},"draw"),ve={draw:xe},be=ve,Ie={labelFontSize:"16px",labelColor:"black",lineColor:"black",iconColor:"#546e7a",descriptionColor:"#6a9955",highlightBg:"rgba(255, 193, 7, 0.15)",highlightStroke:"#ffc107"},Ce=g(({treeView:n})=>{const{labelFontSize:t,labelColor:e,lineColor:r,iconColor:s,descriptionColor:i,highlightBg:o,highlightStroke:a}=N(Ie,n);return`
.treeView-node-label {
font-size: ${t};
fill: ${e};
white-space: pre;
}
.treeView-node-dir {
font-weight: bold;
}
.treeView-node-line {
stroke: ${r};
}
.treeView-node-icon {
color: ${s};
}
.treeView-node-description {
font-size: ${t};
fill: ${i};
font-style: italic;
white-space: pre;
}
.treeView-highlight-bg {
fill: ${o};
stroke: ${a};
stroke-width: 1;
}
`},"styles"),ye=Ce,Ne={db:I,renderer:be,parser:pe,styles:ye};export{Ne as diagram};
@@ -0,0 +1,41 @@
import{p as I}from"./chunk-JWPE2WC7.js";import{s as _,g as E,o as D,n as F,a as P,b as z,_ as c,D as G,p as B,A as w,y as C,B as W,l as b,E as V,d as H}from"./mermaid.core.js";import{p as j}from"./cynefin-OW5HDTMX.js";import"./index.js";var x={showLegend:!0,ticks:5,max:null,min:0,graticule:"circle"},y=32,A={axes:[],curves:[],options:x},m=structuredClone(A),U=W.radar,X=c(()=>w({...U,...C().radar}),"getConfig"),M=c(()=>m.axes,"getAxes"),K=c(()=>m.curves,"getCurves"),N=c(()=>m.options,"getOptions"),Y=c(a=>{m.axes=a.map(t=>({name:t.name,label:t.label??t.name}))},"setAxes"),Z=c(a=>{m.curves=a.map(t=>({name:t.name,label:t.label??t.name,entries:q(t.entries)}))},"setCurves"),q=c(a=>{if(a[0].axis==null)return a.map(e=>e.value);const t=M();if(t.length===0)throw new Error("Axes must be populated before curves for reference entries");return t.map(e=>{const r=a.find(s=>s.axis?.$refText===e.name);if(r===void 0)throw new Error("Missing entry for axis "+e.label);return r.value})},"computeCurveEntries"),J=c(a=>{const t=a.reduce((e,r)=>(e[r.name]=r,e),{});m.options={showLegend:t.showLegend?.value??x.showLegend,ticks:t.ticks?.value??x.ticks,max:t.max?.value??x.max,min:t.min?.value??x.min,graticule:t.graticule?.value??x.graticule},m.options.ticks>y&&(b.warn(`Radar diagram ticks (${m.options.ticks}) exceeds maximum allowed (${y}). Using ${y} instead.`),m.options.ticks=y)},"setOptions"),Q=c(()=>{B(),m=structuredClone(A)},"clear"),$={getAxes:M,getCurves:K,getOptions:N,setAxes:Y,setCurves:Z,setOptions:J,getConfig:X,clear:Q,setAccTitle:z,getAccTitle:P,setDiagramTitle:F,getDiagramTitle:D,getAccDescription:E,setAccDescription:_},tt=c(a=>{I(a,$);const{axes:t,curves:e,options:r}=a;$.setAxes(t),$.setCurves(e),$.setOptions(r)},"populate"),et={parse:c(async a=>{const t=await j("radar",a);b.debug(t),tt(t)},"parse")},at=c((a,t,e,r)=>{const s=r.db,i=s.getAxes(),l=s.getCurves(),n=s.getOptions(),o=s.getConfig(),d=s.getDiagramTitle(),p=G(t),u=rt(p,o),g=n.max??Math.max(...l.map(f=>Math.max(...f.entries))),h=n.min,v=Math.min(o.width,o.height)/2;st(u,i,v,n.ticks,n.graticule),nt(u,i,v,o),L(u,i,l,h,g,n.graticule,o),k(u,l,n.showLegend,o),u.append("text").attr("class","radarTitle").text(d).attr("x",0).attr("y",-o.height/2-o.marginTop)},"draw"),rt=c((a,t)=>{const e=t.width+t.marginLeft+t.marginRight,r=t.height+t.marginTop+t.marginBottom,s={x:t.marginLeft+t.width/2,y:t.marginTop+t.height/2};return H(a,r,e,t.useMaxWidth??!0),a.attr("viewBox",`0 0 ${e} ${r}`).attr("overflow","visible"),a.append("g").attr("transform",`translate(${s.x}, ${s.y})`)},"drawFrame"),st=c((a,t,e,r,s)=>{if(s==="circle")for(let i=0;i<r;i++){const l=e*(i+1)/r;a.append("circle").attr("r",l).attr("class","radarGraticule")}else if(s==="polygon"){const i=t.length;for(let l=0;l<r;l++){const n=e*(l+1)/r,o=t.map((d,p)=>{const u=2*p*Math.PI/i-Math.PI/2,g=n*Math.cos(u),h=n*Math.sin(u);return`${g},${h}`}).join(" ");a.append("polygon").attr("points",o).attr("class","radarGraticule")}}},"drawGraticule"),nt=c((a,t,e,r)=>{const s=t.length;for(let i=0;i<s;i++){const l=t[i].label,n=2*i*Math.PI/s-Math.PI/2,o=Math.cos(n),d=Math.sin(n);a.append("line").attr("x1",0).attr("y1",0).attr("x2",e*r.axisScaleFactor*o).attr("y2",e*r.axisScaleFactor*d).attr("class","radarAxisLine");const p=o>.01?"start":o<-.01?"end":"middle",u=d>.01?"hanging":d<-.01?"auto":"central",g=4;a.append("text").text(l).attr("x",e*r.axisLabelFactor*o+g*o).attr("y",e*r.axisLabelFactor*d+g*d).attr("text-anchor",p).attr("dominant-baseline",u).attr("class","radarAxisLabel")}},"drawAxes");function L(a,t,e,r,s,i,l){const n=t.length,o=Math.min(l.width,l.height)/2;e.forEach((d,p)=>{if(d.entries.length!==n)return;const u=d.entries.map((g,h)=>{const v=2*Math.PI*h/n-Math.PI/2,f=T(g,r,s,o),O=f*Math.cos(v),R=f*Math.sin(v);return{x:O,y:R}});i==="circle"?a.append("path").attr("d",S(u,l.curveTension)).attr("class",`radarCurve-${p}`):i==="polygon"&&a.append("polygon").attr("points",u.map(g=>`${g.x},${g.y}`).join(" ")).attr("class",`radarCurve-${p}`)})}c(L,"drawCurves");function T(a,t,e,r){const s=Math.min(Math.max(a,t),e);return r*(s-t)/(e-t)}c(T,"relativeRadius");function S(a,t){const e=a.length;let r=`M${a[0].x},${a[0].y}`;for(let s=0;s<e;s++){const i=a[(s-1+e)%e],l=a[s],n=a[(s+1)%e],o=a[(s+2)%e],d={x:l.x+(n.x-i.x)*t,y:l.y+(n.y-i.y)*t},p={x:n.x-(o.x-l.x)*t,y:n.y-(o.y-l.y)*t};r+=` C${d.x},${d.y} ${p.x},${p.y} ${n.x},${n.y}`}return`${r} Z`}c(S,"closedRoundCurve");function k(a,t,e,r){if(!e)return;const s=(r.width/2+r.marginRight)*3/4,i=-(r.height/2+r.marginTop)*3/4,l=20;t.forEach((n,o)=>{const d=a.append("g").attr("transform",`translate(${s}, ${i+o*l})`);d.append("rect").attr("width",12).attr("height",12).attr("class",`radarLegendBox-${o}`),d.append("text").attr("x",16).attr("y",0).attr("class","radarLegendText").text(n.label)})}c(k,"drawLegend");var ot={draw:at},it=c((a,t)=>{let e="";for(let r=0;r<a.THEME_COLOR_LIMIT;r++){const s=a[`cScale${r}`];e+=`
.radarCurve-${r} {
color: ${s};
fill: ${s};
fill-opacity: ${t.curveOpacity};
stroke: ${s};
stroke-width: ${t.curveStrokeWidth};
}
.radarLegendBox-${r} {
fill: ${s};
fill-opacity: ${t.curveOpacity};
stroke: ${s};
}
`}return e},"genIndexStyles"),lt=c(a=>{const t=V(),e=C(),r=w(t,e.themeVariables),s=w(r.radar,a);return{themeVariables:r,radarOptions:s}},"buildRadarStyleOptions"),ct=c(({radar:a}={})=>{const{themeVariables:t,radarOptions:e}=lt(a);return`
.radarTitle {
font-size: ${t.fontSize};
color: ${t.titleColor};
dominant-baseline: hanging;
text-anchor: middle;
}
.radarAxisLine {
stroke: ${e.axisColor};
stroke-width: ${e.axisStrokeWidth};
}
.radarAxisLabel {
font-size: ${e.axisLabelFontSize}px;
color: ${e.axisColor};
}
.radarGraticule {
fill: ${e.graticuleColor};
fill-opacity: ${e.graticuleOpacity};
stroke: ${e.graticuleColor};
stroke-width: ${e.graticuleStrokeWidth};
}
.radarLegendText {
text-anchor: start;
font-size: ${e.legendFontSize}px;
dominant-baseline: hanging;
}
${it(t,e)}
`},"styles"),mt={parser:et,db:$,renderer:ot,styles:ct};export{mt as diagram};
@@ -0,0 +1,3 @@
import{p as re}from"./chunk-JWPE2WC7.js";import{o as oe,n as se,s as de,g as le,a as ce,b as me,_ as o,l as g,c as T,j as ue,z as xe,p as fe,A as ge,y as M,B as he,i as y,w as P,am as pe}from"./mermaid.core.js";import{p as be,i as ve}from"./cynefin-OW5HDTMX.js";import"./index.js";var $="position frame",D="frame positioned",S="position relation",N="relation positioned",we=o(function(e){g.debug("options str",e)},"setOptions"),ye=o(function(){return{}},"getOptions"),Pe=o(function(){C(),fe()},"clear");function C(){B={}}o(C,"reset");var Se=he.eventmodeling,ke=o(()=>ge({...Se,...M().eventmodeling}),"getConfig"),B={};function O(){let e=Fe;const{ast:n}=B,t=E();if(!n)throw new Error("No data for EventModel");return n.frames.forEach((i,a)=>{const r=G(i,n.dataEntities,t);e=v(e,{$kind:$,index:a,frame:i,textProps:r});let d;K(i)?(g.debug("source frame",i.sourceFrames),d=n.frames.filter(l=>i.sourceFrames.some(c=>c.$refText===l.name)),d.forEach(l=>{e=v(e,{$kind:S,index:a,frame:i,sourceFrame:l})})):e=v(e,{$kind:S,index:a,frame:i})}),e={...e,sortedSwimlanesArray:A(e.swimlanes)},e}o(O,"getState");function I(e){B.ast=e}o(I,"setAst");var s={swimlaneMinHeight:70,swimlanePadding:15,swimlaneGap:10,boxPadding:10,boxOverlap:90,boxDefaultY:0,boxMinWidth:80,boxMaxWidth:450,boxMinHeight:80,boxMaxHeight:750,contentStartX:250,textMaxWidth:430,boxTextFontWeight:"bold",boxTextPadding:10,swimlaneTextFontWeight:"bold",labelUiAutomation:"UI/Automation",labelUiAutomationPrefix:"UI/A: ",labelCommandReadModel:"Command/Read Model",labelCommandReadModelPrefix:"C/RM: ",labelEvents:"Events",labelEventsPrefix:"Stream: "};function E(){return s}o(E,"getDiagramProps");var Fe={boxes:[],swimlanes:{},relations:[],maxR:0,sortedSwimlanesArray:[]};function W(e){const n=e.split(".");if(n.length===2)return n[0]}o(W,"extractNamespace");function H(e){const n=e.split(".");return n.length===2?n[1]:e}o(H,"extractName");function U(e,n){if(!(!n||n.length===0))return Object.values(e).find(t=>t.namespace===n)}o(U,"findSwimlaneByNamespace");function b(e,n,t){return Math.max(n,...Object.keys(e).filter(i=>{const a=Number.parseInt(i);return a>n&&a<t}).map(i=>Number.parseInt(i)))+1}o(b,"findNextAvailableIndex");function _(e,n){const t=W(e.entityIdentifier),i=U(n,t);switch(e.modelEntityType){case"ui":case"pcr":case"processor":return i?{index:i.index,label:i.namespace||s.labelUiAutomation}:t?{index:b(n,0,100),label:s.labelUiAutomationPrefix+t}:{index:0,label:s.labelUiAutomation};case"rmo":case"readmodel":case"cmd":case"command":return i?{index:i.index,label:i.namespace||s.labelCommandReadModel}:t?{index:b(n,100,200),label:s.labelCommandReadModelPrefix+t}:{index:100,label:s.labelCommandReadModel};default:return i?{index:i.index,label:i.namespace||s.labelEvents}:t?{index:b(n,200,300),label:s.labelEventsPrefix+t}:{index:200,label:s.labelEvents}}}o(_,"calculateSwimlaneProps");function L(e){const{themeVariables:n}=M();switch(e.modelEntityType){case"ui":return{fill:n.emUiFill??"white",stroke:n.emUiStroke??"#dbdada"};case"pcr":case"processor":return{fill:n.emProcessorFill??"#edb3f6",stroke:n.emProcessorStroke??"#b88cbf"};case"rmo":case"readmodel":return{fill:n.emReadModelFill??"#d3f1a2",stroke:n.emReadModelStroke??"#a3b732"};case"cmd":case"command":return{fill:n.emCommandFill??"#bcd6fe",stroke:n.emCommandStroke??"#679ac3"};case"evt":case"event":return{fill:n.emEventFill??"#ffb778",stroke:n.emEventStroke??"#c19a0f"};default:return{fill:"red",stroke:"black"}}}o(L,"calculateEntityVisualProps");function G(e,n,t){const i=M(),a=y(H(e.entityIdentifier)??"",i);let r;const d={fontSize:16,fontWeight:700,fontFamily:'"trebuchet ms", verdana, arial, sans-serif',joinWith:"<br/>"};let c=`<b>${P(a,t.textMaxWidth,d)}</b>`;if(e.dataInlineValue&&(r=e.dataInlineValue,r=r.substring(r.indexOf("{")+1),r=r.substring(0,r.lastIndexOf("}")-1),r=y(r,i),r=P(r,t.textMaxWidth,d),r=r.replaceAll(" ","&nbsp;")),e.dataReference){const p=n.find(w=>w.name===e.dataReference?.$refText);p&&(r=p.dataBlockValue,r=r.substring(r.indexOf(`{
`)+2),r=r.substring(0,r.lastIndexOf("}")-1),r=y(r,i),r=P(r,t.textMaxWidth,d),r=r.replaceAll(" ","&nbsp;"),r+="<br/>")}const m=r!==void 0;m&&(c+=`<br/><br/><code style="text-align: left; display: block;max-width:${t.textMaxWidth}px">${r}</code>`);const x={fontSize:d.fontSize,fontWeight:d.fontWeight,fontFamily:d.fontFamily},u=pe(c,x),h=m?u.width/3:u.width,f={content:c,width:h,height:u.height};return g.debug(`[${e.name}] ${e.entityIdentifier} text`,f),f}o(G,"calculateTextProps");function V(e,n){const t=n,i=L(t.frame),a={width:t.textProps.width+2*s.boxTextPadding,height:t.textProps.height+2*s.boxTextPadding};return[{$kind:D,frame:t.frame,index:t.index,visual:i,dimension:a,textProps:t.textProps}]}o(V,"decidePositionFrame");function X(e,n,t){return n===void 0?s.contentStartX:n.index===e.index&&e.r?e.r+s.boxPadding:t===void 0?s.contentStartX:t.r-s.boxOverlap+s.boxPadding}o(X,"calculateX");function j(e,n){const t=[...e.map(i=>i.r),n];return Math.max(...t)}o(j,"calculateMaxRight");function A(e){return Object.values(e).sort((n,t)=>n.index-t.index)}o(A,"sortedSwimlanesArray");function Y(e,n){const t=n,i=_(t.frame,e.swimlanes);let a;i.index in e.swimlanes?a=e.swimlanes[i.index]:a={index:i.index,label:i.label,r:0,y:i.index*s.swimlaneMinHeight+s.swimlaneGap,height:s.swimlaneMinHeight,maxHeight:s.swimlaneMinHeight};const r=e.boxes.length>0?e.boxes[e.boxes.length-1]:void 0,d=e.previousSwimlaneNumber!==void 0?e.swimlanes[e.previousSwimlaneNumber]:void 0,l={width:Math.max(s.boxMinWidth,Math.min(s.boxMaxWidth,t.dimension.width))+2*s.boxPadding,height:Math.max(s.boxMinHeight,Math.min(s.boxMaxHeight,t.dimension.height))+2*s.boxPadding},c=X(a,d,r),m=c+l.width+s.boxPadding,x=j(Object.values(e.swimlanes),m);a.r=c+l.width,a.maxHeight=Math.max(a.maxHeight,l.height),a.height=Math.max(s.swimlaneMinHeight,a.maxHeight)+2*s.swimlanePadding;const u={x:c,y:s.swimlanePadding+a.y,r:m,dimension:l,leftSibling:!1,swimlane:a,visual:t.visual,text:t.textProps.content,frame:t.frame,index:t.index},h={...e,boxes:[...e.boxes,u],swimlanes:{...e.swimlanes,[`${a.index}`]:a},previousSwimlaneNumber:i.index,previousFrame:t.frame,maxR:x},f=A(h.swimlanes);f.length>0&&(f[0].y=0);for(let p=1;p<f.length;p++){const w=f[p],R=f[p-1];w.y=R.y+R.height+s.swimlaneGap}return h}o(Y,"evolveFramePositioned");function z(e,n){return e===0&&n.sourceFrames.length===0}o(z,"isFirstFrame");function K(e){return e.sourceFrames!==void 0&&e.sourceFrames!==null&&e.sourceFrames.length>0}o(K,"hasSourceFrame");function k(e,n){if(n!=null)return e.find(t=>t.frame.name===n.name)}o(k,"findBoxByFrame");function q(e,n,t){if(!(t<0))for(let i=t;i>=0;i--){const a=e[i];if(a.swimlane.index!==n)return a}}o(q,"findBoxByLineIndex");function J(e,n){const t=n;if(ve(t.frame)||z(t.index,t.frame))return[];const i=k(e.boxes,t.frame);if(i===void 0)throw new Error(`Target box not found for frame ${t.frame.name}`);let a;return t.sourceFrame?a=k(e.boxes,t.sourceFrame):a=q(e.boxes,i.swimlane.index,t.index-1),a===void 0?[]:[{$kind:N,frame:t.frame,index:t.index,sourceBox:a,targetBox:i}]}o(J,"decidePositionRelation");function Q(e,n){const t=n,i={visual:{fill:"none",stroke:"#000"},source:{x:t.sourceBox.x,y:t.sourceBox.y},target:{x:t.targetBox.x,y:t.targetBox.y},sourceBox:t.sourceBox,targetBox:t.targetBox};return{...e,relations:[...e.relations,i]}}o(Q,"evolveRelationPositioned");var Me={[$]:V,[S]:J},Be={[D]:Y,[N]:Q};function Z(e,n){const t=Me[n.$kind];if(t==null)return[];const i=t(e,n);return g.debug("decided events",i),i}o(Z,"decide");function ee(e,n){const t=n.reduce((i,a)=>{const r=Be[a.$kind];return r==null?i:r(i,a)},e);return g.debug("evolve events",{state:e,newState:t,events:n}),t}o(ee,"evolve");function v(e,n){const t=Z(e,n);return ee(e,t)}o(v,"dispatch");var F={getConfig:ke,setOptions:we,getOptions:ye,clear:Pe,setAccTitle:me,getAccTitle:ce,getAccDescription:le,setAccDescription:de,setDiagramTitle:se,getDiagramTitle:oe,setAst:I,getDiagramProps:E,getState:O},Ee={parse:o(async e=>{const n=await be("eventmodeling",e);g.debug(n),F.setAst(n),re(n,F)},"parse")},Ae=T(),Re=Ae?.eventmodeling;function te(e,n){return t=>{const i=t.swimlane.y+n.swimlanePadding,a=e.append("g").attr("class","em-box");a.append("rect").attr("x",t.x).attr("y",i).attr("rx","3").attr("width",t.dimension.width).attr("height",t.dimension.height).attr("stroke",t.visual.stroke).attr("fill",t.visual.fill),a.append("foreignObject").attr("x",t.x+n.boxPadding).attr("y",i+10).attr("width",t.dimension.width-2*n.boxPadding).attr("height",t.dimension.height-2*n.boxPadding).append("xhtml:div").style("display","table").style("height","100%").style("width","100%").append("span").style("display","table-cell").style("text-align","center").style("vertical-align","middle").html(t.text)}}o(te,"renderD3Box");function ne(e,n){return e>n}o(ne,"dirUpwards");function ie(e,n,t,i){return a=>{const r=a.sourceBox.swimlane.y+n.swimlanePadding,d=a.targetBox.swimlane.y+n.swimlanePadding,l=ne(r,d),c=a.sourceBox.x+a.sourceBox.dimension.width*2/3,m=a.targetBox.x+a.targetBox.dimeLine truncated
`,"id:",n,t),!Re)throw new Error("EventModeling config not found");const a=i.db,{themeVariables:r,eventmodeling:d}=T(),l=ue(`[id="${n}"]`),c=a.getDiagramProps(),m=a.getState(),x=`em-arrowhead-${n}`,u=r.emArrowhead??"#000000";m.sortedSwimlanesArray.forEach(ae(l,m.maxR,c,r)),m.boxes.forEach(te(l,c)),m.relations.forEach(ie(l,c,x,r)),l.append("defs").append("marker").attr("id",x).attr("markerWidth","10").attr("markerHeight","7").attr("refX","10").attr("refY","3.5").attr("orient","auto").append("polygon").attr("points","0 0, 10 3.5, 0 7").attr("fill",u),xe(void 0,l,d?.padding??30,d?.useMaxWidth)},"draw"),$e={draw:Te},De=o(e=>"","getStyles"),Ne=De,He={parser:Ee,db:F,renderer:$e,styles:Ne};export{He as diagram};
@@ -0,0 +1,24 @@
import{p as ge}from"./chunk-JWPE2WC7.js";import{_ as w,E as ye,y as ae,A as ee,D as Se,d as ve,l as te,bd as B,j as U,b as xe,a as be,n as we,o as Ce,g as Te,s as Le,B as $e,be as Ae,p as Fe}from"./mermaid.core.js";import{s as Ne}from"./chunk-POPQ4Y6H.js";import{p as Me}from"./cynefin-OW5HDTMX.js";import{b as O}from"./defaultLocale.js";import{o as Q}from"./ordinal.js";import"./index.js";import"./init.js";function _e(t){var a=0,l=t.children,n=l&&l.length;if(!n)a=1;else for(;--n>=0;)a+=l[n].value;t.value=a}function ke(){return this.eachAfter(_e)}function ze(t,a){let l=-1;for(const n of this)t.call(a,n,++l,this);return this}function Ve(t,a){for(var l=this,n=[l],r,i,h=-1;l=n.pop();)if(t.call(a,l,++h,this),r=l.children)for(i=r.length-1;i>=0;--i)n.push(r[i]);return this}function De(t,a){for(var l=this,n=[l],r=[],i,h,d,g=-1;l=n.pop();)if(r.push(l),i=l.children)for(h=0,d=i.length;h<d;++h)n.push(i[h]);for(;l=r.pop();)t.call(a,l,++g,this);return this}function Pe(t,a){let l=-1;for(const n of this)if(t.call(a,n,++l,this))return n}function Be(t){return this.eachAfter(function(a){for(var l=+t(a.data)||0,n=a.children,r=n&&n.length;--r>=0;)l+=n[r].value;a.value=l})}function Ee(t){return this.eachBefore(function(a){a.children&&a.children.sort(t)})}function Re(t){for(var a=this,l=We(a,t),n=[a];a!==l;)a=a.parent,n.push(a);for(var r=n.length;t!==l;)n.splice(r,0,t),t=t.parent;return n}function We(t,a){if(t===a)return t;var l=t.ancestors(),n=a.ancestors(),r=null;for(t=l.pop(),a=n.pop();t===a;)r=t,t=l.pop(),a=n.pop();return r}function He(){for(var t=this,a=[t];t=t.parent;)a.push(t);return a}function Ie(){return Array.from(this)}function Oe(){var t=[];return this.eachBefore(function(a){a.children||t.push(a)}),t}function Ge(){var t=this,a=[];return t.each(function(l){l!==t&&a.push({source:l.parent,target:l})}),a}function*qe(){var t=this,a,l=[t],n,r,i;do for(a=l.reverse(),l=[];t=a.pop();)if(yield t,n=t.children)for(r=0,i=n.length;r<i;++r)l.push(n[r]);while(l.length)}function ne(t,a){t instanceof Map?(t=[void 0,t],a===void 0&&(a=Ye)):a===void 0&&(a=je);for(var l=new Z(t),n,r=[l],i,h,d,g;n=r.pop();)if((h=a(n.data))&&(g=(h=Array.from(h)).length))for(n.children=h,d=g-1;d>=0;--d)r.push(i=h[d]=new Z(h[d])),i.parent=n,i.depth=n.depth+1;return l.eachBefore(Ze)}function Xe(){return ne(this).eachBefore(Ue)}function je(t){return t.children}function Ye(t){return Array.isArray(t)?t[1]:null}function Ue(t){t.data.value!==void 0&&(t.value=t.data.value),t.data=t.data.data}function Ze(t){var a=0;do t.height=a;while((t=t.parent)&&t.height<++a)}function Z(t){this.data=t,this.depth=this.height=0,this.parent=null}Z.prototype=ne.prototype={constructor:Z,count:ke,each:ze,eachAfter:De,eachBefore:Ve,find:Pe,sum:Be,sort:Ee,path:Re,ancestors:He,descendants:Ie,leaves:Oe,links:Ge,copy:Xe,[Symbol.iterator]:qe};function Je(t){if(typeof t!="function")throw new Error;return t}function G(){return 0}function q(t){return function(){return t}}function Ke(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Qe(t,a,l,n,r){for(var i=t.children,h,d=-1,g=i.length,c=t.value&&(n-a)/t.value;++d<g;)h=i[d],h.y0=l,h.y1=r,h.x0=a,h.x1=a+=h.value*c}function et(t,a,l,n,r){for(var i=t.children,h,d=-1,g=i.length,c=t.value&&(r-l)/t.value;++d<g;)h=i[d],h.x0=a,h.x1=n,h.y0=l,h.y1=l+=h.value*c}var tt=(1+Math.sqrt(5))/2;function at(t,a,l,n,r,i){for(var h=[],d=a.children,g,c,p=0,b=0,s=d.length,x,S,v=a.value,u,y,N,$,V,W,M;p<s;){x=r-l,S=i-n;do u=d[b++].value;while(!u&&b<s);for(y=N=u,W=Math.max(S/x,x/S)/(v*t),M=u*u*W,V=Math.max(N/M,M/y);b<s;++b){if(u+=c=d[b].value,c<y&&(y=c),c>N&&(N=c),M=u*u*W,$=Math.max(N/M,M/y),$>V){u-=c;break}V=$}h.push(g={value:u,dice:x<S,children:d.slice(p,b)}),g.dice?Qe(g,l,n,r,v?n+=S*u/v:i):et(g,l,n,v?l+=x*u/v:r,i),v-=u,p=b}return h}const nt=(function t(a){function l(n,r,i,h,d){at(a,n,r,i,h,d)}return l.ratio=function(n){return t((n=+n)>1?n:1)},l})(tt);function lt(){var t=nt,a=!1,l=1,n=1,r=[0],i=G,h=G,d=G,g=G,c=G;function p(s){return s.x0=s.y0=0,s.x1=l,s.y1=n,s.eachBefore(b),r=[0],a&&s.eachBefore(Ke),s}function b(s){var x=r[s.depth],S=s.x0+x,v=s.y0+x,u=s.x1-x,y=s.y1-x;u<S&&(S=u=(S+u)/2),y<v&&(v=y=(v+y)/2),s.x0=S,s.y0=v,s.x1=u,s.y1=y,s.children&&(x=r[s.depth+1]=i(s)/2,S+=c(s)-x,v+=h(s)-x,u-=d(s)-x,y-=g(s)-x,u<S&&(S=u=(S+u)/2),y<v&&(v=y=(v+y)/2),t(s,S,v,u,y))}return p.round=function(s){return arguments.length?(a=!!s,p):a},p.size=function(s){return arguments.length?(l=+s[0],n=+s[1],p):[l,n]},p.tile=function(s){return arguments.length?(t=Je(s),p):t},p.padding=function(s){return arguments.length?p.paddingInner(s).paddingOuter(s):p.paddingInner()},p.paddingInner=function(s){return arguments.length?(i=typeof s=="function"?s:q(+s),p):i},p.paddingOuter=function(s){return arguments.length?p.paddingTop(s).paddingRight(s).paddingBottom(s).paddingLeft(s):p.paddingTop()},p.paddingTop=function(s){return arguments.length?(h=typeof s=="function"?s:q(+s),p):h},p.paddingRight=function(s){return arguments.length?(d=typeof s=="function"?s:q(+s),p)Line truncated
.treemapNode.section {
stroke: ${r.sectionStrokeColor};
stroke-width: ${r.sectionStrokeWidth};
fill: ${r.sectionFillColor};
}
.treemapNode.leaf {
stroke: ${r.leafStrokeColor};
stroke-width: ${r.leafStrokeWidth};
fill: ${r.leafFillColor};
}
.treemapLabel {
fill: ${h};
font-size: ${r.labelFontSize};
}
.treemapValue {
fill: ${d};
font-size: ${r.valueFontSize};
}
.treemapTitle {
fill: ${i};
font-size: ${r.titleFontSize};
}
`},"getStyles"),ut=pt,Ct={parser:he,get db(){return new oe},renderer:ht,styles:ut};export{Ct as diagram};
Loaded 100 of 181 files, more files were not shown because too many files have changed in this diff. Show more