diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.yml b/.github/ISSUE_TEMPLATE/1-bug-report.yml new file mode 100644 index 0000000000000000000000000000000000000000..c370cc642bdda3c8b3f030d2189f00ad8ce3dd96 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug-report.yml @@ -0,0 +1,74 @@ +name: Bug Report +description: Report an issue that should be fixed +labels: + - bug + - needs triage +body: + - type: markdown + attributes: + value: | + Thank you for submitting a bug report! It helps make Kimi Code better for everyone. + + Make sure you are running the latest version of Kimi Code CLI. The bug you are experiencing may already have been fixed. + + Please try to include as much information as possible. + + If you plan to submit a fix: check the Contribution box below and wait for a maintainer's `/approve` comment in this issue before opening a PR. + + - type: input + id: version + attributes: + label: What version of Kimi Code is running? + description: Copy the output of `kimi --version` or `/version` + validations: + required: true + - type: input + id: plan + attributes: + label: Which open platform/subscription were you using? + description: The one you selected when running `/login` + validations: + required: true + - type: input + id: model + attributes: + label: Which model were you using? + description: The one you can see on the bottom status line, like `kimi-k2.6`, `kimi-for-coding`, etc. + - type: input + id: platform + attributes: + label: What platform is your computer? + description: | + For MacOS and Linux: copy the output of `uname -mprs` + For Windows: copy the output of `"$([Environment]::OSVersion | ForEach-Object VersionString) $(if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" })"` in the PowerShell console + - type: textarea + id: actual + attributes: + label: What issue are you seeing? + description: Please include the full error messages and prompts with any private information redacted. If possible, please provide text instead of a screenshot. + validations: + required: true + - type: textarea + id: steps + attributes: + label: What steps can reproduce the bug? + description: Explain the bug and provide a code snippet that can reproduce it. Please include session id and context usage if applicable. + validations: + required: true + - type: textarea + id: expected + attributes: + label: What is the expected behavior? + description: If possible, please provide text instead of a screenshot. + - type: textarea + id: notes + attributes: + label: Additional information + description: Is there anything else you think we should know? + + - type: checkboxes + id: willing-to-pr + attributes: + label: Contribution + options: + - label: I am willing to submit a PR for this bug fix myself (please wait for maintainer approval in this issue first) diff --git a/.github/ISSUE_TEMPLATE/2-feature-request.yml b/.github/ISSUE_TEMPLATE/2-feature-request.yml new file mode 100644 index 0000000000000000000000000000000000000000..1f2b10713ae420cda1bcea88b6998f998ab3bccf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature-request.yml @@ -0,0 +1,26 @@ +name: Feature Request +description: Propose a new feature for Kimi Code +labels: + - enhancement +body: + - type: markdown + attributes: + value: | + Is Kimi Code missing a feature that you'd like to see? Feel free to propose it here. + + Before you submit a feature: + 1. Search existing issues for similar features. If you find one, 👍 it rather than opening a new one. + 2. The Kimi Code team will try to balance the varying needs of the community when prioritizing or rejecting new features. Please understand that not all features will be accepted. + 3. Do not open a feature PR. External feature PRs are not accepted — features are discussed and decided in this issue; if accepted, the team will implement it or explicitly invite you to contribute. + + - type: textarea + id: feature + attributes: + label: What feature would you like to see? + validations: + required: true + - type: textarea + id: notes + attributes: + label: Additional information + description: Is there anything else you think we should know? diff --git a/.github/ISSUE_TEMPLATE/3-bug-report-zh-cn.yml b/.github/ISSUE_TEMPLATE/3-bug-report-zh-cn.yml new file mode 100644 index 0000000000000000000000000000000000000000..3dd6f4d7f64293634bf1b74a86d8f24f9689d4fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-bug-report-zh-cn.yml @@ -0,0 +1,73 @@ +name: Bug 报告 +description: 报告需要修复的问题 +labels: + - bug + - needs triage +body: + - type: markdown + attributes: + value: | + 感谢你提交 bug 报告!这能帮助 Kimi Code 变得更好。 + + 请确认你正在运行最新版本的 Kimi Code CLI——你遇到的问题可能已经被修复。 + + 请尽量提供完整的信息。 + + 如果你打算提交修复:勾选下方 Contribution 选项,并等待维护者在本 issue 中以 `/approve` 评论批准后再提 PR。 + + - type: input + id: version + attributes: + label: 你运行的 Kimi Code 版本是? + description: 复制 `kimi --version` 或 `/version` 的输出 + validations: + required: true + - type: input + id: plan + attributes: + label: 你使用的是哪个开放平台/订阅? + description: 运行 `/login` 时选择的那个 + validations: + required: true + - type: input + id: model + attributes: + label: 你使用的是哪个模型? + description: 底部状态栏可见,如 `kimi-k2.6`、`kimi-for-coding` 等 + - type: input + id: platform + attributes: + label: 你的电脑平台是? + description: | + macOS 和 Linux:复制 `uname -mprs` 的输出 + Windows:在 PowerShell 中运行 `"$([Environment]::OSVersion | ForEach-Object VersionString) $(if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" })"` 并复制输出 + - type: textarea + id: actual + attributes: + label: 你遇到了什么问题? + description: 请包含完整的错误信息和提示词(隐去隐私信息)。如可能,请提供文本而非截图。 + validations: + required: true + - type: textarea + id: steps + attributes: + label: 复现步骤? + description: 说明 bug 并给出可复现的代码片段。如适用,请提供 session id 和上下文用量。 + validations: + required: true + - type: textarea + id: expected + attributes: + label: 期望的行为是什么? + description: 如可能,请提供文本而非截图。 + - type: textarea + id: notes + attributes: + label: 补充信息 + description: 还有什么想让我们知道的? + - type: checkboxes + id: willing-to-pr + attributes: + label: Contribution + options: + - label: 我愿意自己提交修复此 bug 的 PR(请先等待维护者在本 issue 中批准) diff --git a/.github/ISSUE_TEMPLATE/4-feature-request-zh-cn.yml b/.github/ISSUE_TEMPLATE/4-feature-request-zh-cn.yml new file mode 100644 index 0000000000000000000000000000000000000000..b7892ff60615aa56e878b5d266ead0b88670a9e2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/4-feature-request-zh-cn.yml @@ -0,0 +1,26 @@ +name: 功能建议 +description: 为 Kimi Code 提议新功能 +labels: + - enhancement +body: + - type: markdown + attributes: + value: | + Kimi Code 缺少你想要的某个功能?欢迎在这里提议。 + + 提交功能建议前: + 1. 先搜索已有 issue,如有类似功能,点 👍 而不是新开 issue。 + 2. Kimi Code 团队会在排序或拒绝新功能时尽量平衡社区的不同需求,请理解并非所有功能都会被接受。 + 3. 不要提交 feature PR。不接受外部功能 PR——功能在本 issue 中讨论和决定;如被接受,由团队实现或明确邀请你来贡献。 + + - type: textarea + id: feature + attributes: + label: 你希望看到什么功能? + validations: + required: true + - type: textarea + id: notes + attributes: + label: 补充信息 + description: 还有什么想让我们知道的? diff --git a/.github/actions/macos-keychain-cleanup/action.yml b/.github/actions/macos-keychain-cleanup/action.yml new file mode 100644 index 0000000000000000000000000000000000000000..1cc377a1c4aba05efd79a0c2e8cc76081cd9c2c2 --- /dev/null +++ b/.github/actions/macos-keychain-cleanup/action.yml @@ -0,0 +1,12 @@ +name: macOS keychain cleanup +description: Delete the temporary keychain created by macos-keychain-setup. + +runs: + using: composite + steps: + - name: Cleanup keychain + shell: bash + run: | + if [[ -n "${APPLE_KEYCHAIN_PATH:-}" && -f "${APPLE_KEYCHAIN_PATH}" ]]; then + security delete-keychain "$APPLE_KEYCHAIN_PATH" || true + fi diff --git a/.github/actions/macos-keychain-setup/action.yml b/.github/actions/macos-keychain-setup/action.yml new file mode 100644 index 0000000000000000000000000000000000000000..199f8ed7f9e9598d0814ae953b277f06aa14c188 --- /dev/null +++ b/.github/actions/macos-keychain-setup/action.yml @@ -0,0 +1,82 @@ +name: macOS keychain setup +description: | + Create a temporary keychain, import a Developer ID Application certificate, + discover the signing identity, and export APPLE_SIGNING_IDENTITY + + APPLE_KEYCHAIN_PATH to GITHUB_ENV for subsequent steps. Must be paired + with macos-keychain-cleanup in an if: always() step at job end. + +inputs: + certificate-p12: + description: Base64-encoded P12 certificate + required: true + certificate-password: + description: P12 password + required: true + +runs: + using: composite + steps: + - name: Import signing certificate + shell: bash + env: + APPLE_CERTIFICATE_P12: ${{ inputs.certificate-p12 }} + APPLE_CERTIFICATE_PASSWORD: ${{ inputs.certificate-password }} + KEYCHAIN_PASSWORD: actions + run: | + set -euo pipefail + + # 0. Validate inputs early — base64 decoding "" gives 0-byte .p12 → security import reports + # "SecKeychainItemImport: One or more parameters passed to a function were not valid" + # which is cryptic. Fail loudly here instead. + if [ -z "$APPLE_CERTIFICATE_P12" ]; then + echo "::error::APPLE_CERTIFICATE_P12 secret is empty. Configure it in repo settings, or pass sign-macos=false." + exit 1 + fi + if [ -z "$APPLE_CERTIFICATE_PASSWORD" ]; then + echo "::error::APPLE_CERTIFICATE_PASSWORD secret is empty." + exit 1 + fi + + # 1. Decode certificate + cert_path="${RUNNER_TEMP}/certificate.p12" + printf '%s' "$APPLE_CERTIFICATE_P12" | base64 -d > "$cert_path" + if [ ! -s "$cert_path" ]; then + echo "::error::Decoded certificate is empty. APPLE_CERTIFICATE_P12 secret value may not be valid base64." + exit 1 + fi + + # 2. Create temporary keychain (don't pollute runner default keychain) + keychain_path="${RUNNER_TEMP}/signing.keychain-db" + security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path" + security set-keychain-settings -lut 21600 "$keychain_path" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path" + + # 3. Add to user keychain search list and set default + security list-keychains -d user -s "$keychain_path" $(security list-keychains -d user | tr -d '"') + security default-keychain -s "$keychain_path" + + # 4. Import cert, authorize codesign + security tools + security import "$cert_path" -k "$keychain_path" \ + -P "$APPLE_CERTIFICATE_PASSWORD" \ + -T /usr/bin/codesign -T /usr/bin/security + + # 5. Non-interactive private key access + security set-key-partition-list -S apple-tool:,apple: \ + -s -k "$KEYCHAIN_PASSWORD" "$keychain_path" > /dev/null + + # 6. Discover identity (don't hardcode team ID) + IDENTITY=$(security find-identity -v -p codesigning "$keychain_path" \ + | grep "Developer ID Application" | head -1 \ + | sed -n 's/.*"\(Developer ID Application[^"]*\)".*/\1/p') + + if [[ -z "$IDENTITY" ]]; then + echo "::error::No Developer ID Application identity found in keychain" + security find-identity -v -p codesigning "$keychain_path" + exit 1 + fi + + echo "Found signing identity: $IDENTITY" + echo "APPLE_SIGNING_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" + echo "APPLE_KEYCHAIN_PATH=$keychain_path" >> "$GITHUB_ENV" + + rm -f "$cert_path" diff --git a/.github/actions/macos-notarize/action.yml b/.github/actions/macos-notarize/action.yml new file mode 100644 index 0000000000000000000000000000000000000000..9a919d810ae16fbbda9e5388a73696f6bb91cc19 --- /dev/null +++ b/.github/actions/macos-notarize/action.yml @@ -0,0 +1,95 @@ +name: macOS notarize +description: | + Submit a signed binary to Apple notary service via notarytool, wait for + result, and run Gatekeeper online check (spctl). Fails the job with the + notarytool log on rejection. + +inputs: + binary-path: + description: Absolute path to the signed binary + required: true + notarization-key-p8: + description: Base64-encoded App Store Connect API Key (.p8) + required: true + notarization-key-id: + description: API Key ID + required: true + notarization-issuer-id: + description: Issuer ID + required: true + timeout: + description: notarytool wait timeout (e.g. 15m) + required: false + default: '15m' + +runs: + using: composite + steps: + - name: Submit to notary service + shell: bash + env: + BINARY_PATH: ${{ inputs.binary-path }} + APPLE_NOTARIZATION_KEY_P8: ${{ inputs.notarization-key-p8 }} + APPLE_NOTARIZATION_KEY_ID: ${{ inputs.notarization-key-id }} + APPLE_NOTARIZATION_ISSUER_ID: ${{ inputs.notarization-issuer-id }} + NOTARY_TIMEOUT: ${{ inputs.timeout }} + run: | + set -euo pipefail + + if [[ ! -f "$BINARY_PATH" ]]; then + echo "::error::Binary not found at $BINARY_PATH" + exit 1 + fi + + # 1. Decode API key + key_path="${RUNNER_TEMP}/AuthKey.p8" + printf '%s' "$APPLE_NOTARIZATION_KEY_P8" | base64 -d > "$key_path" + + # 2. Pack with ditto (--norsrc avoids ._AppleDouble files) + binary_name=$(basename "$BINARY_PATH") + zip_path="${RUNNER_TEMP}/${binary_name}.notarize.zip" + ditto -c -k --norsrc --keepParent "$BINARY_PATH" "$zip_path" + + echo "==> Submitting $binary_name for notarization..." + + # 3. Submit and capture log + log_path="${RUNNER_TEMP}/notarize-${binary_name}.log" + set +e + xcrun notarytool submit "$zip_path" \ + --key "$key_path" \ + --key-id "$APPLE_NOTARIZATION_KEY_ID" \ + --issuer "$APPLE_NOTARIZATION_ISSUER_ID" \ + --wait --timeout "$NOTARY_TIMEOUT" 2>&1 | tee "$log_path" + notarize_rc=${PIPESTATUS[0]} + set -e + + # 4. Inspect status + if ! grep -q "status: Accepted" "$log_path"; then + echo "::error::Notarization failed (exit=$notarize_rc)" + submission_id=$(grep -m1 "id:" "$log_path" | awk '{print $2}' || true) + if [[ -n "$submission_id" ]]; then + echo "Fetching detailed log for submission $submission_id..." + xcrun notarytool log "$submission_id" \ + --key "$key_path" \ + --key-id "$APPLE_NOTARIZATION_KEY_ID" \ + --issuer "$APPLE_NOTARIZATION_ISSUER_ID" || true + fi + rm -f "$key_path" "$zip_path" + exit 1 + fi + + echo "==> Notarization accepted" + + # 5. Cleanup + rm -f "$key_path" "$zip_path" + + - name: Verify with Gatekeeper online check + shell: bash + env: + BINARY_PATH: ${{ inputs.binary-path }} + run: | + set -euo pipefail + echo "==> codesign -dv $BINARY_PATH" + codesign -dv --verbose=2 "$BINARY_PATH" + echo "==> spctl -a -vvv -t install $BINARY_PATH" + spctl -a -vvv -t install "$BINARY_PATH" diff --git a/.github/workflows/_native-build.yml b/.github/workflows/_native-build.yml new file mode 100644 index 0000000000000000000000000000000000000000..483c58e419b525c9af2a6e54f6dcb3b41243b179 --- /dev/null +++ b/.github/workflows/_native-build.yml @@ -0,0 +1,128 @@ +name: _native-build + +on: + workflow_call: + inputs: + upload-artifact-prefix: + description: 'Prefix for uploaded artifact name' + required: false + type: string + default: 'kimi-code-native' + retention-days: + description: 'Artifact retention in days' + required: false + type: number + default: 3 + sign-macos: + description: 'Whether to sign + notarize macOS builds (requires Apple secrets)' + required: false + type: boolean + default: false + secrets: + APPLE_CERTIFICATE_P12: + required: false + APPLE_CERTIFICATE_PASSWORD: + required: false + APPLE_NOTARIZATION_KEY_P8: + required: false + APPLE_NOTARIZATION_KEY_ID: + required: false + APPLE_NOTARIZATION_ISSUER_ID: + required: false + +permissions: + contents: read + +jobs: + native-bundle: + name: Native bundle (${{ matrix.target }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-24.04 + target: linux-x64 + - os: ubuntu-24.04-arm + target: linux-arm64 + - os: macos-15-intel + target: darwin-x64 + - os: macos-15 + target: darwin-arm64 + - os: windows-2025-vs2026 + target: win32-x64 + - os: windows-11-arm + target: win32-arm64 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Setup macOS keychain (release only) + if: runner.os == 'macOS' && inputs.sign-macos + uses: ./.github/actions/macos-keychain-setup + with: + certificate-p12: ${{ secrets.APPLE_CERTIFICATE_P12 }} + certificate-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + + - name: Generate built-in catalog (release artifacts) + if: inputs.sign-macos + shell: bash + run: | + CATALOG_FILE="$RUNNER_TEMP/kimi-code-built-in-catalog.json" + node apps/kimi-code/scripts/update-catalog.mjs --out "$CATALOG_FILE" + echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV" + + - name: Build Kimi web assets + # The SEA blob step embeds apps/kimi-code/dist-web. The bundle is + # committed (synced from the code-app repo) — just verify it is in place. + run: node apps/kimi-code/scripts/check-web-assets.mjs + + - name: Build native executable (release profile, macOS signed) + if: runner.os == 'macOS' && inputs.sign-macos + run: pnpm --filter @moonshot-ai/kimi-code run build:native:release + + - name: Build native executable (local profile) + if: '!(runner.os == ''macOS'' && inputs.sign-macos)' + run: pnpm --filter @moonshot-ai/kimi-code run build:native:sea + + - name: Notarize macOS binary + if: runner.os == 'macOS' && inputs.sign-macos + uses: ./.github/actions/macos-notarize + with: + binary-path: ${{ github.workspace }}/apps/kimi-code/dist-native/bin/${{ matrix.target }}/kimi + notarization-key-p8: ${{ secrets.APPLE_NOTARIZATION_KEY_P8 }} + notarization-key-id: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }} + notarization-issuer-id: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }} + + - name: Cleanup macOS keychain + if: always() && runner.os == 'macOS' && inputs.sign-macos + uses: ./.github/actions/macos-keychain-cleanup + + - name: Smoke test native executable + run: pnpm --filter @moonshot-ai/kimi-code run test:native:smoke + + - name: Package native artifact + run: pnpm --filter @moonshot-ai/kimi-code run package:native + + - name: Upload native artifact + uses: actions/upload-artifact@v7 + with: + name: ${{ inputs.upload-artifact-prefix }}-${{ matrix.target }} + retention-days: ${{ inputs.retention-days }} + path: | + apps/kimi-code/dist-native/artifacts/kimi-code-${{ matrix.target }}.zip + apps/kimi-code/dist-native/artifacts/kimi-code-${{ matrix.target }}.zip.sha256 + if-no-files-found: ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..636568d71d2f09cb71348f05759a695c23e7a55d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,154 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: pnpm run build + - name: Smoke test CLI bundle + run: pnpm -C apps/kimi-code run smoke + + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4, 5] + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: pnpm run test --shard=${{ matrix.shard }}/5 + + # pi-tui's suite runs on node:test (not vitest), so the root `pnpm run test` + # does not execute it; it needs its own job. + test-pi-tui: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: pnpm --filter @moonshot-ai/pi-tui test + + # The VS Code extension suite runs on the default (v2) engine as part of the + # sharded root run above; this job reruns it on the legacy v1 engine, which + # the extension selects through the rollback env var. + test-vscode-legacy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: pnpm --filter kimi-code test + env: + KIMI_CODE_LEGACY_FLAG: "1" + + test-windows: + runs-on: windows-latest + # Temporarily disabled while Windows tests are being stabilized. + if: false + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + # Windows runners are slower and run the whole suite (including + # in-process e2e tests) under more contention, so the default 5s test + # timeout causes flaky failures. Give it more headroom. + - run: pnpm run test -- --testTimeout=30000 + + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: pnpm run lint + - run: pnpm run sherif + + typecheck: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + - name: Typecheck + run: | + pnpm dlx --package @typescript/native-preview@beta tsgo --version + for config in packages/*/tsconfig.json apps/kimi-code/tsconfig.json; do + echo "Typechecking ${config}" + pnpm dlx --package @typescript/native-preview@beta tsgo -p "${config}" --noEmit + done + - name: Typecheck VS Code extension + run: pnpm --filter kimi-code run typecheck + - name: Typecheck vis-server + run: pnpm --filter @moonshot-ai/vis-server run typecheck + - name: Typecheck vis-web + run: pnpm --filter @moonshot-ai/vis-web run typecheck diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml new file mode 100644 index 0000000000000000000000000000000000000000..21cd768cb96ca576a831c2b85ce1054e6aa757ea --- /dev/null +++ b/.github/workflows/docs-deploy.yml @@ -0,0 +1,51 @@ +name: Deploy Docs to GitHub Pages + +on: + workflow_call: + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: pnpm/action-setup@v6 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Build docs + run: pnpm -C docs run build + env: + VITEPRESS_BASE: /${{ github.event.repository.name }}/ + + - name: Upload artifact + uses: actions/upload-pages-artifact@v5 + with: + path: docs/.vitepress/dist + + deploy: + if: github.ref == 'refs/heads/main' + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/manual-native-bundle.yml b/.github/workflows/manual-native-bundle.yml new file mode 100644 index 0000000000000000000000000000000000000000..88bbf0d53bc701c0ed0d8f10f2c9a77190d336f9 --- /dev/null +++ b/.github/workflows/manual-native-bundle.yml @@ -0,0 +1,21 @@ +name: Manual Native Bundle + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + uses: ./.github/workflows/_native-build.yml + with: + upload-artifact-prefix: kimi-code-native + retention-days: 3 + sign-macos: true + secrets: + APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_NOTARIZATION_KEY_P8: ${{ secrets.APPLE_NOTARIZATION_KEY_P8 }} + APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }} + APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }} diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml new file mode 100644 index 0000000000000000000000000000000000000000..abf0122b10bbe22268513ea4f69049ef295d67a5 --- /dev/null +++ b/.github/workflows/nix-build.yml @@ -0,0 +1,190 @@ +name: Nix Build + +on: + pull_request: + branches: + - main + push: + branches: + - main + +permissions: + contents: read + pull-requests: write + +jobs: + check-workspace-sync: + name: Check flake.nix workspace sync + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Check workspace sync + id: check + run: | + set -euo pipefail + if node scripts/check-nix-workspace.mjs; then + echo "SYNC_OK=true" >> "$GITHUB_OUTPUT" + else + echo "SYNC_OK=false" >> "$GITHUB_OUTPUT" + fi + + - name: Extract missing items + if: steps.check.outputs.SYNC_OK == 'false' && github.event_name == 'pull_request' + id: missing + run: | + { + echo "body<" + echo "❌ flake.nix workspace lists out of sync" + echo "" + echo "The recursive workspace dependencies of \`apps/kimi-code\` do not match \`flake.nix\`. Please run \`node scripts/check-nix-workspace.mjs\` locally for details." + echo "" + echo "Typical fix: add the missing package name to \`workspaceNames\` and its path to \`workspacePaths\` in \`flake.nix\`." + echo "EOF" + } >> "$GITHUB_OUTPUT" + + - name: Post or update PR comment + if: steps.check.outputs.SYNC_OK == 'false' && github.event_name == 'pull_request' + uses: actions/github-script@v7 + env: + COMMENT_BODY: ${{ steps.missing.outputs.body }} + with: + script: | + const marker = ''; + const body = process.env.COMMENT_BODY; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const existing = comments.find(c => + c.user.login === 'github-actions[bot]' && c.body.includes(marker) + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body, + }); + } + + - name: Fail if workspace sync failed + if: steps.check.outputs.SYNC_OK == 'false' + run: exit 1 + + nix-build: + name: nix build .#kimi-code + needs: check-workspace-sync + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + nix-path: nixpkgs=channel:nixos-unstable + + - name: Build + id: build + run: | + set -euo pipefail + LOG_FILE="$(mktemp)" + if nix build .#kimi-code --print-build-logs 2>&1 | tee "$LOG_FILE"; then + echo "BUILD_FAILED=false" >> "$GITHUB_OUTPUT" + else + echo "BUILD_FAILED=true" >> "$GITHUB_OUTPUT" + echo "LOG_FILE=$LOG_FILE" >> "$GITHUB_OUTPUT" + fi + + - name: Extract error log + if: steps.build.outputs.BUILD_FAILED == 'true' && github.event_name == 'pull_request' + id: error + run: | + LOG_FILE="${{ steps.build.outputs.LOG_FILE }}" + + # Extract hash mismatch info + SPECIFIED=$(grep -oP 'specified:\s+\K\S+' "$LOG_FILE" || true) + GOT=$(grep -oP 'got:\s+\K\S+' "$LOG_FILE" || true) + + if [ -n "$SPECIFIED" ] && [ -n "$GOT" ]; then + { + echo "body<> "$GITHUB_OUTPUT" + else + TAIL=$(tail -n 80 "$LOG_FILE" | sed 's/^/ /') + { + echo "body<> "$GITHUB_OUTPUT" + fi + + - name: Post or update PR comment + if: steps.build.outputs.BUILD_FAILED == 'true' && github.event_name == 'pull_request' + uses: actions/github-script@v7 + env: + COMMENT_BODY: ${{ steps.error.outputs.body }} + with: + script: | + const marker = ''; + const body = marker + '\n' + process.env.COMMENT_BODY; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + const existing = comments.find(c => + c.user.login === 'github-actions[bot]' && c.body.includes(marker) + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body, + }); + } + + - name: Fail the job if build failed + if: steps.build.outputs.BUILD_FAILED == 'true' + run: exit 1 diff --git a/.github/workflows/pkg-pr-new.yml b/.github/workflows/pkg-pr-new.yml new file mode 100644 index 0000000000000000000000000000000000000000..86de76975a615770a1f5744f44b652a7a7bdcd9d --- /dev/null +++ b/.github/workflows/pkg-pr-new.yml @@ -0,0 +1,50 @@ +name: pkg.pr.new + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + publish: + name: Publish Kimi Code preview + runs-on: ubuntu-latest + if: github.repository_owner == 'MoonshotAI' && github.event.pull_request.draft == false + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build package dependencies + run: pnpm run build:packages + + - name: Generate Kimi Code built-in catalog + shell: bash + run: | + CATALOG_FILE="$RUNNER_TEMP/kimi-code-built-in-catalog.json" + node apps/kimi-code/scripts/update-catalog.mjs --out "$CATALOG_FILE" + echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV" + + - name: Build Kimi Code package + run: pnpm --filter @moonshot-ai/kimi-code run build + + - name: Publish pkg.pr.new preview + run: pnpm exec pkg-pr-new publish --bin --commentWithSha --packageManager=pnpm,npm --no-template './apps/kimi-code' diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml new file mode 100644 index 0000000000000000000000000000000000000000..00bfdf20fdef3f690d909314fc9b3f7b383e3fbc --- /dev/null +++ b/.github/workflows/pr-title-checker.yml @@ -0,0 +1,15 @@ +name: PR Title Checker + +on: + pull_request: + types: [opened, edited, labeled] + +jobs: + check: + runs-on: ubuntu-latest + name: pr-title-checker + steps: + - uses: thehanimo/pr-title-checker@v1.4.3 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + configuration_path: ".github/pr-title-checker-config.json" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000000000000000000000000000000000..7b96653ed32b7076c6901e81b54e27e74cd87874 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,130 @@ +name: Release + +on: + push: + branches: + - main + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + release: + name: Release + runs-on: ubuntu-latest + if: github.repository_owner == 'MoonshotAI' + outputs: + packages_published: ${{ steps.changesets.outputs.published }} + kimi_native_release: ${{ steps.kimi-release.outputs.should_publish }} + kimi_release_tag: ${{ steps.kimi-release.outputs.tag }} + permissions: + contents: write + pull-requests: write + id-token: write # Required for NPM Trusted Publishing (OIDC) + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: "pnpm" + registry-url: "https://registry.npmjs.org" + + - name: Upgrade npm for Trusted Publishing + run: npm install -g npm@11 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Generate Kimi Code built-in catalog + shell: bash + run: | + CATALOG_FILE="$RUNNER_TEMP/kimi-code-built-in-catalog.json" + node apps/kimi-code/scripts/update-catalog.mjs --out "$CATALOG_FILE" + echo "KIMI_CODE_BUILT_IN_CATALOG_FILE=$CATALOG_FILE" >> "$GITHUB_ENV" + + - name: Build packages + run: pnpm build + + - name: Create Release Pull Request or Publish to npm + id: changesets + uses: changesets/action@v1 + with: + publish: pnpm changeset publish + version: pnpm run version:release + commit: "ci: release packages" + title: "ci: release packages" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # NPM_TOKEN is not needed with Trusted Publishing (OIDC) + + - name: Resolve Kimi Code native release + if: steps.changesets.outputs.published == 'true' + id: kimi-release + run: node apps/kimi-code/scripts/native/resolve-release.mjs + env: + CHANGESETS_PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }} + + deploy-docs: + name: Deploy docs + needs: release + if: needs.release.outputs.packages_published == 'true' + uses: ./.github/workflows/docs-deploy.yml + permissions: + contents: read + pages: write + id-token: write + + native-artifacts: + name: Native release artifact + needs: release + if: needs.release.outputs.kimi_native_release == 'true' + uses: ./.github/workflows/_native-build.yml + with: + upload-artifact-prefix: kimi-code-native + retention-days: 7 + sign-macos: true + secrets: + APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} + APPLE_NOTARIZATION_KEY_P8: ${{ secrets.APPLE_NOTARIZATION_KEY_P8 }} + APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }} + APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }} + + publish-native-assets: + name: Publish native release assets + needs: + - release + - native-artifacts + if: needs.release.outputs.kimi_native_release == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Download native artifacts + uses: actions/download-artifact@v8 + with: + pattern: kimi-code-native-* + path: dist-native-release + merge-multiple: true + + - name: Produce manifest.json + env: + RELEASE_TAG: ${{ needs.release.outputs.kimi_release_tag }} + run: node apps/kimi-code/scripts/native/produce-manifest.mjs dist-native-release "$RELEASE_TAG" + + - name: Upload assets to GitHub Release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ needs.release.outputs.kimi_release_tag }} + run: gh release upload "$RELEASE_TAG" dist-native-release/* --clobber diff --git a/.github/workflows/vscode-publish.yml b/.github/workflows/vscode-publish.yml new file mode 100644 index 0000000000000000000000000000000000000000..23b12e12f856ea8be54e2279cf7dc688e9cad2f1 --- /dev/null +++ b/.github/workflows/vscode-publish.yml @@ -0,0 +1,177 @@ +name: Publish VS Code extension + +# 把 0.7.3 手动发版流程固化成 CI 流水线: +# +# pnpm install → package:platform(全 6 平台)→ package:verify +# → extension host 冒烟(xvfb)→ publish:vsix → publish:ovsx +# +# 触发语义(参照 kimi-code-app 仓 desktop release.yml 的判定方式): +# 只在"本次 push 改动了 apps/vscode/package.json 的 version"时发布, +# 即 changesets 版本 PR("ci: release packages")合入后自动触发; +# 普通 PR 合入不会改变版本号,不会发布。版本号比较以 push 事件的 +# before SHA 为基准(git show),可覆盖一次 push 含多个 commit 的情况, +# 不依赖工作区状态。workflow_dispatch 为手动兜底, +# 跳过版本号变化检查,直接走后续幂等闸门。 +# +# 幂等(两道保险,可安全重跑,失败即停不自动重试): +# 1. 发布前逐平台核验 VS Marketplace(vsce show)与 Open VSX(REST) +# 线上版本:6 个 targetPlatform(darwin/linux/win32 × x64/arm64) +# 全部在线才跳过对应发布步骤;任一平台缺失(如上次部分发布失败) +# 即放行给发布步骤补齐,重跑可补齐; +# 2. 发布脚本自身带 --skip-duplicate(vsce)/ already-exists 跳过(ovsx)。 +# +# 前置条件:仓库管理员需先配置 secrets VSCE_PAT / OVSX_PAT, +# 未配置时 publish 步骤会失败,属预期。 + +on: + push: + branches: + - main + workflow_dispatch: + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +permissions: + contents: read + +jobs: + publish: + name: Publish VSIX to marketplaces + runs-on: ubuntu-latest + if: github.repository_owner == 'MoonshotAI' + timeout-minutes: 90 + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 # 需要按 push 事件的 before SHA 取旧版本号比较 + + - name: Setup pnpm + uses: pnpm/action-setup@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Resolve publish gate + id: gate + shell: bash + env: + EVENT_NAME: ${{ github.event_name }} + BEFORE_SHA: ${{ github.event.before }} + run: | + set -euo pipefail + pkg="apps/vscode/package.json" + version="$(node -p "require('./${pkg}').version")" + echo "version=${version}" >> "$GITHUB_OUTPUT" + echo "extension version: ${version}" + + if [ "${EVENT_NAME}" = "workflow_dispatch" ]; then + echo "manual dispatch — skipping version-change check" + else + # 以 push 事件的 before SHA 为比较基准(覆盖多 commit 的单次 push)。 + # before 为空或全 0(如新分支首推)时无法比较,prev 视为空 → + # 判定版本变化放行 —— 宁可多查一次线上闸门,不可漏发。 + prev="" + if [ -n "${BEFORE_SHA}" ] && [ -n "${BEFORE_SHA//0/}" ]; then + if git show "${BEFORE_SHA}:${pkg}" > /tmp/prev-vscode-pkg.json 2> /dev/null; then + prev="$(node -p "require('/tmp/prev-vscode-pkg.json').version")" + fi + else + echo "push event has no usable before SHA ('${BEFORE_SHA}') — treating as a version change" + fi + if [ "${prev}" = "${version}" ]; then + echo "apps/vscode version unchanged in this push (${version}) — nothing to publish" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "version changed ${prev:-} -> ${version} — release push" + fi + echo "should_publish=true" >> "$GITHUB_OUTPUT" + + # 线上闸门:逐平台核验,6 个 targetPlatform 全部在线才跳过对应市场; + # 任一平台缺失即放行给 publish 步骤幂等补齐。 + # fail-closed:查询失败视为未发布 → 放行,交给 publish 步骤决定成败。 + platforms="darwin-x64 darwin-arm64 linux-x64 linux-arm64 win32-x64 win32-arm64" + + ovsx_missing="" + for target in ${platforms}; do + if ! curl -fsS -o /dev/null "https://open-vsx.org/api/moonshot-ai/kimi-code/${target}/${version}"; then + ovsx_missing="${ovsx_missing} ${target}" + fi + done + if [ -z "${ovsx_missing}" ]; then + echo "${version} is fully on Open VSX (all 6 platforms) — publish:ovsx will be skipped" + echo "ovsx_published=true" >> "$GITHUB_OUTPUT" + else + echo "Open VSX missing platform(s):${ovsx_missing} — publish:ovsx will run to backfill" + echo "ovsx_published=false" >> "$GITHUB_OUTPUT" + fi + + if pnpm --filter kimi-code exec vsce show moonshot-ai.kimi-code --json \ + | node -e "const v=process.argv[1];const want=process.argv[2].split(' ');let d='';process.stdin.on('data',c=>d+=c).on('end',()=>{const j=JSON.parse(d);const got=new Set((j.versions||[]).filter(x=>x.version===v).map(x=>x.targetPlatform||''));const missing=want.filter(p=>!got.has(p));if(missing.length){console.error('VS Marketplace missing platform(s): '+missing.join(' '));process.exit(1)}process.exit(0)})" "${version}" "${platforms}"; then + echo "${version} is fully on VS Marketplace (all 6 platforms) — publish:vsix will be skipped" + echo "vsix_published=true" >> "$GITHUB_OUTPUT" + else + echo "vsix_published=false" >> "$GITHUB_OUTPUT" + fi + + - name: Check publish secrets + if: steps.gate.outputs.should_publish == 'true' + shell: bash + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + OVSX_PAT: ${{ secrets.OVSX_PAT }} + run: | + set -euo pipefail + missing=() + [ -z "${VSCE_PAT:-}" ] && missing+=(VSCE_PAT) + [ -z "${OVSX_PAT:-}" ] && missing+=(OVSX_PAT) + if [ "${#missing[@]}" -gt 0 ]; then + echo "::error::missing repository secrets: ${missing[*]} — a repo admin must configure them before publishing" + exit 1 + fi + + - name: Package all platform VSIX + if: steps.gate.outputs.should_publish == 'true' + run: pnpm --filter kimi-code run package:platform + + - name: Verify VSIX packages + if: steps.gate.outputs.should_publish == 'true' + run: pnpm --filter kimi-code run package:verify + + - name: Upload VSIX artifacts + if: steps.gate.outputs.should_publish == 'true' + uses: actions/upload-artifact@v7 + with: + name: kimi-code-vsix-${{ steps.gate.outputs.version }} + path: apps/vscode/artifacts/vsix/*.vsix + retention-days: 14 + + - name: Install extension-host smoke dependencies + if: steps.gate.outputs.should_publish == 'true' + run: | + sudo apt-get update + sudo apt-get install -y xvfb libgtk-3-0 libgbm1 libasound2t64 + + - name: Extension host smoke test + if: steps.gate.outputs.should_publish == 'true' + # 1.100.0 即 package.json engines.vscode 下限,与 0.7.3 手动发版的冒烟口径一致 + run: xvfb-run -a pnpm --filter kimi-code run test:extension-host -- --version 1.100.0 + + - name: Publish to VS Marketplace + if: steps.gate.outputs.should_publish == 'true' && steps.gate.outputs.vsix_published != 'true' + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + run: pnpm --filter kimi-code run publish:vsix + + - name: Publish to Open VSX + if: steps.gate.outputs.should_publish == 'true' && steps.gate.outputs.ovsx_published != 'true' + env: + OVSX_PAT: ${{ secrets.OVSX_PAT }} + run: pnpm --filter kimi-code run publish:ovsx diff --git a/apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0acaaff03d4bb7606de02a827aeee338e5a86910 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9ff4a5e04421e5107f74c28e27354e0b2a4e7ef8 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4e98259c3b54076d684bf3459baeaeae8dbce97a Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..ab2ad21da6fbe6c171bb869240954d0ead8f68fd Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..5931794de4a2a485fa70099bf2659b145976d043 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-BMLOBm91.woff b/apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-BMLOBm91.woff new file mode 100644 index 0000000000000000000000000000000000000000..6f43b594b6c1d863a0e3f93b001f8dd503316464 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Main-Italic-BMLOBm91.woff differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dd45e1ed2e18b32c516d9b481ebed3cb8bffa711 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..29657023adc09956249f6295746c8ce4469b50d3 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf new file mode 100644 index 0000000000000000000000000000000000000000..70d559b4e937ca1b805eb39f544cbebe3c58ca6f Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-flOr_0UB.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..215c143fd7805a5c2b222bd7892a1a2b09610020 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Math-Italic-t53AETM-.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..cfaa3bda59246b49e94298478d6de3b3208066c8 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..349c06dc609f896392fd5bc8b364d3bc3efc9330 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf b/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d5850df98ec19de2eee9ff922ef59586efe471d0 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf new file mode 100644 index 0000000000000000000000000000000000000000..871fd7d19d8658f64d8696ed9cdfc82c821ed76d Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c5a8462fbfe2c39a7c1857b9e296e62500a8a8a5 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7a212caf91c0007e826fee2d622bf48acbd30dde Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff b/apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff new file mode 100644 index 0000000000000000000000000000000000000000..e6e9b658dcf1cd031ac82b6b8f312444c55d4fc0 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf new file mode 100644 index 0000000000000000000000000000000000000000..74f08921f00f71f413ca42c9d1c90202e672ef38 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Size4-Regular-DWFBv043.ttf differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff b/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff new file mode 100644 index 0000000000000000000000000000000000000000..2432419f28936aff53ddfa2a732d027e6a6648fd Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 b/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..771f1af705f5cef5f578b3a1e7d8eff66f9b76b0 Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf b/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c83252c5714c71a3e0ec62195884167339a0129b Binary files /dev/null and b/apps/kimi-code/dist-web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf differ diff --git a/apps/kimi-code/dist-web/assets/andromeeda-C4gqWexZ.js b/apps/kimi-code/dist-web/assets/andromeeda-C4gqWexZ.js new file mode 100644 index 0000000000000000000000000000000000000000..2b65c9b4c3678580dec894ed31b96389b7e29477 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/andromeeda-C4gqWexZ.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"colors":{"activityBar.background":"#23262E","activityBar.dropBackground":"#3a404e","activityBar.foreground":"#BAAFC0","activityBarBadge.background":"#00b0ff","activityBarBadge.foreground":"#20232B","badge.background":"#00b0ff","badge.foreground":"#20232B","button.background":"#00e8c5cc","button.hoverBackground":"#07d4b6cc","debugExceptionWidget.background":"#FF9F2E60","debugExceptionWidget.border":"#FF9F2E60","debugToolBar.background":"#20232A","diffEditor.insertedTextBackground":"#29BF1220","diffEditor.removedTextBackground":"#F21B3F20","dropdown.background":"#2b303b","dropdown.border":"#363c49","editor.background":"#23262E","editor.findMatchBackground":"#f39d1256","editor.findMatchBorder":"#f39d12b6","editor.findMatchHighlightBackground":"#59b8b377","editor.foreground":"#D5CED9","editor.hoverHighlightBackground":"#373941","editor.lineHighlightBackground":"#2e323d","editor.lineHighlightBorder":"#2e323d","editor.rangeHighlightBackground":"#372F3C","editor.selectionBackground":"#3D4352","editor.selectionHighlightBackground":"#4F435580","editor.wordHighlightBackground":"#4F4355","editor.wordHighlightStrongBackground":"#db45a280","editorBracketMatch.background":"#746f77","editorBracketMatch.border":"#746f77","editorCodeLens.foreground":"#746f77","editorCursor.foreground":"#FFF","editorError.foreground":"#FC644D","editorGroup.background":"#23262E","editorGroup.dropBackground":"#495061d7","editorGroupHeader.tabsBackground":"#23262E","editorGutter.addedBackground":"#9BC53DBB","editorGutter.deletedBackground":"#FC644DBB","editorGutter.modifiedBackground":"#5BC0EBBB","editorHoverWidget.background":"#373941","editorHoverWidget.border":"#00e8c5cc","editorIndentGuide.activeBackground":"#585C66","editorIndentGuide.background":"#333844","editorLineNumber.foreground":"#746f77","editorLink.activeForeground":"#3B79C7","editorOverviewRuler.border":"#1B1D23","editorRuler.foreground":"#4F4355","editorSuggestWidget.background":"#20232A","editorSuggestWidget.border":"#372F3C","editorSuggestWidget.selectedBackground":"#373941","editorWarning.foreground":"#FF9F2E","editorWhitespace.foreground":"#333844","editorWidget.background":"#20232A","errorForeground":"#FC644D","extensionButton.prominentBackground":"#07d4b6cc","extensionButton.prominentHoverBackground":"#07d4b5b0","focusBorder":"#746f77","foreground":"#D5CED9","gitDecoration.ignoredResourceForeground":"#555555","input.background":"#2b303b","input.placeholderForeground":"#746f77","inputOption.activeBorder":"#C668BA","inputValidation.errorBackground":"#D65343","inputValidation.errorBorder":"#D65343","inputValidation.infoBackground":"#3A6395","inputValidation.infoBorder":"#3A6395","inputValidation.warningBackground":"#DE9237","inputValidation.warningBorder":"#DE9237","list.activeSelectionBackground":"#23262E","list.activeSelectionForeground":"#00e8c6","list.dropBackground":"#3a404e","list.focusBackground":"#282b35","list.focusForeground":"#eee","list.hoverBackground":"#23262E","list.hoverForeground":"#eee","list.inactiveSelectionBackground":"#23262E","list.inactiveSelectionForeground":"#00e8c6","merge.currentContentBackground":"#F9267240","merge.currentHeaderBackground":"#F92672","merge.incomingContentBackground":"#3B79C740","merge.incomingHeaderBackground":"#3B79C7BB","minimapSlider.activeBackground":"#60698060","minimapSlider.background":"#58607460","minimapSlider.hoverBackground":"#60698060","notification.background":"#2d313b","notification.buttonBackground":"#00e8c5cc","notification.buttonHoverBackground":"#07d4b5b0","notification.errorBackground":"#FC644D","notification.infoBackground":"#00b0ff","notification.warningBackground":"#FF9F2E","panel.background":"#23262E","panel.border":"#1B1D23","panelTitle.activeBorder":"#23262E","panelTitle.inactiveForeground":"#746f77","peekView.border":"#23262E","peekViewEditor.background":"#1A1C22","peekViewEditor.matchHighlightBackground":"#FF9F2E60","peekViewResult.background":"#1A1C22","peekViewResult.matchHighlightBackground":"#FF9F2E60","peekViewResult.selectionBackground":"#23262E","peekViewTitle.background":"#1A1C22","peekViewTitleDescription.foreground":"#746f77","pickerGroup.border":"#4F4355","pickerGroup.foreground":"#746f77","progressBar.background":"#C668BA","scrollbar.shadow":"#23262E","scrollbarSlider.activeBackground":"#3A3F4CCC","scrollbarSlider.background":"#3A3F4C77","scrollbarSlider.hoverBackground":"#3A3F4CAA","selection.background":"#746f77","sideBar.background":"#23262E","sideBar.foreground":"#999999","sideBarSectionHeader.background":"#23262E","sideBarTitle.foreground":"#00e8c6","statusBar.background":"#23262E","statusBar.debuggingBackground":"#FC644D","statusBar.noFolderBackground":"#23262E","statusBarItem.activeBackground":"#00e8c5cc","statusBarItem.hoverBackground":"#07d4b5b0","statusBarItem.prominentBackground":"#07d4b5b0","statusBarItem.prominentHoverBackground":"#00e8c5cc","tab.activeBackground":"#23262e","tab.activeBorder":"#00e8c6","tab.activeForeground":"#00e8c6","tab.inactiveBackground":"#23262E","tab.inactiveForeground":"#746f77","terminal.ansiBlue":"#7cb7ff","terminal.ansiBrightBlue":"#7cb7ff","terminal.ansiBrightCyan":"#00e8c6","terminal.ansiBrightGreen":"#96E072","terminal.ansiBrightMagenta":"#ff00aa","terminal.ansiBrightRed":"#ee5d43","terminal.ansiBrightYellow":"#FFE66D","terminal.ansiCyan":"#00e8c6","terminal.ansiGreen":"#96E072","terminal.ansiMagenta":"#ff00aa","terminal.ansiRed":"#ee5d43","terminal.ansiYellow":"#FFE66D","terminalCursor.background":"#23262E","terminalCursor.foreground":"#FFE66D","titleBar.activeBackground":"#23262E","walkThrough.embeddedEditorBackground":"#23262E","widget.shadow":"#14151A"},"displayName":"Andromeeda","name":"andromeeda","semanticTokenColors":{"property.declaration:javascript":"#D5CED9","variable.defaultLibrary:javascript":"#f39c12"},"tokenColors":[{"settings":{"background":"#23262E","foreground":"#D5CED9"}},{"scope":["comment","markup.quote.markdown","meta.diff","meta.diff.header"],"settings":{"foreground":"#A0A1A7cc"}},{"scope":["meta.template.expression.js","constant.name.attribute.tag.jade","punctuation.definition.metadata.markdown","punctuation.definition.string.end.markdown","punctuation.definition.string.begin.markdown","string.unquoted.cmake"],"settings":{"foreground":"#D5CED9"}},{"scope":["variable","support.variable","entity.name.tag.yaml","constant.character.entity.html","source.css entity.name.tag.reference","beginning.punctuation.definition.list.markdown","source.css entity.other.attribute-name.parent-selector","meta.structure.dictionary.json support.type.property-name"],"settings":{"foreground":"#00e8c6"}},{"scope":["markup.bold","constant.numeric","meta.group.regexp","constant.other.php","support.constant.ext.php","constant.other.class.php","support.constant.core.php","fenced_code.block.language","constant.other.caps.python","entity.other.attribute-name","support.type.exception.python","source.css keyword.other.unit","variable.other.object.property.js.jsx","variable.other.object.js"],"settings":{"foreground":"#f39c12"}},{"scope":["markup.list","text.xml string","entity.name.type","support.function","entity.other.attribute-name","meta.at-rule.extend","entity.name.function","entity.other.inherited-class","entity.other.keyframe-offset.css","text.html.markdown string.quoted","meta.function-call.generic.python","meta.at-rule.extend support.constant","entity.other.attribute-name.class.jade","source.css entity.other.attribute-name","text.xml punctuation.definition.string"],"settings":{"foreground":"#FFE66D"}},{"scope":["markup.heading","variable.language.this.js","variable.language.special.self.python"],"settings":{"foreground":"#ff00aa"}},{"scope":["punctuation.definition.interpolation","punctuation.section.embedded.end.php","punctuation.section.embedded.end.ruby","punctuation.section.embedded.begin.php","punctuation.section.embedded.begin.ruby","punctuation.definition.template-expression","entity.name.tag"],"settings":{"foreground":"#f92672"}},{"scope":["storage","keyword","meta.link","meta.image","markup.italic","source.js support.type","support.type"],"settings":{"foreground":"#c74ded"}},{"scope":["string.regexp","markup.changed"],"settings":{"foreground":"#7cb7ff"}},{"scope":["constant","support.class","keyword.operator","support.constant","text.html.markdown string","source.css support.function","source.php support.function","support.function.magic.python","entity.other.attribute-name.id","markup.deleted"],"settings":{"foreground":"#ee5d43"}},{"scope":["string","text.html.php string","markup.inline.raw","markup.inserted","punctuation.definition.string","punctuation.definition.markdown","text.html meta.embedded source.js string","text.html.php punctuation.definition.string","text.html meta.embedded source.js punctuation.definition.string","text.html punctuation.definition.string","text.html string"],"settings":{"foreground":"#96E072"}},{"scope":["entity.other.inherited-class"],"settings":{"fontStyle":"underline"}}],"type":"dark"}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/angular-html-DA-rfuFy.js b/apps/kimi-code/dist-web/assets/angular-html-DA-rfuFy.js new file mode 100644 index 0000000000000000000000000000000000000000..dea2101413f59b8c92b070ee4f37f29588342f6a --- /dev/null +++ b/apps/kimi-code/dist-web/assets/angular-html-DA-rfuFy.js @@ -0,0 +1 @@ +import n from"./html-pp8916En.js";const a=Object.freeze(JSON.parse('{"injectionSelector":"L:text.html -comment","name":"angular-expression","patterns":[{"include":"#ngExpression"}],"repository":{"arrayLiteral":{"begin":"\\\\[","beginCaptures":{"0":{"name":"meta.brace.square.ts"}},"end":"]","endCaptures":{"0":{"name":"meta.brace.square.ts"}},"name":"meta.array.literal.ts","patterns":[{"include":"#ngExpression"},{"include":"#punctuationComma"}]},"booleanLiteral":{"patterns":[{"match":"(?>>??|\\\\|)=","name":"keyword.operator.assignment.compound.bitwise.ts"},{"match":"<<|>>>?","name":"keyword.operator.bitwise.shift.ts"},{"match":"[!=]==?","name":"keyword.operator.comparison.ts"},{"match":"<=|>=|<>|[<>]","name":"keyword.operator.relational.ts"},{"match":"!|&&|\\\\?\\\\?|\\\\|\\\\|","name":"keyword.operator.logical.ts"},{"match":"[\\\\&^|~]","name":"keyword.operator.bitwise.ts"},{"match":"=","name":"keyword.operator.assignment.ts"},{"match":"--","name":"keyword.operator.decrement.ts"},{"match":"\\\\+\\\\+","name":"keyword.operator.increment.ts"},{"match":"[-%*+/]","name":"keyword.operator.arithmetic.ts"},{"captures":{"1":{"name":"keyword.operator.arithmetic.ts"}},"match":"(?<=[$_[:alnum:]])\\\\s*(/)(?![*/])"},{"include":"#typeofOperator"}]},"functionCall":{"begin":"(?=(\\\\??\\\\.\\\\s*)?([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\()","end":"(?<=\\\\))(?!(\\\\??\\\\.\\\\s*)?([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\()","patterns":[{"match":"\\\\?","name":"punctuation.accessor.ts"},{"match":"\\\\.","name":"punctuation.accessor.ts"},{"match":"([$_[:alpha:]][$_[:alnum:]]*)","name":"entity.name.function.ts"},{"begin":"<","beginCaptures":{"0":{"name":"punctuation.definition.typeparameters.begin.ts"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.typeparameters.end.ts"}},"name":"meta.type.parameters.ts","patterns":[{"include":"#type"},{"include":"#punctuationComma"}]},{"include":"#parenExpression"}]},"functionParameters":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.parameters.begin.ts"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.parameters.end.ts"}},"name":"meta.parameters.ts","patterns":[{"include":"#decorator"},{"include":"#parameterName"},{"include":"#variableInitializer"},{"match":",","name":"punctuation.separator.parameter.ts"}]},"identifiers":{"patterns":[{"match":"([$_[:alpha:]][$_[:alnum:]]*)(?=\\\\s*\\\\.\\\\s*prototype\\\\b(?!\\\\$))","name":"support.class.ts"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"constant.other.object.property.ts"},"3":{"name":"variable.other.object.property.ts"}},"match":"([!?]?\\\\.)\\\\s*(?:(\\\\p{upper}[$_\\\\d[:upper:]]*)|([$_[:alpha:]][$_[:alnum:]]*))(?=\\\\s*\\\\.\\\\s*[$_[:alpha:]][$_[:alnum:]]*)"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"entity.name.function.ts"}},"match":"(?:([!?]?\\\\.)\\\\s*)?([$_[:alpha:]][$_[:alnum:]]*)(?=\\\\s*=\\\\s*((async\\\\s+)|(function\\\\s*[(<])|(function\\\\s+)|([$_[:alpha:]][$_[:alnum:]]*\\\\s*=>)|((<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)(\\\\s*:\\\\s*(.)*)?\\\\s*=>)))"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"constant.other.property.ts"}},"match":"([!?]?\\\\.)\\\\s*(\\\\p{upper}[$_\\\\d[:upper:]]*)(?![$_[:alnum:]])"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"variable.other.property.ts"}},"match":"([!?]?\\\\.)\\\\s*([$_[:alpha:]][$_[:alnum:]]*)"},{"captures":{"1":{"name":"constant.other.object.ts"},"2":{"name":"variable.other.object.ts"}},"match":"(?:(\\\\p{upper}[$_\\\\d[:upper:]]*)|([$_[:alpha:]][$_[:alnum:]]*))(?=\\\\s*\\\\.\\\\s*[$_[:alpha:]][$_[:alnum:]]*)"},{"match":"(\\\\p{upper}[$_\\\\d[:upper:]]*)(?![$_[:alnum:]])","name":"constant.character.other"},{"match":"[$_[:alpha:]][$_[:alnum:]]*","name":"variable.other.readwrite.ts"}]},"literal":{"name":"literal.ts","patterns":[{"include":"#numericLiteral"},{"include":"#booleanLiteral"},{"include":"#nullLiteral"},{"include":"#undefinedLiteral"},{"include":"#numericConstantLiteral"},{"include":"#arrayLiteral"},{"include":"#thisLiteral"}]},"ngExpression":{"name":"meta.expression.ng","patterns":[{"include":"#string"},{"include":"#literal"},{"include":"#ternaryExpression"},{"include":"#expressionOperator"},{"include":"#functionCall"},{"include":"#identifiers"},{"include":"#parenExpression"},{"include":"#punctuationComma"},{"include":"#punctuationSemicolon"},{"include":"#punctuationAccessor"}]},"nullLiteral":{"match":"(?)|((<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)(\\\\s*:\\\\s*(.)*)?\\\\s*=>)))|(:\\\\s*((<)|(\\\\(\\\\s*((\\\\))|(\\\\.\\\\.\\\\.)|([$_[:alnum:]]+\\\\s*(([,:=?])|(\\\\)\\\\s*=>))))))))"},{"captures":{"1":{"name":"storage.modifier.ts"},"2":{"name":"storage.modifier.ts"},"3":{"name":"keyword.operator.rest.ts"},"4":{"name":"variable.parameter.ts"},"5":{"name":"keyword.operator.optional.ts"}},"match":"(?:\\\\s*\\\\b(readonly)\\\\s+)?(?:\\\\s*\\\\b(p(?:ublic|rivate|rotected))\\\\s+)?(\\\\.\\\\.\\\\.)?\\\\s*(?\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))(([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>)*(?))*(?)*(?\\\\s*)?`)","end":"(?=`)","patterns":[{"begin":"(?=(([$_[:alpha:]][$_[:alnum:]]*\\\\s*\\\\??\\\\.\\\\s*)*|(\\\\??\\\\.\\\\s*)?)([$_[:alpha:]][$_[:alnum:]]*))","end":"(?=(<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))(([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>)*(?))*(?)*(?\\\\s*)?`)","patterns":[{"include":"#support-function-call-identifiers"},{"match":"([$_[:alpha:]][$_[:alnum:]]*)","name":"entity.name.function.tagged-template.ts"}]},{"include":"#typeArguments"}]},{"begin":"([$_[:alpha:]][$_[:alnum:]]*)?\\\\s*(?=(<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))(([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>)*(?))*(?)*(?\\\\s*)`)","beginCaptures":{"1":{"name":"entity.name.function.tagged-template.ts"}},"end":"(?=`)","patterns":[{"include":"#typeArguments"}]}]},"templateLiteralSubstitutionElement":{"begin":"\\\\$\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.template-expression.begin.ts"}},"contentName":"meta.embedded.line.ts","end":"}","endCaptures":{"0":{"name":"punctuation.definition.template-expression.end.ts"}},"name":"meta.template.expression.ts","patterns":[{"include":"#ngExpression"}]},"ternaryExpression":{"begin":"(?!\\\\?\\\\.\\\\s*\\\\D)(\\\\?)(?!\\\\?)","beginCaptures":{"1":{"name":"keyword.operator.ternary.ts"}},"end":"\\\\s*(:)","endCaptures":{"1":{"name":"keyword.operator.ternary.ts"}},"patterns":[{"include":"#ngExpression"}]},"thisLiteral":{"match":"(?])|(?<=[]$)>_}[:alpha:]])\\\\s*(?=\\\\{)","name":"meta.type.annotation.ts","patterns":[{"include":"#type"}]},"typeArguments":{"begin":"<","beginCaptures":{"0":{"name":"punctuation.definition.typeparameters.begin.ts"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.typeparameters.end.ts"}},"name":"meta.type.parameters.ts","patterns":[{"include":"#typeArgumentsBody"}]},"typeArgumentsBody":{"patterns":[{"captures":{"0":{"name":"keyword.operator.type.ts"}},"match":"(?)\\\\s*(?=\\\\()","end":"(?<=\\\\))","include":"#typeofOperator","name":"meta.type.function.ts","patterns":[{"include":"#functionParameters"}]},{"begin":"((?=\\\\(\\\\s*((\\\\))|(\\\\.\\\\.\\\\.)|([$_[:alnum:]]+\\\\s*(([,:=?])|(\\\\)\\\\s*=>))))))","end":"(?<=\\\\))","name":"meta.type.function.ts","patterns":[{"include":"#functionParameters"}]}]},"typeName":{"patterns":[{"captures":{"1":{"name":"entity.name.type.module.ts"},"2":{"name":"punctuation.accessor.ts"}},"match":"([$_[:alpha:]][$_[:alnum:]]*)\\\\s*([!?]?\\\\.)"},{"match":"[$_[:alpha:]][$_[:alnum:]]*","name":"entity.name.type.ts"}]},"typeObject":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"name":"meta.object.type.ts","patterns":[{"include":"#typeObjectMembers"}]},"typeObjectMembers":{"patterns":[{"include":"#typeAnnotation"},{"include":"#punctuationComma"},{"include":"#punctuationSemicolon"}]},"typeOperators":{"patterns":[{"include":"#typeofOperator"},{"match":"[\\\\&|]","name":"keyword.operator.type.ts"},{"match":"(?\\\\s]*)(?)","endCaptures":{"1":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.unrecognized.html.derivative","patterns":[{"include":"text.html.basic#attribute"}]}],"scopeName":"text.html.derivative.ng","embeddedLangs":["html","angular-expression","angular-let-declaration","angular-template","angular-template-blocks"]}')),l=[...n,...e,...r,...t,...m,p],u=Object.freeze(Object.defineProperty({__proto__:null,default:l},Symbol.toStringTag,{value:"Module"}));export{l as a,t as b,e as c,r as d,m as e,u as f}; diff --git a/apps/kimi-code/dist-web/assets/applescript-Co6uUVPk.js b/apps/kimi-code/dist-web/assets/applescript-Co6uUVPk.js new file mode 100644 index 0000000000000000000000000000000000000000..38bcb1a23de7555cebe78603ac22d3b748b631a8 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/applescript-Co6uUVPk.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"AppleScript","fileTypes":["applescript","scpt","script editor"],"firstLineMatch":"^#!.*(osascript)","name":"applescript","patterns":[{"include":"#blocks"},{"include":"#inline"}],"repository":{"attributes.considering-ignoring":{"patterns":[{"match":",","name":"punctuation.separator.array.attributes.applescript"},{"match":"\\\\b(and)\\\\b","name":"keyword.control.attributes.and.applescript"},{"match":"\\\\b(?i:case|diacriticals|hyphens|numeric\\\\s+strings|punctuation|white\\\\s+space)\\\\b","name":"constant.other.attributes.text.applescript"},{"match":"\\\\b(?i:application\\\\s+responses)\\\\b","name":"constant.other.attributes.application.applescript"}]},"blocks":{"patterns":[{"begin":"^\\\\s*(script)\\\\s+(\\\\w+)","beginCaptures":{"1":{"name":"keyword.control.script.applescript"},"2":{"name":"entity.name.type.script-object.applescript"}},"end":"^\\\\s*(end(?:\\\\s+script)?)(?=\\\\s*(--.*?)?$)","endCaptures":{"1":{"name":"keyword.control.script.applescript"}},"name":"meta.block.script.applescript","patterns":[{"include":"$self"}]},{"begin":"^\\\\s*(to|on)\\\\s+(\\\\w+)(\\\\()((?:[,:{}\\\\s]*\\\\w+{0,1})*)(\\\\))","beginCaptures":{"1":{"name":"keyword.control.function.applescript"},"2":{"name":"entity.name.function.handler.applescript"},"3":{"name":"punctuation.definition.parameters.begin.applescript"},"4":{"name":"variable.parameter.handler.applescript"},"5":{"name":"punctuation.definition.parameters.end.applescript"}},"end":"^\\\\s*(end)(?:\\\\s+(\\\\2))?(?=\\\\s*(--.*?)?$)","endCaptures":{"1":{"name":"keyword.control.function.applescript"}},"name":"meta.function.positional.applescript","patterns":[{"include":"$self"}]},{"begin":"^\\\\s*(to|on)\\\\s+(\\\\w+)(?:\\\\s+(of|in)\\\\s+(\\\\w+))?(?=\\\\s+(above|against|apart\\\\s+from|around|aside\\\\s+from|at|below|beneath|beside|between|by|for|from|instead\\\\s+of|into|on|onto|out\\\\s+of|over|thru|under)\\\\b)","beginCaptures":{"1":{"name":"keyword.control.function.applescript"},"2":{"name":"entity.name.function.handler.applescript"},"3":{"name":"keyword.control.function.applescript"},"4":{"name":"variable.parameter.handler.direct.applescript"}},"end":"^\\\\s*(end)(?:\\\\s+(\\\\2))?(?=\\\\s*(--.*?)?$)","endCaptures":{"1":{"name":"keyword.control.function.applescript"}},"name":"meta.function.prepositional.applescript","patterns":[{"captures":{"1":{"name":"keyword.control.preposition.applescript"},"2":{"name":"variable.parameter.handler.applescript"}},"match":"\\\\b(?i:above|against|apart\\\\s+from|around|aside\\\\s+from|at|below|beneath|beside|between|by|for|from|instead\\\\s+of|into|on|onto|out\\\\s+of|over|thru|under)\\\\s+(\\\\w+)\\\\b"},{"include":"$self"}]},{"begin":"^\\\\s*(to|on)\\\\s+(\\\\w+)(?=\\\\s*(--.*?)?$)","beginCaptures":{"1":{"name":"keyword.control.function.applescript"},"2":{"name":"entity.name.function.handler.applescript"}},"end":"^\\\\s*(end)(?:\\\\s+(\\\\2))?(?=\\\\s*(--.*?)?$)","endCaptures":{"1":{"name":"keyword.control.function.applescript"}},"name":"meta.function.parameterless.applescript","patterns":[{"include":"$self"}]},{"include":"#blocks.tell"},{"include":"#blocks.repeat"},{"include":"#blocks.statement"},{"include":"#blocks.other"}]},"blocks.other":{"patterns":[{"begin":"^\\\\s*(considering)\\\\b","end":"^\\\\s*(end(?:\\\\s+considering)?)(?=\\\\s*(--.*?)?$)","name":"meta.block.considering.applescript","patterns":[{"begin":"(?<=considering)","end":"(?≠≥]|>=|≤|<=)","name":"keyword.operator.comparison.applescript"},{"match":"(?i)\\\\b(and|or|div|mod|as|not|(a\\\\s+)?(ref(?:(\\\\s+to)?|erence\\\\s+to))|equal(s|\\\\s+to)|contains?|comes\\\\s+(after|before)|(start|begin|end)s?\\\\s+with)\\\\b","name":"keyword.operator.word.applescript"},{"match":"(?i)\\\\b(is(n't|\\\\s+not)?(\\\\s+(equal(\\\\s+to)?|(less|greater)\\\\s+than(\\\\s+or\\\\s+equal(\\\\s+to)?)?|in|contained\\\\s+by))?|does(n't|\\\\s+not)\\\\s+(equal|come\\\\s+(before|after)|contain))\\\\b","name":"keyword.operator.word.applescript"},{"match":"\\\\b(?i:some|every|whose|where|that|id|index|\\\\d+(st|nd|rd|th)|first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|last|front|back|middle|named|beginning|end|from|to|thr(u|ough)|before|(front|back|beginning|end)\\\\s+of|after|behind|in\\\\s+(front|back|beginning|end)\\\\s+of)\\\\b","name":"keyword.operator.reference.applescript"},{"match":"\\\\b(?i:continue|return|exit(\\\\s+repeat)?)\\\\b","name":"keyword.control.loop.applescript"},{"match":"\\\\b(?i:about|above|after|against|and|apart\\\\s+from|around|as|aside\\\\s+from|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|contains??|contains|copy|div|does|eighth|else|end|equals??|error|every|false|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|instead\\\\s+of|into|is|its??|last|local|me|middle|mod|my|ninth|not|of|on|onto|or|out\\\\s+of|over|prop|property|put|ref|reference|repeat|returning|script|second|set|seventh|since|sixth|some|tell|tenth|that|then??|third|through|thru|timeout|times|to|transaction|true|try|until|where|while|whose|with|without)\\\\b","name":"keyword.other.applescript"}]},"built-in.punctuation":{"patterns":[{"match":"¬","name":"punctuation.separator.continuation.line.applescript"},{"match":":","name":"punctuation.separator.key-value.property.applescript"},{"match":"[()]","name":"punctuation.section.group.applescript"}]},"built-in.support":{"patterns":[{"match":"\\\\b(?i:POSIX\\\\s+path|frontmost|id|name|running|version|days?|weekdays?|months?|years?|time|date\\\\s+string|time\\\\s+string|length|rest|reverse|items?|contents|quoted\\\\s+form|characters?|paragraphs?|words?)\\\\b","name":"support.function.built-in.property.applescript"},{"match":"\\\\b(?i:activate|log|clipboard\\\\s+info|set\\\\s+the\\\\s+clipboard\\\\s+to|the\\\\s+clipboard|info\\\\s+for|list\\\\s+(disks|folder)|mount\\\\s+volume|path\\\\s+to(\\\\s+resource)?|close\\\\s+access|get\\\\s+eof|open\\\\s+for\\\\s+access|read|set\\\\s+eof|write|open\\\\s+location|current\\\\s+date|do\\\\s+shell\\\\s+script|get\\\\s+volume\\\\s+settings|random\\\\s+number|round|set\\\\s+volume|system\\\\s+(attribute|info)|time\\\\s+to\\\\s+GMT|load\\\\s+script|run\\\\s+script|scripting\\\\s+components|store\\\\s+script|copy|count|get|launch|run|set|ASCII\\\\s+(character|number)|localized\\\\s+string|offset|summarize|beep|choose\\\\s+(application|color|file(\\\\s+name)?|folder|from\\\\s+list|remote\\\\s+application|URL)|delay|display\\\\s+(alert|dialog)|say)\\\\b","name":"support.function.built-in.command.applescript"},{"match":"\\\\b(?i:get|run)\\\\b","name":"support.function.built-in.applescript"},{"match":"\\\\b(?i:anything|data|text|upper\\\\s+case|propert(y|ies))\\\\b","name":"support.class.built-in.applescript"},{"match":"\\\\b(?i:alias|class)(es)?\\\\b","name":"support.class.built-in.applescript"},{"match":"\\\\b(?i:app(lication)?|boolean|character|constant|date|event|file(\\\\s+specification)?|handler|integer|item|keystroke|linked\\\\s+list|list|machine|number|picture|preposition|POSIX\\\\s+file|real|record|reference(\\\\s+form)?|RGB\\\\s+color|script|sound|text\\\\s+item|type\\\\s+class|vector|writing\\\\s+code(\\\\s+info)?|zone|((international|styled(\\\\s+(Clipboard|Unicode))?|Unicode)\\\\s+)?text|((C|encoded|Pascal)\\\\s+)?string)s?\\\\b","name":"support.class.built-in.applescript"},{"match":"(?i)\\\\b((cubic\\\\s+(centi)?|square\\\\s+(kilo)?|centi|kilo)met(er|re)s|square\\\\s+(yards|feet|miles)|cubic\\\\s+(yards|feet|inches)|miles|inches|lit(re|er)s|gallons|quarts|(kilo)?grams|ounces|pounds|degrees\\\\s+(Celsius|Fahrenheit|Kelvin))\\\\b","name":"support.class.built-in.unit.applescript"},{"match":"\\\\b(?i:seconds|minutes|hours|days)\\\\b","name":"support.class.built-in.time.applescript"}]},"comments":{"patterns":[{"begin":"^\\\\s*(#!)","captures":{"1":{"name":"punctuation.definition.comment.applescript"}},"end":"\\\\n","name":"comment.line.number-sign.applescript"},{"begin":"(^[\\\\t ]+)?(?=#)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.applescript"}},"end":"(?!\\\\G)","patterns":[{"begin":"#","beginCaptures":{"0":{"name":"punctuation.definition.comment.applescript"}},"end":"\\\\n","name":"comment.line.number-sign.applescript"}]},{"begin":"(^[\\\\t ]+)?(?=--)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.applescript"}},"end":"(?!\\\\G)","patterns":[{"begin":"--","beginCaptures":{"0":{"name":"punctuation.definition.comment.applescript"}},"end":"\\\\n","name":"comment.line.double-dash.applescript"}]},{"begin":"\\\\(\\\\*","captures":{"0":{"name":"punctuation.definition.comment.applescript"}},"end":"\\\\*\\\\)","name":"comment.block.applescript","patterns":[{"include":"#comments.nested"}]}]},"comments.nested":{"patterns":[{"begin":"\\\\(\\\\*","beginCaptures":{"0":{"name":"punctuation.definition.comment.begin.applescript"}},"end":"\\\\*\\\\)","endCaptures":{"0":{"name":"punctuation.definition.comment.end.applescript"}},"name":"comment.block.applescript","patterns":[{"include":"#comments.nested"}]}]},"data-structures":{"patterns":[{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.array.begin.applescript"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.array.end.applescript"}},"name":"meta.array.applescript","patterns":[{"captures":{"1":{"name":"constant.other.key.applescript"},"2":{"name":"meta.identifier.applescript"},"3":{"name":"punctuation.definition.identifier.applescript"},"4":{"name":"punctuation.definition.identifier.applescript"},"5":{"name":"punctuation.separator.key-value.applescript"}},"match":"(\\\\w+|((\\\\|)[^\\\\n|]*(\\\\|)))\\\\s*(:)"},{"match":":","name":"punctuation.separator.key-value.applescript"},{"match":",","name":"punctuation.separator.array.applescript"},{"include":"#inline"}]},{"begin":"(?:(?<=application )|(?<=app ))(\\")","captures":{"1":{"name":"punctuation.definition.string.applescript"}},"end":"(\\")","name":"string.quoted.double.application-name.applescript","patterns":[{"match":"\\\\\\\\.","name":"constant.character.escape.applescript"}]},{"begin":"(\\")","captures":{"1":{"name":"punctuation.definition.string.applescript"}},"end":"(\\")","name":"string.quoted.double.applescript","patterns":[{"match":"\\\\\\\\.","name":"constant.character.escape.applescript"}]},{"captures":{"1":{"name":"punctuation.definition.identifier.applescript"},"2":{"name":"punctuation.definition.identifier.applescript"}},"match":"(\\\\|)[^\\\\n|]*(\\\\|)","name":"meta.identifier.applescript"},{"captures":{"1":{"name":"punctuation.definition.data.applescript"},"2":{"name":"support.class.built-in.applescript"},"3":{"name":"storage.type.utxt.applescript"},"4":{"name":"string.unquoted.data.applescript"},"5":{"name":"punctuation.definition.data.applescript"},"6":{"name":"keyword.operator.applescript"},"7":{"name":"support.class.built-in.applescript"}},"match":"(«)(data) (ut(?:xt|f8))(\\\\h*)(»)(?:\\\\s+(as)\\\\s+(?i:Unicode\\\\s+text))?","name":"constant.other.data.utxt.applescript"},{"begin":"(«)(\\\\w+)\\\\b(?=\\\\s)","beginCaptures":{"1":{"name":"punctuation.definition.data.applescript"},"2":{"name":"support.class.built-in.applescript"}},"end":"(»)","endCaptures":{"1":{"name":"punctuation.definition.data.applescript"}},"name":"constant.other.data.raw.applescript"},{"captures":{"1":{"name":"punctuation.definition.data.applescript"},"2":{"name":"punctuation.definition.data.applescript"}},"match":"(«)[^»]*(»)","name":"invalid.illegal.data.applescript"}]},"finder":{"patterns":[{"match":"\\\\b(item|container|(computer|disk|trash)-object|disk|folder|((alias|application|document|internet location) )?file|clipping|package)s?\\\\b","name":"support.class.finder.items.applescript"},{"match":"\\\\b((Finder|desktop|information|preferences|clipping) )windows?\\\\b","name":"support.class.finder.window-classes.applescript"},{"match":"\\\\b(preferences|(icon|column|list) view options|(label|column|alias list)s?)\\\\b","name":"support.class.finder.type-definitions.applescript"},{"match":"\\\\b(copy|find|sort|clean up|eject|empty( trash)|erase|reveal|update)\\\\b","name":"support.function.finder.items.applescript"},{"match":"\\\\b(insertion location|product version|startup disk|desktop|trash|home|computer container|finder preferences)\\\\b","name":"support.constant.finder.applescript"},{"match":"\\\\b(visible)\\\\b","name":"support.variable.finder.applescript"}]},"inline":{"patterns":[{"include":"#comments"},{"include":"#data-structures"},{"include":"#built-in"},{"include":"#standardadditions"}]},"itunes":{"patterns":[{"match":"\\\\b(artwork|application|encoder|EQ preset|item|source|visual|(EQ |browser )?window|((audio CD|device|shared|URL|file) )?track|playlist window|((audio CD|device|radio tuner|library|folder|user) )?playlist)s?\\\\b","name":"support.class.itunes.applescript"},{"match":"\\\\b(add|back track|convert|fast forward|(next|previous) track|pause|play(pause)?|refresh|resume|rewind|search|stop|update|eject|subscribe|update(Podcast|AllPodcasts)|download)\\\\b","name":"support.function.itunes.applescript"},{"match":"\\\\b(current (playlist|stream (title|URL)|track)|player state)\\\\b","name":"support.constant.itunes.applescript"},{"match":"\\\\b(current (encoder|EQ preset|visual)|EQ enabled|fixed indexing|full screen|mute|player position|sound volume|visuals enabled|visual size)\\\\b","name":"support.variable.itunes.applescript"}]},"standard-suite":{"patterns":[{"match":"\\\\b(colors?|documents?|items?|windows?)\\\\b","name":"support.class.standard-suite.applescript"},{"match":"\\\\b(close|count|delete|duplicate|exists|make|move|open|print|quit|save|activate|select|data size)\\\\b","name":"support.function.standard-suite.applescript"},{"match":"\\\\b(name|frontmost|version)\\\\b","name":"support.constant.standard-suite.applescript"},{"match":"\\\\b(selection)\\\\b","name":"support.variable.standard-suite.applescript"},{"match":"\\\\b(attachments?|attribute runs?|characters?|paragraphs?|texts?|words?)\\\\b","name":"support.class.text-suite.applescript"}]},"standardadditions":{"patterns":[{"match":"\\\\b((alert|dialog) reply)\\\\b","name":"support.class.standardadditions.user-interaction.applescript"},{"match":"\\\\b(file information)\\\\b","name":"support.class.standardadditions.file.applescript"},{"match":"\\\\b(POSIX files?|system information|volume settings)\\\\b","name":"support.class.standardadditions.miscellaneous.applescript"},{"match":"\\\\b(URLs?|internet address(es)?|web pages?|FTP items?)\\\\b","name":"support.class.standardadditions.internet.applescript"},{"match":"\\\\b(info for|list (disks|folder)|mount volume|path to( resource)?)\\\\b","name":"support.function.standardadditions.file.applescript"},{"match":"\\\\b(beep|choose (application|color|file( name)?|folder|from list|remote application|URL)|delay|display (alert|dialog)|say)\\\\b","name":"support.function.standardadditions.user-interaction.applescript"},{"match":"\\\\b(ASCII (character|number)|localized string|offset|summarize)\\\\b","name":"support.function.standardadditions.string.applescript"},{"match":"\\\\b(set the clipboard to|the clipboard|clipboard info)\\\\b","name":"support.function.standardadditions.clipboard.applescript"},{"match":"\\\\b(open for access|close access|read|write|get eof|set eof)\\\\b","name":"support.function.standardadditions.file-i-o.applescript"},{"match":"\\\\b((load|store|run) script|scripting components)\\\\b","name":"support.function.standardadditions.scripting.applescript"},{"match":"\\\\b(current date|do shell script|get volume settings|random number|round|set volume|system attribute|system info|time to GMT)\\\\b","name":"support.function.standardadditions.miscellaneous.applescript"},{"match":"\\\\b(opening folder|((?:clos|mov)ing) folder window for|adding folder items to|removing folder items from)\\\\b","name":"support.function.standardadditions.folder-actions.applescript"},{"match":"\\\\b(open location|handle CGI request)\\\\b","name":"support.function.standardadditions.internet.applescript"}]},"system-events":{"patterns":[{"match":"\\\\b(audio (data|file))\\\\b","name":"support.class.system-events.audio-file.applescript"},{"match":"\\\\b(alias(es)?|(Classic|local|network|system|user) domain objects?|disk( item)?s?|domains?|file( package)?s?|folders?|items?)\\\\b","name":"support.class.system-events.disk-folder-file.applescript"},{"match":"\\\\b(delete|open|move)\\\\b","name":"support.function.system-events.disk-folder-file.applescript"},{"match":"\\\\b(folder actions?|scripts?)\\\\b","name":"support.class.system-events.folder-actions.applescript"},{"match":"\\\\b(attach action to|attached scripts|edit action of|remove action from)\\\\b","name":"support.function.system-events.folder-actions.applescript"},{"match":"\\\\b(movie (?:data|file))\\\\b","name":"support.class.system-events.movie-file.applescript"},{"match":"\\\\b(log out|restart|shut down|sleep)\\\\b","name":"support.function.system-events.power.applescript"},{"match":"\\\\b(((application |desk accessory )?process|(c(?:heck|ombo ))?box)(es)?|(action|attribute|browser|(busy|progress|relevance) indicator|color well|column|drawer|group|grow area|image|incrementor|list|menu( bar)?( item)?|(menu |pop up |radio )?button|outline|(radio|tab|splitter) group|row|scroll (area|bar)|sheet|slider|splitter|static text|table|text (area|field)|tool bar|UI element|window)s?)\\\\b","name":"support.class.system-events.processes.applescript"},{"match":"\\\\b(click|key code|keystroke|perform|select)\\\\b","name":"support.function.system-events.processes.applescript"},{"match":"\\\\b(property list (file|item))\\\\b","name":"support.class.system-events.property-list.applescript"},{"match":"\\\\b(annotation|QuickTime (data|file)|track)s?\\\\b","name":"support.class.system-events.quicktime-file.applescript"},{"match":"\\\\b((abort|begin|end) transaction)\\\\b","name":"support.function.system-events.system-events.applescript"},{"match":"\\\\b(XML (attribute|data|element|file)s?)\\\\b","name":"support.class.system-events.xml.applescript"},{"match":"\\\\b(print settings|users?|login items?)\\\\b","name":"support.class.sytem-events.other.applescript"}]},"textmate":{"patterns":[{"match":"\\\\b(print settings)\\\\b","name":"support.class.textmate.applescript"},{"match":"\\\\b(get url|insert|reload bundles)\\\\b","name":"support.function.textmate.applescript"}]}},"scopeName":"source.applescript"}`)),t=[e];export{t as default}; diff --git a/apps/kimi-code/dist-web/assets/architectureDiagram-ZJ3FMSHR-Dmu6U5j9.js b/apps/kimi-code/dist-web/assets/architectureDiagram-ZJ3FMSHR-Dmu6U5j9.js new file mode 100644 index 0000000000000000000000000000000000000000..57e665bcfe972b5fdcb951805b23fde8b756dde4 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/architectureDiagram-ZJ3FMSHR-Dmu6U5j9.js @@ -0,0 +1,36 @@ +import{p as ke}from"./chunk-JWPE2WC7-K16PVern.js";import{b7 as Ze,_ as gt,D as qe,W as Qe,l as Se,b as Je,a as Ke,n as je,o as _e,g as tr,s as er,p as rr,A as ir,y as ar,B as nr,c as me,a$ as Ee,ai as ve,i as or,d as sr,q as hr,aj as lr,b8 as fr}from"./mermaidParser.worker-BFSlSHEW.js";import{p as cr}from"./cynefin-VYW2F7L2-C-EfYT07.js";import{c as Fe}from"./cytoscape.esm-OyMbaexL.js";var se={exports:{}},he={exports:{}},le={exports:{}},gr=le.exports,Me;function ur(){return Me||(Me=1,(function(L,b){(function(G,N){L.exports=N()})(gr,function(){return(function(A){var G={};function N(v){if(G[v])return G[v].exports;var h=G[v]={i:v,l:!1,exports:{}};return A[v].call(h.exports,h,h.exports,N),h.l=!0,h.exports}return N.m=A,N.c=G,N.i=function(v){return v},N.d=function(v,h,i){N.o(v,h)||Object.defineProperty(v,h,{configurable:!1,enumerable:!0,get:i})},N.n=function(v){var h=v&&v.__esModule?function(){return v.default}:function(){return v};return N.d(h,"a",h),h},N.o=function(v,h){return Object.prototype.hasOwnProperty.call(v,h)},N.p="",N(N.s=28)})([(function(A,G,N){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,A.exports=v}),(function(A,G,N){var v=N(2),h=N(8),i=N(9);function r(f,e,u){v.call(this,u),this.isOverlapingSourceAndTarget=!1,this.vGraphObject=u,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 u=this.getOtherEnd(f),t=e.getGraphManager().getRoot();;){if(u.getOwner()==e)return u;if(u.getOwner()==t)break;u=u.getOwner().getParent()}return null},r.prototype.updateLength=function(){var f=new Array(4);this.isOverlapingSourceAndTarget=h.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)},A.exports=r}),(function(A,G,N){function v(h){this.vGraphObject=h}A.exports=v}),(function(A,G,N){var v=N(2),h=N(10),i=N(13),r=N(0),a=N(16),f=N(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=h.MIN_VALUE,this.inclusionTreeDepth=h.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 u in v)e[u]=v[u];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.rect.width*this.rect.width)/2},e.prototype.setRect=function(t,s){this.rect.x=t.x,this.rect.y=t.y,this.rect.width=s.width,this.rect.height=s.height},e.prototype.setCenter=function(t,s){this.rect.x=t-this.rect.width/2,this.rect.y=s-this.rect.height/2},e.prototype.setLocation=function(t,s){this.rect.x=t,this.rect.y=s},e.prototype.moveBy=function(t,s){this.rect.x+=t,this.rect.y+=s},e.prototype.getEdgeListToNode=function(t){var s=[],o=this;return o.edges.forEach(function(c){if(c.target==t){if(c.source!=o)throw"Incorrect edge source!";s.push(c)}}),s},e.prototype.getEdgesBetween=function(t){var s=[],o=this;return o.edges.forEach(function(c){if(!(c.source==o||c.target==o))throw"Incorrect edge source and/or target";(c.target==t||c.source==t)&&s.push(c)}),s},e.prototype.getNeighborsList=function(){var t=new Set,s=this;return s.edges.forEach(function(o){if(o.source==s)t.add(o.target);else{if(o.target!=s)throw"Incorrect incidency!";t.add(o.source)}}),t},e.prototype.withChildren=function(){var t=new Set,s,o;if(t.add(this),this.child!=null)for(var c=this.child.getNodes(),l=0;ls?(this.rect.x-=(this.labelWidth-s)/2,this.setWidth(this.labelWidth)):this.labelPosHorizontal=="right"&&this.setWidth(s+this.labelWidth)),this.labelHeight&&(this.labelPosVertical=="top"?(this.rect.y-=this.labelHeight,this.setHeight(o+this.labelHeight)):this.labelPosVertical=="center"&&this.labelHeight>o?(this.rect.y-=(this.labelHeight-o)/2,this.setHeight(this.labelHeight)):this.labelPosVertical=="bottom"&&this.setHeight(o+this.labelHeight))}}},e.prototype.getInclusionTreeDepth=function(){if(this.inclusionTreeDepth==h.MAX_VALUE)throw"assert failed";return this.inclusionTreeDepth},e.prototype.transform=function(t){var s=this.rect.x;s>r.WORLD_BOUNDARY?s=r.WORLD_BOUNDARY:s<-r.WORLD_BOUNDARY&&(s=-r.WORLD_BOUNDARY);var o=this.rect.y;o>r.WORLD_BOUNDARY?o=r.WORLD_BOUNDARY:o<-r.WORLD_BOUNDARY&&(o=-r.WORLD_BOUNDARY);var c=new f(s,o),l=t.inverseTransformPoint(c);this.setLocation(l.x,l.y)},e.prototype.getLeft=function(){return this.rect.x},e.prototype.getRight=function(){return this.rect.x+this.rect.width},e.prototype.getTop=function(){return this.rect.y},e.prototype.getBottom=function(){return this.rect.y+this.rect.height},e.prototype.getParent=function(){return this.owner==null?null:this.owner.getParent()},A.exports=e}),(function(A,G,N){var v=N(0);function h(){}for(var i in v)h[i]=v[i];h.MAX_ITERATIONS=2500,h.DEFAULT_EDGE_LENGTH=50,h.DEFAULT_SPRING_STRENGTH=.45,h.DEFAULT_REPULSION_STRENGTH=4500,h.DEFAULT_GRAVITY_STRENGTH=.4,h.DEFAULT_COMPOUND_GRAVITY_STRENGTH=1,h.DEFAULT_GRAVITY_RANGE_FACTOR=3.8,h.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=1.5,h.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION=!0,h.DEFAULT_USE_SMART_REPULSION_RANGE_CALCULATION=!0,h.DEFAULT_COOLING_FACTOR_INCREMENTAL=.3,h.COOLING_ADAPTATION_FACTOR=.33,h.ADAPTATION_LOWER_NODE_LIMIT=1e3,h.ADAPTATION_UPPER_NODE_LIMIT=5e3,h.MAX_NODE_DISPLACEMENT_INCREMENTAL=100,h.MAX_NODE_DISPLACEMENT=h.MAX_NODE_DISPLACEMENT_INCREMENTAL*3,h.MIN_REPULSION_DIST=h.DEFAULT_EDGE_LENGTH/10,h.CONVERGENCE_CHECK_PERIOD=100,h.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=.1,h.MIN_EDGE_LENGTH=1,h.GRID_CALCULATION_CHECK_PERIOD=10,A.exports=h}),(function(A,G,N){function v(h,i){h==null&&i==null?(this.x=0,this.y=0):(this.x=h,this.y=i)}v.prototype.getX=function(){return this.x},v.prototype.getY=function(){return this.y},v.prototype.setX=function(h){this.x=h},v.prototype.setY=function(h){this.y=h},v.prototype.getDifference=function(h){return new DimensionD(this.x-h.x,this.y-h.y)},v.prototype.getCopy=function(){return new v(this.x,this.y)},v.prototype.translate=function(h){return this.x+=h.width,this.y+=h.height,this},A.exports=v}),(function(A,G,N){var v=N(2),h=N(10),i=N(0),r=N(7),a=N(3),f=N(1),e=N(13),u=N(12),t=N(11);function s(c,l,T){v.call(this,T),this.estimatedSize=h.MIN_VALUE,this.margin=i.DEFAULT_GRAPH_MARGIN,this.edges=[],this.nodes=[],this.isConnected=!1,this.parent=c,l!=null&&l instanceof r?this.graphManager=l:l!=null&&l instanceof Layout&&(this.graphManager=l.graphManager)}s.prototype=Object.create(v.prototype);for(var o in v)s[o]=v[o];s.prototype.getNodes=function(){return this.nodes},s.prototype.getEdges=function(){return this.edges},s.prototype.getGraphManager=function(){return this.graphManager},s.prototype.getParent=function(){return this.parent},s.prototype.getLeft=function(){return this.left},s.prototype.getRight=function(){return this.right},s.prototype.getTop=function(){return this.top},s.prototype.getBottom=function(){return this.bottom},s.prototype.isConnected=function(){return this.isConnected},s.prototype.add=function(c,l,T){if(l==null&&T==null){var g=c;if(this.graphManager==null)throw"Graph has no graph mgr!";if(this.getNodes().indexOf(g)>-1)throw"Node already in graph!";return g.owner=this,this.getNodes().push(g),g}else{var d=c;if(!(this.getNodes().indexOf(l)>-1&&this.getNodes().indexOf(T)>-1))throw"Source or target not in graph!";if(!(l.owner==T.owner&&l.owner==this))throw"Both owners must be this graph!";return l.owner!=T.owner?null:(d.source=l,d.target=T,d.isInterGraph=!1,this.getEdges().push(d),l.edges.push(d),T!=l&&T.edges.push(d),d)}},s.prototype.remove=function(c){var l=c;if(c instanceof a){if(l==null)throw"Node is null!";if(!(l.owner!=null&&l.owner==this))throw"Owner graph is invalid!";if(this.graphManager==null)throw"Owner graph manager is invalid!";for(var T=l.edges.slice(),g,d=T.length,C=0;C-1&&P>-1))throw"Source and/or target doesn't know this edge!";g.source.edges.splice(w,1),g.target!=g.source&&g.target.edges.splice(P,1);var S=g.source.owner.getEdges().indexOf(g);if(S==-1)throw"Not in owner's edge list!";g.source.owner.getEdges().splice(S,1)}},s.prototype.updateLeftTop=function(){for(var c=h.MAX_VALUE,l=h.MAX_VALUE,T,g,d,C=this.getNodes(),S=C.length,w=0;wT&&(c=T),l>g&&(l=g)}return c==h.MAX_VALUE?null:(C[0].getParent().paddingLeft!=null?d=C[0].getParent().paddingLeft:d=this.margin,this.left=l-d,this.top=c-d,new u(this.left,this.top))},s.prototype.updateBounds=function(c){for(var l=h.MAX_VALUE,T=-h.MAX_VALUE,g=h.MAX_VALUE,d=-h.MAX_VALUE,C,S,w,P,B,U=this.nodes,V=U.length,M=0;MC&&(l=C),Tw&&(g=w),dC&&(l=C),Tw&&(g=w),d=this.nodes.length){var V=0;T.forEach(function(M){M.owner==c&&V++}),V==this.nodes.length&&(this.isConnected=!0)}},A.exports=s}),(function(A,G,N){var v,h=N(1);function i(r){v=N(6),this.layout=r,this.graphs=[],this.edges=[]}i.prototype.addRoot=function(){var r=this.layout.newGraph(),a=this.layout.newNode(null),f=this.add(r,a);return this.setRootGraph(f),this.rootGraph},i.prototype.add=function(r,a,f,e,u){if(f==null&&e==null&&u==null){if(r==null)throw"Graph is null!";if(a==null)throw"Parent node is null!";if(this.graphs.indexOf(r)>-1)throw"Graph already in this graph mgr!";if(this.graphs.push(r),r.parent!=null)throw"Already has a parent!";if(a.child!=null)throw"Already has a child!";return r.parent=a,a.child=r,r}else{u=f,e=a,f=r;var t=e.getOwner(),s=u.getOwner();if(!(t!=null&&t.getGraphManager()==this))throw"Source not in this graph mgr!";if(!(s!=null&&s.getGraphManager()==this))throw"Target not in this graph mgr!";if(t==s)return f.isInterGraph=!1,t.add(f,e,u);if(f.isInterGraph=!0,f.source=e,f.target=u,this.edges.indexOf(f)>-1)throw"Edge already in inter-graph edge list!";if(this.edges.push(f),!(f.source!=null&&f.target!=null))throw"Edge source and/or target is null!";if(!(f.source.edges.indexOf(f)==-1&&f.target.edges.indexOf(f)==-1))throw"Edge already in source and/or target incidency list!";return f.source.edges.push(f),f.target.edges.push(f),f}},i.prototype.remove=function(r){if(r instanceof v){var a=r;if(a.getGraphManager()!=this)throw"Graph not in this graph mgr";if(!(a==this.rootGraph||a.parent!=null&&a.parent.graphManager==this))throw"Invalid parent node!";var f=[];f=f.concat(a.getEdges());for(var e,u=f.length,t=0;t=r.getRight()?a[0]+=Math.min(r.getX()-i.getX(),i.getRight()-r.getRight()):r.getX()<=i.getX()&&r.getRight()>=i.getRight()&&(a[0]+=Math.min(i.getX()-r.getX(),r.getRight()-i.getRight())),i.getY()<=r.getY()&&i.getBottom()>=r.getBottom()?a[1]+=Math.min(r.getY()-i.getY(),i.getBottom()-r.getBottom()):r.getY()<=i.getY()&&r.getBottom()>=i.getBottom()&&(a[1]+=Math.min(i.getY()-r.getY(),r.getBottom()-i.getBottom()));var u=Math.abs((r.getCenterY()-i.getCenterY())/(r.getCenterX()-i.getCenterX()));r.getCenterY()===i.getCenterY()&&r.getCenterX()===i.getCenterX()&&(u=1);var t=u*a[0],s=a[1]/u;a[0]t)return a[0]=f,a[1]=o,a[2]=u,a[3]=U,!1;if(eu)return a[0]=s,a[1]=e,a[2]=P,a[3]=t,!1;if(fu?(a[0]=l,a[1]=T,n=!0):(a[0]=c,a[1]=o,n=!0):p===y&&(f>u?(a[0]=s,a[1]=o,n=!0):(a[0]=g,a[1]=T,n=!0)),-m===y?u>f?(a[2]=B,a[3]=U,E=!0):(a[2]=P,a[3]=w,E=!0):m===y&&(u>f?(a[2]=S,a[3]=w,E=!0):(a[2]=V,a[3]=U,E=!0)),n&&E)return!1;if(f>u?e>t?(I=this.getCardinalDirection(p,y,4),O=this.getCardinalDirection(m,y,2)):(I=this.getCardinalDirection(-p,y,3),O=this.getCardinalDirection(-m,y,1)):e>t?(I=this.getCardinalDirection(-p,y,1),O=this.getCardinalDirection(-m,y,3)):(I=this.getCardinalDirection(p,y,2),O=this.getCardinalDirection(m,y,4)),!n)switch(I){case 1:W=o,R=f+-C/y,a[0]=R,a[1]=W;break;case 2:R=g,W=e+d*y,a[0]=R,a[1]=W;break;case 3:W=T,R=f+C/y,a[0]=R,a[1]=W;break;case 4:R=l,W=e+-d*y,a[0]=R,a[1]=W;break}if(!E)switch(O){case 1:Q=w,x=u+-_/y,a[2]=x,a[3]=Q;break;case 2:x=V,Q=t+M*y,a[2]=x,a[3]=Q;break;case 3:Q=U,x=u+_/y,a[2]=x,a[3]=Q;break;case 4:x=B,Q=t+-M*y,a[2]=x,a[3]=Q;break}}return!1},h.getCardinalDirection=function(i,r,a){return i>r?a:1+a%4},h.getIntersection=function(i,r,a,f){if(f==null)return this.getIntersection2(i,r,a);var e=i.x,u=i.y,t=r.x,s=r.y,o=a.x,c=a.y,l=f.x,T=f.y,g=void 0,d=void 0,C=void 0,S=void 0,w=void 0,P=void 0,B=void 0,U=void 0,V=void 0;return C=s-u,w=e-t,B=t*u-e*s,S=T-c,P=o-l,U=l*c-o*T,V=C*P-S*w,V===0?null:(g=(w*U-P*B)/V,d=(S*B-C*U)/V,new v(g,d))},h.angleOfVector=function(i,r,a,f){var e=void 0;return i!==a?(e=Math.atan((f-r)/(a-i)),a=0){var T=(-o+Math.sqrt(o*o-4*s*c))/(2*s),g=(-o-Math.sqrt(o*o-4*s*c))/(2*s),d=null;return T>=0&&T<=1?[T]:g>=0&&g<=1?[g]:d}else return null},h.HALF_PI=.5*Math.PI,h.ONE_AND_HALF_PI=1.5*Math.PI,h.TWO_PI=2*Math.PI,h.THREE_PI=3*Math.PI,A.exports=h}),(function(A,G,N){function v(){}v.sign=function(h){return h>0?1:h<0?-1:0},v.floor=function(h){return h<0?Math.ceil(h):Math.floor(h)},v.ceil=function(h){return h<0?Math.floor(h):Math.ceil(h)},A.exports=v}),(function(A,G,N){function v(){}v.MAX_VALUE=2147483647,v.MIN_VALUE=-2147483648,A.exports=v}),(function(A,G,N){var v=(function(){function e(u,t){for(var s=0;s"u"?"undefined":v(i);return i==null||r!="object"&&r!="function"},A.exports=h}),(function(A,G,N){function v(o){if(Array.isArray(o)){for(var c=0,l=Array(o.length);c0&&c;){for(C.push(w[0]);C.length>0&&c;){var P=C[0];C.splice(0,1),d.add(P);for(var B=P.getEdges(),g=0;g-1&&w.splice(_,1)}d=new Set,S=new Map}}return o},s.prototype.createDummyNodesForBendpoints=function(o){for(var c=[],l=o.source,T=this.graphManager.calcLowestCommonAncestor(o.source,o.target),g=0;g0){for(var T=this.edgeToDummyNodes.get(l),g=0;g=0&&c.splice(U,1);var V=S.getNeighborsList();V.forEach(function(n){if(l.indexOf(n)<0){var E=T.get(n),p=E-1;p==1&&P.push(n),T.set(n,p)}})}l=l.concat(P),(c.length==1||c.length==2)&&(g=!0,d=c[0])}return d},s.prototype.setGraphManager=function(o){this.graphManager=o},A.exports=s}),(function(A,G,N){function v(){}v.seed=1,v.x=0,v.nextDouble=function(){return v.x=Math.sin(v.seed++)*1e4,v.x-Math.floor(v.x)},A.exports=v}),(function(A,G,N){var v=N(5);function h(i,r){this.lworldOrgX=0,this.lworldOrgY=0,this.ldeviceOrgX=0,this.ldeviceOrgY=0,this.lworldExtX=1,this.lworldExtY=1,this.ldeviceExtX=1,this.ldeviceExtY=1}h.prototype.getWorldOrgX=function(){return this.lworldOrgX},h.prototype.setWorldOrgX=function(i){this.lworldOrgX=i},h.prototype.getWorldOrgY=function(){return this.lworldOrgY},h.prototype.setWorldOrgY=function(i){this.lworldOrgY=i},h.prototype.getWorldExtX=function(){return this.lworldExtX},h.prototype.setWorldExtX=function(i){this.lworldExtX=i},h.prototype.getWorldExtY=function(){return this.lworldExtY},h.prototype.setWorldExtY=function(i){this.lworldExtY=i},h.prototype.getDeviceOrgX=function(){return this.ldeviceOrgX},h.prototype.setDeviceOrgX=function(i){this.ldeviceOrgX=i},h.prototype.getDeviceOrgY=function(){return this.ldeviceOrgY},h.prototype.setDeviceOrgY=function(i){this.ldeviceOrgY=i},h.prototype.getDeviceExtX=function(){return this.ldeviceExtX},h.prototype.setDeviceExtX=function(i){this.ldeviceExtX=i},h.prototype.getDeviceExtY=function(){return this.ldeviceExtY},h.prototype.setDeviceExtY=function(i){this.ldeviceExtY=i},h.prototype.transformX=function(i){var r=0,a=this.lworldExtX;return a!=0&&(r=this.ldeviceOrgX+(i-this.lworldOrgX)*this.ldeviceExtX/a),r},h.prototype.transformY=function(i){var r=0,a=this.lworldExtY;return a!=0&&(r=this.ldeviceOrgY+(i-this.lworldOrgY)*this.ldeviceExtY/a),r},h.prototype.inverseTransformX=function(i){var r=0,a=this.ldeviceExtX;return a!=0&&(r=this.lworldOrgX+(i-this.ldeviceOrgX)*this.lworldExtX/a),r},h.prototype.inverseTransformY=function(i){var r=0,a=this.ldeviceExtY;return a!=0&&(r=this.lworldOrgY+(i-this.ldeviceOrgY)*this.lworldExtY/a),r},h.prototype.inverseTransformPoint=function(i){var r=new v(this.inverseTransformX(i.x),this.inverseTransformY(i.y));return r},A.exports=h}),(function(A,G,N){function v(t){if(Array.isArray(t)){for(var s=0,o=Array(t.length);si.ADAPTATION_LOWER_NODE_LIMIT&&(this.coolingFactor=Math.max(this.coolingFactor*i.COOLING_ADAPTATION_FACTOR,this.coolingFactor-(t-i.ADAPTATION_LOWER_NODE_LIMIT)/(i.ADAPTATION_UPPER_NODE_LIMIT-i.ADAPTATION_LOWER_NODE_LIMIT)*this.coolingFactor*(1-i.COOLING_ADAPTATION_FACTOR))),this.maxNodeDisplacement=i.MAX_NODE_DISPLACEMENT_INCREMENTAL):(t>i.ADAPTATION_LOWER_NODE_LIMIT?this.coolingFactor=Math.max(i.COOLING_ADAPTATION_FACTOR,1-(t-i.ADAPTATION_LOWER_NODE_LIMIT)/(i.ADAPTATION_UPPER_NODE_LIMIT-i.ADAPTATION_LOWER_NODE_LIMIT)*(1-i.COOLING_ADAPTATION_FACTOR)):this.coolingFactor=1,this.initialCoolingFactor=this.coolingFactor,this.maxNodeDisplacement=i.MAX_NODE_DISPLACEMENT),this.maxIterations=Math.max(this.getAllNodes().length*5,this.maxIterations),this.displacementThresholdPerNode=3*i.DEFAULT_EDGE_LENGTH/100,this.totalDisplacementThreshold=this.displacementThresholdPerNode*this.getAllNodes().length,this.repulsionRange=this.calcRepulsionRange()},e.prototype.calcSpringForces=function(){for(var t=this.getAllEdges(),s,o=0;o0&&arguments[0]!==void 0?arguments[0]:!0,s=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,o,c,l,T,g=this.getAllNodes(),d;if(this.useFRGridVariant)for(this.totalIterations%i.GRID_CALCULATION_CHECK_PERIOD==1&&t&&this.updateGrid(),d=new Set,o=0;oC||d>C)&&(t.gravitationForceX=-this.gravityConstant*l,t.gravitationForceY=-this.gravityConstant*T)):(C=s.getEstimatedSize()*this.compoundGravityRangeFactor,(g>C||d>C)&&(t.gravitationForceX=-this.gravityConstant*l*this.compoundGravityConstant,t.gravitationForceY=-this.gravityConstant*T*this.compoundGravityConstant))},e.prototype.isConverged=function(){var t,s=!1;return this.totalIterations>this.maxIterations/3&&(s=Math.abs(this.totalDisplacement-this.oldTotalDisplacement)<2),t=this.totalDisplacement=g.length||C>=g[0].length)){for(var S=0;Se}}]),a})();A.exports=r}),(function(A,G,N){function v(){}v.svd=function(h){this.U=null,this.V=null,this.s=null,this.m=0,this.n=0,this.m=h.length,this.n=h[0].length;var i=Math.min(this.m,this.n);this.s=(function(Tt){for(var Ct=[];Tt-- >0;)Ct.push(0);return Ct})(Math.min(this.m+1,this.n)),this.U=(function(Tt){var Ct=function Bt(bt){if(bt.length==0)return 0;for(var zt=[],St=0;St0;)Ct.push(0);return Ct})(this.n),a=(function(Tt){for(var Ct=[];Tt-- >0;)Ct.push(0);return Ct})(this.m),f=!0,e=Math.min(this.m-1,this.n),u=Math.max(0,Math.min(this.n-2,this.m)),t=0;t=0;m--)if(this.s[m]!==0){for(var y=m+1;y=0;z--){if((function(Tt,Ct){return Tt&&Ct})(z0;){var J=void 0,It=void 0;for(J=n-2;J>=-1&&J!==-1;J--)if(Math.abs(r[J])<=ht+tt*(Math.abs(this.s[J])+Math.abs(this.s[J+1]))){r[J]=0;break}if(J===n-2)It=4;else{var Nt=void 0;for(Nt=n-1;Nt>=J&&Nt!==J;Nt--){var vt=(Nt!==n?Math.abs(r[Nt]):0)+(Nt!==J+1?Math.abs(r[Nt-1]):0);if(Math.abs(this.s[Nt])<=ht+tt*vt){this.s[Nt]=0;break}}Nt===J?It=3:Nt===n-1?It=1:(It=2,J=Nt)}switch(J++,It){case 1:{var it=r[n-2];r[n-2]=0;for(var ut=n-2;ut>=J;ut--){var Et=v.hypot(this.s[ut],it),wt=this.s[ut]/Et,Ot=it/Et;this.s[ut]=Et,ut!==J&&(it=-Ot*r[ut-1],r[ut-1]=wt*r[ut-1]);for(var mt=0;mt=this.s[J+1]);){var Lt=this.s[J];if(this.s[J]=this.s[J+1],this.s[J+1]=Lt,JMath.abs(i)?(r=i/h,r=Math.abs(h)*Math.sqrt(1+r*r)):i!=0?(r=h/i,r=Math.abs(i)*Math.sqrt(1+r*r)):r=0,r},A.exports=v}),(function(A,G,N){var v=(function(){function r(a,f){for(var e=0;e2&&arguments[2]!==void 0?arguments[2]:1,u=arguments.length>3&&arguments[3]!==void 0?arguments[3]:-1,t=arguments.length>4&&arguments[4]!==void 0?arguments[4]:-1;h(this,r),this.sequence1=a,this.sequence2=f,this.match_score=e,this.mismatch_penalty=u,this.gap_penalty=t,this.iMax=a.length+1,this.jMax=f.length+1,this.grid=new Array(this.iMax);for(var s=0;s=0;a--){var f=this.listeners[a];f.event===i&&f.callback===r&&this.listeners.splice(a,1)}},h.emit=function(i,r){for(var a=0;a{var G={45:((i,r,a)=>{var f={};f.layoutBase=a(551),f.CoSEConstants=a(806),f.CoSEEdge=a(767),f.CoSEGraph=a(880),f.CoSEGraphManager=a(578),f.CoSELayout=a(765),f.CoSENode=a(991),f.ConstraintHandler=a(902),i.exports=f}),806:((i,r,a)=>{var f=a(551).FDLayoutConstants;function e(){}for(var u in f)e[u]=f[u];e.DEFAULT_USE_MULTI_LEVEL_SCALING=!1,e.DEFAULT_RADIAL_SEPARATION=f.DEFAULT_EDGE_LENGTH,e.DEFAULT_COMPONENT_SEPERATION=60,e.TILE=!0,e.TILING_PADDING_VERTICAL=10,e.TILING_PADDING_HORIZONTAL=10,e.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,e.ENFORCE_CONSTRAINTS=!0,e.APPLY_LAYOUT=!0,e.RELAX_MOVEMENT_ON_CONSTRAINTS=!0,e.TREE_REDUCTION_ON_INCREMENTAL=!0,e.PURE_INCREMENTAL=e.DEFAULT_INCREMENTAL,i.exports=e}),767:((i,r,a)=>{var f=a(551).FDLayoutEdge;function e(t,s,o){f.call(this,t,s,o)}e.prototype=Object.create(f.prototype);for(var u in f)e[u]=f[u];i.exports=e}),880:((i,r,a)=>{var f=a(551).LGraph;function e(t,s,o){f.call(this,t,s,o)}e.prototype=Object.create(f.prototype);for(var u in f)e[u]=f[u];i.exports=e}),578:((i,r,a)=>{var f=a(551).LGraphManager;function e(t){f.call(this,t)}e.prototype=Object.create(f.prototype);for(var u in f)e[u]=f[u];i.exports=e}),765:((i,r,a)=>{var f=a(551).FDLayout,e=a(578),u=a(880),t=a(991),s=a(767),o=a(806),c=a(902),l=a(551).FDLayoutConstants,T=a(551).LayoutConstants,g=a(551).Point,d=a(551).PointD,C=a(551).DimensionD,S=a(551).Layout,w=a(551).Integer,P=a(551).IGeometry,B=a(551).LGraph,U=a(551).Transform,V=a(551).LinkedList;function M(){f.call(this),this.toBeTiled={},this.constraints={}}M.prototype=Object.create(f.prototype);for(var _ in f)M[_]=f[_];M.prototype.newGraphManager=function(){var n=new e(this);return this.graphManager=n,n},M.prototype.newGraph=function(n){return new u(null,this.graphManager,n)},M.prototype.newNode=function(n){return new t(this.graphManager,n)},M.prototype.newEdge=function(n){return new s(null,null,n)},M.prototype.initParameters=function(){f.prototype.initParameters.call(this,arguments),this.isSubLayout||(o.DEFAULT_EDGE_LENGTH<10?this.idealEdgeLength=10:this.idealEdgeLength=o.DEFAULT_EDGE_LENGTH,this.useSmartIdealEdgeLengthCalculation=o.DEFAULT_USE_SMART_IDEAL_EDGE_LENGTH_CALCULATION,this.gravityConstant=l.DEFAULT_GRAVITY_STRENGTH,this.compoundGravityConstant=l.DEFAULT_COMPOUND_GRAVITY_STRENGTH,this.gravityRangeFactor=l.DEFAULT_GRAVITY_RANGE_FACTOR,this.compoundGravityRangeFactor=l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR,this.prunedNodesAll=[],this.growTreeIterations=0,this.afterGrowthIterations=0,this.isTreeGrowing=!1,this.isGrowthFinished=!1)},M.prototype.initSpringEmbedder=function(){f.prototype.initSpringEmbedder.call(this),this.coolingCycle=0,this.maxCoolingCycle=this.maxIterations/l.CONVERGENCE_CHECK_PERIOD,this.finalTemperature=.04,this.coolingAdjuster=1},M.prototype.layout=function(){var n=T.DEFAULT_CREATE_BENDS_AS_NEEDED;return n&&(this.createBendpoints(),this.graphManager.resetAllEdges()),this.level=0,this.classicLayout()},M.prototype.classicLayout=function(){if(this.nodesWithGravity=this.calculateNodesToApplyGravitationTo(),this.graphManager.setAllNodesToApplyGravitation(this.nodesWithGravity),this.calcNoOfChildrenForAllNodes(),this.graphManager.calcLowestCommonAncestors(),this.graphManager.calcInclusionTreeDepths(),this.graphManager.getRoot().calcEstimatedSize(),this.calcIdealEdgeLengths(),this.incremental){if(o.TREE_REDUCTION_ON_INCREMENTAL){this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var E=new Set(this.getAllNodes()),p=this.nodesWithGravity.filter(function(I){return E.has(I)});this.graphManager.setAllNodesToApplyGravitation(p)}}else{var n=this.getFlatForest();if(n.length>0)this.positionNodesRadially(n);else{this.reduceTrees(),this.graphManager.resetAllNodesToApplyGravitation();var E=new Set(this.getAllNodes()),p=this.nodesWithGravity.filter(function(m){return E.has(m)});this.graphManager.setAllNodesToApplyGravitation(p),this.positionNodesRandomly()}}return Object.keys(this.constraints).length>0&&(c.handleConstraints(this),this.initConstraintVariables()),this.initSpringEmbedder(),o.APPLY_LAYOUT&&this.runSpringEmbedder(),!0},M.prototype.tick=function(){if(this.totalIterations++,this.totalIterations===this.maxIterations&&!this.isTreeGrowing&&!this.isGrowthFinished)if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;if(this.totalIterations%l.CONVERGENCE_CHECK_PERIOD==0&&!this.isTreeGrowing&&!this.isGrowthFinished){if(this.isConverged())if(this.prunedNodesAll.length>0)this.isTreeGrowing=!0;else return!0;this.coolingCycle++,this.layoutQuality==0?this.coolingAdjuster=this.coolingCycle:this.layoutQuality==1&&(this.coolingAdjuster=this.coolingCycle/3),this.coolingFactor=Math.max(this.initialCoolingFactor-Math.pow(this.coolingCycle,Math.log(100*(this.initialCoolingFactor-this.finalTemperature))/Math.log(this.maxCoolingCycle))/100*this.coolingAdjuster,this.finalTemperature),this.animationPeriod=Math.ceil(this.initialAnimationPeriod*Math.sqrt(this.coolingFactor))}if(this.isTreeGrowing){if(this.growTreeIterations%10==0)if(this.prunedNodesAll.length>0){this.graphManager.updateBounds(),this.updateGrid(),this.growTree(this.prunedNodesAll),this.graphManager.resetAllNodesToApplyGravitation();var n=new Set(this.getAllNodes()),E=this.nodesWithGravity.filter(function(y){return n.has(y)});this.graphManager.setAllNodesToApplyGravitation(E),this.graphManager.updateBounds(),this.updateGrid(),o.PURE_INCREMENTAL?this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL/2:this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL}else this.isTreeGrowing=!1,this.isGrowthFinished=!0;this.growTreeIterations++}if(this.isGrowthFinished){if(this.isConverged())return!0;this.afterGrowthIterations%10==0&&(this.graphManager.updateBounds(),this.updateGrid()),o.PURE_INCREMENTAL?this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL/2*((100-this.afterGrowthIterations)/100):this.coolingFactor=l.DEFAULT_COOLING_FACTOR_INCREMENTAL*((100-this.afterGrowthIterations)/100),this.afterGrowthIterations++}var p=!this.isTreeGrowing&&!this.isGrowthFinished,m=this.growTreeIterations%10==1&&this.isTreeGrowing||this.afterGrowthIterations%10==1&&this.isGrowthFinished;return this.totalDisplacement=0,this.graphManager.updateBounds(),this.calcSpringForces(),this.calcRepulsionForces(p,m),this.calcGravitationalForces(),this.moveNodes(),this.animate(),!1},M.prototype.getPositionsData=function(){for(var n=this.graphManager.getAllNodes(),E={},p=0;p0&&this.updateDisplacements();for(var p=0;p0&&(m.fixedNodeWeight=I)}}if(this.constraints.relativePlacementConstraint){var O=new Map,R=new Map;if(this.dummyToNodeForVerticalAlignment=new Map,this.dummyToNodeForHorizontalAlignment=new Map,this.fixedNodesOnHorizontal=new Set,this.fixedNodesOnVertical=new Set,this.fixedNodeSet.forEach(function(D){n.fixedNodesOnHorizontal.add(D),n.fixedNodesOnVertical.add(D)}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var W=this.constraints.alignmentConstraint.vertical,p=0;p=2*D.length/3;tt--)H=Math.floor(Math.random()*(tt+1)),k=D[tt],D[tt]=D[H],D[H]=k;return D},this.nodesInRelativeHorizontal=[],this.nodesInRelativeVertical=[],this.nodeToRelativeConstraintMapHorizontal=new Map,this.nodeToRelativeConstraintMapVertical=new Map,this.nodeToTempPositionMapHorizontal=new Map,this.nodeToTempPositionMapVertical=new Map,this.constraints.relativePlacementConstraint.forEach(function(D){if(D.left){var H=O.has(D.left)?O.get(D.left):D.left,k=O.has(D.right)?O.get(D.right):D.right;n.nodesInRelativeHorizontal.includes(H)||(n.nodesInRelativeHorizontal.push(H),n.nodeToRelativeConstraintMapHorizontal.set(H,[]),n.dummyToNodeForVerticalAlignment.has(H)?n.nodeToTempPositionMapHorizontal.set(H,n.idToNodeMap.get(n.dummyToNodeForVerticalAlignment.get(H)[0]).getCenterX()):n.nodeToTempPositionMapHorizontal.set(H,n.idToNodeMap.get(H).getCenterX())),n.nodesInRelativeHorizontal.includes(k)||(n.nodesInRelativeHorizontal.push(k),n.nodeToRelativeConstraintMapHorizontal.set(k,[]),n.dummyToNodeForVerticalAlignment.has(k)?n.nodeToTempPositionMapHorizontal.set(k,n.idToNodeMap.get(n.dummyToNodeForVerticalAlignment.get(k)[0]).getCenterX()):n.nodeToTempPositionMapHorizontal.set(k,n.idToNodeMap.get(k).getCenterX())),n.nodeToRelativeConstraintMapHorizontal.get(H).push({right:k,gap:D.gap}),n.nodeToRelativeConstraintMapHorizontal.get(k).push({left:H,gap:D.gap})}else{var tt=R.has(D.top)?R.get(D.top):D.top,ht=R.has(D.bottom)?R.get(D.bottom):D.bottom;n.nodesInRelativeVertical.includes(tt)||(n.nodesInRelativeVertical.push(tt),n.nodeToRelativeConstraintMapVertical.set(tt,[]),n.dummyToNodeForHorizontalAlignment.has(tt)?n.nodeToTempPositionMapVertical.set(tt,n.idToNodeMap.get(n.dummyToNodeForHorizontalAlignment.get(tt)[0]).getCenterY()):n.nodeToTempPositionMapVertical.set(tt,n.idToNodeMap.get(tt).getCenterY())),n.nodesInRelativeVertical.includes(ht)||(n.nodesInRelativeVertical.push(ht),n.nodeToRelativeConstraintMapVertical.set(ht,[]),n.dummyToNodeForHorizontalAlignment.has(ht)?n.nodeToTempPositionMapVertical.set(ht,n.idToNodeMap.get(n.dummyToNodeForHorizontalAlignment.get(ht)[0]).getCenterY()):n.nodeToTempPositionMapVertical.set(ht,n.idToNodeMap.get(ht).getCenterY())),n.nodeToRelativeConstraintMapVertical.get(tt).push({bottom:ht,gap:D.gap}),n.nodeToRelativeConstraintMapVertical.get(ht).push({top:tt,gap:D.gap})}});else{var Q=new Map,z=new Map;this.constraints.relativePlacementConstraint.forEach(function(D){if(D.left){var H=O.has(D.left)?O.get(D.left):D.left,k=O.has(D.right)?O.get(D.right):D.right;Q.has(H)?Q.get(H).push(k):Q.set(H,[k]),Q.has(k)?Q.get(k).push(H):Q.set(k,[H])}else{var tt=R.has(D.top)?R.get(D.top):D.top,ht=R.has(D.bottom)?R.get(D.bottom):D.bottom;z.has(tt)?z.get(tt).push(ht):z.set(tt,[ht]),z.has(ht)?z.get(ht).push(tt):z.set(ht,[tt])}});var X=function(H,k){var tt=[],ht=[],J=new V,It=new Set,Nt=0;return H.forEach(function(vt,it){if(!It.has(it)){tt[Nt]=[],ht[Nt]=!1;var ut=it;for(J.push(ut),It.add(ut),tt[Nt].push(ut);J.length!=0;){ut=J.shift(),k.has(ut)&&(ht[Nt]=!0);var Et=H.get(ut);Et.forEach(function(wt){It.has(wt)||(J.push(wt),It.add(wt),tt[Nt].push(wt))})}Nt++}}),{components:tt,isFixed:ht}},rt=X(Q,n.fixedNodesOnHorizontal);this.componentsOnHorizontal=rt.components,this.fixedComponentsOnHorizontal=rt.isFixed;var $=X(z,n.fixedNodesOnVertical);this.componentsOnVertical=$.components,this.fixedComponentsOnVertical=$.isFixed}}},M.prototype.updateDisplacements=function(){var n=this;if(this.constraints.fixedNodeConstraint&&this.constraints.fixedNodeConstraint.forEach(function($){var D=n.idToNodeMap.get($.nodeId);D.displacementX=0,D.displacementY=0}),this.constraints.alignmentConstraint){if(this.constraints.alignmentConstraint.vertical)for(var E=this.constraints.alignmentConstraint.vertical,p=0;p1){var R;for(R=0;Rm&&(m=Math.floor(O.y)),I=Math.floor(O.x+o.DEFAULT_COMPONENT_SEPERATION)}this.transform(new d(T.WORLD_CENTER_X-O.x/2,T.WORLD_CENTER_Y-O.y/2))},M.radialLayout=function(n,E,p){var m=Math.max(this.maxDiagonalInTree(n),o.DEFAULT_RADIAL_SEPARATION);M.branchRadialLayout(E,null,0,359,0,m);var y=B.calculateBounds(n),I=new U;I.setDeviceOrgX(y.getMinX()),I.setDeviceOrgY(y.getMinY()),I.setWorldOrgX(p.x),I.setWorldOrgY(p.y);for(var O=0;O1;){var k=H[0];H.splice(0,1);var tt=z.indexOf(k);tt>=0&&z.splice(tt,1),$--,X--}E!=null?D=(z.indexOf(H[0])+1)%$:D=0;for(var ht=Math.abs(m-p)/X,J=D;rt!=X;J=++J%$){var It=z[J].getOtherEnd(n);if(It!=E){var Nt=(p+rt*ht)%360,vt=(Nt+ht)%360;M.branchRadialLayout(It,n,Nt,vt,y+I,I),rt++}}},M.maxDiagonalInTree=function(n){for(var E=w.MIN_VALUE,p=0;pE&&(E=y)}return E},M.prototype.calcRepulsionRange=function(){return 2*(this.level+1)*this.idealEdgeLength},M.prototype.groupZeroDegreeMembers=function(){var n=this,E={};this.memberGroups={},this.idToDummyNode={};for(var p=[],m=this.graphManager.getAllNodes(),y=0;y"u"&&(E[R]=[]),E[R]=E[R].concat(I)}Object.keys(E).forEach(function(W){if(E[W].length>1){var x="DummyCompound_"+W;n.memberGroups[x]=E[W];var Q=E[W][0].getParent(),z=new t(n.graphManager);z.id=x,z.paddingLeft=Q.paddingLeft||0,z.paddingRight=Q.paddingRight||0,z.paddingBottom=Q.paddingBottom||0,z.paddingTop=Q.paddingTop||0,n.idToDummyNode[x]=z;var X=n.getGraphManager().add(n.newGraph(),z),rt=Q.getChild();rt.add(z);for(var $=0;$y?(m.rect.x-=(m.labelWidth-y)/2,m.setWidth(m.labelWidth),m.labelMarginLeft=(m.labelWidth-y)/2):m.labelPosHorizontal=="right"&&m.setWidth(y+m.labelWidth)),m.labelHeight&&(m.labelPosVertical=="top"?(m.rect.y-=m.labelHeight,m.setHeight(I+m.labelHeight),m.labelMarginTop=m.labelHeight):m.labelPosVertical=="center"&&m.labelHeight>I?(m.rect.y-=(m.labelHeight-I)/2,m.setHeight(m.labelHeight),m.labelMarginTop=(m.labelHeight-I)/2):m.labelPosVertical=="bottom"&&m.setHeight(I+m.labelHeight))}})},M.prototype.repopulateCompounds=function(){for(var n=this.compoundOrder.length-1;n>=0;n--){var E=this.compoundOrder[n],p=E.id,m=E.paddingLeft,y=E.paddingTop,I=E.labelMarginLeft,O=E.labelMarginTop;this.adjustLocations(this.tiledMemberPack[p],E.rect.x,E.rect.y,m,y,I,O)}},M.prototype.repopulateZeroDegreeMembers=function(){var n=this,E=this.tiledZeroDegreePack;Object.keys(E).forEach(function(p){var m=n.idToDummyNode[p],y=m.paddingLeft,I=m.paddingTop,O=m.labelMarginLeft,R=m.labelMarginTop;n.adjustLocations(E[p],m.rect.x,m.rect.y,y,I,O,R)})},M.prototype.getToBeTiled=function(n){var E=n.id;if(this.toBeTiled[E]!=null)return this.toBeTiled[E];var p=n.getChild();if(p==null)return this.toBeTiled[E]=!1,!1;for(var m=p.getNodes(),y=0;y0)return this.toBeTiled[E]=!1,!1;if(I.getChild()==null){this.toBeTiled[I.id]=!1;continue}if(!this.getToBeTiled(I))return this.toBeTiled[E]=!1,!1}return this.toBeTiled[E]=!0,!0},M.prototype.getNodeDegree=function(n){n.id;for(var E=n.getEdges(),p=0,m=0;mQ&&(Q=X.rect.height)}p+=Q+n.verticalPadding}},M.prototype.tileCompoundMembers=function(n,E){var p=this;this.tiledMemberPack=[],Object.keys(n).forEach(function(m){var y=E[m];if(p.tiledMemberPack[m]=p.tileNodes(n[m],y.paddingLeft+y.paddingRight),y.rect.width=p.tiledMemberPack[m].width,y.rect.height=p.tiledMemberPack[m].height,y.setCenter(p.tiledMemberPack[m].centerX,p.tiledMemberPack[m].centerY),y.labelMarginLeft=0,y.labelMarginTop=0,o.NODE_DIMENSIONS_INCLUDE_LABELS){var I=y.rect.width,O=y.rect.height;y.labelWidth&&(y.labelPosHorizontal=="left"?(y.rect.x-=y.labelWidth,y.setWidth(I+y.labelWidth),y.labelMarginLeft=y.labelWidth):y.labelPosHorizontal=="center"&&y.labelWidth>I?(y.rect.x-=(y.labelWidth-I)/2,y.setWidth(y.labelWidth),y.labelMarginLeft=(y.labelWidth-I)/2):y.labelPosHorizontal=="right"&&y.setWidth(I+y.labelWidth)),y.labelHeight&&(y.labelPosVertical=="top"?(y.rect.y-=y.labelHeight,y.setHeight(O+y.labelHeight),y.labelMarginTop=y.labelHeight):y.labelPosVertical=="center"&&y.labelHeight>O?(y.rect.y-=(y.labelHeight-O)/2,y.setHeight(y.labelHeight),y.labelMarginTop=(y.labelHeight-O)/2):y.labelPosVertical=="bottom"&&y.setHeight(O+y.labelHeight))}})},M.prototype.tileNodes=function(n,E){var p=this.tileNodesByFavoringDim(n,E,!0),m=this.tileNodesByFavoringDim(n,E,!1),y=this.getOrgRatio(p),I=this.getOrgRatio(m),O;return IR&&(R=$.getWidth())});var W=I/y,x=O/y,Q=Math.pow(p-m,2)+4*(W+m)*(x+p)*y,z=(m-p+Math.sqrt(Q))/(2*(W+m)),X;E?(X=Math.ceil(z),X==z&&X++):X=Math.floor(z);var rt=X*(W+m)-m;return R>rt&&(rt=R),rt+=m*2,rt},M.prototype.tileNodesByFavoringDim=function(n,E,p){var m=o.TILING_PADDING_VERTICAL,y=o.TILING_PADDING_HORIZONTAL,I=o.TILING_COMPARE_BY,O={rows:[],rowWidth:[],rowHeight:[],width:0,height:E,verticalPadding:m,horizontalPadding:y,centerX:0,centerY:0};I&&(O.idealRowWidth=this.calcIdealRowWidth(n,p));var R=function(D){return D.rect.width*D.rect.height},W=function(D,H){return R(H)-R(D)};n.sort(function($,D){var H=W;return O.idealRowWidth?(H=I,H($.id,D.id)):H($,D)});for(var x=0,Q=0,z=0;z0&&(O+=n.horizontalPadding),n.rowWidth[p]=O,n.width0&&(R+=n.verticalPadding);var W=0;R>n.rowHeight[p]&&(W=n.rowHeight[p],n.rowHeight[p]=R,W=n.rowHeight[p]-W),n.height+=W,n.rows[p].push(E)},M.prototype.getShortestRowIndex=function(n){for(var E=-1,p=Number.MAX_VALUE,m=0;mp&&(E=m,p=n.rowWidth[m]);return E},M.prototype.canAddHorizontal=function(n,E,p){if(n.idealRowWidth){var m=n.rows.length-1,y=n.rowWidth[m];return y+E+n.horizontalPadding<=n.idealRowWidth}var I=this.getShortestRowIndex(n);if(I<0)return!0;var O=n.rowWidth[I];if(O+n.horizontalPadding+E<=n.width)return!0;var R=0;n.rowHeight[I]0&&(R=p+n.verticalPadding-n.rowHeight[I]);var W;n.width-O>=E+n.horizontalPadding?W=(n.height+R)/(O+E+n.horizontalPadding):W=(n.height+R)/n.width,R=p+n.verticalPadding;var x;return n.widthI&&E!=p){m.splice(-1,1),n.rows[p].push(y),n.rowWidth[E]=n.rowWidth[E]-I,n.rowWidth[p]=n.rowWidth[p]+I,n.width=n.rowWidth[instance.getLongestRowIndex(n)];for(var O=Number.MIN_VALUE,R=0;RO&&(O=m[R].height);E>0&&(O+=n.verticalPadding);var W=n.rowHeight[E]+n.rowHeight[p];n.rowHeight[E]=O,n.rowHeight[p]0)for(var rt=y;rt<=I;rt++)X[0]+=this.grid[rt][O-1].length+this.grid[rt][O].length-1;if(I0)for(var rt=O;rt<=R;rt++)X[3]+=this.grid[y-1][rt].length+this.grid[y][rt].length-1;for(var $=w.MAX_VALUE,D,H,k=0;k{var f=a(551).FDLayoutNode,e=a(551).IMath;function u(s,o,c,l){f.call(this,s,o,c,l)}u.prototype=Object.create(f.prototype);for(var t in f)u[t]=f[t];u.prototype.calculateDisplacement=function(){var s=this.graphManager.getLayout();this.getChild()!=null&&this.fixedNodeWeight?(this.displacementX+=s.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.fixedNodeWeight,this.displacementY+=s.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.fixedNodeWeight):(this.displacementX+=s.coolingFactor*(this.springForceX+this.repulsionForceX+this.gravitationForceX)/this.noOfChildren,this.displacementY+=s.coolingFactor*(this.springForceY+this.repulsionForceY+this.gravitationForceY)/this.noOfChildren),Math.abs(this.displacementX)>s.coolingFactor*s.maxNodeDisplacement&&(this.displacementX=s.coolingFactor*s.maxNodeDisplacement*e.sign(this.displacementX)),Math.abs(this.displacementY)>s.coolingFactor*s.maxNodeDisplacement&&(this.displacementY=s.coolingFactor*s.maxNodeDisplacement*e.sign(this.displacementY)),this.child&&this.child.getNodes().length>0&&this.propogateDisplacementToChildren(this.displacementX,this.displacementY)},u.prototype.propogateDisplacementToChildren=function(s,o){for(var c=this.getChild().getNodes(),l,T=0;T{function f(c){if(Array.isArray(c)){for(var l=0,T=Array(c.length);l0){var Lt=0;ot.forEach(function(st){Z=="horizontal"?(et.set(st,g.has(st)?d[g.get(st)]:q.get(st)),Lt+=et.get(st)):(et.set(st,g.has(st)?C[g.get(st)]:q.get(st)),Lt+=et.get(st))}),Lt=Lt/ot.length,lt.forEach(function(st){K.has(st)||et.set(st,Lt)})}else{var ft=0;lt.forEach(function(st){Z=="horizontal"?ft+=g.has(st)?d[g.get(st)]:q.get(st):ft+=g.has(st)?C[g.get(st)]:q.get(st)}),ft=ft/lt.length,lt.forEach(function(st){et.set(st,ft)})}});for(var At=function(){var ot=dt.shift(),Lt=Y.get(ot);Lt.forEach(function(ft){if(et.get(ft.id)st&&(st=kt),KtXt&&(Xt=Kt)}}catch(ee){Ct=!0,Bt=ee}finally{try{!Tt&&bt.return&&bt.return()}finally{if(Ct)throw Bt}}var fe=(Lt+st)/2-(ft+Xt)/2,Qt=!0,jt=!1,_t=void 0;try{for(var Jt=lt[Symbol.iterator](),ne;!(Qt=(ne=Jt.next()).done);Qt=!0){var te=ne.value;et.set(te,et.get(te)+fe)}}catch(ee){jt=!0,_t=ee}finally{try{!Qt&&Jt.return&&Jt.return()}finally{if(jt)throw _t}}})}return et},_=function(Y){var Z=0,K=0,q=0,at=0;if(Y.forEach(function(j){j.left?d[g.get(j.left)]-d[g.get(j.right)]>=0?Z++:K++:C[g.get(j.top)]-C[g.get(j.bottom)]>=0?q++:at++}),Z>K&&q>at)for(var ct=0;ctK)for(var nt=0;ntat)for(var et=0;et1)l.fixedNodeConstraint.forEach(function(F,Y){m[Y]=[F.position.x,F.position.y],y[Y]=[d[g.get(F.nodeId)],C[g.get(F.nodeId)]]}),I=!0;else if(l.alignmentConstraint)(function(){var F=0;if(l.alignmentConstraint.vertical){for(var Y=l.alignmentConstraint.vertical,Z=function(et){var j=new Set;Y[et].forEach(function(pt){j.add(pt)});var dt=new Set([].concat(f(j)).filter(function(pt){return R.has(pt)})),At=void 0;dt.size>0?At=d[g.get(dt.values().next().value)]:At=V(j).x,Y[et].forEach(function(pt){m[F]=[At,C[g.get(pt)]],y[F]=[d[g.get(pt)],C[g.get(pt)]],F++})},K=0;K0?At=d[g.get(dt.values().next().value)]:At=V(j).y,q[et].forEach(function(pt){m[F]=[d[g.get(pt)],At],y[F]=[d[g.get(pt)],C[g.get(pt)]],F++})},ct=0;ctz&&(z=Q[rt].length,X=rt);if(z0){var mt={x:0,y:0};l.fixedNodeConstraint.forEach(function(F,Y){var Z={x:d[g.get(F.nodeId)],y:C[g.get(F.nodeId)]},K=F.position,q=U(K,Z);mt.x+=q.x,mt.y+=q.y}),mt.x/=l.fixedNodeConstraint.length,mt.y/=l.fixedNodeConstraint.length,d.forEach(function(F,Y){d[Y]+=mt.x}),C.forEach(function(F,Y){C[Y]+=mt.y}),l.fixedNodeConstraint.forEach(function(F){d[g.get(F.nodeId)]=F.position.x,C[g.get(F.nodeId)]=F.position.y})}if(l.alignmentConstraint){if(l.alignmentConstraint.vertical)for(var Dt=l.alignmentConstraint.vertical,Rt=function(Y){var Z=new Set;Dt[Y].forEach(function(at){Z.add(at)});var K=new Set([].concat(f(Z)).filter(function(at){return R.has(at)})),q=void 0;K.size>0?q=d[g.get(K.values().next().value)]:q=V(Z).x,Z.forEach(function(at){R.has(at)||(d[g.get(at)]=q)})},Ht=0;Ht0?q=C[g.get(K.values().next().value)]:q=V(Z).y,Z.forEach(function(at){R.has(at)||(C[g.get(at)]=q)})},Ft=0;Ft{i.exports=A})},N={};function v(i){var r=N[i];if(r!==void 0)return r.exports;var a=N[i]={exports:{}};return G[i](a,a.exports,v),a.exports}var h=v(45);return h})()})})(he)),he.exports}var pr=se.exports,De;function yr(){return De||(De=1,(function(L,b){(function(G,N){L.exports=N(vr())})(pr,function(A){return(()=>{var G={658:(i=>{i.exports=Object.assign!=null?Object.assign.bind(Object):function(r){for(var a=arguments.length,f=Array(a>1?a-1:0),e=1;e{var f=(function(){function t(s,o){var c=[],l=!0,T=!1,g=void 0;try{for(var d=s[Symbol.iterator](),C;!(l=(C=d.next()).done)&&(c.push(C.value),!(o&&c.length===o));l=!0);}catch(S){T=!0,g=S}finally{try{!l&&d.return&&d.return()}finally{if(T)throw g}}return c}return function(s,o){if(Array.isArray(s))return s;if(Symbol.iterator in Object(s))return t(s,o);throw new TypeError("Invalid attempt to destructure non-iterable instance")}})(),e=a(140).layoutBase.LinkedList,u={};u.getTopMostNodes=function(t){for(var s={},o=0;o0&&I.merge(x)});for(var O=0;O1){C=g[0],S=C.connectedEdges().length,g.forEach(function(y){y.connectedEdges().length0&&c.set("dummy"+(c.size+1),B),U},u.relocateComponent=function(t,s,o){if(!o.fixedNodeConstraint){var c=Number.POSITIVE_INFINITY,l=Number.NEGATIVE_INFINITY,T=Number.POSITIVE_INFINITY,g=Number.NEGATIVE_INFINITY;if(o.quality=="draft"){var d=!0,C=!1,S=void 0;try{for(var w=s.nodeIndexes[Symbol.iterator](),P;!(d=(P=w.next()).done);d=!0){var B=P.value,U=f(B,2),V=U[0],M=U[1],_=o.cy.getElementById(V);if(_){var n=_.boundingBox(),E=s.xCoords[M]-n.w/2,p=s.xCoords[M]+n.w/2,m=s.yCoords[M]-n.h/2,y=s.yCoords[M]+n.h/2;El&&(l=p),mg&&(g=y)}}}catch(x){C=!0,S=x}finally{try{!d&&w.return&&w.return()}finally{if(C)throw S}}var I=t.x-(l+c)/2,O=t.y-(g+T)/2;s.xCoords=s.xCoords.map(function(x){return x+I}),s.yCoords=s.yCoords.map(function(x){return x+O})}else{Object.keys(s).forEach(function(x){var Q=s[x],z=Q.getRect().x,X=Q.getRect().x+Q.getRect().width,rt=Q.getRect().y,$=Q.getRect().y+Q.getRect().height;zl&&(l=X),rtg&&(g=$)});var R=t.x-(l+c)/2,W=t.y-(g+T)/2;Object.keys(s).forEach(function(x){var Q=s[x];Q.setCenter(Q.getCenterX()+R,Q.getCenterY()+W)})}}},u.calcBoundingBox=function(t,s,o,c){for(var l=Number.MAX_SAFE_INTEGER,T=Number.MIN_SAFE_INTEGER,g=Number.MAX_SAFE_INTEGER,d=Number.MIN_SAFE_INTEGER,C=void 0,S=void 0,w=void 0,P=void 0,B=t.descendants().not(":parent"),U=B.length,V=0;VC&&(l=C),Tw&&(g=w),d{var f=a(548),e=a(140).CoSELayout,u=a(140).CoSENode,t=a(140).layoutBase.PointD,s=a(140).layoutBase.DimensionD,o=a(140).layoutBase.LayoutConstants,c=a(140).layoutBase.FDLayoutConstants,l=a(140).CoSEConstants,T=function(d,C){var S=d.cy,w=d.eles,P=w.nodes(),B=w.edges(),U=void 0,V=void 0,M=void 0,_={};d.randomize&&(U=C.nodeIndexes,V=C.xCoords,M=C.yCoords);var n=function(x){return typeof x=="function"},E=function(x,Q){return n(x)?x(Q):x},p=f.calcParentsWithoutChildren(S,w),m=function W(x,Q,z,X){for(var rt=Q.length,$=0;$0){var J=void 0;J=z.getGraphManager().add(z.newGraph(),k),W(J,H,z,X)}}},y=function(x,Q,z){for(var X=0,rt=0,$=0;$0?l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=X/rt:n(d.idealEdgeLength)?l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=50:l.DEFAULT_EDGE_LENGTH=c.DEFAULT_EDGE_LENGTH=d.idealEdgeLength,l.MIN_REPULSION_DIST=c.MIN_REPULSION_DIST=c.DEFAULT_EDGE_LENGTH/10,l.DEFAULT_RADIAL_SEPARATION=c.DEFAULT_EDGE_LENGTH)},I=function(x,Q){Q.fixedNodeConstraint&&(x.constraints.fixedNodeConstraint=Q.fixedNodeConstraint),Q.alignmentConstraint&&(x.constraints.alignmentConstraint=Q.alignmentConstraint),Q.relativePlacementConstraint&&(x.constraints.relativePlacementConstraint=Q.relativePlacementConstraint)};d.nestingFactor!=null&&(l.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=c.PER_LEVEL_IDEAL_EDGE_LENGTH_FACTOR=d.nestingFactor),d.gravity!=null&&(l.DEFAULT_GRAVITY_STRENGTH=c.DEFAULT_GRAVITY_STRENGTH=d.gravity),d.numIter!=null&&(l.MAX_ITERATIONS=c.MAX_ITERATIONS=d.numIter),d.gravityRange!=null&&(l.DEFAULT_GRAVITY_RANGE_FACTOR=c.DEFAULT_GRAVITY_RANGE_FACTOR=d.gravityRange),d.gravityCompound!=null&&(l.DEFAULT_COMPOUND_GRAVITY_STRENGTH=c.DEFAULT_COMPOUND_GRAVITY_STRENGTH=d.gravityCompound),d.gravityRangeCompound!=null&&(l.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=c.DEFAULT_COMPOUND_GRAVITY_RANGE_FACTOR=d.gravityRangeCompound),d.initialEnergyOnIncremental!=null&&(l.DEFAULT_COOLING_FACTOR_INCREMENTAL=c.DEFAULT_COOLING_FACTOR_INCREMENTAL=d.initialEnergyOnIncremental),d.tilingCompareBy!=null&&(l.TILING_COMPARE_BY=d.tilingCompareBy),d.quality=="proof"?o.QUALITY=2:o.QUALITY=0,l.NODE_DIMENSIONS_INCLUDE_LABELS=c.NODE_DIMENSIONS_INCLUDE_LABELS=o.NODE_DIMENSIONS_INCLUDE_LABELS=d.nodeDimensionsIncludeLabels,l.DEFAULT_INCREMENTAL=c.DEFAULT_INCREMENTAL=o.DEFAULT_INCREMENTAL=!d.randomize,l.ANIMATE=c.ANIMATE=o.ANIMATE=d.animate,l.TILE=d.tile,l.TILING_PADDING_VERTICAL=typeof d.tilingPaddingVertical=="function"?d.tilingPaddingVertical.call():d.tilingPaddingVertical,l.TILING_PADDING_HORIZONTAL=typeof d.tilingPaddingHorizontal=="function"?d.tilingPaddingHorizontal.call():d.tilingPaddingHorizontal,l.DEFAULT_INCREMENTAL=c.DEFAULT_INCREMENTAL=o.DEFAULT_INCREMENTAL=!0,l.PURE_INCREMENTAL=!d.randomize,o.DEFAULT_UNIFORM_LEAF_NODE_SIZES=d.uniformNodeDimensions,d.step=="transformed"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!0,l.ENFORCE_CONSTRAINTS=!1,l.APPLY_LAYOUT=!1),d.step=="enforced"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!0,l.APPLY_LAYOUT=!1),d.step=="cose"&&(l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!1,l.APPLY_LAYOUT=!0),d.step=="all"&&(d.randomize?l.TRANSFORM_ON_CONSTRAINT_HANDLING=!0:l.TRANSFORM_ON_CONSTRAINT_HANDLING=!1,l.ENFORCE_CONSTRAINTS=!0,l.APPLY_LAYOUT=!0),d.fixedNodeConstraint||d.alignmentConstraint||d.relativePlacementConstraint?l.TREE_REDUCTION_ON_INCREMENTAL=!1:l.TREE_REDUCTION_ON_INCREMENTAL=!0;var O=new e,R=O.newGraphManager();return m(R.addRoot(),f.getTopMostNodes(P),O,d),y(O,R,B),I(O,d),O.runLayout(),_};i.exports={coseLayout:T}}),212:((i,r,a)=>{var f=(function(){function d(C,S){for(var w=0;w0)if(p){var I=t.getTopMostNodes(w.eles.nodes());if(M=t.connectComponents(P,w.eles,I),M.forEach(function(vt){var it=vt.boundingBox();_.push({x:it.x1+it.w/2,y:it.y1+it.h/2})}),w.randomize&&M.forEach(function(vt){w.eles=vt,U.push(o(w))}),w.quality=="default"||w.quality=="proof"){var O=P.collection();if(w.tile){var R=new Map,W=[],x=[],Q=0,z={nodeIndexes:R,xCoords:W,yCoords:x},X=[];if(M.forEach(function(vt,it){vt.edges().length==0&&(vt.nodes().forEach(function(ut,Et){O.merge(vt.nodes()[Et]),ut.isParent()||(z.nodeIndexes.set(vt.nodes()[Et].id(),Q++),z.xCoords.push(vt.nodes()[0].position().x),z.yCoords.push(vt.nodes()[0].position().y))}),X.push(it))}),O.length>1){var rt=O.boundingBox();_.push({x:rt.x1+rt.w/2,y:rt.y1+rt.h/2}),M.push(O),U.push(z);for(var $=X.length-1;$>=0;$--)M.splice(X[$],1),U.splice(X[$],1),_.splice(X[$],1)}}M.forEach(function(vt,it){w.eles=vt,V.push(l(w,U[it])),t.relocateComponent(_[it],V[it],w)})}else M.forEach(function(vt,it){t.relocateComponent(_[it],U[it],w)});var D=new Set;if(M.length>1){var H=[],k=B.filter(function(vt){return vt.css("display")=="none"});M.forEach(function(vt,it){var ut=void 0;if(w.quality=="draft"&&(ut=U[it].nodeIndexes),vt.nodes().not(k).length>0){var Et={};Et.edges=[],Et.nodes=[];var wt=void 0;vt.nodes().not(k).forEach(function(Ot){if(w.quality=="draft")if(!Ot.isParent())wt=ut.get(Ot.id()),Et.nodes.push({x:U[it].xCoords[wt]-Ot.boundingbox().w/2,y:U[it].yCoords[wt]-Ot.boundingbox().h/2,width:Ot.boundingbox().w,height:Ot.boundingbox().h});else{var mt=t.calcBoundingBox(Ot,U[it].xCoords,U[it].yCoords,ut);Et.nodes.push({x:mt.topLeftX,y:mt.topLeftY,width:mt.width,height:mt.height})}else V[it][Ot.id()]&&Et.nodes.push({x:V[it][Ot.id()].getLeft(),y:V[it][Ot.id()].getTop(),width:V[it][Ot.id()].getWidth(),height:V[it][Ot.id()].getHeight()})}),vt.edges().forEach(function(Ot){var mt=Ot.source(),Dt=Ot.target();if(mt.css("display")!="none"&&Dt.css("display")!="none")if(w.quality=="draft"){var Rt=ut.get(mt.id()),Ht=ut.get(Dt.id()),Ut=[],Pt=[];if(mt.isParent()){var Ft=t.calcBoundingBox(mt,U[it].xCoords,U[it].yCoords,ut);Ut.push(Ft.topLeftX+Ft.width/2),Ut.push(Ft.topLeftY+Ft.height/2)}else Ut.push(U[it].xCoords[Rt]),Ut.push(U[it].yCoords[Rt]);if(Dt.isParent()){var Yt=t.calcBoundingBox(Dt,U[it].xCoords,U[it].yCoords,ut);Pt.push(Yt.topLeftX+Yt.width/2),Pt.push(Yt.topLeftY+Yt.height/2)}else Pt.push(U[it].xCoords[Ht]),Pt.push(U[it].yCoords[Ht]);Et.edges.push({startX:Ut[0],startY:Ut[1],endX:Pt[0],endY:Pt[1]})}else V[it][mt.id()]&&V[it][Dt.id()]&&Et.edges.push({startX:V[it][mt.id()].getCenterX(),startY:V[it][mt.id()].getCenterY(),endX:V[it][Dt.id()].getCenterX(),endY:V[it][Dt.id()].getCenterY()})}),Et.nodes.length>0&&(H.push(Et),D.add(it))}});var tt=E.packComponents(H,w.randomize).shifts;if(w.quality=="draft")U.forEach(function(vt,it){var ut=vt.xCoords.map(function(wt){return wt+tt[it].dx}),Et=vt.yCoords.map(function(wt){return wt+tt[it].dy});vt.xCoords=ut,vt.yCoords=Et});else{var ht=0;D.forEach(function(vt){Object.keys(V[vt]).forEach(function(it){var ut=V[vt][it];ut.setCenter(ut.getCenterX()+tt[ht].dx,ut.getCenterY()+tt[ht].dy)}),ht++})}}}else{var m=w.eles.boundingBox();if(_.push({x:m.x1+m.w/2,y:m.y1+m.h/2}),w.randomize){var y=o(w);U.push(y)}w.quality=="default"||w.quality=="proof"?(V.push(l(w,U[0])),t.relocateComponent(_[0],V[0],w)):t.relocateComponent(_[0],U[0],w)}var J=function(it,ut){if(w.quality=="default"||w.quality=="proof"){typeof it=="number"&&(it=ut);var Et=void 0,wt=void 0,Ot=it.data("id");return V.forEach(function(Dt){Ot in Dt&&(Et={x:Dt[Ot].getRect().getCenterX(),y:Dt[Ot].getRect().getCenterY()},wt=Dt[Ot])}),w.nodeDimensionsIncludeLabels&&(wt.labelWidth&&(wt.labelPosHorizontal=="left"?Et.x+=wt.labelWidth/2:wt.labelPosHorizontal=="right"&&(Et.x-=wt.labelWidth/2)),wt.labelHeight&&(wt.labelPosVertical=="top"?Et.y+=wt.labelHeight/2:wt.labelPosVertical=="bottom"&&(Et.y-=wt.labelHeight/2))),Et==null&&(Et={x:it.position("x"),y:it.position("y")}),{x:Et.x,y:Et.y}}else{var mt=void 0;return U.forEach(function(Dt){var Rt=Dt.nodeIndexes.get(it.id());Rt!=null&&(mt={x:Dt.xCoords[Rt],y:Dt.yCoords[Rt]})}),mt==null&&(mt={x:it.position("x"),y:it.position("y")}),{x:mt.x,y:mt.y}}};if(w.quality=="default"||w.quality=="proof"||w.randomize){var It=t.calcParentsWithoutChildren(P,B),Nt=B.filter(function(vt){return vt.css("display")=="none"});w.eles=B.not(Nt),B.nodes().not(":parent").not(Nt).layoutPositions(S,w,J),It.length>0&&It.forEach(function(vt){vt.position(J(vt))})}else console.log("If randomize option is set to false, then quality option must be 'default' or 'proof'.")}}]),d})();i.exports=g}),657:((i,r,a)=>{var f=a(548),e=a(140).layoutBase.Matrix,u=a(140).layoutBase.SVD,t=function(o){var c=o.cy,l=o.eles,T=l.nodes(),g=l.nodes(":parent"),d=new Map,C=new Map,S=new Map,w=[],P=[],B=[],U=[],V=[],M=[],_=[],n=[],E=void 0,p=1e8,m=1e-9,y=o.piTol,I=o.samplingType,O=o.nodeSeparation,R=void 0,W=function(){for(var Y=0,Z=0,K=!1;Z=at;){nt=q[at++];for(var xt=w[nt],lt=0;ltdt&&(dt=V[Lt],At=Lt)}return At},Q=function(Y){var Z=void 0;if(Y){Z=Math.floor(Math.random()*E);for(var q=0;q=1)break;j=et}for(var pt=0;pt=1)break;j=et}for(var lt=0;lt0&&(Z.isParent()?w[Y].push(S.get(Z.id())):w[Y].push(Z.id()))})});var Nt=function(Y){var Z=C.get(Y),K=void 0;d.get(Y).forEach(function(q){c.getElementById(q).isParent()?K=S.get(q):K=q,w[Z].push(K),w[C.get(K)].push(Y)})},vt=!0,it=!1,ut=void 0;try{for(var Et=d.keys()[Symbol.iterator](),wt;!(vt=(wt=Et.next()).done);vt=!0){var Ot=wt.value;Nt(Ot)}}catch(F){it=!0,ut=F}finally{try{!vt&&Et.return&&Et.return()}finally{if(it)throw ut}}E=C.size;var mt=void 0;if(E>2){R=E{var f=a(212),e=function(t){t&&t("layout","fcose",f)};typeof cytoscape<"u"&&e(cytoscape),i.exports=e}),140:(i=>{i.exports=A})},N={};function v(i){var r=N[i];if(r!==void 0)return r.exports;var a=N[i]={exports:{}};return G[i](a,a.exports,v),a.exports}var h=v(579);return h})()})})(se)),se.exports}var mr=yr(),Er=Ze(mr),xe={L:"left",R:"right",T:"top",B:"bottom"},Ie={L:gt(L=>`${L},${L/2} 0,${L} 0,0`,"L"),R:gt(L=>`0,${L/2} ${L},0 ${L},${L}`,"R"),T:gt(L=>`0,0 ${L},0 ${L/2},${L}`,"T"),B:gt(L=>`${L/2},0 ${L},${L} 0,${L}`,"B")},oe={L:gt((L,b)=>L-b+2,"L"),R:gt((L,b)=>L-2,"R"),T:gt((L,b)=>L-b+2,"T"),B:gt((L,b)=>L-2,"B")},Tr=gt(function(L){return Wt(L)?L==="L"?"R":"L":L==="T"?"B":"T"},"getOppositeArchitectureDirection"),Re=gt(function(L){const b=L;return b==="L"||b==="R"||b==="T"||b==="B"},"isArchitectureDirection"),Wt=gt(function(L){const b=L;return b==="L"||b==="R"},"isArchitectureDirectionX"),qt=gt(function(L){const b=L;return b==="T"||b==="B"},"isArchitectureDirectionY"),Te=gt(function(L,b){const A=Wt(L)&&qt(b),G=qt(L)&&Wt(b);return A||G},"isArchitectureDirectionXY"),Nr=gt(function(L){const b=L[0],A=L[1],G=Wt(b)&&qt(A),N=qt(b)&&Wt(A);return G||N},"isArchitecturePairXY"),Lr=gt(function(L){return L!=="LL"&&L!=="RR"&&L!=="TT"&&L!=="BB"},"isValidArchitectureDirectionPair"),pe=gt(function(L,b){const A=`${L}${b}`;return Lr(A)?A:void 0},"getArchitectureDirectionPair"),Cr=gt(function([L,b],A){const G=A[0],N=A[1];return Wt(G)?qt(N)?[L+(G==="L"?-1:1),b+(N==="T"?1:-1)]:[L+(G==="L"?-1:1),b]:Wt(N)?[L+(N==="L"?1:-1),b+(G==="T"?1:-1)]:[L,b+(G==="T"?1:-1)]},"shiftPositionByArchitectureDirectionPair"),wr=gt(function(L){return L==="LT"||L==="TL"?[1,1]:L==="BL"||L==="LB"?[1,-1]:L==="BR"||L==="RB"?[-1,-1]:[-1,1]},"getArchitectureDirectionXYFactors"),Ar=gt(function(L,b){return Te(L,b)?"bend":Wt(L)?"horizontal":"vertical"},"getArchitectureDirectionAlignment"),Mr=gt(function(L){return L.type==="service"},"isArchitectureService"),Or=gt(function(L){return L.type==="junction"},"isArchitectureJunction"),be=gt(L=>L.data(),"edgeData"),ie=gt(L=>L.data(),"nodeData"),Dr=nr.architecture,Pe=class{constructor(){this.nodes={},this.groups={},this.edges=[],this.layoutHints=[],this.registeredIds={},this.elements={},this.diagramId="",this.setAccTitle=Je,this.getAccTitle=Ke,this.setDiagramTitle=je,this.getDiagramTitle=_e,this.getAccDescription=tr,this.setAccDescription=er,this.clear()}static{gt(this,"ArchitectureDB")}setDiagramId(L){this.diagramId=L}getDiagramId(){return this.diagramId}clear(){this.nodes={},this.groups={},this.edges=[],this.layoutHints=[],this.registeredIds={},this.dataStructures=void 0,this.elements={},this.diagramId="",rr()}addService({id:L,icon:b,in:A,title:G,iconText:N}){if(this.registeredIds[L]!==void 0)throw new Error(`The service id [${L}] is already in use by another ${this.registeredIds[L]}`);if(A!==void 0){if(L===A)throw new Error(`The service [${L}] cannot be placed within itself`);if(this.registeredIds[A]===void 0)throw new Error(`The service [${L}]'s parent does not exist. Please make sure the parent is created before this service`);if(this.registeredIds[A]==="node")throw new Error(`The service [${L}]'s parent is not a group`)}this.registeredIds[L]="node",this.nodes[L]={id:L,type:"service",icon:b,iconText:N,title:G,edges:[],in:A}}getServices(){return Object.values(this.nodes).filter(Mr)}addJunction({id:L,in:b}){if(this.registeredIds[L]!==void 0)throw new Error(`The junction id [${L}] is already in use by another ${this.registeredIds[L]}`);if(b!==void 0){if(L===b)throw new Error(`The junction [${L}] cannot be placed within itself`);if(this.registeredIds[b]===void 0)throw new Error(`The junction [${L}]'s parent does not exist. Please make sure the parent is created before this junction`);if(this.registeredIds[b]==="node")throw new Error(`The junction [${L}]'s parent is not a group`)}this.registeredIds[L]="node",this.nodes[L]={id:L,type:"junction",edges:[],in:b}}getJunctions(){return Object.values(this.nodes).filter(Or)}getNodes(){return Object.values(this.nodes)}getNode(L){return this.nodes[L]??null}addGroup({id:L,icon:b,in:A,title:G}){if(this.registeredIds?.[L]!==void 0)throw new Error(`The group id [${L}] is already in use by another ${this.registeredIds[L]}`);if(A!==void 0){if(L===A)throw new Error(`The group [${L}] cannot be placed within itself`);if(this.registeredIds?.[A]===void 0)throw new Error(`The group [${L}]'s parent does not exist. Please make sure the parent is created before this group`);if(this.registeredIds?.[A]==="node")throw new Error(`The group [${L}]'s parent is not a group`)}this.registeredIds[L]="group",this.groups[L]={id:L,icon:b,title:G,in:A}}getGroups(){return Object.values(this.groups)}addEdge({lhsId:L,rhsId:b,lhsDir:A,rhsDir:G,lhsInto:N,rhsInto:v,lhsGroup:h,rhsGroup:i,title:r}){if(!Re(A))throw new Error(`Invalid direction given for left hand side of edge ${L}--${b}. Expected (L,R,T,B) got ${String(A)}`);if(!Re(G))throw new Error(`Invalid direction given for right hand side of edge ${L}--${b}. Expected (L,R,T,B) got ${String(G)}`);if(this.nodes[L]===void 0&&this.groups[L]===void 0)throw new Error(`The left-hand id [${L}] does not yet exist. Please create the service/group before declaring an edge to it.`);if(this.nodes[b]===void 0&&this.groups[b]===void 0)throw new Error(`The right-hand id [${b}] does not yet exist. Please create the service/group before declaring an edge to it.`);const a=this.nodes[L].in,f=this.nodes[b].in;if(h&&a&&f&&a==f)throw new Error(`The left-hand id [${L}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);if(i&&a&&f&&a==f)throw new Error(`The right-hand id [${b}] is modified to traverse the group boundary, but the edge does not pass through two groups.`);const e={lhsId:L,lhsDir:A,lhsInto:N,lhsGroup:h,rhsId:b,rhsDir:G,rhsInto:v,rhsGroup:i,title:r};this.edges.push(e),this.nodes[L]&&this.nodes[b]&&(this.nodes[L].edges.push(this.edges[this.edges.length-1]),this.nodes[b].edges.push(this.edges[this.edges.length-1]))}getEdges(){return this.edges}addLayoutHint(L){if(L.members.length<2)throw new Error(`An align directive requires at least two members; got ${L.members.length}`);const b=new Set;L.members.forEach(A=>{if(this.registeredIds[A]!=="node")throw new Error(`align ${L.direction} references [${A}], which is not a service or junction`);if(b.has(A))throw new Error(`align ${L.direction} lists [${A}] more than once`);b.add(A)}),this.layoutHints.push(L)}getLayoutHints(){return this.layoutHints}getDataStructures(){if(this.dataStructures===void 0){const L={},b=Object.entries(this.nodes).reduce((i,[r,a])=>(i[r]=a.edges.reduce((f,e)=>{const u=this.getNode(e.lhsId)?.in,t=this.getNode(e.rhsId)?.in;if(u&&t&&u!==t){const s=Ar(e.lhsDir,e.rhsDir);s!=="bend"&&(L[u]??={},L[u][t]=s,L[t]??={},L[t][u]=s)}if(e.lhsId===r){const s=pe(e.lhsDir,e.rhsDir);s&&(f[s]=e.rhsId)}else{const s=pe(e.rhsDir,e.lhsDir);s&&(f[s]=e.lhsId)}return f},{}),i),{}),A=Object.keys(b)[0],G={[A]:1},N=Object.keys(b).reduce((i,r)=>r===A?i:{...i,[r]:1},{}),v=gt(i=>{const r={[i]:[0,0]},a=[i];for(;a.length>0;){const f=a.shift();if(f){G[f]=1,delete N[f];const e=b[f],[u,t]=r[f];Object.entries(e).forEach(([s,o])=>{G[o]||(r[o]=Cr([u,t],s),a.push(o))})}}return r},"BFS"),h=[v(A)];for(;Object.keys(N).length>0;)h.push(v(Object.keys(N)[0]));this.dataStructures={adjList:b,spatialMaps:h,groupAlignments:L}}return this.dataStructures}setElementForId(L,b){this.elements[L]=b}getElementById(L){return this.elements[L]}getConfig(){return ir({...Dr,...ar().architecture})}getConfigField(L){return this.getConfig()[L]}},xr=gt((L,b)=>{ke(L,b),L.groups.map(A=>b.addGroup(A)),L.services.map(A=>b.addService({...A,type:"service"})),L.junctions.map(A=>b.addJunction({...A,type:"junction"})),L.edges.map(A=>b.addEdge(A)),L.alignments?.map(A=>b.addLayoutHint({direction:A.direction,members:[...A.members]}))},"populateDb"),Ge={parser:{yy:void 0},parse:gt(async L=>{const b=await cr("architecture",L);Se.debug(b);const A=Ge.parser?.yy;if(!(A instanceof Pe))throw new Error("parser.parser?.yy was not a ArchitectureDB. This is due to a bug within Mermaid, please report this issue at https://github.com/mermaid-js/mermaid/issues.");xr(b,A)},"parse")},Ir=gt(L=>` + .edge { + stroke-width: ${L.archEdgeWidth}; + stroke: ${L.archEdgeColor}; + fill: none; + } + + .arrow { + fill: ${L.archEdgeArrowColor}; + } + + .node-bkg { + fill: none; + stroke: ${L.archGroupBorderColor}; + stroke-width: ${L.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"),Rr=Ir;function ye(L,b){if(L===0)return b();const A=Math.random;let G=L>>>0;Math.random=function(){G=G+1831565813>>>0;let N=G;return N=Math.imul(N^N>>>15,N|1),N^=N+Math.imul(N^N>>>7,N|61),((N^N>>>14)>>>0)/4294967296};try{return b()}finally{Math.random=A}}gt(ye,"withSeededRandom");var re=gt(L=>`${L}`,"wrapIcon"),ae={prefix:"mermaid-architecture",height:80,width:80,icons:{database:{body:re('')},server:{body:re('')},disk:{body:re('')},internet:{body:re('')},cloud:{body:re('')},unknown:fr,blank:{body:re("")}}},Sr=gt(async function(L,b,A,G){const N=A.getConfigField("padding"),v=A.getConfigField("iconSize"),h=v/2,i=v/6,r=i/2;await Promise.all(b.edges().map(async a=>{const{source:f,sourceDir:e,sourceArrow:u,sourceGroup:t,target:s,targetDir:o,targetArrow:c,targetGroup:l,label:T}=be(a);let{x:g,y:d}=a[0].sourceEndpoint();const{x:C,y:S}=a[0].midpoint();let{x:w,y:P}=a[0].targetEndpoint();const B=N+4;if(t&&(Wt(e)?g+=e==="L"?-B:B:d+=e==="T"?-B:B+18),l&&(Wt(o)?w+=o==="L"?-B:B:P+=o==="T"?-B:B+18),!t&&A.getNode(f)?.type==="junction"&&(Wt(e)?g+=e==="L"?h:-h:d+=e==="T"?h:-h),!l&&A.getNode(s)?.type==="junction"&&(Wt(o)?w+=o==="L"?h:-h:P+=o==="T"?h:-h),a[0]._private.rscratch){const U=L.insert("g");if(U.insert("path").attr("d",`M ${g},${d} L ${C},${S} L${w},${P} `).attr("class","edge").attr("id",`${G}-${hr(f,s,{prefix:"L"})}`),u){const V=Wt(e)?oe[e](g,i):g-r,M=qt(e)?oe[e](d,i):d-r;U.insert("polygon").attr("points",Ie[e](i)).attr("transform",`translate(${V},${M})`).attr("class","arrow")}if(c){const V=Wt(o)?oe[o](w,i):w-r,M=qt(o)?oe[o](P,i):P-r;U.insert("polygon").attr("points",Ie[o](i)).attr("transform",`translate(${V},${M})`).attr("class","arrow")}if(T){const V=Te(e,o)?"XY":Wt(e)?"X":"Y";let M=0;V==="X"?M=Math.abs(g-w):V==="Y"?M=Math.abs(d-P)/1.5:M=Math.abs(g-w)/2;const _=U.append("g");if(await Ee(_,T,{useHtmlLabels:!1,width:M,classes:"architecture-service-label"},me()),_.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","middle").attr("text-anchor","middle"),V==="X")_.attr("transform","translate("+C+", "+S+")");else if(V==="Y")_.attr("transform","translate("+C+", "+S+") rotate(-90)");else if(V==="XY"){const n=pe(e,o);if(n&&Nr(n)){const E=_.node().getBoundingClientRect(),[p,m]=wr(n);_.attr("dominant-baseline","auto").attr("transform",`rotate(${-1*p*m*45})`);const y=_.node().getBoundingClientRect();_.attr("transform",` + translate(${C}, ${S-E.height/2}) + translate(${p*y.width/2}, ${m*y.height/2}) + rotate(${-1*p*m*45}, 0, ${E.height/2}) + `)}}}}}))},"drawEdges"),Fr=gt(async function(L,b,A,G){const v=A.getConfigField("padding")*.75,h=A.getConfigField("fontSize"),r=A.getConfigField("iconSize")/2;await Promise.all(b.nodes().map(async a=>{const f=ie(a);if(f.type==="group"){const{h:e,w:u,x1:t,y1:s}=a.boundingBox(),o=L.append("rect");o.attr("id",`${G}-group-${f.id}`).attr("x",t+r).attr("y",s+r).attr("width",u).attr("height",e).attr("class","node-bkg");const c=L.append("g");let l=t,T=s;if(f.icon){const g=c.append("g");g.html(`${await ve(f.icon,{height:v,width:v,fallbackPrefix:ae.prefix})}`),g.attr("transform","translate("+(l+r+1)+", "+(T+r+1)+")"),l+=v,T+=h/2-1-2}if(f.label){const g=c.append("g");await Ee(g,f.label,{useHtmlLabels:!1,width:u,classes:"architecture-service-label"},me()),g.attr("dy","1em").attr("alignment-baseline","middle").attr("dominant-baseline","start").attr("text-anchor","start"),g.attr("transform","translate("+(l+r+4)+", "+(T+r+2)+")")}A.setElementForId(f.id,o)}}))},"drawGroups"),br=gt(async function(L,b,A,G){const N=me();for(const v of A){const h=b.append("g"),i=L.getConfigField("iconSize");if(v.title){const e=h.append("g");await Ee(e,v.title,{useHtmlLabels:!1,width:i*1.5,classes:"architecture-service-label"},N),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=h.append("g");if(v.icon)r.html(`${await ve(v.icon,{height:i,width:i,fallbackPrefix:ae.prefix})}`);else if(v.iconText){r.html(`${await ve("blank",{height:i,width:i,fallbackPrefix:ae.prefix})}`);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(or(v.iconText,N)),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",`${G}-node-${v.id}`).attr("d",`M0,${i} V5 Q0,0 5,0 H${i-5} Q${i},0 ${i},5 V${i} Z`);h.attr("id",`${G}-service-${v.id}`).attr("class","architecture-service");const{width:a,height:f}=h.node().getBBox();v.width=a,v.height=f,L.setElementForId(v.id,h)}return 0},"drawServices"),Pr=gt(function(L,b,A,G){A.forEach(N=>{const v=b.append("g"),h=L.getConfigField("iconSize");v.append("g").append("rect").attr("id",`${G}-node-${N.id}`).attr("fill-opacity","0").attr("width",h).attr("height",h),v.attr("class","architecture-junction");const{width:r,height:a}=v._groups[0][0].getBBox();v.width=r,v.height=a,L.setElementForId(N.id,v)})},"drawJunctions");lr([{name:ae.prefix,icons:ae}]);Fe.use(Er);function Ue(L,b,A){L.forEach(G=>{b.add({group:"nodes",data:{type:"service",id:G.id,icon:G.icon,label:G.title,parent:G.in,width:A.getConfigField("iconSize"),height:A.getConfigField("iconSize")},classes:"node-service"})})}gt(Ue,"addServices");function Ye(L,b,A){L.forEach(G=>{b.add({group:"nodes",data:{type:"junction",id:G.id,parent:G.in,width:A.getConfigField("iconSize"),height:A.getConfigField("iconSize")},classes:"node-junction"})})}gt(Ye,"addJunctions");function Xe(L,b){b.nodes().map(A=>{const G=ie(A);if(G.type==="group")return;G.x=A.position().x,G.y=A.position().y,L.getElementById(G.id).attr("transform","translate("+(G.x||0)+","+(G.y||0)+")")})}gt(Xe,"positionNodes");function He(L,b){L.forEach(A=>{b.add({group:"nodes",data:{type:"group",id:A.id,icon:A.icon,label:A.title,parent:A.in},classes:"node-group"})})}gt(He,"addGroups");function We(L,b){L.forEach(A=>{const{lhsId:G,rhsId:N,lhsInto:v,lhsGroup:h,rhsInto:i,lhsDir:r,rhsDir:a,rhsGroup:f,title:e}=A,u=Te(A.lhsDir,A.rhsDir)?"segments":"straight",t={id:`${G}-${N}`,label:e,source:G,sourceDir:r,sourceArrow:v,sourceGroup:h,sourceEndpoint:r==="L"?"0 50%":r==="R"?"100% 50%":r==="T"?"50% 0":"50% 100%",target:N,targetDir:a,targetArrow:i,targetGroup:f,targetEndpoint:a==="L"?"0 50%":a==="R"?"100% 50%":a==="T"?"50% 0":"50% 100%"};b.add({group:"edges",data:t,classes:u})})}gt(We,"addEdges");function Ve(L,b,A,G=[]){const N=gt((u,t)=>Object.entries(u).reduce((s,[o,c])=>{let l=0;const T=Object.entries(c);if(T.length===1)return s[o]=T[0][1],s;for(let g=0;g{const t={},s={};return Object.entries(u).forEach(([o,[c,l]])=>{const T=L.getNode(o)?.in??"default";t[l]??={},t[l][T]??=[],t[l][T].push(o),s[c]??={},s[c][T]??=[],s[c][T].push(o)}),{horiz:Object.values(N(t,"horizontal")).filter(o=>o.length>1),vert:Object.values(N(s,"vertical")).filter(o=>o.length>1)}}),[h,i]=v.reduce(([u,t],{horiz:s,vert:o})=>[[...u,...s],[...t,...o]],[[],[]]),r=new Set;G.forEach(u=>u.members.forEach(t=>r.add(t)));const a=gt(u=>u.filter(t=>!t.some(s=>r.has(s))),"dropOverlapping"),f=a(h),e=a(i);return G.forEach(u=>{u.members.length<2||(u.direction==="row"?f.push([...u.members]):e.push([...u.members]))}),{horizontal:f,vertical:e}}gt(Ve,"getAlignments");function ze(L,b,A=[]){const G=[],N=b.getConfigField("iconSize"),v=b.getConfigField("idealEdgeLengthMultiplier"),h=v*N,i=new Set;A.forEach(f=>{for(let e=0;e`${f[0]},${f[1]}`,"posToStr"),a=gt(f=>f.split(",").map(e=>parseInt(e)),"strToPos");return L.forEach(f=>{const e=Object.fromEntries(Object.entries(f).map(([o,c])=>[r(c),o])),u=[r([0,0])],t={},s={L:[-1,0],R:[1,0],T:[0,1],B:[0,-1]};for(;u.length>0;){const o=u.shift();if(o){t[o]=1;const c=e[o];if(c){const l=a(o);Object.entries(s).forEach(([T,g])=>{const d=r([l[0]+g[0],l[1]+g[1]]),C=e[d];if(C&&!t[d]){if(u.push(d),i.has(`${c}|${C}`))return;G.push({[xe[T]]:C,[xe[Tr(T)]]:c,gap:v*N})}})}}}}),G}gt(ze,"getRelativeConstraints");function Be(L,b,A,G,N,{spatialMaps:v,groupAlignments:h}){return new Promise(i=>{const r=sr("body").append("div").attr("id","cy").attr("style","display:none"),a=Fe({container:document.getElementById("cy"),style:[{selector:"edge",style:{"curve-style":"straight","source-endpoint":"data(sourceEndpoint)","target-endpoint":"data(targetEndpoint)"}},{selector:"edge[label]",style:{label:"data(label)"}},{selector:"edge.segments",style:{"curve-style":"segments","segment-weights":"0","segment-distances":[.5],"edge-distances":"endpoints","source-endpoint":"data(sourceEndpoint)","target-endpoint":"data(targetEndpoint)"}},{selector:"node",style:{"compound-sizing-wrt-labels":"include"}},{selector:"node[label]",style:{"text-valign":"bottom","text-halign":"center","font-size":`${N.getConfigField("fontSize")}px`}},{selector:".node-service",style:{label:"data(label)",width:"data(width)",height:"data(height)"}},{selector:".node-junction",style:{width:"data(width)",height:"data(height)"}},{selector:".node-group",style:{padding:`${N.getConfigField("padding")}px`}}],layout:{name:"grid",boundingBox:{x1:0,x2:100,y1:0,y2:100}}});r.remove(),He(A,a),Ue(L,a,N),Ye(b,a,N),We(G,a);const f=N.getLayoutHints(),e=Ve(N,v,h,f),u=ze(v,N,f),t=N.getConfigField("iconSize"),s=N.getConfigField("idealEdgeLengthMultiplier")*t,o=.5*t,c=N.getConfigField("edgeElasticity"),l=N.getConfigField("seed"),T=a.layout({name:"fcose",quality:"proof",randomize:N.getConfigField("randomize"),nodeSeparation:N.getConfigField("nodeSeparation"),numIter:N.getConfigField("numIter"),styleEnabled:!1,animate:!1,nodeDimensionsIncludeLabels:!1,idealEdgeLength(g){const[d,C]=g.connectedNodes(),{parent:S}=ie(d),{parent:w}=ie(C);return S===w?s:o},edgeElasticity(g){const[d,C]=g.connectedNodes(),{parent:S}=ie(d),{parent:w}=ie(C);return S===w?c:.001},alignmentConstraint:e,relativePlacementConstraint:u});T.one("layoutstop",()=>{function g(d,C,S,w){let P,B;const{x:U,y:V}=d,{x:M,y:_}=C;B=(w-V+(U-S)*(V-_)/(U-M))/Math.sqrt(1+Math.pow((V-_)/(U-M),2)),P=Math.sqrt(Math.pow(w-V,2)+Math.pow(S-U,2)-Math.pow(B,2));const n=Math.sqrt(Math.pow(M-U,2)+Math.pow(_-V,2));P=P/n;let E=(M-U)*(w-V)-(_-V)*(S-U);switch(!0){case E>=0:E=1;break;case E<0:E=-1;break}let p=(M-U)*(S-U)+(_-V)*(w-V);switch(!0){case p>=0:p=1;break;case p<0:p=-1;break}return B=Math.abs(B)*E,P=P*p,{distances:B,weights:P}}gt(g,"getSegmentWeights"),a.startBatch();for(const d of Object.values(a.edges()))if(d.data?.()){const{x:C,y:S}=d.source().position(),{x:w,y:P}=d.target().position();if(C!==w&&S!==P){const B=d.sourceEndpoint(),U=d.targetEndpoint(),{sourceDir:V}=be(d),[M,_]=qt(V)?[B.x,U.y]:[U.x,B.y],{weights:n,distances:E}=g(B,U,M,_);d.style("segment-distances",E),d.style("segment-weights",n)}}a.endBatch(),ye(l,()=>T.run())});try{ye(l,()=>T.run())}catch(g){throw g instanceof RangeError&&g.message.includes("Invalid array length")?new Error("Architecture layout failed: a declared `align row|column` directive likely contradicts the edge directions, or two declared alignments overlap on a shared node. Check that the order of members in each `align` chain is consistent with the edges between them, and that no node appears in two `align` directives along the same axis."):g}a.ready(g=>{Se.info("Ready",g),i(a)})})}gt(Be,"layoutArchitecture");var Gr=gt(async(L,b,A,G)=>{const N=G.db;N.setDiagramId(b);const v=N.getServices(),h=N.getJunctions(),i=N.getGroups(),r=N.getEdges(),a=N.getDataStructures(),f=qe(b),e=f.append("g");e.attr("class","architecture-edges");const u=f.append("g");u.attr("class","architecture-services");const t=f.append("g");t.attr("class","architecture-groups"),await br(N,u,v,b),Pr(N,u,h,b);const s=await Be(v,h,i,r,N,a);await Sr(e,s,N,b),await Fr(t,s,N,b),Xe(N,s),Qe(void 0,f,N.getConfigField("padding"),N.getConfigField("useMaxWidth"))},"draw"),Ur={draw:Gr},Vr={parser:Ge,get db(){return new Pe},renderer:Ur,styles:Rr};export{Vr as diagram}; diff --git a/apps/kimi-code/dist-web/assets/beancount-k_qm7-4y.js b/apps/kimi-code/dist-web/assets/beancount-k_qm7-4y.js new file mode 100644 index 0000000000000000000000000000000000000000..28b83dc015a6744aca7363a8e0948474f7fae693 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/beancount-k_qm7-4y.js @@ -0,0 +1 @@ +const n=Object.freeze(JSON.parse(`{"displayName":"Beancount","fileTypes":["beancount"],"name":"beancount","patterns":[{"match":";.*","name":"comment.line.beancount"},{"begin":"^\\\\s*(p(?:op|ush)tag)\\\\s+(#)([\\\\--9A-Z_a-z]+)","beginCaptures":{"1":{"name":"support.function.beancount"},"2":{"name":"keyword.operator.tag.beancount"},"3":{"name":"entity.name.tag.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.tag.beancount","patterns":[{"include":"#comments"},{"include":"#illegal"}]},{"begin":"^\\\\s*(include)\\\\s+(\\".*\\")","beginCaptures":{"1":{"name":"support.function.beancount"},"2":{"name":"string.quoted.double.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.include.beancount","patterns":[{"include":"#comments"},{"include":"#illegal"}]},{"begin":"^\\\\s*(option)\\\\s+(\\".*\\")\\\\s+(\\".*\\")","beginCaptures":{"1":{"name":"support.function.beancount"},"2":{"name":"support.variable.beancount"},"3":{"name":"string.quoted.double.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.option.beancount","patterns":[{"include":"#comments"},{"include":"#illegal"}]},{"begin":"^\\\\s*(plugin)\\\\s*(\\"(.*?)\\")\\\\s*(\\".*?\\")?","beginCaptures":{"1":{"name":"support.function.beancount"},"2":{"name":"string.quoted.double.beancount"},"3":{"name":"entity.name.function.beancount"},"4":{"name":"string.quoted.double.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"keyword.operator.directive.beancount","patterns":[{"include":"#comments"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s+(open|close|pad)\\\\b","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#account"},{"include":"#commodity"},{"match":",","name":"punctuation.separator.beancount"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s+(custom)\\\\b","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#string"},{"include":"#bool"},{"include":"#amount"},{"include":"#number"},{"include":"#date"},{"include":"#account"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s(event)","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.directive.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#string"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s(commodity)","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.directive.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#commodity"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s(note|document)","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.directive.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#account"},{"include":"#string"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s(price)","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.directive.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#commodity"},{"include":"#amount"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s(balance)","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.directive.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.dated.beancount","patterns":[{"include":"#comments"},{"include":"#meta"},{"include":"#account"},{"include":"#amount"},{"include":"#illegal"}]},{"begin":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})\\\\s*(txn|[!#%\\\\&*?CMPR-U])\\\\s*(\\".*?\\")?\\\\s*(\\".*?\\")?","beginCaptures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"},"6":{"name":"support.function.directive.beancount","patterns":[{"match":"txn|\\\\*","name":"support.function.directive.txn.completed.beancount"},{"match":"!","name":"support.function.directive.txn.incomplete.beancount"},{"match":"P","name":"support.function.directive.txn.padding.beancount"}]},"7":{"name":"string.quoted.tiers.beancount"},"8":{"name":"string.quoted.narration.beancount"}},"end":"(?=^(\\\\s*$|\\\\S))","name":"meta.directive.transaction.beancount","patterns":[{"include":"#comments"},{"include":"#posting"},{"include":"#meta"},{"include":"#tag"},{"include":"#link"},{"include":"#illegal"}]}],"repository":{"account":{"begin":"([A-Z][a-z]+)(:)","beginCaptures":{"1":{"name":"variable.language.beancount"},"2":{"name":"punctuation.separator.beancount"}},"end":"\\\\s","name":"meta.account.beancount","patterns":[{"begin":"(\\\\S+)(:?)","beginCaptures":{"1":{"name":"variable.other.account.beancount"},"2":{"name":"punctuation.separator.beancount"}},"end":"(:?)|(\\\\s)","patterns":[{"include":"$self"},{"include":"#illegal"}]}]},"amount":{"captures":{"1":{"name":"keyword.operator.modifier.beancount"},"2":{"name":"constant.numeric.currency.beancount"},"3":{"name":"entity.name.type.commodity.beancount"}},"match":"([-+|]?)(\\\\d+(?:,\\\\d{3})*(?:\\\\.\\\\d*)?)\\\\s*([A-Z][-'.0-9A-Z_]{0,22}[0-9A-Z])","name":"meta.amount.beancount"},"bool":{"captures":{"0":{"name":"constant.language.bool.beancount"},"2":{"name":"constant.numeric.currency.beancount"},"3":{"name":"entity.name.type.commodity.beancount"}},"match":"TRUE|FALSE"},"comments":{"captures":{"1":{"name":"comment.line.beancount"}},"match":"(;.*)$"},"commodity":{"match":"([A-Z][-'.0-9A-Z_]{0,22}[0-9A-Z])","name":"entity.name.type.commodity.beancount"},"cost":{"begin":"\\\\{\\\\{?","beginCaptures":{"0":{"name":"keyword.operator.assignment.beancount"}},"end":"}}?","endCaptures":{"0":{"name":"keyword.operator.assignment.beancount"}},"name":"meta.cost.beancount","patterns":[{"include":"#amount"},{"include":"#date"},{"match":",","name":"punctuation.separator.beancount"},{"include":"#illegal"}]},"date":{"captures":{"1":{"name":"constant.numeric.date.year.beancount"},"2":{"name":"punctuation.separator.beancount"},"3":{"name":"constant.numeric.date.month.beancount"},"4":{"name":"punctuation.separator.beancount"},"5":{"name":"constant.numeric.date.day.beancount"}},"match":"([0-9]{4})([-/|])([0-9]{2})([-/|])([0-9]{2})","name":"meta.date.beancount"},"flag":{"match":"(?<=\\\\s)([!#%\\\\&*?CMPR-U])(?=\\\\s+)","name":"keyword.other.beancount"},"illegal":{"match":"\\\\S","name":"invalid.illegal.unrecognized.beancount"},"link":{"captures":{"1":{"name":"keyword.operator.link.beancount"},"2":{"name":"markup.underline.link.beancount"}},"match":"(\\\\^)([\\\\--9A-Z_a-z]+)"},"meta":{"begin":"^\\\\s*([a-z][-0-9A-Z_a-z]+)(:)","beginCaptures":{"1":{"name":"keyword.operator.directive.beancount"},"2":{"name":"punctuation.separator.beancount"}},"end":"\\\\n","name":"meta.meta.beancount","patterns":[{"include":"#string"},{"include":"#account"},{"include":"#bool"},{"include":"#commodity"},{"include":"#date"},{"include":"#tag"},{"include":"#amount"},{"include":"#number"},{"include":"#comments"},{"include":"#illegal"}]},"number":{"captures":{"1":{"name":"keyword.operator.modifier.beancount"},"2":{"name":"constant.numeric.currency.beancount"}},"match":"([-+|]?)(\\\\d+(?:,\\\\d{3})*(?:\\\\.\\\\d*)?)"},"posting":{"begin":"^\\\\s+(?=([!A-Z]))","end":"(?=^(\\\\s*$|\\\\S|\\\\s*[A-Z]))","name":"meta.posting.beancount","patterns":[{"include":"#meta"},{"include":"#comments"},{"include":"#flag"},{"include":"#account"},{"include":"#amount"},{"include":"#cost"},{"include":"#date"},{"include":"#price"},{"include":"#illegal"}]},"price":{"begin":"@@?","beginCaptures":{"0":{"name":"keyword.operator.assignment.beancount"}},"end":"(?=([\\\\n;]))","name":"meta.price.beancount","patterns":[{"include":"#amount"},{"include":"#illegal"}]},"string":{"begin":"\\"","end":"\\"","name":"string.quoted.double.beancount","patterns":[{"match":"\\\\\\\\.","name":"constant.character.escape.beancount"}]},"tag":{"captures":{"1":{"name":"keyword.operator.tag.beancount"},"2":{"name":"entity.name.tag.beancount"}},"match":"(#)([\\\\--9A-Z_a-z]+)"}},"scopeName":"text.beancount"}`)),e=[n];export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/blade-2xfisSek.js b/apps/kimi-code/dist-web/assets/blade-2xfisSek.js new file mode 100644 index 0000000000000000000000000000000000000000..bc5c3e628cc702cb9afe5aba7047e9ec313b4459 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/blade-2xfisSek.js @@ -0,0 +1 @@ +import e from"./html-derivative-DlHx6ybY.js";import t from"./html-pp8916En.js";import n from"./xml-sdJ4AIDG.js";import a from"./sql-CRqJ_cUM.js";import r from"./javascript-wDzz0qaB.js";import i from"./json-Cp-IABpG.js";import p from"./css-CLj8gQPS.js";import"./java-CylS5w8V.js";const o=Object.freeze(JSON.parse(`{"displayName":"Blade","fileTypes":["blade.php"],"foldingStartMarker":"(/\\\\*|\\\\{\\\\s*$|<<))","beginCaptures":{"0":{"name":"punctuation.whitespace.embedded.leading.php"}},"end":"(?!\\\\G)(\\\\s*$\\\\n)?","endCaptures":{"0":{"name":"punctuation.whitespace.embedded.trailing.php"}},"patterns":[{"begin":"<\\\\?(?i:php|=)?","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"}},"contentName":"source.php","end":"(\\\\?)>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"source.php"}},"name":"meta.embedded.block.php","patterns":[{"include":"#language"}]}]},{"begin":"<\\\\?(?i:php|=)?(?![^?]*\\\\?>)","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"}},"contentName":"source.php","end":"(\\\\?)>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"source.php"}},"name":"meta.embedded.block.php","patterns":[{"include":"#language"}]},{"begin":"<\\\\?(?i:php|=)?","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"}},"end":">","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"}},"name":"meta.embedded.line.php","patterns":[{"captures":{"1":{"name":"source.php"},"2":{"name":"punctuation.section.embedded.end.php"},"3":{"name":"source.php"}},"match":"\\\\G(\\\\s*)((\\\\?))(?=>)","name":"meta.special.empty-tag.php"},{"begin":"\\\\G","contentName":"source.php","end":"(\\\\?)(?=>)","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"source.php"}},"patterns":[{"include":"#language"}]}]}]}},"name":"blade","patterns":[{"include":"text.html.derivative"}],"repository":{"balance_brackets":{"patterns":[{"begin":"\\\\(","end":"\\\\)","patterns":[{"include":"#balance_brackets"}]},{"match":"[^()]+"}]},"blade":{"patterns":[{"begin":"\\\\{\\\\{--","beginCaptures":{"0":{"name":"punctuation.definition.comment.begin.blade"}},"end":"--}}","endCaptures":{"0":{"name":"punctuation.definition.comment.end.blade"}},"name":"comment.block.blade","patterns":[{"begin":"^(\\\\s*)(?=<\\\\?(?![^?]*\\\\?>))","beginCaptures":{"0":{"name":"punctuation.whitespace.embedded.leading.php"}},"end":"(?!\\\\G)(\\\\s*$\\\\n)?","endCaptures":{"0":{"name":"punctuation.whitespace.embedded.trailing.php"}},"name":"invalid.illegal.php-code-in-comment.blade","patterns":[{"begin":"<\\\\?(?i:php|=)?","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"}},"contentName":"source.php","end":"(\\\\?)>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"source.php"}},"name":"meta.embedded.block.php","patterns":[{"include":"#language"}]}]},{"begin":"<\\\\?(?i:php|=)?(?![^?]*\\\\?>)","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"}},"contentName":"source.php","end":"(\\\\?)>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"source.php"}},"name":"invalid.illegal.php-code-in-comment.blade.meta.embedded.block.php","patterns":[{"include":"#language"}]},{"begin":"<\\\\?(?i:php|=)?","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"}},"end":">","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"}},"name":"invalid.illegal.php-code-in-comment.blade.meta.embedded.line.php","patterns":[{"captures":{"1":{"name":"source.php"},"2":{"name":"punctuation.section.embedded.end.php"},"3":{"name":"source.php"}},"match":"\\\\G(\\\\s*)((\\\\?))(?=>)","name":"meta.special.empty-tag.php"},{"begin":"\\\\G","contentName":"source.php","end":"(\\\\?)(?=>)","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"source.php"}},"patterns":[{"include":"#language"}]}]}]},{"begin":"(?)","name":"comment.line.double-slash.php"}]},{"begin":"(^\\\\s+)?(?=#)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.php"}},"end":"(?!\\\\G)","patterns":[{"begin":"#","beginCaptures":{"0":{"name":"punctuation.definition.comment.php"}},"end":"\\\\n|(?=\\\\?>)","name":"comment.line.number-sign.php"}]}]},"constants":{"patterns":[{"match":"(?i)\\\\b(TRUE|FALSE|NULL|__(FILE|DIR|FUNCTION|CLASS|METHOD|LINE|NAMESPACE)__|ON|OFF|YES|NO|NL|BR|TAB)\\\\b","name":"constant.language.php"},{"captures":{"1":{"name":"punctuation.separator.inheritance.php"}},"match":"(\\\\\\\\)?\\\\b(DEFAULT_INCLUDE_PATH|EAR_(INSTALL|EXTENSION)_DIR|E_(ALL|COMPILE_(ERROR|WARNING)|CORE_(ERROR|WARNING)|DEPRECATED|ERROR|NOTICE|PARSE|RECOVERABLE_ERROR|STRICT|USER_(DEPRECATED|ERROR|NOTICE|WARNING)|WARNING)|PHP_(ROUND_HALF_(DOWN|EVEN|ODD|UP)|(MAJOR|MINOR|RELEASE)_VERSION|MAXPATHLEN|BINDIR|SHLIB_SUFFIX|SYSCONFDIR|SAPI|CONFIG_FILE_(PATH|SCAN_DIR)|INT_(MAX|SIZE)|ZTS|OS|OUTPUT_HANDLER_(START|CONT|END)|DEBUG|DATADIR|URL_(SCHEME|HOST|USER|PORT|PASS|PATH|QUERY|FRAGMENT)|PREFIX|EXTRA_VERSION|EXTENSION_DIR|EOL|VERSION(_ID)?|WINDOWS_(NT_(SERVER|DOMAIN_CONTROLLER|WORKSTATION)|VERSION_(M(?:AJOR|INOR))|BUILD|SUITEMASK|SP_(M(?:AJOR|INOR))|PRODUCTTYPE|PLATFORM)|LIBDIR|LOCALSTATEDIR)|STD(ERR|IN|OUT)|ZEND_(DEBUG_BUILD|THREAD_SAFE))\\\\b","name":"support.constant.core.php"},{"captures":{"1":{"name":"punctuation.separator.inheritance.php"}},"match":"(\\\\\\\\)?\\\\b(__COMPILER_HALT_OFFSET__|AB(MON_([1-9]|10|11|12)|DAY[1-7])|AM_STR|ASSERT_(ACTIVE|BAIL|CALLBACK_QUIET_EVAL|WARNING)|ALT_DIGITS|CASE_(UPPER|LOWER)|CHAR_MAX|CONNECTION_(ABORTED|NORMAL|TIMEOUT)|CODESET|COUNT_(NORMAL|RECURSIVE)|CREDITS_(ALL|DOCS|FULLPAGE|GENERAL|GROUP|MODULES|QA|SAPI)|CRYPT_(BLOWFISH|EXT_DES|MD5|SHA(256|512)|SALT_LENGTH|STD_DES)|CURRENCY_SYMBOL|D_(T_)?FMT|DATE_(ATOM|COOKIE|ISO8601|RFC(822|850|1036|1123|2822|3339)|RSS|W3C)|DAY_[1-7]|DECIMAL_POINT|DIRECTORY_SEPARATOR|ENT_(COMPAT|IGNORE|(NO)?QUOTES)|EXTR_(IF_EXISTS|OVERWRITE|PREFIX_(ALL|IF_EXISTS|INVALID|SAME)|REFS|SKIP)|ERA(_(D_(T_)?FMT)|T_FMT|YEAR)?|FRAC_DIGITS|GROUPING|HASH_HMAC|HTML_(ENTITIES|SPECIALCHARS)|INF|INFO_(ALL|CREDITS|CONFIGURATION|ENVIRONMENT|GENERAL|LICENSEMODULES|VARIABLES)|INI_(ALL|CANNER_(NORMAL|RAW)|PERDIR|SYSTEM|USER)|INT_(CURR_SYMBOL|FRAC_DIGITS)|LC_(ALL|COLLATE|CTYPE|MESSAGES|MONETARY|NUMERIC|TIME)|LOCK_(EX|NB|SH|UN)|LOG_(ALERT|AUTH(PRIV)?|CRIT|CRON|CONS|DAEMON|DEBUG|EMERG|ERR|INFO|LOCAL[1-7]|LPR|KERN|MAIL|NEWS|NODELAY|NOTICE|NOWAIT|ODELAY|PID|PERROR|WARNING|SYSLOG|UCP|USER)|M_(1_PI|SQRT(1_2|[23]|PI)|2_(SQRT)?PI|PI(_([24]))?|E(ULER)?|LN(10|2|PI)|LOG(10|2)E)|MON_([1-9]|10|11|12|DECIMAL_POINT|GROUPING|THOUSANDS_SEP)|N_(CS_PRECEDES|SEP_BY_SPACE|SIGN_POSN)|NAN|NEGATIVE_SIGN|NO(EXPR|STR)|P_(CS_PRECEDES|SEP_BY_SPACE|SIGN_POSN)|PM_STR|POSITIVE_SIGN|PATH(_SEPARATOR|INFO_(EXTENSION|(BASE|DIR|FILE)NAME))|RADIXCHAR|SEEK_(CUR|END|SET)|SORT_(ASC|DESC|LOCALE_STRING|REGULAR|STRING)|STR_PAD_(BOTH|LEFT|RIGHT)|T_FMT(_AMPM)?|THOUSEP|THOUSANDS_SEP|UPLOAD_ERR_(CANT_WRITE|EXTENSION|(FORM|INI)_SIZE|NO_(FILE|TMP_DIR)|OK|PARTIAL)|YES(EXPR|STR))\\\\b","name":"support.constant.std.php"},{"captures":{"1":{"name":"punctuation.separator.inheritance.php"}},"match":"(\\\\\\\\)?\\\\b(GLOB_(MARK|BRACE|NO(SORT|CHECK|ESCAPE)|ONLYDIR|ERR|AVAILABLE_FLAGS)|XML_(SAX_IMPL|(DTD|DOCUMENT(_(FRAG|TYPE))?|HTML_DOCUMENT|NOTATION|NAMESPACE_DECL|PI|COMMENT|DATA_SECTION|TEXT)_NODE|OPTION_(SKIP_(TAGSTART|WHITE)|CASE_FOLDING|TARGET_ENCODING)|ERROR_((BAD_CHAR|(ATTRIBUTE_EXTERNAL|BINARY|PARAM|RECURSIVE)_ENTITY)_REF|MISPLACED_XML_PI|SYNTAX|NONE|NO_(MEMORY|ELEMENTS)|TAG_MISMATCH|INCORRECT_ENCODING|INVALID_TOKEN|DUPLICATE_ATTRIBUTE|UNCLOSED_(CDATA_SECTION|TOKEN)|UNDEFINED_ENTITY|UNKNOWN_ENCODING|JUNK_AFTER_DOC_ELEMENT|PARTIAL_CHAR|EXTERNAL_ENTITY_HANDLING|ASYNC_ENTITY)|ENTITY_(((REF|DECL)_)?NODE)|ELEMENT(_DECL)?_NODE|LOCAL_NAMESPACE|ATTRIBUTE_(N(?:MTOKEN(S)?|OTATION|ODE))|CDATA|ID(REF(S)?)?|DECL_NODE|ENTITY|ENUMERATION)|MHASH_(RIPEMD(128|160|256|320)|GOST|MD([245])|SHA(1|224|256|384|512)|SNEFRU256|HAVAL(128|160|192|224|256)|CRC23(B)?|TIGER(1(?:28|60))?|WHIRLPOOL|ADLER32)|MYSQL_(BOTH|NUM|CLIENT_(SSL|COMPRESS|IGNORE_SPACE|INTERACTIVE|ASSOC))|MYSQLI_(REPORT_(STRICT|INDEX|OFF|ERROR|ALL)|REFRESH_(GRANT|MASTER|BACKUP_LOG|STATUS|SLAVE|HOSTS|THREADS|TABLES|LOG)|READ_DEFAULT_(FILE|GROUP)|(GROUP|MULTIPLE_KEY|BINARY|BLOB)_FLAG|BOTH|STMT_ATTR_(CURSOR_TYPE|UPDATE_MAX_LENGTH|PREFETCH_ROWS)|STORE_RESULT|SERVER_QUERY_(NO_((GOOD_)?INDEX_USED)|WAS_SLOW)|SET_(CHARSET_NAME|FLAG)|NO_(D(?:EFAULT_VALUE_FLAG|ATA))|NOT_NULL_FLAG|NUM(_FLAG)?|CURSOR_TYPE_(READ_ONLY|SCROLLABLE|NO_CURSOR|FOR_UPDATE)|CLIENT_(SSL|NO_SCHEMA|COMPRESS|IGNORE_SPACE|INTERACTIVE|FOUND_ROWS)|TYPE_(GEOMETRY|((MEDIUM|LONG|TINY)_)?BLOB|BIT|SHORT|STRING|SET|YEAR|NULL|NEWDECIMAL|NEWDATE|CHAR|TIME(STAMP)?|TINY|INT24|INTERVAL|DOUBLE|DECIMAL|DATE(TIME)?|ENUM|VAR_STRING|FLOAT|LONG(LONG)?)|TIME_STAMP_FLAG|INIT_COMMAND|ZEROFILL_FLAG|ON_UPDATE_NOW_FLAG|OPT_(NET_((CMD|READ)_BUFFER_SIZE)|CONNECT_TIMEOUT|INT_AND_FLOAT_NATIVE|LOCAL_INFILE)|DEBUG_TRACE_ENABLED|DATA_TRUNCATED|USE_RESULT|(ENUM|(PART|PRI|UNIQUE)_KEY|UNSIGNED)_FLAG|ASSOC|ASYNC|AUTO_INCREMENT_FLAG)|MCRYPT_(RC([26])|RIJNDAEL_(128|192|256)|RAND|GOST|XTEA|MODE_(STREAM|NOFB|CBC|CFB|OFB|ECB)|MARS|BLOWFISH(_COMPAT)?|SERPENT|SKIPJACK|SAFER(64|128|PLUS)|CRYPT|CAST_(128|256)|TRIPLEDES|THREEWAY|TWOFISH|IDEA|(3)?DES|DECRYPT|DEV_(U)?RANDOM|PANAMA|ENCRYPT|ENIGNA|WAKE|LOKI97|ARCFOUR(_IV)?)|STREAM_(REPORT_ERRORS|MUST_SEEK|MKDIR_RECURSIVE|BUFFER_(NONE|FULL|LINE)|SHUT_(RD)?WR|SOCK_(RDM|RAW|STREAM|SEQPACKET|DGRAM)|SERVER_(BIND|LISTEN)|NOTIFY_(REDIRECTED|RESOLVE|MIME_TYPE_IS|SEVERITY_(INFO|ERR|WARN)|COMPLETED|CONNECT|PROGRESS|FILE_SIZE_IS|FAILURE|AUTH_(RE(?:QUIRED|SULT)))|CRYPTO_METHOD_((SSLv2(3)?|SSLv3|TLS)_(CLIENT|SERVER))|CLIENT_((ASYNC_)?CONNECT|PERSISTENT)|CAST_(AS_STREAM|FOR_SELECT)|(I(?:GNORE|S))_URL|IPPROTO_(RAW|TCP|ICMP|IP|UDP)|OOB|OPTION_(READ_(BUFFER|TIMEOUT)|BLOCKING|WRITE_BUFFER)|URL_STAT_(LINK|QUIET)|USE_PATH|PEEK|PF_(INET(6)?|UNIX)|ENFORCE_SAFE_MODE|FILTER_(ALL|READ|WRITE))|SUNFUNCS_RET_(DOUBLE|STRING|TIMESTAMP)|SQLITE_(READONLY|ROW|MISMATCH|MISUSE|BOTH|BUSY|SCHEMA|NOMEM|NOTFOUND|NOTADB|NOLFS|NUM|CORRUPT|CONSTRAINT|CANTOPEN|TOOBIG|INTERRUPT|INTERNAL|IOERR|OK|DONE|PROTOCOL|PERM|ERROR|EMPTY|FORMAT|FULL|LOCKED|ABORT|ASSOC|AUTH)|SQLITE3_(BOTH|BLOB|NUM|NULL|TEXT|INTEGER|OPEN_(READ(ONLY|WRITE)|CREATE)|FLOAT_ASSOC)|CURL(M_(BAD_((EASY)?HANDLE)|CALL_MULTI_PERFORM|INTERNAL_ERROR|OUT_OF_MEMORY|OK)|MSG_DONE|SSH_AUTH_(HOST|NONE|DEFAULT|PUBLICKEY|PASSWORD|KEYBOARD)|CLOSEPOLICY_(SLOWEST|CALLBACK|OLDEST|LEAST_(RECENTLY_USED|TRAFFIC)|INFO_(REDIRECT_(COUNT|TIME)|REQUEST_SIZE|SSL_VERIFYRESULT|STARTTRANSFER_TIME|(S(?:IZE|PEED))_((?:DOWN|UP)LOAD)|HTTP_CODE|HEADER_(OUT|SIZE)|NAMELOOKUP_TIME|CONNECT_TIME|CONTENT_(TYPE|LENGTH_((?:DOWN|UP)LOAD))|CERTINFO|TOTAL_TIME|PRIVATE|PRETRANSFER_TIME|EFFECTIVE_URL|FILETIME)|OPT_(RESUME_FROM|RETURNTRANSFER|REDIR_PROTOCOLS|REFERER|READ(DATA|FUNCTION)|RANGE|RANDOM_FILE|MAX(CONNECTS|REDIRS)|BINARYTRANSFER|BUFFERSIZE|SSH_(HOST_PUBLIC_KEY_MD5|(P(?:RIVATE|UBLIC))_KEYFILE)|AUTH_TYPES)|SSL(CERT(TYPE|PASSWD)?|ENGINE(_DEFAULT)?|VERSION|KEY(TYPE|PASSWD)?)|SSL_(CIPHER_LIST|VERIFY(HOST|PEER))|STDERR|HTTP(GET|HEADER|200ALIASES|_VERSION|PROXYTUNNEL|AUTH)|HEADER(FUNCTION)?|NO(BODY|SIGNAL|PROGRESS)|NETRC|CRLF|CONNECTTIMEOUT(_MS)?|COOKIE(SESSION|JAR|FILE)?|CUSTOMREQUEST|CERTINFO|CLOSEPOLICY|CA(INFO|PATH)|TRANSFERTEXT|TCP_NODELAY|TIME(CONDITION|OUT(_MS)?|VALUE)|INTERFACE|INFILE(SIZE)?|IPRESOLVE|DNS_(CACHE_TIMEOUT|USE_GLOBAL_CACHE)|URL|USER(AGENT|PWD)|UNRESTRICTED_AUTH|UPLOAD|PRIVATE|PROGRESSFUNCTION|PROXY(TYPE|USERPWD|PORT|AUTH)?|PROTOCOLS|PORT|POST(REDIR|QUOTE|FIELDS)?|PUT|EGDSOCKET|ENCODING|VERBOSE|KRB4LEVEL|KEYPASSWD|QUOTE|FRESH_CONNECT|FTP(APPEND|LISTONLY|PORT|SSLAUTH)|FTP_(SSL|SKIP_PASV_IP|CREATE_MISSING_DIRS|USE_EP(RT|SV)|FILEMETHOD)|FILE(TIME)?|FORBID_REUSE|FOLLOWLOCATION|FAILONERROR|WRITE(FUNCTION|HEADER)|LOW_SPEED_(LIMIT|TIME)|AUTOREFERER)|PROXY_(HTTP|SOCKS([45]))|PROTO_(SCP|SFTP|HTTP(S)?|TELNET|TFTP|DICT|FTP(S)?|FILE|LDAP(S)?|ALL)|E_((RE(?:CV|AD))_ERROR|GOT_NOTHING|MALFORMAT_USER|BAD_(CONTENT_ENCODING|CALLING_ORDER|PASSWORD_ENTERED|FUNCTION_ARGUMENT)|SSH|SSL_(CIPHER|CONNECT_ERROR|CERTPROBLEM|CACERT|PEER_CERTIFICATE|ENGINE_(NOTFOUND|SETFAILED))|SHARE_IN_USE|SEND_ERROR|HTTP_(RANGE_ERROR|NOT_FOUND|PORT_FAILED|POST_ERROR)|COULDNT_(RESOLVE_(HOST|PROXY)|CONNECT)|TOO_MANY_REDIRECTS|TELNET_OPTION_SYNTAX|OBSOLETE|OUT_OF_MEMORY|OPERATION|TIMEOUTED|OK|URL_MALFORMAT(_USER)?|UNSUPPORTED_PROTOCOL|UNKNOWN_TELNET_OPTION|PARTIAL_FILE|FTP_(BAD_DOWNLOAD_RESUME|SSL_FAILED|COULDNT_(RETR_FILE|GET_SIZE|STOR_FILE|SET_(BINARY|ASCII)|USE_REST)|CANT_(GET_HOST|RECONNECT)|USER_PASSWORD_INCORRECT|PORT_FAILED|QUOTE_ERROR|WRITE_ERROR|WEIRD_((PASS|PASV|SERVER|USER)_REPLY|227_FORMAT)|ACCESS_DENIED)|FILESIZE_EXCEEDED|FILE_COULDNT_READ_FILE|FUNCTION_NOT_FOUND|FAILED_INIT|WRITE_ERROR|LIBRARY_NOT_FOUND|LDAP_(SEARCH_FAILED|CANNOT_BIND|INVALID_URL)|ABORTED_BY_CALLBACK)|VERSION_NOW|FTP(METHOD_(MULTI|SINGLE|NO)CWD|SSL_(ALL|NONE|CONTROL|TRY)|AUTH_(DEFAULT|SSL|TLS))|AUTH_(ANY(SAFE)?|BASIC|DIGEST|GSSNEGOTIATE|NTLM))|CURL_(HTTP_VERSION_(1_([01])|NONE)|NETRC_(REQUIRED|IGNORED|OPTIONAL)|TIMECOND_(IF(UN)?MODSINCE|LASTMOD)|IPRESOLVE_(V([46])|WHATEVER)|VERSION_(SSL|IPV6|KERBEROS4|LIBZ))|IMAGETYPE_(GIF|XBM|BMP|SWF|COUNT|TIFF_(MM|II)|ICO|IFF|UNKNOWN|JB2|JPX|JP2|JPC|JPEG(2000)?|PSD|PNG|WBMP)|INPUT_(REQUEST|GET|SERVER|SESSION|COOKIE|POST|ENV)|ICONV_(MIME_DECODE_(STRICT|CONTINUE_ON_ERROR)|IMPL|VERSION)|DNS_(MX|SRV|SOA|HINFO|NS|NAPTR|CNAME|TXT|PTR|ANY|ALL|AAAA|A(6)?)|DOM(STRING_SIZE_ERR)|DOM_((SYNTAX|HIERARCHY_REQUEST|NO_((?:MODIFICATION|DATA)_ALLOWED)|NOT_(FOUND|SUPPORTED)|NAMESPACE|INDEX_SIZE|USE_ATTRIBUTE|VALID_(MODIFICATION|STATE|CHARACTER|ACCESS)|PHP|VALIDATION|WRONG_DOCUMENT)_ERR)|JSON_(HEX_(TAG|QUOT|AMP|APOS)|NUMERIC_CHECK|ERROR_(SYNTAX|STATE_MISMATCH|NONE|CTRL_CHAR|DEPTH|UTF8)|FORCE_OBJECT)|PREG_((D_UTF8(_OFFSET)?|NO|INTERNAL|(BACKTRACK|RECURSION)_LIMIT)_ERROR|GREP_INVERT|SPLIT_(NO_EMPTY|(DELIM|OFFSET)_CAPTURE)|SET_ORDER|OFFSET_CAPTURE|PATTERN_ORDER)|PSFS_(PASS_ON|ERR_FATAL|FEED_ME|FLAG_(NORMAL|FLUSH_(CLOSE|INC)))|PCRE_VERSION|POSIX_(([FRWX])_OK|S_IF(REG|BLK|SOCK|CHR|IFO))|FNM_(NOESCAPE|CASEFOLD|PERIOD|PATHNAME)|FILTER_(REQUIRE_(SCALAR|ARRAY)|NULL_ON_FAILURE|CALLBACK|DEFAULT|UNSAFE_RAW|SANITIZE_(MAGIC_QUOTES|STRING|STRIPPED|SPECIAL_CHARS|NUMBER_(INT|FLOAT)|URL|EMAIL|ENCODED|FULL_SPCIAL_CHARS)|VALIDATE_(REGEXP|BOOLEAN|INT|IP|URL|EMAIL|FLOAT)|FORCE_ARRAY|FLAG_(SCHEME_REQUIRED|STRIP_(BACKTICK|HIGH|LOW)|HOST_REQUIRED|NONE|NO_(RES|PRIV)_RANGE|ENCODE_QUOTES|IPV([46])|PATH_REQUIRED|EMPTY_STRING_NULL|ENCODE_(HIGH|LOW|AMP)|QUERY_REQUIRED|ALLOW_(SCIENTIFIC|HEX|THOUSAND|OCTAL|FRACTION)))|FILE_(BINARY|SKIP_EMPTY_LINES|NO_DEFAULT_CONTEXT|TEXT|IGNORE_NEW_LINES|USE_INCLUDE_PATH|APPEND)|FILEINFO_(RAW|MIME(_(ENCODING|TYPE))?|SYMLINK|NONE|CONTINUE|DEVICES|PRESERVE_ATIME)|FORCE_(DEFLATE|GZIP)|LIBXML_(XINCLUDE|NSCLEAN|NO(XMLDECL|BLANKS|NET|CDATA|ERROR|EMPTYTAG|ENT|WARNING)|COMPACT|DTD(VALID|LOAD|ATTR)|((DOTTED|LOADED)_)?VERSION|PARSEHUGE|ERR_(NONE|ERROR|FATAL|WARNING)))\\\\b","name":"support.constant.ext.php"},{"captures":{"1":{"name":"punctuation.separator.inheritance.php"}},"match":"(\\\\\\\\)?\\\\b(T_(RETURN|REQUIRE(_ONCE)?|GOTO|GLOBAL|(MINUS|MOD|MUL|XOR)_EQUAL|METHOD_C|ML_COMMENT|BREAK|BOOL_CAST|BOOLEAN_(AND|OR)|BAD_CHARACTER|SR(_EQUAL)?|STRING(_CAST|VARNAME)?|START_HEREDOC|STATIC|SWITCH|SL(_EQUAL)?|HALT_COMPILER|NS_(C|SEPARATOR)|NUM_STRING|NEW|NAMESPACE|CHARACTER|COMMENT|CONSTANT(_ENCAPSED_STRING)?|CONCAT_EQUAL|CONTINUE|CURLY_OPEN|CLOSE_TAG|CLONE|CLASS(_C)?|CASE|CATCH|TRY|THROW|IMPLEMENTS|ISSET|IS_((GREATER|SMALLER)_OR_EQUAL|(NOT_)?(IDENTICAL|EQUAL))|INSTANCEOF|INCLUDE(_ONCE)?|INC|INT_CAST|INTERFACE|INLINE_HTML|IF|OR_EQUAL|OBJECT_(CAST|OPERATOR)|OPEN_TAG(_WITH_ECHO)?|OLD_FUNCTION|DNUMBER|DIR|DIV_EQUAL|DOC_COMMENT|DOUBLE_(ARROW|CAST|COLON)|DOLLAR_OPEN_CURLY_BRACES|DO|DEC|DECLARE|DEFAULT|USE|UNSET(_CAST)?|PRINT|PRIVATE|PROTECTED|PUBLIC|PLUS_EQUAL|PAAMAYIM_NEKUDOTAYIM|EXTENDS|EXIT|EMPTY|ENCAPSED_AND_WHITESPACE|END(SWITCH|IF|DECLARE|FOR(EACH)?|WHILE)|END_HEREDOC|ECHO|EVAL|ELSE(IF)?|VAR(IABLE)?|FINAL|FILE|FOR(EACH)?|FUNC_C|FUNCTION|WHITESPACE|WHILE|LNUMBER|LIST|LINE|LOGICAL_(AND|OR|XOR)|ARRAY_(CAST)?|ABSTRACT|AS|AND_EQUAL))\\\\b","name":"support.constant.parser-token.php"},{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"constant.other.php"}]},"function-call":{"patterns":[{"begin":"(?i)(\\\\\\\\?\\\\b[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*(?:\\\\\\\\[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)+)\\\\s*(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"#namespace"},{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"entity.name.function.php"}]},"2":{"name":"punctuation.definition.arguments.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.bracket.round.php"}},"name":"meta.function-call.php","patterns":[{"include":"#language"}]},{"begin":"(?i)(\\\\\\\\)?\\\\b([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"#namespace"}]},"2":{"patterns":[{"include":"#support"},{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"entity.name.function.php"}]},"3":{"name":"punctuation.definition.arguments.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.bracket.round.php"}},"name":"meta.function-call.php","patterns":[{"include":"#language"}]},{"match":"(?i)\\\\b(print|echo)\\\\b","name":"support.function.construct.output.php"}]},"function-parameters":{"patterns":[{"include":"#comments"},{"match":",","name":"punctuation.separator.delimiter.php"},{"begin":"(?i)(array)\\\\s+((&)?\\\\s*(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(=)\\\\s*(array)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"storage.type.php"},"2":{"name":"variable.other.php"},"3":{"name":"storage.modifier.reference.php"},"4":{"name":"punctuation.definition.variable.php"},"5":{"name":"keyword.operator.assignment.php"},"6":{"name":"support.function.construct.php"},"7":{"name":"punctuation.definition.array.begin.bracket.round.php"}},"contentName":"meta.array.php","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.array.end.bracket.round.php"}},"name":"meta.function.parameter.array.php","patterns":[{"include":"#comments"},{"include":"#strings"},{"include":"#numbers"}]},{"captures":{"1":{"name":"storage.type.php"},"2":{"name":"variable.other.php"},"3":{"name":"storage.modifier.reference.php"},"4":{"name":"punctuation.definition.variable.php"},"5":{"name":"keyword.operator.assignment.php"},"6":{"name":"constant.language.php"},"7":{"name":"punctuation.section.array.begin.php"},"8":{"patterns":[{"include":"#parameter-default-types"}]},"9":{"name":"punctuation.section.array.end.php"},"10":{"name":"invalid.illegal.non-null-typehinted.php"}},"match":"(?i)(array|callable)\\\\s+((&)?\\\\s*(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)(?:\\\\s*(=)\\\\s*(?:(null)|(\\\\[)((?>[^]\\\\[]+|\\\\[\\\\g<8>])*)(])|(\\\\S*?\\\\(\\\\)|\\\\S*?)))?\\\\s*(?=[),]|/[*/]|#|$)","name":"meta.function.parameter.array.php"},{"begin":"(?i)(\\\\\\\\?(?:[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*\\\\\\\\)*)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s+((&)?\\\\s*(\\\\.\\\\.\\\\.)?(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)","beginCaptures":{"1":{"name":"support.other.namespace.php","patterns":[{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"storage.type.php"},{"match":"\\\\\\\\","name":"punctuation.separator.inheritance.php"}]},"2":{"name":"storage.type.php"},"3":{"name":"variable.other.php"},"4":{"name":"storage.modifier.reference.php"},"5":{"name":"keyword.operator.variadic.php"},"6":{"name":"punctuation.definition.variable.php"}},"end":"(?=[),]|/[*/]|#)","name":"meta.function.parameter.typehinted.php","patterns":[{"begin":"=","beginCaptures":{"0":{"name":"keyword.operator.assignment.php"}},"end":"(?=[),]|/[*/]|#)","patterns":[{"include":"#language"}]}]},{"captures":{"1":{"name":"variable.other.php"},"2":{"name":"storage.modifier.reference.php"},"3":{"name":"keyword.operator.variadic.php"},"4":{"name":"punctuation.definition.variable.php"}},"match":"(?i)((&)?\\\\s*(\\\\.\\\\.\\\\.)?(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(?=[),]|/[*/]|#|$)","name":"meta.function.parameter.no-default.php"},{"begin":"(?i)((&)?\\\\s*(\\\\.\\\\.\\\\.)?(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(=)\\\\s*(?:(\\\\[)((?>[^]\\\\[]+|\\\\[\\\\g<6>])*)(]))?","beginCaptures":{"1":{"name":"variable.other.php"},"2":{"name":"storage.modifier.reference.php"},"3":{"name":"keyword.operator.variadic.php"},"4":{"name":"punctuation.definition.variable.php"},"5":{"name":"keyword.operator.assignment.php"},"6":{"name":"punctuation.section.array.begin.php"},"7":{"patterns":[{"include":"#parameter-default-types"}]},"8":{"name":"punctuation.section.array.end.php"}},"end":"(?=[),]|/[*/]|#)","name":"meta.function.parameter.default.php","patterns":[{"include":"#parameter-default-types"}]}]},"heredoc":{"patterns":[{"begin":"(?i)(?=<<<\\\\s*(\\"?)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)(\\\\1)\\\\s*$)","end":"(?!\\\\G)","name":"string.unquoted.heredoc.php","patterns":[{"include":"#heredoc_interior"}]},{"begin":"(?=<<<\\\\s*'([A-Z_a-z]+[0-9A-Z_a-z]*)'\\\\s*$)","end":"(?!\\\\G)","name":"string.unquoted.nowdoc.php","patterns":[{"include":"#nowdoc_interior"}]}]},"heredoc_interior":{"patterns":[{"begin":"(<<<)\\\\s*(\\"?)(HTML)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"text.html","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.html","patterns":[{"include":"#interpolation"},{"include":"text.html.basic"}]},{"begin":"(<<<)\\\\s*(\\"?)(BLADE)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"text.blade","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.blade","patterns":[{"include":"#interpolation"},{"include":"text.html.basic"},{"include":"#blade"}]},{"begin":"(<<<)\\\\s*(\\"?)(XML)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"text.xml","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.xml","patterns":[{"include":"#interpolation"},{"include":"text.xml"}]},{"begin":"(<<<)\\\\s*(\\"?)(SQL)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.sql","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.sql","patterns":[{"include":"#interpolation"},{"include":"source.sql"}]},{"begin":"(<<<)\\\\s*(\\"?)(J(?:AVASCRIPT|S))(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.js","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.js","patterns":[{"include":"#interpolation"},{"include":"source.js"}]},{"begin":"(<<<)\\\\s*(\\"?)(JSON)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.json","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.json","patterns":[{"include":"#interpolation"},{"include":"source.json"}]},{"begin":"(<<<)\\\\s*(\\"?)(CSS)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.css","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"name":"meta.embedded.css","patterns":[{"include":"#interpolation"},{"include":"source.css"}]},{"begin":"(<<<)\\\\s*(\\"?)(REGEXP?)(\\\\2)(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"string.regexp.heredoc.php","end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.heredoc.php"}},"patterns":[{"include":"#interpolation"},{"match":"(\\\\\\\\){1,2}[]$.\\\\[^{}]","name":"constant.character.escape.regex.php"},{"captures":{"1":{"name":"punctuation.definition.arbitrary-repitition.php"},"3":{"name":"punctuation.definition.arbitrary-repitition.php"}},"match":"(\\\\{)\\\\d+(,\\\\d+)?(})","name":"string.regexp.arbitrary-repitition.php"},{"begin":"\\\\[(?:\\\\^?])?","captures":{"0":{"name":"punctuation.definition.character-class.php"}},"end":"]","name":"string.regexp.character-class.php","patterns":[{"match":"\\\\\\\\[]'\\\\[\\\\\\\\]","name":"constant.character.escape.php"}]},{"match":"[$*+^]","name":"keyword.operator.regexp.php"},{"begin":"(?i)(?<=^|\\\\s)(#)\\\\s(?=[-\\\\t !,.0-9?_a-z\\\\x7F-ÿ[^\\\\x00-\\\\x7F]]*$)","beginCaptures":{"1":{"name":"punctuation.definition.comment.php"}},"end":"$","endCaptures":{"0":{"name":"punctuation.definition.comment.php"}},"name":"comment.line.number-sign.php"}]},{"begin":"(?i)(<<<)\\\\s*(\\"?)([_a-z\\\\x7F-ÿ]+[0-9_a-z\\\\x7F-ÿ]*)(\\\\2)(\\\\s*)","beginCaptures":{"1":{"name":"punctuation.definition.string.php"},"3":{"name":"keyword.operator.heredoc.php"},"5":{"name":"invalid.illegal.trailing-whitespace.php"}},"end":"^\\\\s*(\\\\3)\\\\b","endCaptures":{"1":{"name":"keyword.operator.heredoc.php"}},"patterns":[{"include":"#interpolation"}]}]},"instantiation":{"begin":"(?i)(new)\\\\s+","beginCaptures":{"1":{"name":"keyword.other.new.php"}},"end":"(?i)(?=[^0-9\\\\\\\\_a-z\\\\x7F-ÿ])","patterns":[{"match":"(?i)(parent|static|self)(?![0-9_a-z\\\\x7F-ÿ])","name":"storage.type.php"},{"include":"#class-name"},{"include":"#variable-name"}]},"interpolation":{"patterns":[{"match":"\\\\\\\\[0-7]{1,3}","name":"constant.character.escape.octal.php"},{"match":"\\\\\\\\x\\\\h{1,2}","name":"constant.character.escape.hex.php"},{"match":"\\\\\\\\u\\\\{\\\\h+}","name":"constant.character.escape.unicode.php"},{"match":"\\\\\\\\[\\"$\\\\\\\\efnrtv]","name":"constant.character.escape.php"},{"begin":"\\\\{(?=\\\\$.*?})","beginCaptures":{"0":{"name":"punctuation.definition.variable.php"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.variable.php"}},"patterns":[{"include":"#language"}]},{"include":"#variable-name"}]},"invoke-call":{"captures":{"1":{"name":"punctuation.definition.variable.php"},"2":{"name":"variable.other.php"}},"match":"(?i)(\\\\$+)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)(?=\\\\s*\\\\()","name":"meta.function-call.invoke.php"},"language":{"patterns":[{"include":"#comments"},{"begin":"(?i)^\\\\s*(interface)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(extends)?\\\\s*","beginCaptures":{"1":{"name":"storage.type.interface.php"},"2":{"name":"entity.name.type.interface.php"},"3":{"name":"storage.modifier.extends.php"}},"end":"(?i)((?:[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*\\\\s*,\\\\s*)*)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?\\\\s*(?:(?=\\\\{)|$)","endCaptures":{"1":{"patterns":[{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"entity.other.inherited-class.php"},{"match":",","name":"punctuation.separator.classes.php"}]},"2":{"name":"entity.other.inherited-class.php"}},"name":"meta.interface.php","patterns":[{"include":"#namespace"}]},{"begin":"(?i)^\\\\s*(trait)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)","beginCaptures":{"1":{"name":"storage.type.trait.php"},"2":{"name":"entity.name.type.trait.php"}},"end":"(?=\\\\{)","name":"meta.trait.php","patterns":[{"include":"#comments"}]},{"captures":{"1":{"name":"keyword.other.namespace.php"},"2":{"name":"entity.name.type.namespace.php","patterns":[{"match":"\\\\\\\\","name":"punctuation.separator.inheritance.php"}]}},"match":"(?i)(?:^|(?<=<\\\\?php))\\\\s*(namespace)\\\\s+([0-9\\\\\\\\_a-z\\\\x7F-ÿ]+)(?=\\\\s*;)","name":"meta.namespace.php"},{"begin":"(?i)(?:^|(?<=<\\\\?php))\\\\s*(namespace)\\\\s+","beginCaptures":{"1":{"name":"keyword.other.namespace.php"}},"end":"(?<=})|(?=\\\\?>)","name":"meta.namespace.php","patterns":[{"include":"#comments"},{"captures":{"0":{"patterns":[{"match":"\\\\\\\\","name":"punctuation.separator.inheritance.php"}]}},"match":"(?i)[0-9\\\\\\\\_a-z\\\\x7F-ÿ]+","name":"entity.name.type.namespace.php"},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.namespace.begin.bracket.curly.php"}},"end":"}|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.namespace.end.bracket.curly.php"}},"patterns":[{"include":"#language"}]},{"match":"\\\\S+","name":"invalid.illegal.identifier.php"}]},{"match":"\\\\s+(?=use\\\\b)"},{"begin":"(?i)\\\\buse\\\\b","beginCaptures":{"0":{"name":"keyword.other.use.php"}},"end":"(?<=})|(?=;)","name":"meta.use.php","patterns":[{"match":"\\\\b(const|function)\\\\b","name":"storage.type.\${1:/downcase}.php"},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.use.begin.bracket.curly.php"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.use.end.bracket.curly.php"}},"patterns":[{"include":"#scope-resolution"},{"captures":{"1":{"name":"keyword.other.use-as.php"},"2":{"name":"storage.modifier.php"},"3":{"name":"entity.other.alias.php"}},"match":"(?i)\\\\b(as)\\\\s+(final|abstract|public|private|protected|static)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\b"},{"captures":{"1":{"name":"keyword.other.use-as.php"},"2":{"patterns":[{"match":"^(?:final|abstract|public|private|protected|static)$","name":"storage.modifier.php"},{"match":".+","name":"entity.other.alias.php"}]}},"match":"(?i)\\\\b(as)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\b"},{"captures":{"1":{"name":"keyword.other.use-insteadof.php"},"2":{"name":"support.class.php"}},"match":"(?i)\\\\b(insteadof)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)"},{"match":";","name":"punctuation.terminator.expression.php"},{"include":"#use-inner"}]},{"include":"#use-inner"}]},{"begin":"(?i)^\\\\s*(?:(abstract|final)\\\\s+)?(class)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)","beginCaptures":{"1":{"name":"storage.modifier.\${1:/downcase}.php"},"2":{"name":"storage.type.class.php"},"3":{"name":"entity.name.type.class.php"}},"end":"}|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.class.end.bracket.curly.php"}},"name":"meta.class.php","patterns":[{"include":"#comments"},{"begin":"(?i)(extends)\\\\s+","beginCaptures":{"1":{"name":"storage.modifier.extends.php"}},"contentName":"meta.other.inherited-class.php","end":"(?i)(?=[^0-9\\\\\\\\_a-z\\\\x7F-ÿ])","patterns":[{"begin":"(?i)(?=\\\\\\\\?[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*\\\\\\\\)","end":"(?i)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?(?=[^0-9\\\\\\\\_a-z\\\\x7F-ÿ])","endCaptures":{"1":{"name":"entity.other.inherited-class.php"}},"patterns":[{"include":"#namespace"}]},{"include":"#class-builtin"},{"include":"#namespace"},{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"entity.other.inherited-class.php"}]},{"begin":"(?i)(implements)\\\\s+","beginCaptures":{"1":{"name":"storage.modifier.implements.php"}},"end":"(?i)(?=[;{])","patterns":[{"include":"#comments"},{"begin":"(?i)(?=[0-9\\\\\\\\_a-z\\\\x7F-ÿ]+)","contentName":"meta.other.inherited-class.php","end":"(?i)\\\\s*(?:,|(?=[^0-9\\\\\\\\_a-z\\\\x7F-ÿ\\\\s]))\\\\s*","patterns":[{"begin":"(?i)(?=\\\\\\\\?[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*\\\\\\\\)","end":"(?i)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?(?=[^0-9\\\\\\\\_a-z\\\\x7F-ÿ])","endCaptures":{"1":{"name":"entity.other.inherited-class.php"}},"patterns":[{"include":"#namespace"}]},{"include":"#class-builtin"},{"include":"#namespace"},{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"entity.other.inherited-class.php"}]}]},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.class.begin.bracket.curly.php"}},"contentName":"meta.class.body.php","end":"(?=}|\\\\?>)","patterns":[{"include":"#language"}]}]},{"include":"#switch_statement"},{"captures":{"1":{"name":"keyword.control.\${1:/downcase}.php"}},"match":"\\\\s*\\\\b(break|case|continue|declare|default|die|do|else(if)?|end(declare|for(each)?|if|switch|while)|exit|for(each)?|if|return|switch|use|while|yield)\\\\b"},{"begin":"(?i)\\\\b((?:require|include)(?:_once)?)\\\\s+","beginCaptures":{"1":{"name":"keyword.control.import.include.php"}},"end":"(?=[;\\\\s]|$|\\\\?>)","name":"meta.include.php","patterns":[{"include":"#language"}]},{"begin":"\\\\b(catch)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"keyword.control.exception.catch.php"},"2":{"name":"punctuation.definition.parameters.begin.bracket.round.php"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.parameters.end.bracket.round.php"}},"name":"meta.catch.php","patterns":[{"include":"#namespace"},{"captures":{"1":{"name":"support.class.exception.php"},"2":{"patterns":[{"match":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","name":"support.class.exception.php"},{"match":"\\\\|","name":"punctuation.separator.delimiter.php"}]},"3":{"name":"variable.other.php"},"4":{"name":"punctuation.definition.variable.php"}},"match":"(?i)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)((?:\\\\s*\\\\|\\\\s*[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)*)\\\\s*((\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)"}]},{"match":"\\\\b(catch|try|throw|exception|finally)\\\\b","name":"keyword.control.exception.php"},{"begin":"(?i)\\\\b(function)\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"storage.type.function.php"}},"end":"(?=\\\\{)","name":"meta.function.closure.php","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.parameters.begin.bracket.round.php"}},"contentName":"meta.function.parameters.php","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.parameters.end.bracket.round.php"}},"patterns":[{"include":"#function-parameters"}]},{"begin":"(?i)(use)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"keyword.other.function.use.php"},"2":{"name":"punctuation.definition.parameters.begin.bracket.round.php"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.parameters.end.bracket.round.php"}},"patterns":[{"captures":{"1":{"name":"variable.other.php"},"2":{"name":"storage.modifier.reference.php"},"3":{"name":"punctuation.definition.variable.php"}},"match":"(?i)((&)?\\\\s*(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(?=[),])","name":"meta.function.closure.use.php"}]}]},{"begin":"((?:(?:final|abstract|public|private|protected|static)\\\\s+)*)(function)\\\\s+(?i:(__(?:call|construct|debugInfo|destruct|get|set|isset|unset|tostring|clone|set_state|sleep|wakeup|autoload|invoke|callStatic))|([A-Z_a-z\\\\x7F-ÿ][0-9A-Z_a-z\\\\x7F-ÿ]*))\\\\s*(\\\\()","beginCaptures":{"1":{"patterns":[{"match":"final|abstract|public|private|protected|static","name":"storage.modifier.php"}]},"2":{"name":"storage.type.function.php"},"3":{"name":"support.function.magic.php"},"4":{"name":"entity.name.function.php"},"5":{"name":"punctuation.definition.parameters.begin.bracket.round.php"}},"contentName":"meta.function.parameters.php","end":"(\\\\))(?:\\\\s*(:)\\\\s*([A-Z_a-z\\\\x7F-ÿ][0-9A-Z_a-z\\\\x7F-ÿ]*))?","endCaptures":{"1":{"name":"punctuation.definition.parameters.end.bracket.round.php"},"2":{"name":"keyword.operator.return-value.php"},"3":{"name":"storage.type.php"}},"name":"meta.function.php","patterns":[{"include":"#function-parameters"}]},{"include":"#invoke-call"},{"include":"#scope-resolution"},{"include":"#variables"},{"include":"#strings"},{"captures":{"1":{"name":"support.function.construct.php"},"2":{"name":"punctuation.definition.array.begin.bracket.round.php"},"3":{"name":"punctuation.definition.array.end.bracket.round.php"}},"match":"(array)(\\\\()(\\\\))","name":"meta.array.empty.php"},{"begin":"(array)(\\\\()","beginCaptures":{"1":{"name":"support.function.construct.php"},"2":{"name":"punctuation.definition.array.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.array.end.bracket.round.php"}},"name":"meta.array.php","patterns":[{"include":"#language"}]},{"captures":{"1":{"name":"punctuation.definition.storage-type.begin.bracket.round.php"},"2":{"name":"storage.type.php"},"3":{"name":"punctuation.definition.storage-type.end.bracket.round.php"}},"match":"(?i)(\\\\()\\\\s*(array|real|double|float|int(?:eger)?|bool(?:ean)?|string|object|binary|unset)\\\\s*(\\\\))"},{"match":"(?i)\\\\b(array|real|double|float|int(eger)?|bool(ean)?|string|class|var|function|interface|trait|parent|self|object)\\\\b","name":"storage.type.php"},{"match":"(?i)\\\\b(global|abstract|const|extends|implements|final|private|protected|public|static)\\\\b","name":"storage.modifier.php"},{"include":"#object"},{"match":";","name":"punctuation.terminator.expression.php"},{"match":":","name":"punctuation.terminator.statement.php"},{"include":"#heredoc"},{"include":"#numbers"},{"match":"(?i)\\\\bclone\\\\b","name":"keyword.other.clone.php"},{"match":"\\\\.=?","name":"keyword.operator.string.php"},{"match":"=>","name":"keyword.operator.key.php"},{"captures":{"1":{"name":"keyword.operator.assignment.php"},"2":{"name":"storage.modifier.reference.php"},"3":{"name":"storage.modifier.reference.php"}},"match":"(?i)(=)(&)|(&)(?=[$_a-z])"},{"match":"@","name":"keyword.operator.error-control.php"},{"match":"===?|!==?|<>","name":"keyword.operator.comparison.php"},{"match":"(?:|[-%\\\\&*+/^|]|<<|>>)=","name":"keyword.operator.assignment.php"},{"match":"<=>?|>=|[<>]","name":"keyword.operator.comparison.php"},{"match":"--|\\\\+\\\\+","name":"keyword.operator.increment-decrement.php"},{"match":"[-%*+/]","name":"keyword.operator.arithmetic.php"},{"match":"(?i)(!|&&|\\\\|\\\\|)|\\\\b(and|or|xor|as)\\\\b","name":"keyword.operator.logical.php"},{"include":"#function-call"},{"match":"<<|>>|[\\\\&^|~]","name":"keyword.operator.bitwise.php"},{"begin":"(?i)\\\\b(instanceof)\\\\s+(?=[$\\\\\\\\_a-z])","beginCaptures":{"1":{"name":"keyword.operator.type.php"}},"end":"(?=[^$0-9\\\\\\\\_a-z\\\\x7F-ÿ])","patterns":[{"include":"#class-name"},{"include":"#variable-name"}]},{"include":"#instantiation"},{"captures":{"1":{"name":"keyword.control.goto.php"},"2":{"name":"support.other.php"}},"match":"(?i)(goto)\\\\s+([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)"},{"captures":{"1":{"name":"entity.name.goto-label.php"}},"match":"(?i)^\\\\s*([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*:(?!:)"},{"include":"#string-backtick"},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.begin.bracket.curly.php"}},"end":"}|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.end.bracket.curly.php"}},"patterns":[{"include":"#language"}]},{"begin":"\\\\[","beginCaptures":{"0":{"name":"punctuation.section.array.begin.php"}},"end":"]|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.section.array.end.php"}},"patterns":[{"include":"#language"}]},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.end.bracket.round.php"}},"patterns":[{"include":"#language"}]},{"include":"#constants"},{"match":",","name":"punctuation.separator.delimiter.php"}]},"namespace":{"begin":"(?i)(?:(namespace)|[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?(\\\\\\\\)(?=.*?[^0-9\\\\\\\\_a-z\\\\x7F-ÿ])","beginCaptures":{"1":{"name":"variable.language.namespace.php"},"2":{"name":"punctuation.separator.inheritance.php"}},"end":"(?i)(?=[0-9_a-z\\\\x7F-ÿ]*[^0-9\\\\\\\\_a-z\\\\x7F-ÿ])","name":"support.other.namespace.php","patterns":[{"match":"\\\\\\\\","name":"punctuation.separator.inheritance.php"}]},"nowdoc_interior":{"patterns":[{"begin":"(<<<)\\\\s*'(HTML)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"text.html","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.html","patterns":[{"include":"text.html.basic"}]},{"begin":"(<<<)\\\\s*'(BLADE)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"text.blade","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.blade","patterns":[{"include":"text.html.basic"},{"include":"#blade"}]},{"begin":"(<<<)\\\\s*'(XML)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"text.xml","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.xml","patterns":[{"include":"text.xml"}]},{"begin":"(<<<)\\\\s*'(SQL)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.sql","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.sql","patterns":[{"include":"source.sql"}]},{"begin":"(<<<)\\\\s*'(J(?:AVASCRIPT|S))'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.js","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.js","patterns":[{"include":"source.js"}]},{"begin":"(<<<)\\\\s*'(JSON)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.json","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.json","patterns":[{"include":"source.json"}]},{"begin":"(<<<)\\\\s*'(CSS)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"source.css","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"name":"meta.embedded.css","patterns":[{"include":"source.css"}]},{"begin":"(<<<)\\\\s*'(REGEXP?)'(\\\\s*)$","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.php"},"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"contentName":"string.regexp.nowdoc.php","end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"0":{"name":"punctuation.section.embedded.end.php"},"1":{"name":"keyword.operator.nowdoc.php"}},"patterns":[{"match":"(\\\\\\\\){1,2}[]$.\\\\[^{}]","name":"constant.character.escape.regex.php"},{"captures":{"1":{"name":"punctuation.definition.arbitrary-repitition.php"},"3":{"name":"punctuation.definition.arbitrary-repitition.php"}},"match":"(\\\\{)\\\\d+(,\\\\d+)?(})","name":"string.regexp.arbitrary-repitition.php"},{"begin":"\\\\[(?:\\\\^?])?","captures":{"0":{"name":"punctuation.definition.character-class.php"}},"end":"]","name":"string.regexp.character-class.php","patterns":[{"match":"\\\\\\\\[]'\\\\[\\\\\\\\]","name":"constant.character.escape.php"}]},{"match":"[$*+^]","name":"keyword.operator.regexp.php"},{"begin":"(?i)(?<=^|\\\\s)(#)\\\\s(?=[-\\\\t !,.0-9?_a-z\\\\x7F-ÿ[^\\\\x00-\\\\x7F]]*$)","beginCaptures":{"1":{"name":"punctuation.definition.comment.php"}},"end":"$","endCaptures":{"0":{"name":"punctuation.definition.comment.php"}},"name":"comment.line.number-sign.php"}]},{"begin":"(?i)(<<<)\\\\s*'([_a-z\\\\x7F-ÿ]+[0-9_a-z\\\\x7F-ÿ]*)'(\\\\s*)","beginCaptures":{"1":{"name":"punctuation.definition.string.php"},"2":{"name":"keyword.operator.nowdoc.php"},"3":{"name":"invalid.illegal.trailing-whitespace.php"}},"end":"^\\\\s*(\\\\2)\\\\b","endCaptures":{"1":{"name":"keyword.operator.nowdoc.php"}}}]},"numbers":{"patterns":[{"match":"0[Xx]\\\\h+","name":"constant.numeric.hex.php"},{"match":"0[Bb][01]+","name":"constant.numeric.binary.php"},{"match":"0[0-7]+","name":"constant.numeric.octal.php"},{"captures":{"1":{"name":"punctuation.separator.decimal.period.php"},"2":{"name":"punctuation.separator.decimal.period.php"}},"match":"[0-9]*(\\\\.)[0-9]+(?:[Ee][-+]?[0-9]+)?|[0-9]+(\\\\.)[0-9]*(?:[Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+","name":"constant.numeric.decimal.php"},{"match":"0|[1-9][0-9]*","name":"constant.numeric.decimal.php"}]},"object":{"patterns":[{"begin":"(->)(\\\\$?\\\\{)","beginCaptures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"punctuation.definition.variable.php"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.variable.php"}},"patterns":[{"include":"#language"}]},{"begin":"(?i)(->)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"entity.name.function.php"},"3":{"name":"punctuation.definition.arguments.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.bracket.round.php"}},"name":"meta.method-call.php","patterns":[{"include":"#language"}]},{"captures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"variable.other.property.php"},"3":{"name":"punctuation.definition.variable.php"}},"match":"(?i)(->)((\\\\$+)?[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?"}]},"parameter-default-types":{"patterns":[{"include":"#strings"},{"include":"#numbers"},{"include":"#string-backtick"},{"include":"#variables"},{"match":"=>","name":"keyword.operator.key.php"},{"match":"=","name":"keyword.operator.assignment.php"},{"match":"&(?=\\\\s*\\\\$)","name":"storage.modifier.reference.php"},{"begin":"(array)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"support.function.construct.php"},"2":{"name":"punctuation.definition.array.begin.bracket.round.php"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.array.end.bracket.round.php"}},"name":"meta.array.php","patterns":[{"include":"#parameter-default-types"}]},{"include":"#instantiation"},{"begin":"(?i)(?=[0-9\\\\\\\\_a-z\\\\x7F-ÿ]+(::)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?)","end":"(?i)(::)([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)?","endCaptures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"constant.other.class.php"}},"patterns":[{"include":"#class-name"}]},{"include":"#constants"}]},"php_doc":{"patterns":[{"match":"^(?!\\\\s*\\\\*).*?(?:(?=\\\\*/)|$\\\\n?)","name":"invalid.illegal.missing-asterisk.phpdoc.php"},{"captures":{"1":{"name":"keyword.other.phpdoc.php"},"3":{"name":"storage.modifier.php"},"4":{"name":"invalid.illegal.wrong-access-type.phpdoc.php"}},"match":"^\\\\s*\\\\*\\\\s*(@access)\\\\s+((p(?:ublic|rivate|rotected))|(.+))\\\\s*$"},{"captures":{"1":{"name":"keyword.other.phpdoc.php"},"2":{"name":"markup.underline.link.php"}},"match":"(@xlink)\\\\s+(.+)\\\\s*$"},{"begin":"(@(?:global|param|property(-(read|write))?|return|throws|var))\\\\s+(?=[(A-Z\\\\\\\\_a-z\\\\x7F-ÿ])","beginCaptures":{"1":{"name":"keyword.other.phpdoc.php"}},"contentName":"meta.other.type.phpdoc.php","end":"(?=\\\\s|\\\\*/)","patterns":[{"include":"#php_doc_types_array_multiple"},{"include":"#php_doc_types_array_single"},{"include":"#php_doc_types"}]},{"match":"@(api|abstract|author|category|copyright|example|global|inherit[Dd]oc|internal|license|link|method|property(-(read|write))?|package|param|return|see|since|source|static|subpackage|throws|todo|var|version|uses|deprecated|final|ignore)\\\\b","name":"keyword.other.phpdoc.php"},{"captures":{"1":{"name":"keyword.other.phpdoc.php"}},"match":"\\\\{(@(link|inherit[Dd]oc)).+?}","name":"meta.tag.inline.phpdoc.php"}]},"php_doc_types":{"captures":{"0":{"patterns":[{"match":"\\\\b(string|integer|int|boolean|bool|float|double|object|mixed|array|resource|void|null|callback|false|true|self)\\\\b","name":"keyword.other.type.php"},{"include":"#class-name"},{"match":"\\\\|","name":"punctuation.separator.delimiter.php"}]}},"match":"(?i)[\\\\\\\\_a-z\\\\x7F-ÿ][0-9\\\\\\\\_a-z\\\\x7F-ÿ]*(\\\\|[\\\\\\\\_a-z\\\\x7F-ÿ][0-9\\\\\\\\_a-z\\\\x7F-ÿ]*)*"},"php_doc_types_array_multiple":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.type.begin.bracket.round.phpdoc.php"}},"end":"(\\\\))(\\\\[])|(?=\\\\*/)","endCaptures":{"1":{"name":"punctuation.definition.type.end.bracket.round.phpdoc.php"},"2":{"name":"keyword.other.array.phpdoc.php"}},"patterns":[{"include":"#php_doc_types_array_multiple"},{"include":"#php_doc_types_array_single"},{"include":"#php_doc_types"},{"match":"\\\\|","name":"punctuation.separator.delimiter.php"}]},"php_doc_types_array_single":{"captures":{"1":{"patterns":[{"include":"#php_doc_types"}]},"2":{"name":"keyword.other.array.phpdoc.php"}},"match":"(?i)([\\\\\\\\_a-z\\\\x7F-ÿ][0-9\\\\\\\\_a-z\\\\x7F-ÿ]*)(\\\\[])"},"regex-double-quoted":{"begin":"\\"/(?=(\\\\\\\\.|[^\\"/])++/[ADSUXeimsux]*\\")","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"end":"(/)([ADSUXeimsux]*)(\\")","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.regexp.double-quoted.php","patterns":[{"match":"(\\\\\\\\){1,2}[]$.\\\\[^{}]","name":"constant.character.escape.regex.php"},{"include":"#interpolation"},{"captures":{"1":{"name":"punctuation.definition.arbitrary-repetition.php"},"3":{"name":"punctuation.definition.arbitrary-repetition.php"}},"match":"(\\\\{)\\\\d+(,\\\\d+)?(})","name":"string.regexp.arbitrary-repetition.php"},{"begin":"\\\\[(?:\\\\^?])?","captures":{"0":{"name":"punctuation.definition.character-class.php"}},"end":"]","name":"string.regexp.character-class.php","patterns":[{"include":"#interpolation"}]},{"match":"[$*+^]","name":"keyword.operator.regexp.php"}]},"regex-single-quoted":{"begin":"'/(?=(\\\\\\\\(?:\\\\\\\\(?:\\\\\\\\['\\\\\\\\]?|[^'])|.)|[^'/])++/[ADSUXeimsux]*')","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"end":"(/)([ADSUXeimsux]*)(')","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.regexp.single-quoted.php","patterns":[{"include":"#single_quote_regex_escape"},{"captures":{"1":{"name":"punctuation.definition.arbitrary-repetition.php"},"3":{"name":"punctuation.definition.arbitrary-repetition.php"}},"match":"(\\\\{)\\\\d+(,\\\\d+)?(})","name":"string.regexp.arbitrary-repetition.php"},{"begin":"\\\\[(?:\\\\^?])?","captures":{"0":{"name":"punctuation.definition.character-class.php"}},"end":"]","name":"string.regexp.character-class.php"},{"match":"[$*+^]","name":"keyword.operator.regexp.php"}]},"scope-resolution":{"patterns":[{"captures":{"1":{"patterns":[{"match":"\\\\b(self|static|parent)\\\\b","name":"storage.type.php"},{"match":"\\\\w+","name":"entity.name.class.php"},{"include":"#class-name"},{"include":"#variable-name"}]}},"match":"(?i)\\\\b([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)(?=\\\\s*::)"},{"begin":"(?i)(::)\\\\s*([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"entity.name.function.php"},"3":{"name":"punctuation.definition.arguments.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.bracket.round.php"}},"name":"meta.method-call.static.php","patterns":[{"include":"#language"}]},{"captures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"keyword.other.class.php"}},"match":"(?i)(::)\\\\s*(class)\\\\b"},{"captures":{"1":{"name":"keyword.operator.class.php"},"2":{"name":"variable.other.class.php"},"3":{"name":"punctuation.definition.variable.php"},"4":{"name":"constant.other.class.php"}},"match":"(?i)(::)\\\\s*(?:((\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)|([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*))?"}]},"single_quote_regex_escape":{"match":"\\\\\\\\(?:\\\\\\\\(?:\\\\\\\\['\\\\\\\\]?|[^'])|.)","name":"constant.character.escape.php"},"sql-string-double-quoted":{"begin":"\\"\\\\s*(?=(SELECT|INSERT|UPDATE|DELETE|CREATE|REPLACE|ALTER|AND)\\\\b)","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"contentName":"source.sql.embedded.php","end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.quoted.double.sql.php","patterns":[{"captures":{"1":{"name":"punctuation.definition.comment.sql"}},"match":"(#)(\\\\\\\\\\"|[^\\"])*(?=\\"|$)","name":"comment.line.number-sign.sql"},{"captures":{"1":{"name":"punctuation.definition.comment.sql"}},"match":"(--)(\\\\\\\\\\"|[^\\"])*(?=\\"|$)","name":"comment.line.double-dash.sql"},{"match":"\\\\\\\\[\\"'\\\\\\\\\`]","name":"constant.character.escape.php"},{"match":"'(?=((\\\\\\\\')|[^\\"'])*(\\"|$))","name":"string.quoted.single.unclosed.sql"},{"match":"\`(?=((\\\\\\\\\`)|[^\\"\`])*(\\"|$))","name":"string.quoted.other.backtick.unclosed.sql"},{"begin":"'","end":"'","name":"string.quoted.single.sql","patterns":[{"include":"#interpolation"}]},{"begin":"\`","end":"\`","name":"string.quoted.other.backtick.sql","patterns":[{"include":"#interpolation"}]},{"include":"#interpolation"},{"include":"source.sql"}]},"sql-string-single-quoted":{"begin":"'\\\\s*(?=(SELECT|INSERT|UPDATE|DELETE|CREATE|REPLACE|ALTER|AND)\\\\b)","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"contentName":"source.sql.embedded.php","end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.quoted.single.sql.php","patterns":[{"captures":{"1":{"name":"punctuation.definition.comment.sql"}},"match":"(#)(\\\\\\\\'|[^'])*(?='|$)","name":"comment.line.number-sign.sql"},{"captures":{"1":{"name":"punctuation.definition.comment.sql"}},"match":"(--)(\\\\\\\\'|[^'])*(?='|$)","name":"comment.line.double-dash.sql"},{"match":"\\\\\\\\[\\"'\\\\\\\\\`]","name":"constant.character.escape.php"},{"match":"\`(?=((\\\\\\\\\`)|[^'\`])*('|$))","name":"string.quoted.other.backtick.unclosed.sql"},{"match":"\\"(?=((\\\\\\\\\\")|[^\\"'])*('|$))","name":"string.quoted.double.unclosed.sql"},{"include":"source.sql"}]},"string-backtick":{"begin":"\`","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"end":"\`","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.interpolated.php","patterns":[{"match":"\\\\\\\\.","name":"constant.character.escape.php"},{"include":"#interpolation"}]},"string-double-quoted":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.quoted.double.php","patterns":[{"include":"#interpolation"}]},"string-single-quoted":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.php"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.php"}},"name":"string.quoted.single.php","patterns":[{"match":"\\\\\\\\['\\\\\\\\]","name":"constant.character.escape.php"}]},"strings":{"patterns":[{"include":"#regex-double-quoted"},{"include":"#sql-string-double-quoted"},{"include":"#string-double-quoted"},{"include":"#regex-single-quoted"},{"include":"#sql-string-single-quoted"},{"include":"#string-single-quoted"}]},"support":{"patterns":[{"match":"(?i)\\\\bapc_(store|sma_info|compile_file|clear_cache|cas|cache_info|inc|dec|define_constants|delete(_file)?|exists|fetch|load_constants|add|bin_(dump|load)(file)?)\\\\b","name":"support.function.apc.php"},{"match":"(?i)\\\\b(shuffle|sizeof|sort|next|nat(case)?sort|count|compact|current|in_array|usort|uksort|uasort|pos|prev|end|each|extract|ksort|key(_exists)?|krsort|list|asort|arsort|rsort|reset|range|array(_(shift|sum|splice|search|slice|chunk|change_key_case|count_values|column|combine|(diff|intersect)(_(u)?(key|assoc))?|u(diff|intersect)(_(u)?assoc)?|unshift|unique|pop|push|pad|product|values|keys|key_exists|filter|fill(_keys)?|flip|walk(_recursive)?|reduce|replace(_recursive)?|reverse|rand|multisort|merge(_recursive)?|map)?))\\\\b","name":"support.function.array.php"},{"match":"(?i)\\\\b(show_source|sys_getloadavg|sleep|highlight_(file|string)|constant|connection_(aborted|status)|time_(nanosleep|sleep_until)|ignore_user_abort|die|define(d)?|usleep|uniqid|unpack|__halt_compiler|php_(check_syntax|strip_whitespace)|pack|eval|exit|get_browser)\\\\b","name":"support.function.basic_functions.php"},{"match":"(?i)\\\\bbc(scale|sub|sqrt|comp|div|pow(mod)?|add|mod|mul)\\\\b","name":"support.function.bcmath.php"},{"match":"(?i)\\\\bblenc_encrypt\\\\b","name":"support.function.blenc.php"},{"match":"(?i)\\\\bbz(compress|close|open|decompress|errstr|errno|error|flush|write|read)\\\\b","name":"support.function.bz2.php"},{"match":"(?i)\\\\b((French|Gregorian|Jewish|Julian)ToJD|cal_(to_jd|info|days_in_month|from_jd)|unixtojd|jdto(unix|jewish)|easter_(da(?:te|ys))|JD(MonthName|To(Gregorian|Julian|French)|DayOfWeek))\\\\b","name":"support.function.calendar.php"},{"match":"(?i)\\\\b(class_alias|all_user_method(_array)?|is_(a|subclass_of)|__autoload|(class|interface|method|property|trait)_exists|get_(class(_(vars|methods))?|(called|parent)_class|object_vars|declared_(classes|interfaces|traits)))\\\\b","name":"support.function.classobj.php"},{"match":"(?i)\\\\b(com_(create_guid|print_typeinfo|event_sink|load_typelib|get_active_object|message_pump)|variant_(sub|set(_type)?|not|neg|cast|cat|cmp|int|idiv|imp|or|div|date_(from|to)_timestamp|pow|eqv|fix|and|add|abs|round|get_type|xor|mod|mul))\\\\b","name":"support.function.com.php"},{"begin":"(?i)\\\\b(isset|unset|eval|empty|list)\\\\b","name":"support.function.construct.php"},{"match":"(?i)\\\\b(print|echo)\\\\b","name":"support.function.construct.output.php"},{"match":"(?i)\\\\bctype_(space|cntrl|digit|upper|punct|print|lower|alnum|alpha|graph|xdigit)\\\\b","name":"support.function.ctype.php"},{"match":"(?i)\\\\bcurl_(share_(close|init|setopt)|strerror|setopt(_array)?|copy_handle|close|init|unescape|pause|escape|errno|error|exec|version|file_create|reset|getinfo|multi_(strerror|setopt|select|close|init|info_read|(add|remove)_handle|getcontent|exec))\\\\b","name":"support.function.curl.php"},{"match":"(?i)\\\\b(strtotime|str[fp]time|checkdate|time|timezone_name_(from_abbr|get)|idate|timezone_((location|offset|transitions|version)_get|(abbreviations|identifiers)_list|open)|date(_(sun(rise|set)|sun_info|sub|create(_(immutable_)?from_format)?|timestamp_([gs]et)|timezone_([gs]et)|time_set|isodate_set|interval_(create_from_date_string|format)|offset_get|diff|default_timezone_([gs]et)|date_set|parse(_from_format)?|format|add|get_last_errors|modify))?|localtime|get(date|timeofday)|gm(strftime|date|mktime)|microtime|mktime)\\\\b","name":"support.function.datetime.php"},{"match":"(?i)\\\\bdba_(sync|handlers|nextkey|close|insert|optimize|open|delete|popen|exists|key_split|firstkey|fetch|list|replace)\\\\b","name":"support.function.dba.php"},{"match":"(?i)\\\\bdbx_(sort|connect|compare|close|escape_string|error|query|fetch_row)\\\\b","name":"support.function.dbx.php"},{"match":"(?i)\\\\b(scandir|chdir|chroot|closedir|opendir|dir|rewinddir|readdir|getcwd)\\\\b","name":"support.function.dir.php"},{"match":"(?i)\\\\beio_(sync(fs)?|sync_file_range|symlink|stat(vfs)?|sendfile|set_min_parallel|set_max_(idle|poll_(reqs|time)|parallel)|seek|n(threads|op|pending|reqs|ready)|chown|chmod|custom|close|cancel|truncate|init|open|dup2|unlink|utime|poll|event_loop|f(sync|stat(vfs)?|chown|chmod|truncate|datasync|utime|allocate)|write|lstat|link|rename|realpath|read(ahead|dir|link)?|rmdir|get_(event_stream|last_error)|grp(_(add|cancel|limit))?|mknod|mkdir|busy)\\\\b","name":"support.function.eio.php"},{"match":"(?i)\\\\benchant_(dict_(store_replacement|suggest|check|is_in_session|describe|quick_check|add_to_(personal|session)|get_error)|broker_(set_ordering|init|dict_exists|describe|free(_dict)?|list_dicts|request_(pwl_)?dict|get_error))\\\\b","name":"support.function.enchant.php"},{"match":"(?i)\\\\bsplit(i)?|sql_regcase|ereg(i)?(_replace)?\\\\b","name":"support.function.ereg.php"},{"match":"(?i)\\\\b((restore|set)_(e(?:rror|xception)_handler)|trigger_error|debug_(print_)?backtrace|user_error|error_(log|reporting|get_last))\\\\b","name":"support.function.errorfunc.php"},{"match":"(?i)\\\\bshell_exec|system|passthru|proc_(nice|close|terminate|open|get_status)|escapeshell(arg|cmd)|exec\\\\b","name":"support.function.exec.php"},{"match":"(?i)\\\\b(exif_(thumbnail|tagname|imagetype|read_data)|read_exif_data)\\\\b","name":"support.function.exif.php"},{"match":"(?i)\\\\bfann_((duplicate|length|merge|shuffle|subset)_train_data|scale_(train(_data)?|((?:in|out)put)(_train_data)?)|set_(scaling_params|sarprop_(step_error_(shift|threshold_factor)|temperature|weight_decay_shift)|cascade_(num_candidate_groups|candidate_(change_fraction|limit|stagnation_epochs)|output_(change_fraction|stagnation_epochs)|weight_multiplier|activation_(functions|steepnesses)|(m(?:ax|in))_(cand|out)_epochs)|callback|training_algorithm|train_(error|stop)_function|((?:in|out)put)_scaling_params|error_log|quickprop_(decay|mu)|weight(_array)?|learning_(momentum|rate)|bit_fail_limit|activation_(function|steepness)(_(hidden|layer|output))?|rprop_(((?:de|in)crease)_factor|delta_(max|min|zero)))|save(_train)?|num_((?:in|out)put)_train_data|copy|clear_scaling_params|cascadetrain_on_(file|data)|create_((s(?:parse|hortcut|tandard))(_array)?|train(_from_callback)?|from_file)|test(_data)?|train(_(on_(file|data)|epoch))?|init_weights|descale_(input|output|train)|destroy(_train)?|print_error|run|reset_(MSE|err(no|str))|read_train_from_file|randomize_weights|get_(sarprop_(step_error_(shift|threshold_factor)|temperature|weight_decay_shift)|num_(input|output|layers)|network_type|MSE|connection_(array|rate)|bias_array|bit_fail(_limit)?|cascade_(num_(candidate(?:s|_groups))|(candidate|output)_(change_fraction|limit|stagnation_epochs)|weight_multiplier|activation_(functions|steepnesses)(_count)?|(m(?:ax|in))_(cand|out)_epochs)|total_((?:connecti|neur)ons)|training_algorithm|train_(error|stop)_function|err(no|str)|quickprop_(decay|mu)|learning_(momentum|rate)|layer_array|activation_(function|steepness)|rprop_(((?:de|in)crease)_factor|delta_(max|min|zero))))\\\\b","name":"support.function.fann.php"},{"match":"(?i)\\\\b(symlink|stat|set_file_buffer|chown|chgrp|chmod|copy|clearstatcache|touch|tempnam|tmpfile|is_(dir|(uploaded_)?file|executable|link|readable|writ(e)?able)|disk_(free|total)_space|diskfreespace|dirname|delete|unlink|umask|pclose|popen|pathinfo|parse_ini_(file|string)|fscanf|fstat|fseek|fnmatch|fclose|ftell|ftruncate|file(size|[acm]time|type|inode|owner|perms|group)?|file_(exists|(get|put)_contents)|f(open|puts|putcsv|passthru|eof|flush|write|lock|read|gets(s)?|getc(sv)?)|lstat|lchown|lchgrp|link(info)?|rename|rewind|read(file|link)|realpath(_cache_(get|size))?|rmdir|glob|move_uploaded_file|mkdir|basename)\\\\b","name":"support.function.file.php"},{"match":"(?i)\\\\b(finfo_(set_flags|close|open|file|buffer)|mime_content_type)\\\\b","name":"support.function.fileinfo.php"},{"match":"(?i)\\\\bfilter_(has_var|input(_array)?|id|var(_array)?|list)\\\\b","name":"support.function.filter.php"},{"match":"(?i)\\\\bfastcgi_finish_request\\\\b","name":"support.function.fpm.php"},{"match":"(?i)\\\\b(call_user_(func|method)(_array)?|create_function|unregister_tick_function|forward_static_call(_array)?|function_exists|func_(num_args|get_arg(s)?)|register_(shutdown|tick)_function|get_defined_functions)\\\\b","name":"support.function.funchand.php"},{"match":"(?i)\\\\b((n)?gettext|textdomain|d((?:(n)?|c(n)?)gettext)|bind(textdomain|_textdomain_codeset))\\\\b","name":"support.function.gettext.php"},{"match":"(?i)\\\\bgmp_(scan[01]|strval|sign|sub|setbit|sqrt(rem)?|hamdist|neg|nextprime|com|clrbit|cmp|testbit|intval|init|invert|import|or|div(exact)?|div_(qr??|r)|jacobi|popcount|pow(m)?|perfect_square|prob_prime|export|fact|legendre|and|add|abs|root(rem)?|random(_(bits|range))?|gcd(ext)?|xor|mod|mul)\\\\b","name":"support.function.gmp.php"},{"match":"(?i)\\\\bhash(_(hmac(_file)?|copy|init|update(_(file|stream))?|pbkdf2|equals|file|final|algos))?\\\\b","name":"support.function.hash.php"},{"match":"(?i)\\\\b(http_(support|send_(status|stream|content_(disposition|type)|data|file|last_modified)|head|negotiate_(charset|content_type|language)|chunked_decode|cache_(etag|last_modified)|throttle|inflate|deflate|date|post_(data|fields)|put_(data|file|stream)|persistent_handles_(count|clean|ident)|parse_(cookie|headers|message|params)|redirect|request(_(method_(exists|name|(un)?register)|body_encode))?|get(_request_(headers|body(_stream)?))?|match_(etag|modified|request_header)|build_(cookie|str|url))|ob_(etag|deflate|inflate)handler)\\\\b","name":"support.function.http.php"},{"match":"(?i)\\\\b(iconv(_(str(pos|len|rpos)|substr|([gs]et)_encoding|mime_(decode(_headers)?|encode)))?|ob_iconv_handler)\\\\b","name":"support.function.iconv.php"},{"match":"(?i)\\\\biis_((st(?:art|op))_(serv(?:ice|er))|set_(script_map|server_rights|dir_security|app_settings)|(add|remove)_server|get_(script_map|service_state|server_(rights|by_(comment|path))|dir_security))\\\\b","name":"support.function.iisfunc.php"},{"match":"(?i)\\\\b(iptc(embed|parse)|(jpeg|png)2wbmp|gd_info|getimagesize(fromstring)?|image(s[xy]|scale|(char|string)(up)?|set(style|thickness|tile|interpolation|pixel|brush)|savealpha|convolution|copy(resampled|resized|merge(gray)?)?|colors(forindex|total)|color(set|closest(alpha|hwb)?|transparent|deallocate|(allocate|exact|resolve)(alpha)?|at|match)|crop(auto)?|create(truecolor|from(string|jpeg|png|wbmp|webp|gif|gd(2(part)?)?|xpm|xbm))?|types|ttf(bbox|text)|truecolortopalette|istruecolor|interlace|2wbmp|destroy|dashedline|jpeg|_type_to_(extension|mime_type)|ps(slantfont|text|(encode|extend|free|load)font|bbox)|png|polygon|palette(copy|totruecolor)|ellipse|ft(text|bbox)|filter|fill|filltoborder|filled(arc|ellipse|polygon|rectangle)|font(height|width)|flip|webp|wbmp|line|loadfont|layereffect|antialias|affine(matrix(concat|get))?|alphablending|arc|rotate|rectangle|gif|gd(2)?|gammacorrect|grab(screen|window)|xbm))\\\\b","name":"support.function.image.php"},{"match":"(?i)\\\\b(sys_get_temp_dir|set_(time_limit|include_path|magic_quotes_runtime)|cli_([gs]et)_process_title|ini_(alter|get(_all)?|restore|set)|zend_(thread_id|version|logo_guid)|dl|php(credits|info|version)|php_(sapi_name|ini_(scanned_files|loaded_file)|uname|logo_guid)|putenv|extension_loaded|version_compare|assert(_options)?|restore_include_path|gc_(collect_cycles|disable|enable(d)?)|getopt|get_(cfg_var|current_user|defined_constants|extension_funcs|include_path|included_files|loaded_extensions|magic_quotes_(gpc|runtime)|required_files|resources)|get(env|lastmod|rusage|my(inode|[gpu]id))|memory_get_(peak_)?usage|main|magic_quotes_runtime)\\\\b","name":"support.function.info.php"},{"match":"(?i)\\\\bibase_(set_event_handler|service_((?:at|de)tach)|server_info|num_(fields|params)|name_result|connect|commit(_ret)?|close|trans|delete_user|drop_db|db_info|pconnect|param_info|prepare|err(code|msg)|execute|query|field_info|fetch_(assoc|object|row)|free_(event_handler|query|result)|wait_event|add_user|affected_rows|rollback(_ret)?|restore|gen_id|modify_user|maintain_db|backup|blob_(cancel|close|create|import|info|open|echo|add|get))\\\\b","name":"support.function.interbase.php"},{"match":"(?i)\\\\b(normalizer_(normalize|is_normalized)|idn_to_(unicode|utf8|ascii)|numfmt_(set_(symbol|(text_)?attribute|pattern)|create|(parse|format)(_currency)?|get_(symbol|(text_)?attribute|pattern|error_(code|message)|locale))|collator_(sort(_with_sort_keys)?|set_(attribute|strength)|compare|create|asort|get_(strength|sort_key|error_(code|message)|locale|attribute))|transliterator_(create(_(inverse|from_rules))?|transliterate|list_ids|get_error_(code|message))|intl(cal|tz)_get_error_(code|message)|intl_(is_failure|error_name|get_error_(code|message))|datefmt_(set_(calendar|lenient|pattern|timezone(_id)?)|create|is_lenient|parse|format(_object)?|localtime|get_(calendar(_object)?|time(type|zone(_id)?)|datetype|pattern|error_(code|message)|locale))|locale_(set_default|compose|canonicalize|parse|filter_matches|lookup|accept_from_http|get_(script|display_(script|name|variant|language|region)|default|primary_language|keywords|all_variants|region))|resourcebundle_(create|count|locales|get(_(error_(code|message)))?)|grapheme_(str(i?str|r?i?pos|len)|substr|extract)|msgfmt_(set_pattern|create|(format|parse)(_message)?|get_(pattern|error_(code|message)|locale)))\\\\b","name":"support.function.intl.php"},{"match":"(?i)\\\\bjson_(decode|encode|last_error(_msg)?)\\\\b","name":"support.function.json.php"},{"match":"(?i)\\\\bldap_(start|tls|sort|search|sasl_bind|set_(option|rebind_proc)|(first|next)_(attribute|entry|reference)|connect|control_paged_result(_response)?|count_entries|compare|close|t61_to_8859|8859_to_t61|dn2ufn|delete|unbind|parse_(re(?:ference|sult))|escape|errno|err2str|error|explode_dn|bind|free_result|list|add|rename|read|get_(option|dn|entries|values(_len)?|attributes)|modify(_batch)?|mod_(add|del|replace))\\\\b","name":"support.function.ldap.php"},{"match":"(?i)\\\\blibxml_(set_(streams_context|external_entity_loader)|clear_errors|disable_entity_loader|use_internal_errors|get_(errors|last_error))\\\\b","name":"support.function.libxml.php"},{"match":"(?i)\\\\b(ezmlm_hash|mail)\\\\b","name":"support.function.mail.php"},{"match":"(?i)\\\\b((a)?(cos|sin|tan)(h)?|sqrt|srand|hypot|hexdec|ceil|is_(nan|(in)?finite)|octdec|dec(hex|oct|bin)|deg2rad|pi|pow|exp(m1)?|floor|fmod|lcg_value|log(1([0p]))?|atan2|abs|round|rand|rad2deg|getrandmax|mt_(srand|rand|getrandmax)|max|min|bindec|base_convert)\\\\b","name":"support.function.math.php"},{"match":"(?i)\\\\bmb_(str(cut|str|to(lower|upper)|istr|ipos|imwidth|pos|width|len|rchr|richr|ripos|rpos)|substitute_character|substr(_count)?|split|send_mail|http_((?:in|out)put)|check_encoding|convert_(case|encoding|kana|variables)|internal_encoding|output_handler|decode_(numericentity|mimeheader)|detect_(encoding|order)|parse_str|preferred_mime_name|encoding_aliases|encode_(numericentity|mimeheader)|ereg(i(_replace)?)?|ereg_(search(_(get(pos|regs)|init|regs|(set)?pos))?|replace(_callback)?|match)|list_encodings|language|regex_(set_options|encoding)|get_info)\\\\b","name":"support.function.mbstring.php"},{"match":"(?i)\\\\b(m(?:crypt_(cfb|create_iv|cbc|ofb|decrypt|encrypt|ecb|list_(algorithms|modes)|generic(_((de)?init|end))?|enc_(self_test|is_block_(algorithm|algorithm_mode|mode)|get_(supported_key_sizes|(block|iv|key)_size|(algorithms|modes)_name))|get_(cipher_name|(block|iv|key)_size)|module_(close|self_test|is_block_(algorithm|algorithm_mode|mode)|open|get_(supported_key_sizes|algo_(block|key)_size)))|decrypt_generic))\\\\b","name":"support.function.mcrypt.php"},{"match":"(?i)\\\\bmemcache_debug\\\\b","name":"support.function.memcache.php"},{"match":"(?i)\\\\bmhash(_(count|keygen_s2k|get_(hash_name|block_size)))?\\\\b","name":"support.function.mhash.php"},{"match":"(?i)\\\\b(log_(cmd_(insert|delete|update)|killcursor|write_batch|reply|getmore)|bson_((?:de|en)code))\\\\b","name":"support.function.mongo.php"},{"match":"(?i)\\\\bmysql_(stat|set_charset|select_db|num_(fields|rows)|connect|client_encoding|close|create_db|escape_string|thread_id|tablename|insert_id|info|data_seek|drop_db|db_(name|query)|unbuffered_query|pconnect|ping|errno|error|query|field_(seek|name|type|table|flags|len)|fetch_(object|field|lengths|assoc|array|row)|free_result|list_(tables|dbs|processes|fields)|affected_rows|result|real_escape_string|get_(client|host|proto|server)_info)\\\\b","name":"support.function.mysql.php"},{"match":"(?i)\\\\bmysqli_(ssl_set|store_result|stat|send_(query|long_data)|set_(charset|opt|local_infile_(default|handler))|stmt_(store_result|send_long_data|next_result|close|init|data_seek|prepare|execute|fetch|free_result|attr_([gs]et)|result_metadata|reset|get_(result|warnings)|more_results|bind_(param|result))|select_db|slave_query|savepoint|next_result|change_user|character_set_name|connect|commit|client_encoding|close|thread_safe|init|options|((?:en|dis)able)_(r(?:eads_from_master|pl_parse))|dump_debug_info|debug|data_seek|use_result|ping|poll|param_count|prepare|escape_string|execute|embedded_server_(start|end)|kill|query|field_seek|free_result|autocommit|rollback|report|refresh|fetch(_(object|fields|field(_direct)?|assoc|all|array|row))?|rpl_(parse_enabled|probe|query_type)|release_savepoint|reap_async_query|real_(connect|escape_string|query)|more_results|multi_query|get_(charset|connection_stats|client_(stats|info|version)|cache_stats|warnings|links_stats|metadata)|master_query|bind_(param|result)|begin_transaction)\\\\b","name":"support.function.mysqli.php"},{"match":"(?i)\\\\bmysqlnd_memcache_(set|get_config)\\\\b","name":"support.function.mysqlnd-memcache.php"},{"match":"(?i)\\\\bmysqlnd_ms_(set_(user_pick_server|qos)|dump_servers|query_is_select|fabric_select_(shard|global)|get_(stats|last_(used_connection|gtid))|xa_(commit|rollback|gc|begin)|match_wild)\\\\b","name":"support.function.mysqlnd-ms.php"},{"match":"(?i)\\\\bmysqlnd_qc_(set_(storage_handler|cache_condition|is_select|user_handlers)|clear_cache|get_(normalized_query_trace_log|core_stats|cache_info|query_trace_log|available_handlers))\\\\b","name":"support.function.mysqlnd-qc.php"},{"match":"(?i)\\\\bmysqlnd_uh_(set_(statement|connection)_proxy|convert_to_mysqlnd)\\\\b","name":"support.function.mysqlnd-uh.php"},{"match":"(?i)\\\\b(syslog|socket_(set_(blocking|timeout)|get_status)|set(raw)?cookie|http_response_code|openlog|headers_(list|sent)|header(_(re(?:gister_callback|move)))?|checkdnsrr|closelog|inet_(ntop|pton)|ip2long|openlog|dns_(check_record|get_(record|mx))|define_syslog_variables|(p)?fsockopen|long2ip|get(servby(name|port)|host(name|by(name(l)?|addr))|protoby(n(?:ame|umber))|mxrr))\\\\b","name":"support.function.network.php"},{"match":"(?i)\\\\bnsapi_(virtual|response_headers|request_headers)\\\\b","name":"support.function.nsapi.php"},{"match":"(?i)\\\\b(oci(?:(statementtype|setprefetch|serverversion|savelob(file)?|numcols|new(collection|cursor|descriptor)|nlogon|column(scale|size|name|type(raw)?|isnull|precision)|coll(size|trim|assign(elem)?|append|getelem|max)|commit|closelob|cancel|internaldebug|definebyname|plogon|parse|error|execute|fetch(statement|into)?|free(statement|collection|cursor|desc)|write(temporarylob|lobtofile)|loadlob|log(o(?:n|ff))|rowcount|rollback|result|bindbyname)|_(statement_type|set_(client_(i(?:nfo|dentifier))|prefetch|edition|action|module_name)|server_version|num_(fields|rows)|new_(connect|collection|cursor|descriptor)|connect|commit|client_version|close|cancel|internal_debug|define_by_name|pconnect|password_change|parse|error|execute|bind_(array_)?by_name|field_(scale|size|name|type(_raw)?|is_null|precision)|fetch(_(object|assoc|all|array|row))?|free_(statement|descriptor)|lob_(copy|is_equal)|rollback|result|get_implicit_resultset)))\\\\b","name":"support.function.oci8.php"},{"match":"(?i)\\\\bopcache_(compile_file|invalidate|reset|get_(status|configuration))\\\\b","name":"support.function.opcache.php"},{"match":"(?i)\\\\bopenssl_(sign|spki_(new|export(_challenge)?|verify)|seal|csr_(sign|new|export(_to_file)?|get_(subject|public_key))|cipher_iv_length|open|dh_compute_key|digest|decrypt|public_((?:de|en)crypt)|encrypt|error_string|pkcs12_(export(_to_file)?|read)|pkcs7_(sign|decrypt|encrypt|verify)|verify|free_key|random_pseudo_bytes|pkey_(new|export(_to_file)?|free|get_(details|public|private))|private_((?:de|en)crypt)|pbkdf2|get_((cipher|md)_methods|cert_locations|(p(?:ublic|rivate))key)|x509_(check_private_key|checkpurpose|parse|export(_to_file)?|fingerprint|free|read))\\\\b","name":"support.function.openssl.php"},{"match":"(?i)\\\\b(output_(add_rewrite_var|reset_rewrite_vars)|flush|ob_(start|clean|implicit_flush|end_(clean|flush)|flush|list_handlers|gzhandler|get_(status|contents|clean|flush|length|level)))\\\\b","name":"support.function.output.php"},{"match":"(?i)\\\\bpassword_(hash|needs_rehash|verify|get_info)\\\\b","name":"support.function.password.php"},{"match":"(?i)\\\\bpcntl_(strerror|signal(_dispatch)?|sig(timedwait|procmask|waitinfo)|setpriority|errno|exec|fork|w(stopsig|termsig|if((?:stopp|signal|exit)ed))|wait(pid)?|alarm|getpriority|get_last_error)\\\\b","name":"support.function.pcntl.php"},{"match":"(?i)\\\\bpg_(socket|send_(prepare|execute|query(_params)?)|set_(client_encoding|error_verbosity)|select|host|num_(fields|rows)|consume_input|connection_(status|reset|busy)|connect(_poll)?|convert|copy_(from|to)|client_encoding|close|cancel_query|tty|transaction_status|trace|insert|options|delete|dbname|untrace|unescape_bytea|update|pconnect|ping|port|put_line|parameter_status|prepare|version|query(_params)?|escape_(string|identifier|literal|bytea)|end_copy|execute|flush|free_result|last_(notice|error|oid)|field_(size|num|name|type(_oid)?|table|is_null|prtlen)|affected_rows|result_(status|seek|error(_field)?)|fetch_(object|assoc|all(_columns)?|array|row|result)|get_(notify|pid|result)|meta_data|lo_(seek|close|create|tell|truncate|import|open|unlink|export|write|read(_all)?)|)\\\\b","name":"support.function.pgsql.php"},{"match":"(?i)\\\\b(virtual|getallheaders|apache_(([gs]et)env|note|child_terminate|lookup_uri|response_headers|reset_timeout|request_headers|get_(version|modules)))\\\\b","name":"support.function.php_apache.php"},{"match":"(?i)\\\\bdom_import_simplexml\\\\b","name":"support.function.php_dom.php"},{"match":"(?i)\\\\bftp_(ssl_connect|systype|site|size|set_option|nlist|nb_(continue|f?(put|get))|ch(dir|mod)|connect|cdup|close|delete|put|pwd|pasv|exec|quit|f(put|get)|login|alloc|rename|raw(list)?|rmdir|get(_option)?|mdtm|mkdir)\\\\b","name":"support.function.php_ftp.php"},{"match":"(?i)\\\\bimap_((create|delete|list|rename|scan)(mailbox)?|status|sort|subscribe|set_quota|set(flag_full|acl)|search|savebody|num_(recent|msg)|check|close|clearflag_full|thread|timeout|open|header(info)?|headers|append|alerts|reopen|8bit|unsubscribe|undelete|utf7_((?:de|en)code)|utf8|uid|ping|errors|expunge|qprint|gc|fetch(structure|header|text|mime|body)|fetch_overview|lsub|list(s(?:can|ubscribed))|last_error|rfc822_(parse_(headers|adrlist)|write_address)|get(subscribed|acl|mailboxes)|get_quota(root)?|msgno|mime_header_decode|mail_(copy|compose|move)|mail|mailboxmsginfo|binary|body(struct)?|base64)\\\\b","name":"support.function.php_imap.php"},{"match":"(?i)\\\\bmssql_(select_db|num_(fields|rows)|next_result|connect|close|init|data_seek|pconnect|execute|query|field_(seek|name|type|length)|fetch_(object|field|assoc|array|row|batch)|free_(statement|result)|rows_affected|result|guid_string|get_last_message|min_(error|message)_severity|bind)\\\\b","name":"support.function.php_mssql.php"},{"match":"(?i)\\\\bodbc_(statistics|specialcolumns|setoption|num_(fields|rows)|next_result|connect|columns|columnprivileges|commit|cursor|close(_all)?|tables|tableprivileges|do|data_source|pconnect|primarykeys|procedures|procedurecolumns|prepare|error(msg)?|exec(ute)?|field_(scale|num|name|type|precision|len)|foreignkeys|free_result|fetch_(into|object|array|row)|longreadlen|autocommit|rollback|result(_all)?|gettypeinfo|binmode)\\\\b","name":"support.function.php_odbc.php"},{"match":"(?i)\\\\bpreg_(split|quote|filter|last_error|replace(_callback)?|grep|match(_all)?)\\\\b","name":"support.function.php_pcre.php"},{"match":"(?i)\\\\b(spl_(classes|object_hash|autoload(_(call|unregister|extensions|functions|register))?)|class_(implements|uses|parents)|iterator_(count|to_array|apply))\\\\b","name":"support.function.php_spl.php"},{"match":"(?i)\\\\bzip_(close|open|entry_(name|compressionmethod|compressedsize|close|open|filesize|read)|read)\\\\b","name":"support.function.php_zip.php"},{"match":"(?i)\\\\bposix_(strerror|set(s|e?u|[ep]?g)id|ctermid|ttyname|times|isatty|initgroups|uname|errno|kill|access|get(sid|cwd|uid|pid|ppid|pwnam|pwuid|pgid|pgrp|euid|egid|login|rlimit|gid|grnam|groups|grgid)|get_last_error|mknod|mkfifo)\\\\b","name":"support.function.posix.php"},{"match":"(?i)\\\\bset(thread|proc)title\\\\b","name":"support.function.proctitle.php"},{"match":"(?i)\\\\bpspell_(store_replacement|suggest|save_wordlist|new(_(config|personal))?|check|clear_session|config_(save_repl|create|ignore|(d(?:ata|ict))_dir|personal|runtogether|repl|mode)|add_to_(session|personal))\\\\b","name":"support.function.pspell.php"},{"match":"(?i)\\\\breadline(_(completion_function|clear_history|callback_(handler_(install|remove)|read_char)|info|on_new_line|write_history|list_history|add_history|redisplay|read_history))?\\\\b","name":"support.function.readline.php"},{"match":"(?i)\\\\brecode(_(string|file))?\\\\b","name":"support.function.recode.php"},{"match":"(?i)\\\\brrd(c_disconnect|_(create|tune|info|update|error|version|first|fetch|last(update)?|restore|graph|xport))\\\\b","name":"support.function.rrd.php"},{"match":"(?i)\\\\b(shm_((get|has|remove|put)_var|detach|attach|remove)|sem_(acquire|release|remove|get)|ftok|msg_((get|remove|set|stat)_queue|send|queue_exists|receive))\\\\b","name":"support.function.sem.php"},{"match":"(?i)\\\\bsession_(status|start|set_(save_handler|cookie_params)|save_path|name|commit|cache_(expire|limiter)|is_registered|id|destroy|decode|unset|unregister|encode|write_close|abort|reset|register(_shutdown)?|regenerate_id|get_cookie_params|module_name)\\\\b","name":"support.function.session.php"},{"match":"(?i)\\\\bshmop_(size|close|open|delete|write|read)\\\\b","name":"support.function.shmop.php"},{"match":"(?i)\\\\bsimplexml_(import_dom|load_(string|file))\\\\b","name":"support.function.simplexml.php"},{"match":"(?i)\\\\b(snmp(?:(walk(oid)?|realwalk|get(next)?|set)|_(set_(valueretrieval|quick_print|enum_print|oid_(numeric_print|output_format))|read_mib|get_(valueretrieval|quick_print))|[23]_(set|walk|real_walk|get(next)?)))\\\\b","name":"support.function.snmp.php"},{"match":"(?i)\\\\b(is_soap_fault|use_soap_error_handler)\\\\b","name":"support.function.soap.php"},{"match":"(?i)\\\\bsocket_(shutdown|strerror|send(to|msg)?|set_((non)?block|option)|select|connect|close|clear_error|bind|create(_(pair|listen))?|cmsg_space|import_stream|write|listen|last_error|accept|recv(from|msg)?|read|get(peer|sock)name|get_option)\\\\b","name":"support.function.sockets.php"},{"match":"(?i)\\\\bsqlite_(single_query|seek|has_(more|prev)|num_(fields|rows)|next|changes|column|current|close|create_(aggregate|function)|open|unbuffered_query|udf_((?:de|en)code)_binary|popen|prev|escape_string|error_string|exec|valid|key|query|field_name|factory|fetch_(string|single|column_types|object|all|array)|lib(encoding|version)|last_(insert_rowid|error)|array_query|rewind|busy_timeout)\\\\b","name":"support.function.sqlite.php"},{"match":"(?i)\\\\bsqlsrv_(send_stream_data|server_info|has_rows|num_(fields|rows)|next_result|connect|configure|commit|client_info|close|cancel|prepare|errors|execute|query|field_metadata|fetch(_(array|object))?|free_stmt|rows_affected|rollback|get_(config|field)|begin_transaction)\\\\b","name":"support.function.sqlsrv.php"},{"match":"(?i)\\\\bstats_(harmonic_mean|covariance|standard_deviation|skew|cdf_(noncentral_(chisquare|f)|negative_binomial|chisquare|cauchy|t|uniform|poisson|exponential|f|weibull|logistic|laplace|gamma|binomial|beta)|stat_(noncentral_t|correlation|innerproduct|independent_t|powersum|percentile|paired_t|gennch|binomial_coef)|dens_(normal|negative_binomial|chisquare|cauchy|t|pmf_(hypergeometric|poisson|binomial)|exponential|f|weibull|logistic|laplace|gamma|beta)|den_uniform|variance|kurtosis|absolute_deviation|rand_(setall|phrase_to_seeds|ranf|get_seeds|gen_(noncentral_[ft]|noncenral_chisquare|normal|chisquare|t|int|i(uniform|poisson|binomial(_negative)?)|exponential|f(uniform)?|gamma|beta)))\\\\b","name":"support.function.stats.php"},{"match":"(?i)\\\\b(s(?:et_socket_blocking|tream_(socket_(shutdown|sendto|server|client|pair|enable_crypto|accept|recvfrom|get_name)|set_(chunk_size|timeout|(read|write)_buffer|blocking)|select|notification_callback|supports_lock|context_(set_(option|default|params)|create|get_(options|default|params))|copy_to_stream|is_local|encoding|filter_(append|prepend|register|remove)|wrapper_((un)?register|restore)|resolve_include_path|register_wrapper|get_(contents|transports|filters|wrappers|line|meta_data)|bucket_(new|prepend|append|make_writeable))))\\\\b","name":"support.function.streamsfuncs.php"},{"match":"(?i)\\\\b(money_format|md5(_file)?|metaphone|bin2hex|sscanf|sha1(_file)?|str(str|c?spn|n(at)?(case)?cmp|chr|coll|(case)?cmp|to(upper|lower)|tok|tr|istr|pos|pbrk|len|rchr|ri?pos|rev)|str_(getcsv|ireplace|pad|repeat|replace|rot13|shuffle|split|word_count)|strip(c?slashes|os)|strip_tags|similar_text|soundex|substr(_(count|compare|replace))?|setlocale|html(specialchars(_decode)?|entities)|html_entity_decode|hex2bin|hebrev(c)?|number_format|nl2br|nl_langinfo|chop|chunk_split|chr|convert_(cyr_string|uu((?:de|en)code))|count_chars|crypt|crc32|trim|implode|ord|uc(first|words)|join|parse_str|print(f)?|echo|explode|v?[fs]?printf|quoted_printable_((?:de|en)code)|quotemeta|wordwrap|lcfirst|[lr]trim|localeconv|levenshtein|addc?slashes|get_html_translation_table)\\\\b","name":"support.function.string.php"},{"match":"(?i)\\\\bsybase_(set_message_handler|select_db|num_(fields|rows)|connect|close|deadlock_retry_count|data_seek|unbuffered_query|pconnect|query|field_seek|fetch_(object|field|assoc|array|row)|free_result|affected_rows|result|get_last_message|min_(client|error|message|server)_severity)\\\\b","name":"support.function.sybase.php"},{"match":"(?i)\\\\b(taint|is_tainted|untaint)\\\\b","name":"support.function.taint.php"},{"match":"(?i)\\\\b(tidy_(([gs]et)opt|set_encoding|save_config|config_count|clean_repair|is_(x(?:html|ml))|diagnose|(access|error|warning)_count|load_config|reset_config|(parse|repair)_(string|file)|get_(status|html(_ver)?|head|config|output|opt_doc|root|release|body))|ob_tidyhandler)\\\\b","name":"support.function.tidy.php"},{"match":"(?i)\\\\btoken_(name|get_all)\\\\b","name":"support.function.tokenizer.php"},{"match":"(?i)\\\\btrader_(stoch([fr]|rsi)?|stddev|sin(h)?|sum|sub|set_(compat|unstable_period)|sqrt|sar(ext)?|sma|ht_(sine|trend(line|mode)|dc(p(?:eriod|hase))|phasor)|natr|cci|cos(h)?|correl|cdl(shootingstar|shortline|sticksandwich|stalledpattern|spinningtop|separatinglines|hikkake(mod)?|highwave|homingpigeon|hangingman|harami(cross)?|hammer|concealbabyswall|counterattack|closingmarubozu|thrusting|tasukigap|takuri|tristar|inneck|invertedhammer|identical3crows|2crows|onneck|doji(star)?|darkcloudcover|dragonflydoji|unique3river|upsidegap2crows|3(starsinsouth|inside|outside|whitesoldiers|linestrike|blackcrows)|piercing|engulfing|evening(doji)?star|kicking(bylength)?|longline|longleggeddoji|ladderbottom|advanceblock|abandonedbaby|risefall3methods|rickshawman|gapsidesidewhite|gravestonedoji|xsidegap3methods|morning(doji)?star|mathold|matchinglow|marubozu|belthold|breakaway)|ceil|cmo|tsf|typprice|t3|tema|tan(h)?|trix|trima|trange|obv|div|dema|dx|ultosc|ppo|plus_d[im]|errno|exp|ema|var|kama|floor|wclprice|willr|wma|ln|log10|bop|beta|bbands|linearreg(_(slope|intercept|angle))?|asin|acos|atan|atr|adosc|add??|adx(r)?|apo|avgprice|aroon(osc)?|rsi|rocp??|rocr(100)?|get_(compat|unstable_period)|min(index)?|minus_d[im]|minmax(index)?|mid(p(?:oint|rice))|mom|mult|medprice|mfi|macd(ext|fix)?|mavp|max(index)?|ma(ma)?)\\\\b","name":"support.function.trader.php"},{"match":"(?i)\\\\buopz_(copy|compose|implement|overload|delete|undefine|extend|function|flags|restore|rename|redefine|backup)\\\\b","name":"support.function.uopz.php"},{"match":"(?i)\\\\b(http_build_query|(raw)?url((?:de|en)code)|parse_url|get_(headers|meta_tags)|base64_((?:de|en)code))\\\\b","name":"support.function.url.php"},{"match":"(?i)\\\\b(strval|settype|serialize|(bool|double|float)val|debug_zval_dump|intval|import_request_variables|isset|is_(scalar|string|null|numeric|callable|int(eger)?|object|double|float|long|array|resource|real|bool)|unset|unserialize|print_r|empty|var_(dump|export)|gettype|get_(defined_vars|resource_type))\\\\b","name":"support.function.var.php"},{"match":"(?i)\\\\bwddx_(serialize_(va(?:lue|rs))|deserialize|packet_(start|end)|add_vars)\\\\b","name":"support.function.wddx.php"},{"match":"(?i)\\\\bxhprof_(sample_)?((?:dis|en)able)\\\\b","name":"support.function.xhprof.php"},{"match":"(?i)\\\\b(utf8_((?:de|en)code)|xml_(set_((notation|(end|start)_namespace|unparsed_entity)_decl_handler|(character_data|default|element|external_entity_ref|processing_instruction)_handler|object)|parse(_into_struct)?|parser_(([gs]et)_option|create(_ns)?|free)|error_string|get_(current_((column|line)_number|byte_index)|error_code)))\\\\b","name":"support.function.xml.php"},{"match":"(?i)\\\\bxmlrpc_(server_(call_method|create|destroy|add_introspection_data|register_(introspection_callback|method))|is_fault|decode(_request)?|parse_method_descriptions|encode(_request)?|([gs]et)_type)\\\\b","name":"support.function.xmlrpc.php"},{"match":"(?i)\\\\bxmlwriter_((end|start|write)_(comment|cdata|dtd(_(attlist|entity|element))?|document|pi|attribute|element)|(start|write)_(attribute|element)_ns|write_raw|set_indent(_string)?|text|output_memory|open_(memory|uri)|full_end_element|flush|)\\\\b","name":"support.function.xmlwriter.php"},{"match":"(?i)\\\\b(zlib_(decode|encode|get_coding_type)|readgzfile|gz(seek|compress|close|tell|inflate|open|decode|deflate|uncompress|puts|passthru|encode|eof|file|write|rewind|read|getc|getss?))\\\\b","name":"support.function.zlib.php"},{"match":"(?i)\\\\bis_int(eger)?\\\\b","name":"support.function.alias.php"}]},"switch_statement":{"patterns":[{"match":"\\\\s+(?=switch\\\\b)"},{"begin":"\\\\bswitch\\\\b(?!\\\\s*\\\\(.*\\\\)\\\\s*:)","beginCaptures":{"0":{"name":"keyword.control.switch.php"}},"end":"}|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.section.switch-block.end.bracket.curly.php"}},"name":"meta.switch-statement.php","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.switch-expression.begin.bracket.round.php"}},"end":"\\\\)|(?=\\\\?>)","endCaptures":{"0":{"name":"punctuation.definition.switch-expression.end.bracket.round.php"}},"patterns":[{"include":"#language"}]},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.section.switch-block.begin.bracket.curly.php"}},"end":"(?=}|\\\\?>)","patterns":[{"include":"#language"}]}]}]},"use-inner":{"patterns":[{"include":"#comments"},{"begin":"(?i)\\\\b(as)\\\\s+","beginCaptures":{"1":{"name":"keyword.other.use-as.php"}},"end":"(?i)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*","endCaptures":{"0":{"name":"entity.other.alias.php"}}},{"include":"#class-name"},{"match":",","name":"punctuation.separator.delimiter.php"}]},"var_basic":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.variable.php"}},"match":"(?i)(\\\\$+)[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*\\\\b","name":"variable.other.php"}]},"var_global":{"captures":{"1":{"name":"punctuation.definition.variable.php"}},"match":"(\\\\$)((_(COOKIE|FILES|GET|POST|REQUEST))|arg([cv]))\\\\b","name":"variable.other.global.php"},"var_global_safer":{"captures":{"1":{"name":"punctuation.definition.variable.php"}},"match":"(\\\\$)((GLOBALS|_(ENV|SERVER|SESSION)))","name":"variable.other.global.safer.php"},"var_language":{"captures":{"1":{"name":"punctuation.definition.variable.php"}},"match":"(\\\\$)this\\\\b","name":"variable.language.this.php"},"variable-name":{"patterns":[{"include":"#var_global"},{"include":"#var_global_safer"},{"captures":{"1":{"name":"variable.other.php"},"2":{"name":"punctuation.definition.variable.php"},"4":{"name":"keyword.operator.class.php"},"5":{"name":"variable.other.property.php"},"6":{"name":"punctuation.section.array.begin.php"},"7":{"name":"constant.numeric.index.php"},"8":{"name":"variable.other.index.php"},"9":{"name":"punctuation.definition.variable.php"},"10":{"name":"string.unquoted.index.php"},"11":{"name":"punctuation.section.array.end.php"}},"match":"(?i)((\\\\$)(?[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*))(?:(->)(\\\\g)|(\\\\[)(?:(\\\\d+)|((\\\\$)\\\\g)|([_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*))(]))?"},{"captures":{"1":{"name":"variable.other.php"},"2":{"name":"punctuation.definition.variable.php"},"4":{"name":"punctuation.definition.variable.php"}},"match":"(?i)((\\\\$\\\\{)(?[_a-z\\\\x7F-ÿ][0-9_a-z\\\\x7F-ÿ]*)(}))"}]},"variables":{"patterns":[{"include":"#var_language"},{"include":"#var_global"},{"include":"#var_global_safer"},{"include":"#var_basic"},{"begin":"\\\\$\\\\{(?=.*?})","beginCaptures":{"0":{"name":"punctuation.definition.variable.php"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.variable.php"}},"patterns":[{"include":"#language"}]}]}},"scopeName":"text.html.php.blade","embeddedLangs":["html-derivative","html","xml","sql","javascript","json","css"]}`)),b=[...e,...t,...n,...a,...r,...i,...p,o];export{b as default}; diff --git a/apps/kimi-code/dist-web/assets/c-BIGW1oBm.js b/apps/kimi-code/dist-web/assets/c-BIGW1oBm.js new file mode 100644 index 0000000000000000000000000000000000000000..10eb5a7e323e952012bdc66c3599894af5b689ac --- /dev/null +++ b/apps/kimi-code/dist-web/assets/c-BIGW1oBm.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"C","name":"c","patterns":[{"include":"#preprocessor-rule-enabled"},{"include":"#preprocessor-rule-disabled"},{"include":"#preprocessor-rule-conditional"},{"include":"#predefined_macros"},{"include":"#comments"},{"include":"#switch_statement"},{"include":"#anon_pattern_1"},{"include":"#storage_types"},{"include":"#anon_pattern_2"},{"include":"#anon_pattern_3"},{"include":"#anon_pattern_4"},{"include":"#anon_pattern_5"},{"include":"#anon_pattern_6"},{"include":"#anon_pattern_7"},{"include":"#operators"},{"include":"#numbers"},{"include":"#strings"},{"include":"#anon_pattern_range_1"},{"include":"#anon_pattern_range_2"},{"include":"#anon_pattern_range_3"},{"include":"#pragma-mark"},{"include":"#anon_pattern_range_4"},{"include":"#anon_pattern_range_5"},{"include":"#anon_pattern_range_6"},{"include":"#anon_pattern_8"},{"include":"#anon_pattern_9"},{"include":"#anon_pattern_10"},{"include":"#anon_pattern_11"},{"include":"#anon_pattern_12"},{"include":"#anon_pattern_13"},{"include":"#block"},{"include":"#parens"},{"include":"#anon_pattern_range_7"},{"include":"#line_continuation_character"},{"include":"#anon_pattern_range_8"},{"include":"#anon_pattern_range_9"},{"include":"#anon_pattern_14"},{"include":"#anon_pattern_15"}],"repository":{"access-method":{"begin":"([A-Z_a-z][0-9A-Z_a-z]*|(?<=[])]))\\\\s*(?:(\\\\.)|(->))((?:[A-Z_a-z][0-9A-Z_a-z]*\\\\s*(?:\\\\.|->))*)\\\\s*([A-Z_a-z][0-9A-Z_a-z]*)(\\\\()","beginCaptures":{"1":{"name":"variable.object.c"},"2":{"name":"punctuation.separator.dot-access.c"},"3":{"name":"punctuation.separator.pointer-access.c"},"4":{"patterns":[{"match":"\\\\.","name":"punctuation.separator.dot-access.c"},{"match":"->","name":"punctuation.separator.pointer-access.c"},{"match":"[A-Z_a-z][0-9A-Z_a-z]*","name":"variable.object.c"},{"match":".+","name":"everything.else.c"}]},"5":{"name":"entity.name.function.member.c"},"6":{"name":"punctuation.section.arguments.begin.bracket.round.function.member.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.arguments.end.bracket.round.function.member.c"}},"name":"meta.function-call.member.c","patterns":[{"include":"#function-call-innards"}]},"anon_pattern_1":{"match":"\\\\b(break|continue|do|else|for|goto|if|_Pragma|return|while)\\\\b","name":"keyword.control.c"},"anon_pattern_10":{"match":"\\\\b((?:int8|int16|int32|int64|uint8|uint16|uint32|uint64|int_least8|int_least16|int_least32|int_least64|uint_least8|uint_least16|uint_least32|uint_least64|int_fast8|int_fast16|int_fast32|int_fast64|uint_fast8|uint_fast16|uint_fast32|uint_fast64|intptr|uintptr|intmax|uintmax)_t)\\\\b","name":"support.type.stdint.c"},"anon_pattern_11":{"match":"\\\\b(noErr|kNilOptions|kInvalidID|kVariableLengthArray)\\\\b","name":"support.constant.mac-classic.c"},"anon_pattern_12":{"match":"\\\\b(AbsoluteTime|Boolean|Byte|ByteCount|ByteOffset|BytePtr|CompTimeValue|ConstLogicalAddress|ConstStrFileNameParam|ConstStringPtr|Duration|Fixed|FixedPtr|Float32|Float32Point|Float64|Float80|Float96|FourCharCode|Fract|FractPtr|Handle|ItemCount|LogicalAddress|OptionBits|OSErr|OSStatus|OSType|OSTypePtr|PhysicalAddress|ProcessSerialNumber|ProcessSerialNumberPtr|ProcHandle|Ptr|ResType|ResTypePtr|ShortFixed|ShortFixedPtr|SignedByte|SInt16|SInt32|SInt64|SInt8|Size|StrFileName|StringHandle|StringPtr|TimeBase|TimeRecord|TimeScale|TimeValue|TimeValue64|UInt16|UInt32|UInt64|UInt8|UniChar|UniCharCount|UniCharCountPtr|UniCharPtr|UnicodeScalarValue|UniversalProcHandle|UniversalProcPtr|UnsignedFixed|UnsignedFixedPtr|UnsignedWide|UTF16Char|UTF32Char|UTF8Char)\\\\b","name":"support.type.mac-classic.c"},"anon_pattern_13":{"match":"\\\\b([0-9A-Z_a-z]+_t)\\\\b","name":"support.type.posix-reserved.c"},"anon_pattern_14":{"match":";","name":"punctuation.terminator.statement.c"},"anon_pattern_15":{"match":",","name":"punctuation.separator.delimiter.c"},"anon_pattern_2":{"match":"typedef","name":"keyword.other.typedef.c"},"anon_pattern_3":{"match":"\\\\b(const|extern|register|restrict|static|volatile|inline)\\\\b","name":"storage.modifier.c"},"anon_pattern_4":{"match":"\\\\bk[A-Z]\\\\w*\\\\b","name":"constant.other.variable.mac-classic.c"},"anon_pattern_5":{"match":"\\\\bg[A-Z]\\\\w*\\\\b","name":"variable.other.readwrite.global.mac-classic.c"},"anon_pattern_6":{"match":"\\\\bs[A-Z]\\\\w*\\\\b","name":"variable.other.readwrite.static.mac-classic.c"},"anon_pattern_7":{"match":"\\\\b(NULL|true|false|TRUE|FALSE)\\\\b","name":"constant.language.c"},"anon_pattern_8":{"match":"\\\\b(u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t)\\\\b","name":"support.type.sys-types.c"},"anon_pattern_9":{"match":"\\\\b(pthread_(?:attr_|cond_|condattr_|mutex_|mutexattr_|once_|rwlock_|rwlockattr_||key_)t)\\\\b","name":"support.type.pthread.c"},"anon_pattern_range_1":{"begin":"((?:(?>\\\\s+)|(/\\\\*)((?>(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+?|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z))((#)\\\\s*define)\\\\b\\\\s+((?","endCaptures":{"0":{"name":"punctuation.definition.string.end.c"}},"name":"string.quoted.other.lt-gt.include.c"}]},"anon_pattern_range_4":{"begin":"^\\\\s*((#)\\\\s*line)\\\\b","beginCaptures":{"1":{"name":"keyword.control.directive.line.c"},"2":{"name":"punctuation.definition.directive.c"}},"end":"(?=/[*/])|(?]+|\\\\(\\\\)|\\\\[]))\\\\s*(\\\\()","beginCaptures":{"1":{"name":"variable.other.c"},"2":{"name":"punctuation.section.parens.begin.bracket.round.initialization.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parens.end.bracket.round.initialization.c"}},"name":"meta.initialization.c","patterns":[{"include":"#function-call-innards"}]},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.c"}},"end":"}|(?=\\\\s*#\\\\s*e(?:lif|lse|ndif)\\\\b)","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.c"}},"patterns":[{"include":"#block_innards"}]},{"include":"#parens-block"},{"include":"$self"}]},"c_conditional_context":{"patterns":[{"include":"$self"},{"include":"#block_innards"}]},"c_function_call":{"begin":"(?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\\\s*\\\\()(?=(?:[A-Z_a-z][0-9A-Z_a-z]*+|::)++\\\\s*\\\\(|(?<=operator)(?:[-!\\\\&*+<=>]+|\\\\(\\\\)|\\\\[])\\\\s*\\\\()","end":"(?<=\\\\))(?!\\\\w)","name":"meta.function-call.c","patterns":[{"include":"#function-call-innards"}]},"case_statement":{"begin":"((?>(?:(?>(?(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z)))((?\\\\s*)(//[!/]+)","beginCaptures":{"1":{"name":"punctuation.definition.comment.documentation.c"}},"end":"(?<=\\\\n)(?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.italic.doxygen.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.bold.doxygen.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.inline.raw.string.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.c"}]},"3":{"name":"variable.parameter.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]param)(?:\\\\s*\\\\[((?:,?\\\\s*(?:in|out)\\\\s*)+)])?\\\\s+\\\\b(\\\\w+)\\\\b"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:arg|attention|authors??|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remarks??|result|returns??|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"\\\\b[A-Z]+:|@[_a-z]+:","name":"storage.type.class.gtkdoc"}]},{"captures":{"1":{"name":"punctuation.definition.comment.begin.documentation.c"},"2":{"patterns":[{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:callergraph|callgraph|else|endif|f\\\\$|f\\\\[|f]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|[\\"-%.<=>]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.italic.doxygen.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.bold.doxygen.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.inline.raw.string.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.c"}]},"3":{"name":"variable.parameter.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]param)(?:\\\\s*\\\\[((?:,?\\\\s*(?:in|out)\\\\s*)+)])?\\\\s+\\\\b(\\\\w+)\\\\b"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:arg|attention|authors??|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remarks??|result|returns??|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"\\\\b[A-Z]+:|@[_a-z]+:","name":"storage.type.class.gtkdoc"}]},"3":{"name":"punctuation.definition.comment.end.documentation.c"}},"match":"(/\\\\*[!*]+(?=\\\\s))(.+)([!*]*\\\\*/)","name":"comment.block.documentation.c"},{"begin":"((?>\\\\s*)/\\\\*[!*]+(?:(?:\\\\n|$)|(?=\\\\s)))","beginCaptures":{"1":{"name":"punctuation.definition.comment.begin.documentation.c"}},"end":"([!*]*\\\\*/)","endCaptures":{"1":{"name":"punctuation.definition.comment.end.documentation.c"}},"name":"comment.block.documentation.c","patterns":[{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:callergraph|callgraph|else|endif|f\\\\$|f\\\\[|f]|hidecallergraph|hidecallgraph|hiderefby|hiderefs|hideinitializer|htmlinclude|n|nosubgrouping|private|privatesection|protected|protectedsection|public|publicsection|pure|showinitializer|showrefby|showrefs|tableofcontents|[\\"-%.<=>]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.italic.doxygen.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.bold.doxygen.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"name":"markup.inline.raw.string.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"captures":{"1":{"name":"storage.type.class.doxygen.c"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.c"}]},"3":{"name":"variable.parameter.c"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]param)(?:\\\\s*\\\\[((?:,?\\\\s*(?:in|out)\\\\s*)+)])?\\\\s+\\\\b(\\\\w+)\\\\b"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:arg|attention|authors??|brief|bug|copyright|date|deprecated|details|exception|invariant|li|note|par|paragraph|param|post|pre|remarks??|result|returns??|retval|sa|see|short|since|test|throw|todo|tparam|version|warning|xrefitem)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:code|cond|docbookonly|dot|htmlonly|internal|latexonly|link|manonly|msc|parblock|rtfonly|secreflist|uml|verbatim|xmlonly|endcode|endcond|enddocbookonly|enddot|endhtmlonly|endinternal|endlatexonly|endlink|endmanonly|endmsc|endparblock|endrtfonly|endsecreflist|enduml|endverbatim|endxmlonly)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.c"},{"match":"\\\\b[A-Z]+:|@[_a-z]+:","name":"storage.type.class.gtkdoc"}]},{"captures":{"1":{"name":"meta.toc-list.banner.block.c"}},"match":"^/\\\\* =(\\\\s*.*?)\\\\s*= \\\\*/$\\\\n?","name":"comment.block.banner.c"},{"begin":"(/\\\\*)","beginCaptures":{"1":{"name":"punctuation.definition.comment.begin.c"}},"end":"(\\\\*/)","endCaptures":{"1":{"name":"punctuation.definition.comment.end.c"}},"name":"comment.block.c"},{"captures":{"1":{"name":"meta.toc-list.banner.line.c"}},"match":"^// =(\\\\s*.*?)\\\\s*=$\\\\n?","name":"comment.line.banner.c"},{"begin":"((?:^[\\\\t ]+)?)(?=//)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.c"}},"end":"(?!\\\\G)","patterns":[{"begin":"(//)","beginCaptures":{"1":{"name":"punctuation.definition.comment.c"}},"end":"(?=\\\\n)","name":"comment.line.double-slash.c","patterns":[{"include":"#line_continuation_character"}]}]}]},{"include":"#block_comment"},{"include":"#line_comment"}]},{"include":"#block_comment"},{"include":"#line_comment"}]},"default_statement":{"begin":"((?>(?:(?>(?(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z)))((?]+|\\\\(\\\\)|\\\\[]))\\\\s*(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.c"},"2":{"name":"punctuation.section.arguments.begin.bracket.round.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.arguments.end.bracket.round.c"}},"patterns":[{"include":"#function-call-innards"}]},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parens.begin.bracket.round.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parens.end.bracket.round.c"}},"patterns":[{"include":"#function-call-innards"}]},{"include":"#block_innards"}]},"function-innards":{"patterns":[{"include":"#comments"},{"include":"#storage_types"},{"include":"#operators"},{"include":"#vararg_ellipses"},{"begin":"(?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\\\s*\\\\()((?:[A-Z_a-z][0-9A-Z_a-z]*+|::)++|(?<=operator)(?:[-!\\\\&*+<=>]+|\\\\(\\\\)|\\\\[]))\\\\s*(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.c"},"2":{"name":"punctuation.section.parameters.begin.bracket.round.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parameters.end.bracket.round.c"}},"name":"meta.function.definition.parameters.c","patterns":[{"include":"#probably_a_parameter"},{"include":"#function-innards"}]},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parens.begin.bracket.round.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parens.end.bracket.round.c"}},"patterns":[{"include":"#function-innards"}]},{"include":"$self"}]},"inline_comment":{"patterns":[{"patterns":[{"captures":{"1":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"2":{"name":"comment.block.c"},"3":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]}},"match":"(/\\\\*)((?>(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/))"},{"captures":{"1":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"2":{"name":"comment.block.c"},"3":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]}},"match":"(/\\\\*)((?:[^*]|\\\\*++[^/])*+(\\\\*++/))"}]},{"captures":{"1":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"2":{"name":"comment.block.c"},"3":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]}},"match":"(/\\\\*)((?:[^*]|\\\\*++[^/])*+(\\\\*++/))"}]},"line_comment":{"patterns":[{"begin":"\\\\s*+(//)","beginCaptures":{"1":{"name":"punctuation.definition.comment.c"}},"end":"(?<=\\\\n)(?\\\\*?))"}]},"5":{"name":"variable.other.member.c"}},"match":"((?:[A-Z_a-z]\\\\w*|(?<=[])]))\\\\s*)(?:(\\\\.\\\\*?)|(->\\\\*?))((?:[A-Z_a-z]\\\\w*\\\\s*(?:\\\\.\\\\*?|->\\\\*?)\\\\s*)*)\\\\s*\\\\b((?!(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|atomic_uintptr_t|atomic_ptrdiff_t|pthread_rwlock_t|atomic_uintmax_t|pthread_mutex_t|atomic_intmax_t|atomic_intptr_t|atomic_char32_t|atomic_char16_t|pthread_attr_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_cond_t|pthread_once_t|uint_fast64_t|uint_fast16_t|atomic_size_t|uint_least8_t|int_least64_t|int_least32_t|int_least16_t|pthread_key_t|atomic_ullong|atomic_ushort|uint_fast32_t|atomic_schar|atomic_short|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast16_t|atomic_ulong|atomic_llong|int_least8_t|atomic_uchar|memory_order|suseconds_t|int_fast8_t|atomic_bool|atomic_char|atomic_uint|atomic_long|atomic_int|useconds_t|_Imaginary|blksize_t|pthread_t|in_addr_t|uintptr_t|in_port_t|uintmax_t|blkcnt_t|uint16_t|unsigned|_Complex|uint32_t|intptr_t|intmax_t|uint64_t|u_quad_t|int64_t|int32_t|ssize_t|caddr_t|clock_t|uint8_t|u_short|swblk_t|segsz_t|int16_t|fixpt_t|daddr_t|nlink_t|qaddr_t|size_t|time_t|mode_t|signed|quad_t|ushort|u_long|u_char|double|int8_t|ino_t|uid_t|pid_t|_Bool|float|dev_t|div_t|short|gid_t|off_t|u_int|key_t|id_t|uint|long|void|char|bool|id_t|int)\\\\b)[A-Z_a-z]\\\\w*\\\\b(?!\\\\())"},"method_access":{"begin":"((?:[A-Z_a-z]\\\\w*|(?<=[])]))\\\\s*)(?:(\\\\.\\\\*?)|(->\\\\*?))((?:[A-Z_a-z]\\\\w*\\\\s*(?:\\\\.\\\\*?|->\\\\*?)\\\\s*)*)\\\\s*([A-Z_a-z]\\\\w*)(\\\\()","beginCaptures":{"1":{"name":"variable.other.object.access.c"},"2":{"name":"punctuation.separator.dot-access.c"},"3":{"name":"punctuation.separator.pointer-access.c"},"4":{"patterns":[{"include":"#member_access"},{"include":"#method_access"},{"captures":{"1":{"name":"variable.other.object.access.c"},"2":{"name":"punctuation.separator.dot-access.c"},"3":{"name":"punctuation.separator.pointer-access.c"}},"match":"((?:[A-Z_a-z]\\\\w*|(?<=[])]))\\\\s*)(?:(\\\\.\\\\*?)|(->\\\\*?))"}]},"5":{"name":"entity.name.function.member.c"},"6":{"name":"punctuation.section.arguments.begin.bracket.round.function.member.c"}},"contentName":"meta.function-call.member.c","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.section.arguments.end.bracket.round.function.member.c"}},"patterns":[{"include":"#function-call-innards"}]},"numbers":{"captures":{"0":{"patterns":[{"begin":"(?=.)","end":"$","patterns":[{"captures":{"1":{"name":"keyword.other.unit.hexadecimal.c"},"2":{"name":"constant.numeric.hexadecimal.c","patterns":[{"match":"(?<=\\\\h)'(?=\\\\h)","name":"punctuation.separator.constant.numeric"}]},"3":{"name":"punctuation.separator.constant.numeric"},"4":{"name":"constant.numeric.hexadecimal.c"},"5":{"name":"constant.numeric.hexadecimal.c","patterns":[{"match":"(?<=\\\\h)'(?=\\\\h)","name":"punctuation.separator.constant.numeric"}]},"6":{"name":"punctuation.separator.constant.numeric"},"8":{"name":"keyword.other.unit.exponent.hexadecimal.c"},"9":{"name":"keyword.operator.plus.exponent.hexadecimal.c"},"10":{"name":"keyword.operator.minus.exponent.hexadecimal.c"},"11":{"name":"constant.numeric.exponent.hexadecimal.c","patterns":[{"match":"(?<=\\\\h)'(?=\\\\h)","name":"punctuation.separator.constant.numeric"}]},"12":{"name":"keyword.other.unit.suffix.floating-point.c"}},"match":"\\\\G(0[Xx])(\\\\h(?:\\\\h|((?<=\\\\h)'(?=\\\\h)))*)?((?<=\\\\h)\\\\.|\\\\.(?=\\\\h))(\\\\h(?:\\\\h|((?<=\\\\h)'(?=\\\\h)))*)?((?>|\\\\|)=","name":"keyword.operator.assignment.compound.bitwise.c"},{"match":"<<|>>","name":"keyword.operator.bitwise.shift.c"},{"match":"!=|<=|>=|==|[<>]","name":"keyword.operator.comparison.c"},{"match":"&&|!|\\\\|\\\\|","name":"keyword.operator.logical.c"},{"match":"[\\\\&^|~]","name":"keyword.operator.c"},{"match":"=","name":"keyword.operator.assignment.c"},{"match":"[-%*+/]","name":"keyword.operator.c"},{"begin":"(\\\\?)","beginCaptures":{"1":{"name":"keyword.operator.ternary.c"}},"end":"(:)","endCaptures":{"1":{"name":"keyword.operator.ternary.c"}},"patterns":[{"include":"#function-call-innards"},{"include":"$self"}]}]},"parens":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parens.begin.bracket.round.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parens.end.bracket.round.c"}},"name":"meta.parens.c","patterns":[{"include":"$self"}]},"parens-block":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parens.begin.bracket.round.c"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parens.end.bracket.round.c"}},"name":"meta.parens.block.c","patterns":[{"include":"#block_innards"},{"match":"(?-im:(?]+|\\\\(\\\\)|\\\\[])\\\\s*\\\\()","end":"(?<=\\\\))(?!\\\\w)|(?]+|\\\\(\\\\)|\\\\[]))\\\\s*(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.c"},"2":{"name":"punctuation.section.arguments.begin.bracket.round.c"}},"end":"(\\\\))|(?])\\\\s*([A-Z_a-z]\\\\w*)\\\\s*(?=(?:\\\\[]\\\\s*)?[),])"},"static_assert":{"begin":"((?>(?:(?>(?(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z)))((?(?:(?>(?(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z)))(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"3":{"name":"comment.block.c"},"4":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]},"5":{"name":"keyword.other.static_assert.c"},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"8":{"name":"comment.block.c"},"9":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]},"10":{"name":"punctuation.section.arguments.begin.bracket.round.static_assert.c"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.section.arguments.end.bracket.round.static_assert.c"}},"patterns":[{"begin":"(,)\\\\s*(?=(?:L|u8?|U\\\\s*\\")?)","beginCaptures":{"1":{"name":"punctuation.separator.delimiter.comma.c"}},"end":"(?=\\\\))","name":"meta.static_assert.message.c","patterns":[{"include":"#string_context"}]},{"include":"#evaluation_context"}]},"storage_types":{"patterns":[{"match":"(?-im:(?\\\\s+)|(/\\\\*)((?>(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+?|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z))(?:\\\\n|$)"},{"include":"#comments"},{"begin":"(((?:(?>\\\\s+)|(/\\\\*)((?>(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+?|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z))\\\\()","beginCaptures":{"1":{"name":"punctuation.section.parens.begin.bracket.round.assembly.c"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"4":{"name":"comment.block.c"},"5":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.section.parens.end.bracket.round.assembly.c"}},"patterns":[{"begin":"(R?)(\\")","beginCaptures":{"1":{"name":"meta.encoding.c"},"2":{"name":"punctuation.definition.string.begin.assembly.c"}},"contentName":"meta.embedded.assembly.c","end":"(\\")","endCaptures":{"1":{"name":"punctuation.definition.string.end.assembly.c"}},"name":"string.quoted.double.c","patterns":[{"include":"source.asm"},{"include":"source.x86"},{"include":"source.x86_64"},{"include":"source.arm"},{"include":"#backslash_escapes"},{"include":"#string_escaped_char"}]},{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.section.parens.begin.bracket.round.assembly.inner.c"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.section.parens.end.bracket.round.assembly.inner.c"}},"patterns":[{"include":"#evaluation_context"}]},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"3":{"name":"comment.block.c"},"4":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]},"5":{"name":"variable.other.asm.label.c"},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"8":{"name":"comment.block.c"},"9":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]}},"match":"\\\\[((?:(?>\\\\s+)|(/\\\\*)((?>(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+?|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z))([A-Z_a-z]\\\\w*)((?:(?>\\\\s+)|(/\\\\*)((?>(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+?|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z))]"},{"match":":","name":"punctuation.separator.delimiter.colon.assembly.c"},{"include":"#comments"}]}]}]},"string_escaped_char":{"patterns":[{"match":"\\\\\\\\([\\"'?\\\\\\\\abefnprtv]|[0-3]\\\\d{0,2}|[4-7]\\\\d?|x\\\\h{0,2}|u\\\\h{0,4}|U\\\\h{0,8})","name":"constant.character.escape.c"},{"match":"\\\\\\\\.","name":"invalid.illegal.unknown-escape.c"}]},"string_placeholder":{"patterns":[{"match":"%(\\\\d+\\\\$)?[- #'+0]*[,:;_]?((-?\\\\d+)|\\\\*(-?\\\\d+\\\\$)?)?(\\\\.((-?\\\\d+)|\\\\*(-?\\\\d+\\\\$)?)?)?(hh?|ll|[Ljlqtz]|vh|vl?|hv|hl)?[%AC-GOSUXac-ginopsux]","name":"constant.other.placeholder.c"},{"captures":{"1":{"name":"invalid.illegal.placeholder.c"}},"match":"(%)(?!\\"\\\\s*(PRI|SCN))"}]},"strings":{"patterns":[{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.c"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.c"}},"name":"string.quoted.double.c","patterns":[{"include":"#string_escaped_char"},{"include":"#string_placeholder"},{"include":"#line_continuation_character"}]},{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.c"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.c"}},"name":"string.quoted.single.c","patterns":[{"include":"#string_escaped_char"},{"include":"#line_continuation_character"}]}]},"switch_conditional_parentheses":{"begin":"((?>(?:(?>(?(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z)))(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.c punctuation.definition.comment.begin.c"},"3":{"name":"comment.block.c"},"4":{"patterns":[{"match":"\\\\*/","name":"comment.block.c punctuation.definition.comment.end.c"},{"match":"\\\\*","name":"comment.block.c"}]},"5":{"name":"punctuation.section.parens.begin.bracket.round.conditional.switch.c"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.section.parens.end.bracket.round.conditional.switch.c"}},"name":"meta.conditional.switch.c","patterns":[{"include":"#evaluation_context"},{"include":"#c_conditional_context"}]},"switch_statement":{"begin":"(((?>(?:(?>(?(?:[^*]|(?>\\\\*+)[^/])*)((?>\\\\*+)/)))+|(?:(?:(?:(?:\\\\b|(?<=\\\\W))|(?=\\\\W))|\\\\A)|\\\\Z)))((?|\\\\?\\\\?>)|(?=[];=>\\\\[])","name":"meta.block.switch.c","patterns":[{"begin":"\\\\G ?","end":"(\\\\{|<%|\\\\?\\\\?<|(?=;))","endCaptures":{"1":{"name":"punctuation.section.block.begin.bracket.curly.switch.c"}},"name":"meta.head.switch.c","patterns":[{"include":"#switch_conditional_parentheses"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","end":"(}|%>|\\\\?\\\\?>)","endCaptures":{"1":{"name":"punctuation.section.block.end.bracket.curly.switch.c"}},"name":"meta.body.switch.c","patterns":[{"include":"#default_statement"},{"include":"#case_statement"},{"include":"$self"},{"include":"#block_innards"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)[\\\\n\\\\s]*","end":"[\\\\n\\\\s]*(?=;)","name":"meta.tail.switch.c","patterns":[{"include":"$self"}]}]},"vararg_ellipses":{"match":"(?)(?!\\\\s*[<=>])","endCaptures":{"1":{"name":"punctuation.definition.type-arguments.end.cadence"}},"name":"meta.type.arguments.cadence","patterns":[{"include":"#type"},{"match":",","name":"punctuation.separator.type-argument.cadence"}]},{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.cadence"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.cadence"}},"name":"meta.group.cadence","patterns":[{"include":"#expression-element-list"}]},{"begin":"(?<=\\\\.)([_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.cadence"},"2":{"name":"punctuation.definition.arguments.begin.cadence"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.cadence"}},"name":"meta.function-call.method.cadence","patterns":[{"include":"#expression-element-list"}]},{"match":"(?<=\\\\.)[_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*","name":"variable.other.member.cadence"},{"include":"#function-call-expression"},{"match":"(?^|~])(:)(?![-!%\\\\&*+./<=>^|~])\\\\s*","beginCaptures":{"1":{"name":"keyword.operator.function-result.cadence"}},"end":"(?","name":"punctuation.separator.mapping.cadence"}]},{"captures":{"1":{"name":"keyword.declaration.entitlement.cadence"},"2":{"name":"entity.name.type.entitlement.cadence"}},"match":"(?","name":"keyword.operator.swap.cadence"},{"match":"\\\\?\\\\.","name":"keyword.operator.optional.chain.cadence"},{"begin":"\\\\b(as(?:\\\\?|!?))\\\\b","beginCaptures":{"0":{"name":"keyword.operator.type.cast.cadence"}},"end":"(?=$|;|//|/\\\\\\\\*|\\")|(?=[),}])|(?<=>)(?=\\\\s*\\\\{(?!\\\\s*[_\\\\p{L}][._\\\\p{L}\\\\p{N}\\\\p{M}]*\\\\s*:))|(?<=[])>?}\\\\p{L}\\\\p{N}])(?=\\\\s*\\\\{(?!\\\\s*[_\\\\p{L}][._\\\\p{L}\\\\p{N}\\\\p{M}]*\\\\s*:))|(?=\\\\?\\\\?)","name":"meta.type.cast-target.cadence","patterns":[{"begin":"\\\\{(?=\\\\s*[_\\\\p{L}][._\\\\p{L}\\\\p{N}\\\\p{M}]*\\\\s*:)","beginCaptures":{"0":{"name":"punctuation.definition.type.dictionary.begin.cadence"}},"end":"(})","endCaptures":{"1":{"name":"punctuation.definition.type.dictionary.end.cadence"}},"name":"meta.type.dictionary.cadence","patterns":[{"include":"#comments"},{"include":"#type"},{"match":":","name":"punctuation.separator.type.dictionary.cadence"},{"match":",","name":"punctuation.separator.type.dictionary.cadence"}]},{"include":"#type"}]},{"match":"-","name":"keyword.operator.arithmetic.unary.cadence"},{"match":"(?<=\\\\))!","name":"keyword.operator.force-unwrap.cadence"},{"match":"!","name":"keyword.operator.logical.not.cadence"},{"match":"=","name":"keyword.operator.assignment.cadence"},{"match":"<-","name":"keyword.operator.move.cadence"},{"match":"<-!","name":"keyword.operator.force-move.cadence"},{"match":"[-*+/]","name":"keyword.operator.arithmetic.cadence"},{"match":"%","name":"keyword.operator.arithmetic.remainder.cadence"},{"match":">>","name":"keyword.operator.bitwise.shift.cadence"},{"match":"<<","name":"keyword.operator.bitwise.shift.cadence"},{"match":"==|!=|[<>]|>=|<=","name":"keyword.operator.comparison.cadence"},{"match":"\\\\?\\\\?","name":"keyword.operator.coalescing.cadence"},{"match":"&&|\\\\|\\\\|","name":"keyword.operator.logical.cadence"},{"match":"[!?]","name":"keyword.operator.type.optional.cadence"}]},"parameter-clause":{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.parameters.begin.cadence"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.parameters.end.cadence"}},"name":"meta.parameter-clause.cadence","patterns":[{"include":"#comments"},{"include":"#parameter-list"}]},"parameter-list":{"patterns":[{"include":"#comments"},{"captures":{"1":{"name":"keyword.operator.unnamed-parameter.cadence"},"2":{"name":"variable.parameter.cadence"}},"match":"(_)\\\\s+([_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*)(?=\\\\s*:)"},{"captures":{"1":{"name":"entity.name.label.cadence"},"2":{"name":"variable.parameter.cadence"}},"match":"([_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*)\\\\s+([_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*)(?=\\\\s*:)"},{"captures":{"1":{"name":"variable.parameter.cadence"}},"match":"([_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*)(?=\\\\s*:)"},{"begin":":\\\\s*(?!\\\\s)","end":"(?=[),])","patterns":[{"include":"#type"},{"match":":","name":"invalid.illegal.extra-colon-in-parameter-list.cadence"}]}]},"path-literals":{"patterns":[{"captures":{"1":{"name":"punctuation.separator.path.cadence"},"2":{"name":"constant.other.path.cadence"}},"match":"(/)((storage|public)(/[_\\\\p{L}][_\\\\p{L}\\\\p{N}\\\\p{M}]*)?)"}]},"pre-post":{"begin":"(?}]|$)","name":"meta.type.function.cadence","patterns":[{"include":"#comments"},{"begin":"\\\\G","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.parameters.end.cadence"}},"patterns":[{"include":"#type"},{"match":",","name":"punctuation.separator.parameter.cadence"}]},{"begin":"(:)","beginCaptures":{"1":{"name":"keyword.operator.function-result.cadence"}},"end":"(?=[]),>}]|$)","name":"meta.function-result.cadence","patterns":[{"include":"#type"}]}]},{"include":"#comments"},{"begin":"(?)","endCaptures":{"1":{"name":"punctuation.definition.type-arguments.end.cadence"}},"name":"meta.type.arguments.cadence","patterns":[{"include":"#type"},{"match":",","name":"punctuation.separator.type-argument.cadence"}]},{"begin":"(?o.lang.round(n.parse(a)[r]);export{t as c}; diff --git a/apps/kimi-code/dist-web/assets/chunk-MOJQB5TN-Dk056XM2.js b/apps/kimi-code/dist-web/assets/chunk-MOJQB5TN-Dk056XM2.js new file mode 100644 index 0000000000000000000000000000000000000000..c9fbd1b3d2650316bc392d7bb9f698f0b6765f40 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/chunk-MOJQB5TN-Dk056XM2.js @@ -0,0 +1,88 @@ +import{_ as p,l as w,D as L,y as E,p as I,E as X,e as H,i as q,c as G}from"./mermaidParser.worker-BFSlSHEW.js";var z="",b="",N="",A=[],R=new Map,k=p(e=>q(e,G()),"sanitizeText"),F=p(e=>{switch(e.type){case"terminal":return{...e,value:k(e.value)};case"nonterminal":return{...e,name:k(e.name)};case"sequence":return{...e,elements:e.elements.map(F)};case"choice":return{...e,alternatives:e.alternatives.map(F)};case"optional":return{...e,element:F(e.element)};case"repetition":return{...e,element:F(e.element),separator:e.separator?F(e.separator):void 0};case"special":return{...e,text:k(e.text)}}},"sanitizeAstNode"),U=p(()=>{z="",b="",N="",A.length=0,R.clear(),I(),w.debug("[Railroad] Database cleared")},"clear"),_=p(e=>{z=k(e),w.debug("[Railroad] Title set:",e)},"setTitle"),W=p(()=>z,"getTitle"),j=p(e=>{const i={...e,name:k(e.name),definition:F(e.definition),comment:e.comment?k(e.comment):void 0};w.debug("[Railroad] Adding rule:",i.name),R.has(i.name)&&w.warn(`[Railroad] Rule '${i.name}' is already defined. Overwriting.`),A.push(i),R.set(i.name,i)},"addRule"),K=p(()=>A,"getRules"),J=p(e=>R.get(e),"getRule"),Q=p(e=>{b=k(e).replace(/^\s+/g,""),w.debug("[Railroad] Accessibility title set:",e)},"setAccTitle"),Z=p(()=>b,"getAccTitle"),V=p(e=>{N=k(e).replace(/\n\s+/g,` +`),w.debug("[Railroad] Accessibility description set:",e)},"setAccDescription"),ee=p(()=>N,"getAccDescription"),te=_,re=W,ie={clear:U,setTitle:_,getTitle:W,addRule:j,getRules:K,getRule:J,setAccTitle:Q,getAccTitle:Z,setAccDescription:V,getAccDescription:ee,setDiagramTitle:te,getDiagramTitle:re},g={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},ne=/^#(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$|^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch)\([\d\s%+,./-]+\)$|^[a-z]+$/i,ae=/^[\w "',.-]+$/,oe=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"]),B=p(e=>e?Object.keys(e).every(i=>i==="railroad"||oe.has(i)):!1,"isRailroadStyleOptions"),le=p(e=>e?"railroad"in e&&e.railroad?e.railroad:B(e)?e:{}:{},"extractRailroadOverrides"),se=p(e=>{if(!e||B(e))return{};const{railroad:i,svgId:a,theme:r,look:t,...n}=e;return n},"extractThemeOverrides"),m=p((e,i)=>{if(typeof e!="string")return i;const a=e.trim();return ne.test(a)?a:i},"sanitizeColorValue"),Y=p((e,i)=>{if(typeof e!="string")return i;const a=e.trim();return ae.test(a)?a:i},"sanitizeFontFamilyValue"),S=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"),de=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"),ce=p(e=>{const i=Y(e.fontFamily,g.fontFamily),a=de(e.fontSize)??g.fontSize;return{...g,fontFamily:i,fontSize:a,terminalFill:m(e.secondBkg??e.secondaryColor,g.terminalFill),terminalStroke:m(e.secondaryBorderColor??e.lineColor,g.terminalStroke),terminalTextColor:m(e.secondaryTextColor??e.textColor,g.terminalTextColor),nonTerminalFill:m(e.mainBkg??e.background,g.nonTerminalFill),nonTerminalStroke:m(e.primaryBorderColor??e.lineColor,g.nonTerminalStroke),nonTerminalTextColor:m(e.primaryTextColor??e.textColor,g.nonTerminalTextColor),lineColor:m(e.lineColor,g.lineColor),markerFill:m(e.lineColor,g.markerFill),commentFill:m(e.labelBackground??e.tertiaryColor,g.commentFill),commentStroke:m(e.tertiaryBorderColor??e.lineColor,g.commentStroke),commentTextColor:m(e.tertiaryTextColor??e.textColor,g.commentTextColor),specialFill:m(e.tertiaryColor??e.secondaryColor,g.specialFill),specialStroke:m(e.tertiaryBorderColor??e.secondaryBorderColor,g.specialStroke),ruleNameColor:m(e.titleColor??e.textColor,g.ruleNameColor)}},"buildThemeDefaults"),M=p(e=>{const i=E(),a={...X(),...i.themeVariables??{},...se(e)},r=ce(a),t={...i.railroad??{},...le(e)};return{compactMode:t.compactMode??r.compactMode,padding:S(t.padding,r.padding),verticalSeparation:S(t.verticalSeparation,r.verticalSeparation),horizontalSeparation:S(t.horizontalSeparation,r.horizontalSeparation),arcRadius:S(t.arcRadius,r.arcRadius),fontSize:S(t.fontSize,r.fontSize),fontFamily:Y(t.fontFamily,r.fontFamily),terminalFill:m(t.terminalFill,r.terminalFill),terminalStroke:m(t.terminalStroke,r.terminalStroke),terminalTextColor:m(t.terminalTextColor,r.terminalTextColor),nonTerminalFill:m(t.nonTerminalFill,r.nonTerminalFill),nonTerminalStroke:m(t.nonTerminalStroke,r.nonTerminalStroke),nonTerminalTextColor:m(t.nonTerminalTextColor,r.nonTerminalTextColor),lineColor:m(t.lineColor,r.lineColor),strokeWidth:S(t.strokeWidth,r.strokeWidth),markerFill:m(t.markerFill,r.markerFill),commentFill:m(t.commentFill,r.commentFill),commentStroke:m(t.commentStroke,r.commentStroke),commentTextColor:m(t.commentTextColor,r.commentTextColor),specialFill:m(t.specialFill,r.specialFill),specialStroke:m(t.specialStroke,r.specialStroke),ruleNameColor:m(t.ruleNameColor,r.ruleNameColor),showMarkers:t.showMarkers??r.showMarkers,markerRadius:S(t.markerRadius,r.markerRadius)}},"buildRailroadStyleOptions"),ue=p(e=>{const{fontFamily:i,fontSize:a,terminalFill:r,terminalStroke:t,terminalTextColor:n,nonTerminalFill:h,nonTerminalStroke:s,nonTerminalTextColor:o,lineColor:u,strokeWidth:c,markerFill:d,commentFill:x,commentStroke:l,commentTextColor:f,specialFill:y,specialStroke:v,ruleNameColor:C}=M(e);return` + .railroad-diagram { + font-family: ${i}; + font-size: ${a}px; + } + + .railroad-terminal rect { + fill: ${r}; + stroke: ${t}; + stroke-width: ${c}px; + } + + .railroad-terminal text { + fill: ${n}; + font-family: ${i}; + font-size: ${a}px; + text-anchor: middle; + dominant-baseline: middle; + } + + .railroad-nonterminal rect { + fill: ${h}; + stroke: ${s}; + stroke-width: ${c}px; + } + + .railroad-nonterminal text { + fill: ${o}; + font-family: ${i}; + font-size: ${a}px; + text-anchor: middle; + dominant-baseline: middle; + } + + .railroad-line { + stroke: ${u}; + stroke-width: ${c}px; + fill: none; + } + + .railroad-start circle, + .railroad-end circle { + fill: ${d}; + } + + .railroad-comment ellipse { + fill: ${x}; + stroke: ${l}; + stroke-width: ${c}px; + } + + .railroad-comment text { + fill: ${f}; + font-style: italic; + font-family: ${i}; + font-size: ${a}px; + text-anchor: middle; + dominant-baseline: middle; + } + + .railroad-special rect { + fill: ${y}; + stroke: ${v}; + stroke-width: ${c}px; + stroke-dasharray: 5,3; + } + + .railroad-special text { + fill: ${o}; + font-family: ${i}; + font-size: ${a}px; + text-anchor: middle; + dominant-baseline: middle; + } + + .railroad-rule-name { + font-weight: bold; + fill: ${C}; + font-family: ${i}; + font-size: ${a}px; + } + + .railroad-group { + /* Grouping container, no specific styles */ + } +`},"getStyles"),T=class{constructor(){this.d=""}static{p(this,"PathBuilder")}moveTo(e,i){return this.d+=`M ${e} ${i} `,this}lineTo(e,i){return this.d+=`L ${e} ${i} `,this}horizontalTo(e){return this.d+=`H ${e} `,this}verticalTo(e){return this.d+=`V ${e} `,this}arcTo(e,i,a,r,t,n,h){return this.d+=`A ${e} ${i} ${a} ${r?1:0} ${t?1:0} ${n} ${h} `,this}build(){return this.d.trim()}},me=class{constructor(e,i=M()){this.textCache=new Map,this.svg=e,this.config=i}static{p(this,"RailroadRenderer")}measureText(e){if(this.textCache.has(e))return this.textCache.get(e);const i=this.svg.append("text").attr("font-family",this.config.fontFamily).attr("font-size",this.config.fontSize).text(e),a=i.node().getBBox(),r={width:a.width,height:a.height};return i.remove(),this.textCache.set(e,r),r}renderTerminal(e,i){const a=this.measureText(i),r=a.width+this.config.padding*2,t=a.height+this.config.padding*2,n=e.append("g").attr("class","railroad-terminal");return n.append("rect").attr("x",0).attr("y",0).attr("width",r).attr("height",t).attr("rx",10).attr("ry",10),n.append("text").attr("x",r/2).attr("y",t/2).text(i),{element:n.node(),dimensions:{width:r,height:t,up:t/2,down:t/2}}}renderNonTerminal(e,i){const a=this.measureText(i),r=a.width+this.config.padding*2,t=a.height+this.config.padding*2,n=e.append("g").attr("class","railroad-nonterminal");return n.append("rect").attr("x",0).attr("y",0).attr("width",r).attr("height",t),n.append("text").attr("x",r/2).attr("y",t/2).text(i),{element:n.node(),dimensions:{width:r,height:t,up:t/2,down:t/2}}}renderSequence(e,i){const a=i.map(o=>this.renderExpression(e,o));let r=0,t=0,n=0;for(const o of a)r+=o.dimensions.width,t=Math.max(t,o.dimensions.up),n=Math.max(n,o.dimensions.down);r+=(a.length-1)*this.config.horizontalSeparation;const h=e.append("g").attr("class","railroad-sequence");let s=0;for(let o=0;othis.renderExpression(e,d));let r=0,t=0;for(const d of a)r=Math.max(r,d.dimensions.width),t+=d.dimensions.height;t+=(a.length-1)*this.config.verticalSeparation;const n=this.config.arcRadius,h=n*4,s=r+h,o=e.append("g").attr("class","railroad-choice");let u=0;const c=t/2;for(const d of a){const x=u,l=x+d.dimensions.up,f=n*2+(r-d.dimensions.width)/2;o.node().appendChild(d.element).setAttribute("transform",`translate(${f}, ${x})`);const v=new T,C=l>c;l===c?v.moveTo(0,c).lineTo(f,l):v.moveTo(0,c).arcTo(n,n,0,!1,C,n,c+(C?n:-n)).lineTo(n,l-(C?n:-n)).arcTo(n,n,0,!1,!C,n*2,l).lineTo(f,l),o.append("path").attr("class","railroad-line").attr("d",v.build());const $=new T,O=f+d.dimensions.width,P=s-n*2;l===c?$.moveTo(O,l).lineTo(s,c):$.moveTo(O,l).lineTo(P,l).arcTo(n,n,0,!1,!C,s-n,l+(C?-n:n)).lineTo(s-n,c+(C?n:-n)).arcTo(n,n,0,!1,C,s,c),o.append("path").attr("class","railroad-line").attr("d",$.build()),u+=d.dimensions.height+this.config.verticalSeparation}return{element:o.node(),dimensions:{width:s,height:t,up:c,down:t-c}}}renderOptional(e,i){const a=this.renderExpression(e,i),r=this.config.arcRadius,t=r*2,n=a.dimensions.width+r*4,h=a.dimensions.height+t,s=e.append("g").attr("class","railroad-optional"),o=r*2,u=t;s.node().appendChild(a.element).setAttribute("transform",`translate(${o}, ${u})`);const d=u+a.dimensions.up,x=new T().moveTo(0,d).lineTo(r*2,d);s.append("path").attr("class","railroad-line").attr("d",x.build());const l=new T().moveTo(o+a.dimensions.width,d).lineTo(n,d);s.append("path").attr("class","railroad-line").attr("d",l.build());const f=new T().moveTo(0,d).arcTo(r,r,0,!1,!1,r,d-r).lineTo(r,r).arcTo(r,r,0,!1,!0,r*2,0).lineTo(n-r*2,0).arcTo(r,r,0,!1,!0,n-r,r).lineTo(n-r,d-r).arcTo(r,r,0,!1,!1,n,d);return s.append("path").attr("class","railroad-line").attr("d",f.build()),{element:s.node(),dimensions:{width:n,height:h,up:d,down:h-d}}}renderRepetition(e,i,a){const r=this.renderExpression(e,i),t=this.config.arcRadius,n=t*2,h=r.dimensions.width+t*4,s=a===0,o=r.dimensions.height+n+(s?n:0),u=e.append("g").attr("class","railroad-repetition"),c=t*2,d=s?n:0;u.node().appendChild(r.element).setAttribute("transform",`translate(${c}, ${d})`);const l=d+r.dimensions.up;u.append("path").attr("class","railroad-line").attr("d",new T().moveTo(0,l).lineTo(t*2,l).build()),u.append("path").attr("class","railroad-line").attr("d",new T().moveTo(c+r.dimensions.width,l).lineTo(h,l).build());const f=d+r.dimensions.height+t,y=new T().moveTo(c+r.dimensions.width,l).arcTo(t,t,0,!1,!0,c+r.dimensions.width+t,l+t).lineTo(c+r.dimensions.width+t,f).arcTo(t,t,0,!1,!0,c+r.dimensions.width,f+t).lineTo(t*2,f+t).arcTo(t,t,0,!1,!0,t,f).lineTo(t,l+t).arcTo(t,t,0,!1,!0,t*2,l);if(u.append("path").attr("class","railroad-line").attr("d",y.build()),s){const v=new T().moveTo(0,l).arcTo(t,t,0,!1,!1,t,l-t).lineTo(t,t).arcTo(t,t,0,!1,!0,t*2,0).lineTo(h-t*2,0).arcTo(t,t,0,!1,!0,h-t,t).lineTo(h-t,l-t).arcTo(t,t,0,!1,!1,h,l);u.append("path").attr("class","railroad-line").attr("d",v.build())}return{element:u.node(),dimensions:{width:h,height:o,up:l,down:o-l}}}renderSpecial(e,i){const a=this.measureText("? "+i+" ?"),r=a.width+this.config.padding*2,t=a.height+this.config.padding*2,n=e.append("g").attr("class","railroad-special");return n.append("rect").attr("x",0).attr("y",0).attr("width",r).attr("height",t),n.append("text").attr("x",r/2).attr("y",t/2).text("? "+i+" ?"),{element:n.node(),dimensions:{width:r,height:t,up:t/2,down:t/2}}}renderExpression(e,i){switch(i.type){case"terminal":return this.renderTerminal(e,i.value);case"nonterminal":return this.renderNonTerminal(e,i.name);case"sequence":return this.renderSequence(e,i.elements);case"choice":return this.renderChoice(e,i.alternatives);case"optional":return this.renderOptional(e,i.element);case"repetition":return this.renderRepetition(e,i.element,i.min);case"special":return this.renderSpecial(e,i.text);default:throw new Error(`Unknown node type: ${i.type}`)}}renderRule(e,i){const a=this.svg.append("g").attr("class","railroad-rule").attr("transform",`translate(0, ${i})`),r=e.name+" =",t=this.measureText(r).width+20,n=t+20,h=a.append("g"),s=this.renderExpression(h,e.definition),o=Math.max(20,s.dimensions.up),u=o-s.dimensions.up;return h.attr("transform",`translate(${n}, ${u})`),a.append("g").attr("class","railroad-rule-name-group").append("text").attr("class","railroad-rule-name").attr("x",0).attr("y",o).text(r),a.append("g").attr("class","railroad-start").append("circle").attr("cx",t).attr("cy",o).attr("r",this.config.markerRadius),a.append("g").attr("class","railroad-end").append("circle").attr("cx",n+s.dimensions.width+10).attr("cy",o).attr("r",this.config.markerRadius),a.append("path").attr("class","railroad-line").attr("d",new T().moveTo(t+this.config.markerRadius,o).lineTo(n,o).build()),a.append("path").attr("class","railroad-line").attr("d",new T().moveTo(n+s.dimensions.width,o).lineTo(n+s.dimensions.width+10-this.config.markerRadius,o).build()),{height:Math.max(40,u+s.dimensions.height+this.config.padding*2),width:n+s.dimensions.width+10+this.config.markerRadius}}renderDiagram(e){let i=this.config.padding,a=0;for(const r of e){const t=this.renderRule(r,i);i+=t.height+this.config.verticalSeparation,a=Math.max(a,t.width)}return{width:a+this.config.padding*2,height:i+this.config.padding}}},D=p((e,i,a)=>{H(e,i.height,i.width,a),e.attr("viewBox",`0 0 ${i.width} ${i.height}`)},"configureRailroadSvgSize"),he=p((e,i,a)=>{w.debug(`[Railroad] Rendering diagram +`+e);try{const r=L(i);r.attr("class","railroad-diagram");const n=E().railroad?.useMaxWidth??!0,h=ie.getRules();if(w.debug(`[Railroad] Rendering ${h.length} rules`),h.length===0){w.warn("[Railroad] No rules to render"),D(r,{height:100,width:200},n);return}const o=new me(r,M()).renderDiagram(h);D(r,o,n),w.debug("[Railroad] Render complete")}catch(r){throw w.error("[Railroad] Render error:",r),r}},"draw"),ge={draw:he};export{ie as d,ue as g,ge as r}; diff --git a/apps/kimi-code/dist-web/assets/chunk-VR4S4FIN-DAoPzKmc.js b/apps/kimi-code/dist-web/assets/chunk-VR4S4FIN-DAoPzKmc.js new file mode 100644 index 0000000000000000000000000000000000000000..9e071eb40e250296b563ef197dfe729f2ef0afd6 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/chunk-VR4S4FIN-DAoPzKmc.js @@ -0,0 +1 @@ +import{_ as a,e as w,l as x}from"./mermaid.core-CCxZmhet.js";var d=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=l(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"),l=a((e,t,i,r,o)=>`${e-o} ${t-o} ${i} ${r}`,"createViewBox");export{d as s}; diff --git a/apps/kimi-code/dist-web/assets/chunk-XXDRQBXY-4Gs_c1bc.js b/apps/kimi-code/dist-web/assets/chunk-XXDRQBXY-4Gs_c1bc.js new file mode 100644 index 0000000000000000000000000000000000000000..6f69b1fc63d0fa593d585f233a48269f2f1fb4f0 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/chunk-XXDRQBXY-4Gs_c1bc.js @@ -0,0 +1 @@ +import{_ as a,d as o}from"./mermaid.core-CCxZmhet.js";var d=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{d as g}; diff --git a/apps/kimi-code/dist-web/assets/cpp-UfJy6YNI.js b/apps/kimi-code/dist-web/assets/cpp-UfJy6YNI.js new file mode 100644 index 0000000000000000000000000000000000000000..00020b0139704e0769d7e1b7ff43a8b46d55777e --- /dev/null +++ b/apps/kimi-code/dist-web/assets/cpp-UfJy6YNI.js @@ -0,0 +1 @@ +import e from"./regexp-CDVJQ6XC.js";import n from"./glsl-DplSGwfg.js";import t from"./sql-CRqJ_cUM.js";import"./c-BIGW1oBm.js";const c=Object.freeze(JSON.parse(`{"displayName":"C++","name":"cpp-macro","patterns":[{"include":"#ever_present_context"},{"include":"#constructor_root"},{"include":"#destructor_root"},{"include":"#function_definition"},{"include":"#operator_overload"},{"include":"#using_namespace"},{"include":"source.cpp#type_alias"},{"include":"source.cpp#using_name"},{"include":"source.cpp#namespace_alias"},{"include":"#namespace_block"},{"include":"#extern_block"},{"include":"#typedef_class"},{"include":"#typedef_struct"},{"include":"#typedef_union"},{"include":"source.cpp#misc_keywords"},{"include":"source.cpp#standard_declares"},{"include":"#class_block"},{"include":"#struct_block"},{"include":"#union_block"},{"include":"#enum_block"},{"include":"source.cpp#template_isolated_definition"},{"include":"#template_definition"},{"include":"source.cpp#template_explicit_instantiation"},{"include":"source.cpp#access_control_keywords"},{"include":"#block"},{"include":"#static_assert"},{"include":"#assembly"},{"include":"#function_pointer"},{"include":"#evaluation_context"}],"repository":{"alignas_attribute":{"begin":"alignas\\\\(","beginCaptures":{"0":{"name":"punctuation.section.attribute.begin.cpp"}},"end":"\\\\)|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.italic.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.bold.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.inline.raw.string.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.cpp"}]},"3":{"patterns":[{"match":"(?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.italic.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.bold.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.inline.raw.string.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.cpp"}]},"3":{"patterns":[{"match":"(?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.italic.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.bold.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.inline.raw.string.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.cpp"}]},"3":{"patterns":[{"match":"(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.call.initializer.cpp"},"2":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"3":{},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"name":"punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp"}},"contentName":"meta.parameter.initialization","end":"\\\\)|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?>(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.call.initializer.cpp"},"2":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"3":{},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"name":"punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp"}},"contentName":"meta.parameter.initialization","end":"\\\\)|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\{)","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?|(?=(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?>(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::))?\\\\s+{0,1}((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\b(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"source.cpp#scope_resolution_function_call_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.function.call.cpp"},"6":{"patterns":[{"include":"source.cpp#inline_comment"}]},"7":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"8":{"name":"comment.block.cpp"},"9":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"10":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"11":{},"12":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"13":{"name":"comment.block.cpp"},"14":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"15":{"name":"punctuation.section.arguments.begin.bracket.round.function.call.cpp"}},"end":"\\\\)|(?=(?|\\\\*/))\\\\s*+(?:((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:__(?:cdec|clrcal|stdcal|fastcal|thiscal|vectorcal)l)?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\b(?|(?=(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|(?=(?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\s*+((?:(?:(?:\\\\[\\\\[.*?]]|__attribute(?:__)?\\\\s*\\\\(\\\\s*\\\\(.*?\\\\)\\\\s*\\\\))|__declspec\\\\(.*?\\\\))|alignas\\\\(.*?\\\\))(?!\\\\)))?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*(?:((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\()(\\\\*)\\\\s+{0,1}((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(?:(\\\\[)(\\\\w*)(])\\\\s+{0,1})*(\\\\))\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?|(?=(?{])(?!\\\\()|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\()(\\\\*)\\\\s+{0,1}((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(?:(\\\\[)(\\\\w*)(])\\\\s+{0,1})*(\\\\))\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?|(?=(?{])(?!\\\\()|(?=(?|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))"}]},"lambdas":{"begin":"(?:(?<=\\\\S|^)(?\\\\[\\\\w])|(?<=(?:\\\\W|^)return))\\\\s+{0,1}(\\\\[(?!\\\\[| *+\\"| *+\\\\d))((?:[^]\\\\[]|((??)++]))*+)(](?!((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)[];=\\\\[]))","beginCaptures":{"1":{"name":"punctuation.definition.capture.begin.lambda.cpp"},"2":{"name":"meta.lambda.capture.cpp","patterns":[{"include":"source.cpp#the_this_keyword"},{"captures":{"1":{"name":"variable.parameter.capture.cpp"},"2":{"patterns":[{"include":"source.cpp#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"punctuation.separator.delimiter.comma.cpp"},"7":{"name":"keyword.operator.assignment.cpp"}},"match":"((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?=]|\\\\z|$)|(,))|(=))"},{"include":"#evaluation_context"}]},"3":{},"4":{"name":"punctuation.definition.capture.end.lambda.cpp"},"5":{"patterns":[{"include":"source.cpp#inline_comment"}]},"6":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"7":{"name":"comment.block.cpp"},"8":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"end":"(?<=[;}])|(?=(?","beginCaptures":{"0":{"name":"punctuation.definition.lambda.return-type.cpp"}},"end":"(?=\\\\{)|(?=(?\\\\*?))((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\s+{0,1}(?:\\\\.\\\\*?|->\\\\*?)\\\\s+{0,1})*)\\\\s+{0,1}(~?(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"source.cpp#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.access.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"},"9":{"patterns":[{"captures":{"1":{"patterns":[{"include":"source.cpp#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.property.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"}},"match":"(?<=\\\\.\\\\*?|->\\\\*??)\\\\s+{0,1}(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))"},{"captures":{"1":{"patterns":[{"include":"source.cpp#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.access.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"}},"match":"(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))"},{"include":"source.cpp#member_access"},{"include":"#method_access"}]},"10":{"name":"entity.name.function.member.cpp"},"11":{"name":"punctuation.section.arguments.begin.bracket.round.function.member.cpp"}},"end":"\\\\)|(?=(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)\\\\s+{0,1}((?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?((?:__(?:cdec|clrcal|stdcal|fastcal|thiscal|vectorcal)l)?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(operator)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(?:(?:(delete\\\\[]|delete|new\\\\[]|<=>|<<=|new|>>=|->\\\\*|/=|%=|&=|>=|\\\\|=|\\\\+\\\\+|--|\\\\(\\\\)|\\\\[]|->|\\\\+\\\\+|<<|>>|--|<=|\\\\^=|==|!=|&&|\\\\|\\\\||\\\\+=|-=|\\\\*=|[!%\\\\&*-\\\\-/<=>^|~])|((?|(?=(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?>|\\\\|)=","name":"keyword.operator.assignment.compound.bitwise.cpp"},{"match":"<<|>>","name":"keyword.operator.bitwise.shift.cpp"},{"match":"!=|<=|>=|==|[<>]","name":"keyword.operator.comparison.cpp"},{"match":"&&|!|\\\\|\\\\|","name":"keyword.operator.logical.cpp"},{"match":"[\\\\&^|~]","name":"keyword.operator.bitwise.cpp"},{"include":"source.cpp#assignment_operator"},{"match":"[-%*+/]","name":"keyword.operator.arithmetic.cpp"},{"include":"#ternary_operator"}]},"parameter":{"begin":"((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?=\\\\w)","beginCaptures":{"1":{"patterns":[{"include":"source.cpp#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"end":"(?:(?=\\\\))|(,))|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|\\\\?\\\\?>)|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?=(?|(?=(?|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\()(\\\\*)\\\\s+{0,1}((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(?:(\\\\[)(\\\\w*)(])\\\\s+{0,1})*(\\\\))\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?|(?=(?{])(?!\\\\()|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[]))|(?=(?|\\\\?\\\\?>|(?=(?|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)|(?=(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)?((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.class.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.class.cpp"}},"name":"meta.head.class.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#inheritance_context"},{"include":"#template_call_range"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.class.cpp"}},"name":"meta.body.class.cpp","patterns":[{"include":"#function_pointer"},{"include":"#static_assert"},{"include":"#constructor_inline"},{"include":"#destructor_inline"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.class.cpp","patterns":[{"include":"$self"}]}]},"class_declare":{"captures":{"1":{"name":"storage.type.class.declare.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"name":"entity.name.type.class.cpp"},"5":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"name":"variable.other.object.declare.cpp"},"13":{"patterns":[{"include":"#inline_comment"}]},"14":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]}},"match":"((?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.italic.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.bold.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.inline.raw.string.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.cpp"}]},"3":{"patterns":[{"match":"(?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.italic.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.bold.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.inline.raw.string.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.cpp"}]},"3":{"patterns":[{"match":"(?]|::|\\\\||---??)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.italic.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\](?:a|em?))\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.bold.doxygen.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\]b)\\\\s+(\\\\S+)"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"name":"markup.inline.raw.string.cpp"}},"match":"((?<=[!*/\\\\s])[@\\\\\\\\][cp])\\\\s+(\\\\S+)"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:a|anchor|[bc]|cite|copybrief|copydetail|copydoc|def|dir|dontinclude|em??|emoji|enum|example|extends|file|idlexcept|implements|include|includedoc|includelineno|latexinclude|link|memberof|namespace|p|package|ref|refitem|related|relates|relatedalso|relatesalso|verbinclude)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"match":"(?<=[!*/\\\\s])[@\\\\\\\\](?:addindex|addtogroup|category|class|defgroup|diafile|dotfile|elseif|fn|headerfile|if|ifnot|image|ingroup|interface|line|mainpage|mscfile|name|overload|page|property|protocol|section|skip|skipline|snippet|snippetdoc|snippetlineno|struct|subpage|subsection|subsubsection|typedef|union|until|vhdlflow|weakgroup)\\\\b(?:\\\\{[^}]*})?","name":"storage.type.class.doxygen.cpp"},{"captures":{"1":{"name":"storage.type.class.doxygen.cpp"},"2":{"patterns":[{"match":"in|out","name":"keyword.other.parameter.direction.$0.cpp"}]},"3":{"patterns":[{"match":"(?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.function.definition.special.constructor.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.function.definition.special.constructor.cpp"}},"name":"meta.head.function.definition.special.constructor.cpp","patterns":[{"include":"#ever_present_context"},{"captures":{"1":{"name":"keyword.operator.assignment.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"keyword.other.default.function.cpp keyword.other.default.constructor.cpp"},"7":{"name":"keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp"}},"match":"(=)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(default)|(delete))"},{"include":"#functional_specifiers_pre_parameters"},{"begin":":","beginCaptures":{"0":{"name":"punctuation.separator.initializers.cpp"}},"end":"(?=\\\\{)","endCaptures":{},"patterns":[{"begin":"((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.call.initializer.cpp"},"2":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"3":{},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"name":"punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp"}},"contentName":"meta.parameter.initialization","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp"}},"patterns":[{"include":"#evaluation_context"}]},{"begin":"((?|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.function.definition.special.constructor.cpp"}},"name":"meta.body.function.definition.special.constructor.cpp","patterns":[{"include":"#function_body_context"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.function.definition.special.constructor.cpp","patterns":[{"include":"$self"}]}]},"constructor_root":{"begin":"\\\\s*+((?:__(?:cdec|clrcal|stdcal|fastcal|thiscal|vectorcal)l)?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?>(?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.function.definition.special.constructor.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.function.definition.special.constructor.cpp"}},"name":"meta.head.function.definition.special.constructor.cpp","patterns":[{"include":"#ever_present_context"},{"captures":{"1":{"name":"keyword.operator.assignment.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"keyword.other.default.function.cpp keyword.other.default.constructor.cpp"},"7":{"name":"keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp"}},"match":"(=)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(default)|(delete))"},{"include":"#functional_specifiers_pre_parameters"},{"begin":":","beginCaptures":{"0":{"name":"punctuation.separator.initializers.cpp"}},"end":"(?=\\\\{)","endCaptures":{},"patterns":[{"begin":"((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.call.initializer.cpp"},"2":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"3":{},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"name":"punctuation.section.arguments.begin.bracket.round.function.call.initializer.cpp"}},"contentName":"meta.parameter.initialization","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.arguments.end.bracket.round.function.call.initializer.cpp"}},"patterns":[{"include":"#evaluation_context"}]},{"begin":"((?|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.function.definition.special.constructor.cpp"}},"name":"meta.body.function.definition.special.constructor.cpp","patterns":[{"include":"#function_body_context"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.function.definition.special.constructor.cpp","patterns":[{"include":"$self"}]}]},"control_flow_keywords":{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"3":{"name":"keyword.control.$3.cpp"}},"match":"(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\{)","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"2":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"3":{"patterns":[{"include":"#inline_comment"}]},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"patterns":[{"include":"#inline_comment"}]},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?]*(>?)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//)))|((\\")[^\\"]*(\\"?)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//))))|((((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*(?:\\\\.(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)*(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//|;))))|(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//|;)))\\\\s+{0,1}(;?)","name":"meta.preprocessor.import.cpp"},"d9bc4796b0b_preprocessor_number_literal":{"captures":{"0":{"patterns":[{"begin":"(?=.)","beginCaptures":{},"end":"$","endCaptures":{},"patterns":[{"captures":{"1":{"name":"keyword.other.unit.hexadecimal.cpp"},"2":{"name":"constant.numeric.hexadecimal.cpp","patterns":[{"match":"(?<=\\\\h)'(?=\\\\h)","name":"punctuation.separator.constant.numeric.cpp"}]},"3":{"name":"punctuation.separator.constant.numeric.cpp"},"4":{"name":"constant.numeric.hexadecimal.cpp"},"5":{"name":"constant.numeric.hexadecimal.cpp","patterns":[{"match":"(?<=\\\\h)'(?=\\\\h)","name":"punctuation.separator.constant.numeric.cpp"}]},"6":{"name":"punctuation.separator.constant.numeric.cpp"},"7":{"name":"keyword.other.unit.exponent.hexadecimal.cpp"},"8":{"name":"keyword.operator.plus.exponent.hexadecimal.cpp"},"9":{"name":"keyword.operator.minus.exponent.hexadecimal.cpp"},"10":{"name":"constant.numeric.exponent.hexadecimal.cpp","patterns":[{"match":"(?<=\\\\h)'(?=\\\\h)","name":"punctuation.separator.constant.numeric.cpp"}]},"11":{"name":"keyword.other.suffix.literal.built-in.floating-point.cpp keyword.other.unit.suffix.floating-point.cpp"}},"match":"\\\\G(0[Xx])(\\\\h(?:\\\\h|((?<=\\\\h)'(?=\\\\h)))*)?((?<=\\\\h)\\\\.|\\\\.(?=\\\\h))(\\\\h(?:\\\\h|((?<=\\\\h)'(?=\\\\h)))*)?(?:(?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.function.definition.special.member.destructor.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.function.definition.special.member.destructor.cpp"}},"name":"meta.head.function.definition.special.member.destructor.cpp","patterns":[{"include":"#ever_present_context"},{"captures":{"1":{"name":"keyword.operator.assignment.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"keyword.other.default.function.cpp keyword.other.default.constructor.cpp keyword.other.default.destructor.cpp"},"7":{"name":"keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp keyword.other.delete.destructor.cpp"}},"match":"(=)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(default)|(delete))"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parameters.begin.bracket.round.special.member.destructor.cpp"}},"contentName":"meta.function.definition.parameters.special.member.destructor","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parameters.end.bracket.round.special.member.destructor.cpp"}},"patterns":[]},{"include":"#qualifiers_and_specifiers_post_parameters"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.function.definition.special.member.destructor.cpp"}},"name":"meta.body.function.definition.special.member.destructor.cpp","patterns":[{"include":"#function_body_context"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.function.definition.special.member.destructor.cpp","patterns":[{"include":"$self"}]}]},"destructor_root":{"begin":"((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:__(?:cdec|clrcal|stdcal|fastcal|thiscal|vectorcal)l)?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?>(?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.function.definition.special.member.destructor.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.function.definition.special.member.destructor.cpp"}},"name":"meta.head.function.definition.special.member.destructor.cpp","patterns":[{"include":"#ever_present_context"},{"captures":{"1":{"name":"keyword.operator.assignment.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"keyword.other.default.function.cpp keyword.other.default.constructor.cpp keyword.other.default.destructor.cpp"},"7":{"name":"keyword.other.delete.function.cpp keyword.other.delete.constructor.cpp keyword.other.delete.destructor.cpp"}},"match":"(=)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(default)|(delete))"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parameters.begin.bracket.round.special.member.destructor.cpp"}},"contentName":"meta.function.definition.parameters.special.member.destructor","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parameters.end.bracket.round.special.member.destructor.cpp"}},"patterns":[]},{"include":"#qualifiers_and_specifiers_post_parameters"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.function.definition.special.member.destructor.cpp"}},"name":"meta.body.function.definition.special.member.destructor.cpp","patterns":[{"include":"#function_body_context"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.function.definition.special.member.destructor.cpp","patterns":[{"include":"$self"}]}]},"diagnostic":{"begin":"^(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(#)\\\\s+{0,1}(error|warning))\\\\b\\\\s+{0,1}","beginCaptures":{"1":{"name":"keyword.control.directive.diagnostic.$7.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"punctuation.definition.directive.cpp"},"7":{}},"end":"(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::))?\\\\s+{0,1}((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.enum.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.enum.cpp"}},"name":"meta.head.enum.cpp","patterns":[{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.enum.cpp"}},"name":"meta.body.enum.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#enumerator_list"},{"include":"#comments"},{"include":"#comma"},{"include":"#semicolon"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.enum.cpp","patterns":[{"include":"$self"}]}]},"enum_declare":{"captures":{"1":{"name":"storage.type.enum.declare.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"name":"entity.name.type.enum.cpp"},"5":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"name":"variable.other.object.declare.cpp"},"13":{"patterns":[{"include":"#inline_comment"}]},"14":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]}},"match":"((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.extern.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.extern.cpp"}},"name":"meta.head.extern.cpp","patterns":[{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.extern.cpp"}},"name":"meta.body.extern.cpp","patterns":[{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.extern.cpp","patterns":[{"include":"$self"}]},{"include":"$self"}]},"function_body_context":{"patterns":[{"include":"#ever_present_context"},{"include":"#using_namespace"},{"include":"#type_alias"},{"include":"#using_name"},{"include":"#namespace_alias"},{"include":"#typedef_class"},{"include":"#typedef_struct"},{"include":"#typedef_union"},{"include":"#misc_keywords"},{"include":"#standard_declares"},{"include":"#class_block"},{"include":"#struct_block"},{"include":"#union_block"},{"include":"#enum_block"},{"include":"#access_control_keywords"},{"include":"#block"},{"include":"#static_assert"},{"include":"#assembly"},{"include":"#function_pointer"},{"include":"#switch_statement"},{"include":"#goto_statement"},{"include":"#evaluation_context"},{"include":"#label"}]},"function_call":{"begin":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\b(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"#scope_resolution_function_call_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.function.call.cpp"},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"8":{"name":"comment.block.cpp"},"9":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"10":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"11":{},"12":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"13":{"name":"comment.block.cpp"},"14":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"15":{"name":"punctuation.section.arguments.begin.bracket.round.function.call.cpp"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.arguments.end.bracket.round.function.call.cpp"}},"patterns":[{"include":"#evaluation_context"}]},"function_definition":{"begin":"(?:(?:^|\\\\G|(?<=[;}]))|(?<=>|\\\\*/))\\\\s*+(?:((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:__(?:cdec|clrcal|stdcal|fastcal|thiscal|vectorcal)l)?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\b(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"14":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"15":{"patterns":[{"include":"#inline_comment"}]},"16":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"17":{"name":"comment.block.cpp"},"18":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"19":{"patterns":[{"include":"#inline_comment"}]},"20":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"21":{"name":"comment.block.cpp"},"22":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"23":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.function.definition.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.function.definition.cpp"}},"name":"meta.head.function.definition.cpp","patterns":[{"include":"#ever_present_context"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parameters.begin.bracket.round.cpp"}},"contentName":"meta.function.definition.parameters","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parameters.end.bracket.round.cpp"}},"patterns":[{"include":"#ever_present_context"},{"include":"#parameter_or_maybe_value"},{"include":"#comma"},{"include":"#evaluation_context"}]},{"captures":{"1":{"name":"punctuation.definition.function.return-type.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"7":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"10":{"name":"comment.block.cpp"},"11":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"12":{"patterns":[{"include":"#inline_comment"}]},"13":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"14":{"name":"comment.block.cpp"},"15":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"16":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\s*+((?:(?:(?:\\\\[\\\\[.*?]]|__attribute(?:__)?\\\\s*\\\\(\\\\s*\\\\(.*?\\\\)\\\\s*\\\\))|__declspec\\\\(.*?\\\\))|alignas\\\\(.*?\\\\))(?!\\\\)))?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*(?:((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.function.definition.cpp"}},"name":"meta.body.function.definition.cpp","patterns":[{"include":"#function_body_context"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.function.definition.cpp","patterns":[{"include":"$self"}]}]},"function_parameter_context":{"patterns":[{"include":"#ever_present_context"},{"include":"#parameter"},{"include":"#comma"}]},"function_pointer":{"begin":"(\\\\s*+((?:(?:(?:\\\\[\\\\[.*?]]|__attribute(?:__)?\\\\s*\\\\(\\\\s*\\\\(.*?\\\\)\\\\s*\\\\))|__declspec\\\\(.*?\\\\))|alignas\\\\(.*?\\\\))(?!\\\\)))?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*(?:((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\()(\\\\*)\\\\s+{0,1}((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(?:(\\\\[)(\\\\w*)(])\\\\s+{0,1})*(\\\\))\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"2":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"3":{"patterns":[{"include":"#inline_comment"}]},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"patterns":[{"include":"#inline_comment"}]},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?{])(?!\\\\()","endCaptures":{"1":{"name":"punctuation.section.parameters.end.bracket.round.function.pointer.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"patterns":[{"include":"#function_parameter_context"}]},"function_pointer_parameter":{"begin":"(\\\\s*+((?:(?:(?:\\\\[\\\\[.*?]]|__attribute(?:__)?\\\\s*\\\\(\\\\s*\\\\(.*?\\\\)\\\\s*\\\\))|__declspec\\\\(.*?\\\\))|alignas\\\\(.*?\\\\))(?!\\\\)))?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*(?:((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\()(\\\\*)\\\\s+{0,1}((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(?:(\\\\[)(\\\\w*)(])\\\\s+{0,1})*(\\\\))\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"2":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"3":{"patterns":[{"include":"#inline_comment"}]},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"patterns":[{"include":"#inline_comment"}]},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?{])(?!\\\\()","endCaptures":{"1":{"name":"punctuation.section.parameters.end.bracket.round.function.pointer.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"patterns":[{"include":"#function_parameter_context"}]},"functional_specifiers_pre_parameters":{"match":"(?]*(>?)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//)))|((\\")[^\\"]*(\\"?)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//))))|((((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*(?:\\\\.(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)*(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//|;))))|(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:\\\\n|$)|(?=//|;)))","name":"meta.preprocessor.include.cpp"},"inheritance_context":{"patterns":[{"include":"#ever_present_context"},{"match":",","name":"punctuation.separator.delimiter.comma.inheritance.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"2":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"3":{"patterns":[{"include":"#inline_comment"}]},"4":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"5":{"patterns":[{"include":"#inline_comment"}]},"6":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"7":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))"}]},"inline_builtin_storage_type":{"captures":{"1":{"name":"storage.type.primitive.cpp storage.type.built-in.primitive.cpp"},"2":{"name":"storage.type.cpp storage.type.built-in.cpp"},"3":{"name":"support.type.posix-reserved.pthread.cpp support.type.built-in.posix-reserved.pthread.cpp"},"4":{"name":"support.type.posix-reserved.cpp support.type.built-in.posix-reserved.cpp"}},"match":"\\\\s*+(?\\\\[\\\\w])|(?<=(?:\\\\W|^)return))\\\\s+{0,1}(\\\\[(?!\\\\[| *+\\"| *+\\\\d))((?:[^]\\\\[]|((??)++]))*+)(](?!((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)[];=\\\\[]))","beginCaptures":{"1":{"name":"punctuation.definition.capture.begin.lambda.cpp"},"2":{"name":"meta.lambda.capture.cpp","patterns":[{"include":"#the_this_keyword"},{"captures":{"1":{"name":"variable.parameter.capture.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"punctuation.separator.delimiter.comma.cpp"},"7":{"name":"keyword.operator.assignment.cpp"}},"match":"((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?=]|\\\\z|$)|(,))|(=))"},{"include":"#evaluation_context"}]},"3":{},"4":{"name":"punctuation.definition.capture.end.lambda.cpp"},"5":{"patterns":[{"include":"#inline_comment"}]},"6":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"7":{"name":"comment.block.cpp"},"8":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"end":"(?<=[;}])","endCaptures":{},"patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.parameters.begin.lambda.cpp"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.parameters.end.lambda.cpp"}},"name":"meta.function.definition.parameters.lambda.cpp","patterns":[{"include":"#function_parameter_context"}]},{"match":"(?","beginCaptures":{"0":{"name":"punctuation.definition.lambda.return-type.cpp"}},"end":"(?=\\\\{)","endCaptures":{},"patterns":[{"include":"#comments"},{"match":"\\\\S+","name":"storage.type.return-type.lambda.cpp"}]},{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.lambda.cpp"}},"end":"}","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.lambda.cpp"}},"name":"meta.function.definition.body.lambda.cpp","patterns":[{"include":"$self"}]}]},"language_constants":{"match":"(?\\\\*??)\\\\s+{0,1}(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.access.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"}},"match":"(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))"},{"include":"#member_access"},{"include":"#method_access"}]},"8":{"name":"variable.other.property.cpp"}},"match":"(?:(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\s+{0,1}(?:\\\\.\\\\*?|->\\\\*?)\\\\s+{0,1})*)\\\\s+{0,1}\\\\b((?!(?:uint_least32_t|uint_least16_t|uint_least64_t|int_least32_t|int_least64_t|uint_fast32_t|uint_fast64_t|uint_least8_t|uint_fast16_t|int_least16_t|int_fast16_t|int_least8_t|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast8_t|suseconds_t|useconds_t|in_addr_t|uintmax_t|in_port_t|uintptr_t|blksize_t|uint32_t|uint64_t|u_quad_t|intmax_t|unsigned|blkcnt_t|uint16_t|intptr_t|swblk_t|wchar_t|u_short|qaddr_t|caddr_t|daddr_t|fixpt_t|nlink_t|segsz_t|clock_t|ssize_t|int16_t|int32_t|int64_t|uint8_t|int8_t|mode_t|quad_t|ushort|u_long|u_char|double|signed|time_t|size_t|key_t|div_t|ino_t|uid_t|gid_t|off_t|pid_t|float|dev_t|u_int|short|bool|id_t|uint|long|char|void|auto|id_t|int)\\\\W)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b(?!\\\\())"},"memory_operators":{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"3":{"name":"keyword.operator.wordlike.cpp"},"4":{"name":"keyword.operator.delete.array.cpp"},"5":{"name":"keyword.operator.delete.array.bracket.cpp"},"6":{"name":"keyword.operator.delete.cpp"},"7":{"name":"keyword.operator.new.cpp"}},"match":"(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:(?:(delete)\\\\s+{0,1}(\\\\[])|(delete))|(new))(?!\\\\w))"},"method_access":{"begin":"(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\s+{0,1}(?:\\\\.\\\\*?|->\\\\*?)\\\\s+{0,1})*)\\\\s+{0,1}(~?(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.access.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"},"9":{"patterns":[{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.property.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"}},"match":"(?<=\\\\.\\\\*?|->\\\\*??)\\\\s+{0,1}(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"variable.language.this.cpp"},"6":{"name":"variable.other.object.access.cpp"},"7":{"name":"punctuation.separator.dot-access.cpp"},"8":{"name":"punctuation.separator.pointer-access.cpp"}},"match":"(?:((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?\\\\*?))"},{"include":"#member_access"},{"include":"#method_access"}]},"10":{"name":"entity.name.function.member.cpp"},"11":{"name":"punctuation.section.arguments.begin.bracket.round.function.member.cpp"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.arguments.end.bracket.round.function.member.cpp"}},"patterns":[{"include":"#evaluation_context"}]},"misc_keywords":{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"3":{"name":"keyword.other.$3.cpp"}},"match":"(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)\\\\s+{0,1}((?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.block.namespace.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.namespace.cpp"}},"name":"meta.head.namespace.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#attributes_context"},{"captures":{"1":{"patterns":[{"include":"#scope_resolution_namespace_block_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.namespace.cpp"},"6":{"name":"punctuation.separator.scope-resolution.namespace.block.cpp"},"7":{"name":"storage.modifier.inline.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)\\\\s+{0,1}((?|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.namespace.cpp"}},"name":"meta.body.namespace.cpp","patterns":[{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.namespace.cpp","patterns":[{"include":"$self"}]}]},"noexcept_operator":{"begin":"((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?((?:__(?:cdec|clrcal|stdcal|fastcal|thiscal|vectorcal)l)?)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(operator)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?:::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(?:(?:(delete\\\\[]|delete|new\\\\[]|<=>|<<=|new|>>=|->\\\\*|/=|%=|&=|>=|\\\\|=|\\\\+\\\\+|--|\\\\(\\\\)|\\\\[]|->|\\\\+\\\\+|<<|>>|--|<=|\\\\^=|==|!=|&&|\\\\|\\\\||\\\\+=|-=|\\\\*=|[!%\\\\&*-\\\\-/<=>^|~])|((?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"6":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"7":{"patterns":[{"include":"#inline_comment"}]},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"patterns":[{"include":"#inline_comment"}]},"12":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"13":{"name":"comment.block.cpp"},"14":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"15":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.function.definition.special.operator-overload.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.function.definition.special.operator-overload.cpp"}},"name":"meta.head.function.definition.special.operator-overload.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#template_call_range"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parameters.begin.bracket.round.special.operator-overload.cpp"}},"contentName":"meta.function.definition.parameters.special.operator-overload","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parameters.end.bracket.round.special.operator-overload.cpp"}},"patterns":[{"include":"#function_parameter_context"},{"include":"#evaluation_context"}]},{"include":"#qualifiers_and_specifiers_post_parameters"},{"captures":{"1":{"name":"keyword.operator.assignment.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"name":"keyword.other.default.function.cpp"},"7":{"name":"keyword.other.delete.function.cpp"}},"match":"(=)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(default)|(delete))"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.function.definition.special.operator-overload.cpp"}},"name":"meta.body.function.definition.special.operator-overload.cpp","patterns":[{"include":"#function_body_context"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.function.definition.special.operator-overload.cpp","patterns":[{"include":"$self"}]}]},"operators":{"patterns":[{"begin":"((?>|\\\\|)=","name":"keyword.operator.assignment.compound.bitwise.cpp"},{"match":"<<|>>","name":"keyword.operator.bitwise.shift.cpp"},{"match":"!=|<=|>=|==|[<>]","name":"keyword.operator.comparison.cpp"},{"match":"&&|!|\\\\|\\\\|","name":"keyword.operator.logical.cpp"},{"match":"[\\\\&^|~]","name":"keyword.operator.bitwise.cpp"},{"include":"#assignment_operator"},{"match":"[-%*+/]","name":"keyword.operator.arithmetic.cpp"},{"include":"#ternary_operator"}]},"over_qualified_types":{"patterns":[{"captures":{"1":{"name":"storage.type.struct.parameter.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"name":"entity.name.type.struct.parameter.cpp"},"5":{"patterns":[{"include":"#inline_comment"}]},"6":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"7":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"patterns":[{"include":"#inline_comment"}]},"13":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"14":{"name":"variable.other.object.declare.cpp"},"15":{"patterns":[{"include":"#inline_comment"}]},"16":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"17":{"patterns":[{"include":"#inline_comment"}]},"18":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"19":{"patterns":[{"include":"#inline_comment"}]},"20":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]}},"match":"\\\\b(struct)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"1":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"patterns":[{"include":"#inline_comment"}]},"5":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"6":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w])","name":"meta.qualified_type.cpp"},"qualifiers_and_specifiers_post_parameters":{"captures":{"1":{"patterns":[{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"5":{"name":"storage.modifier.specifier.functional.post-parameters.$5.cpp"}},"match":"((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_function_call":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_function_call_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_function_call_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_function_call_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.function.call.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_function_definition":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_function_definition_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_function_definition_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_function_definition_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.function.definition.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_function_definition_operator_overload":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_function_definition_operator_overload_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_function_definition_operator_overload_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_function_definition_operator_overload_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.function.definition.operator-overload.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.operator-overload.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_namespace_alias":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_namespace_alias_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_namespace_alias_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_namespace_alias_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.namespace.alias.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_namespace_block":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_namespace_block_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_namespace_block_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_namespace_block_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.namespace.block.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_namespace_using":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_namespace_using_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_namespace_using_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_namespace_using_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.namespace.using.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_parameter":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_parameter_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_parameter_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_parameter_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.parameter.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.parameter.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_template_call":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_template_call_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_template_call_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_template_call_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.template.call.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"scope_resolution_template_definition":{"captures":{"0":{"patterns":[{"include":"#scope_resolution_template_definition_inner_generated"}]},"1":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp"},"2":{"patterns":[{"include":"#template_call_range"}]}},"match":"(::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+"},"scope_resolution_template_definition_inner_generated":{"captures":{"1":{"patterns":[{"include":"#scope_resolution_template_definition_inner_generated"}]},"2":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp"},"3":{"patterns":[{"include":"#template_call_range"}]},"4":{},"5":{"name":"entity.name.scope-resolution.template.definition.cpp"},"6":{"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_range"}]},"7":{},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp"}},"match":"((::)?(?:(?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)((?!\\\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|thread_local|dynamic_cast|synchronized|static_cast|const_cast|consteval|co_return|protected|constinit|constexpr|co_return|consteval|namespace|constexpr|co_await|explicit|volatile|noexcept|co_yield|noexcept|requires|typename|decltype|operator|template|continue|co_await|co_yield|volatile|register|restrict|reflexpr|mutable|alignof|include|private|defined|typedef|_Pragma|__asm__|concept|mutable|warning|default|virtual|alignas|public|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|struct|static|extern|inline|friend|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|compl|while|ifdef|const|bitor|union|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|not|try|for|asm|and|xor|new|do|if|or|if)\\\\b)(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?(::)"},"semicolon":{"match":";","name":"punctuation.terminator.statement.cpp"},"simple_type":{"captures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"2":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"3":{"patterns":[{"include":"#inline_comment"}]},"4":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"5":{"patterns":[{"include":"#inline_comment"}]},"6":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"7":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))((((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*](((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?"},"single_line_macro":{"captures":{"0":{"patterns":[{"include":"#macro"},{"include":"#comments"}]},"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]}},"match":"^(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)#define.*(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.struct.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.struct.cpp"}},"name":"meta.head.struct.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#inheritance_context"},{"include":"#template_call_range"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.struct.cpp"}},"name":"meta.body.struct.cpp","patterns":[{"include":"#function_pointer"},{"include":"#static_assert"},{"include":"#constructor_inline"},{"include":"#destructor_inline"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.struct.cpp","patterns":[{"include":"$self"}]}]},"struct_declare":{"captures":{"1":{"name":"storage.type.struct.declare.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"name":"entity.name.type.struct.cpp"},"5":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"name":"variable.other.object.declare.cpp"},"13":{"patterns":[{"include":"#inline_comment"}]},"14":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]}},"match":"((?|\\\\?\\\\?>)|(?=[];=>\\\\[])","endCaptures":{},"name":"meta.block.switch.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.switch.cpp"}},"name":"meta.head.switch.cpp","patterns":[{"include":"#switch_conditional_parentheses"},{"include":"$self"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.switch.cpp"}},"name":"meta.body.switch.cpp","patterns":[{"include":"#default_statement"},{"include":"#case_statement"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.switch.cpp","patterns":[{"include":"$self"}]}]},"template_argument_defaulted":{"captures":{"1":{"name":"storage.type.template.argument.$1.cpp"},"2":{"name":"entity.name.type.template.cpp"},"3":{"name":"keyword.operator.assignment.cpp"}},"match":"(?<=[,<])\\\\s+{0,1}((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\s+((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(=)"},"template_call_context":{"patterns":[{"include":"#ever_present_context"},{"include":"#template_call_range"},{"include":"#storage_types"},{"include":"#language_constants"},{"include":"#scope_resolution_template_call_inner_generated"},{"include":"#operators"},{"include":"#number_literal"},{"include":"#string_context"},{"include":"#comma_in_template_argument"},{"include":"#qualified_type"}]},"template_call_innards":{"captures":{"0":{"patterns":[{"include":"#template_call_range"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+","name":"meta.template.call.cpp"},"template_call_range":{"begin":"<","beginCaptures":{"0":{"name":"punctuation.section.angle-brackets.begin.template.call.cpp"}},"end":">","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},"template_definition":{"begin":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.definition.cpp"}},"name":"meta.template.definition.cpp","patterns":[{"begin":"(?<=\\\\w)\\\\s+{0,1}<","beginCaptures":{"0":{"name":"punctuation.section.angle-brackets.begin.template.call.cpp"}},"end":">","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"patterns":[{"include":"#template_call_context"}]},{"include":"#template_definition_context"}]},"template_definition_argument":{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"3":{"name":"storage.type.template.argument.$3.cpp"},"4":{"patterns":[{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"storage.type.template.argument.$0.cpp"}]},"5":{"name":"entity.name.type.template.cpp"},"6":{"name":"storage.type.template.argument.$6.cpp"},"7":{"name":"punctuation.vararg-ellipses.template.definition.cpp"},"8":{"name":"entity.name.type.template.cpp"},"9":{"name":"storage.type.template.cpp"},"10":{"name":"punctuation.section.angle-brackets.begin.template.definition.cpp"},"11":{"name":"storage.type.template.argument.$11.cpp"},"12":{"name":"entity.name.type.template.cpp"},"13":{"name":"punctuation.section.angle-brackets.end.template.definition.cpp"},"14":{"name":"storage.type.template.argument.$14.cpp"},"15":{"name":"entity.name.type.template.cpp"},"16":{"name":"keyword.operator.assignment.cpp"},"17":{"name":"punctuation.separator.delimiter.comma.template.argument.cpp"}},"match":"(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(?:(?:(?:((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)|((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\s+)+)((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*))|((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)\\\\s+{0,1}(\\\\.\\\\.\\\\.)\\\\s+{0,1}((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*))|(?)\\\\s+{0,1}(class|typename)(?:\\\\s+((?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*))?)\\\\s+{0,1}(?:(=)\\\\s+{0,1}(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?(?:(,)|(?=>|$))"},"template_definition_context":{"patterns":[{"include":"#scope_resolution_template_definition_inner_generated"},{"include":"#template_definition_argument"},{"include":"#template_argument_defaulted"},{"include":"#template_call_innards"},{"include":"#evaluation_context"}]},"template_explicit_instantiation":{"captures":{"1":{"name":"storage.modifier.specifier.extern.cpp"},"2":{"name":"storage.type.template.cpp"}},"match":"(?)\\\\s+{0,1}$"},"ternary_operator":{"applyEndPatternLast":1,"begin":"\\\\?","beginCaptures":{"0":{"name":"keyword.operator.ternary.cpp"}},"end":":","endCaptures":{"0":{"name":"keyword.operator.ternary.cpp"}},"patterns":[{"include":"#ever_present_context"},{"include":"#string_context"},{"include":"#number_literal"},{"include":"#method_access"},{"include":"#member_access"},{"include":"#predefined_macros"},{"include":"#operators"},{"include":"#memory_operators"},{"include":"#wordlike_operators"},{"include":"#type_casting_operators"},{"include":"#control_flow_keywords"},{"include":"#exception_keywords"},{"include":"#the_this_keyword"},{"include":"#language_constants"},{"include":"#builtin_storage_type_initilizer"},{"include":"#qualifiers_and_specifiers_post_parameters"},{"include":"#functional_specifiers_pre_parameters"},{"include":"#storage_types"},{"include":"#lambdas"},{"include":"#attributes_context"},{"include":"#parentheses"},{"include":"#function_call"},{"include":"#scope_resolution_inner_generated"},{"include":"#square_brackets"},{"include":"#semicolon"},{"include":"#comma"}]},"the_this_keyword":{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"3":{"name":"variable.language.this.cpp"}},"match":"(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"9":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"patterns":[{"include":"#inline_comment"}]},"13":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"14":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))|(.*(?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.class.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.class.cpp"}},"name":"meta.head.class.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#inheritance_context"},{"include":"#template_call_range"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.class.cpp"}},"name":"meta.body.class.cpp","patterns":[{"include":"#function_pointer"},{"include":"#static_assert"},{"include":"#constructor_inline"},{"include":"#destructor_inline"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.class.cpp","patterns":[{"captures":{"1":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"8":{"name":"comment.block.cpp"},"9":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"12":{"name":"comment.block.cpp"},"13":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"14":{"name":"entity.name.type.alias.cpp"}},"match":"(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(\\\\()(\\\\*)\\\\s+{0,1}((?:(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*)?)\\\\s+{0,1}(?:(\\\\[)(\\\\w*)(])\\\\s+{0,1})*(\\\\))\\\\s+{0,1}(\\\\()","beginCaptures":{"1":{"name":"meta.qualified_type.cpp","patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp"},{"match":"(?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"2":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"3":{"patterns":[{"include":"#inline_comment"}]},"4":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"5":{"name":"comment.block.cpp"},"6":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"7":{"patterns":[{"include":"#inline_comment"}]},"8":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"9":{"name":"comment.block.cpp"},"10":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"11":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?{])(?!\\\\()","endCaptures":{"1":{"name":"punctuation.section.parameters.end.bracket.round.function.pointer.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"patterns":[{"include":"#function_parameter_context"}]}]},"typedef_struct":{"begin":"((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.struct.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.struct.cpp"}},"name":"meta.head.struct.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#inheritance_context"},{"include":"#template_call_range"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.struct.cpp"}},"name":"meta.body.struct.cpp","patterns":[{"include":"#function_pointer"},{"include":"#static_assert"},{"include":"#constructor_inline"},{"include":"#destructor_inline"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.struct.cpp","patterns":[{"captures":{"1":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"8":{"name":"comment.block.cpp"},"9":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"12":{"name":"comment.block.cpp"},"13":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"14":{"name":"entity.name.type.alias.cpp"}},"match":"(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.union.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.union.cpp"}},"name":"meta.head.union.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#inheritance_context"},{"include":"#template_call_range"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.union.cpp"}},"name":"meta.body.union.cpp","patterns":[{"include":"#function_pointer"},{"include":"#static_assert"},{"include":"#constructor_inline"},{"include":"#destructor_inline"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.union.cpp","patterns":[{"captures":{"1":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"4":{"name":"comment.block.cpp"},"5":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"8":{"name":"comment.block.cpp"},"9":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"12":{"name":"comment.block.cpp"},"13":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"},"14":{"name":"entity.name.type.alias.cpp"}},"match":"(((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)?(?:[\\\\&*]((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))*[\\\\&*])?((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?","endCaptures":{"0":{"name":"punctuation.section.angle-brackets.end.template.call.cpp"}},"name":"meta.template.call.cpp","patterns":[{"include":"#template_call_context"}]},{"match":"(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*","name":"entity.name.type.cpp"}]},"7":{"patterns":[{"include":"#attributes_context"},{"include":"#number_literal"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"patterns":[{"match":"::","name":"punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.type.cpp"},{"match":"(?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*+)(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z))?(?!(?:transaction_safe_dynamic|__has_cpp_attribute|reinterpret_cast|transaction_safe|atomic_noexcept|atomic_commit|__has_include|atomic_cancel|synchronized|thread_local|dynamic_cast|static_cast|const_cast|constexpr|co_return|constinit|namespace|protected|consteval|constexpr|co_return|consteval|co_await|continue|template|reflexpr|volatile|register|co_await|co_yield|restrict|noexcept|volatile|override|explicit|decltype|operator|noexcept|typename|requires|co_yield|nullptr|alignof|alignas|default|mutable|virtual|mutable|private|include|warning|_Pragma|defined|typedef|__asm__|concept|define|module|sizeof|switch|delete|pragma|and_eq|inline|xor_eq|typeid|import|extern|public|bitand|static|export|return|friend|ifndef|not_eq|false|final|break|const|catch|endif|ifdef|undef|error|audit|while|using|axiom|or_eq|compl|throw|bitor|const|line|case|else|this|true|goto|else|NULL|elif|new|asm|xor|and|try|not|for|do|if|or|if)\\\\b)(?:[A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))(?:[0-9A-Z_a-z]|\\\\\\\\(?:u\\\\h{4}|U\\\\h{8}))*\\\\b((?|(?:[^\\"'/<>]|/[^*])++)*>)?(?![.:<\\\\w]))"},"undef":{"captures":{"1":{"name":"keyword.control.directive.undef.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"name":"punctuation.definition.directive.cpp"},"5":{"patterns":[{"include":"#inline_comment"}]},"6":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"7":{"name":"entity.name.function.preprocessor.cpp"}},"match":"^((((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)(#)\\\\s+{0,1}undef)\\\\b(((?:\\\\s*+/\\\\*(?:[^*]++|\\\\*+(?!/))*+\\\\*/\\\\s*+)+)|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)((?|\\\\?\\\\?>)\\\\s+{0,1}(;)|(;))|(?=[];=>\\\\[])","endCaptures":{"1":{"name":"punctuation.terminator.statement.cpp"},"2":{"name":"punctuation.terminator.statement.cpp"}},"name":"meta.block.union.cpp","patterns":[{"begin":"\\\\G ?","beginCaptures":{},"end":"\\\\{|<%|\\\\?\\\\?<|(?=;)","endCaptures":{"0":{"name":"punctuation.section.block.begin.bracket.curly.union.cpp"}},"name":"meta.head.union.cpp","patterns":[{"include":"#ever_present_context"},{"include":"#inheritance_context"},{"include":"#template_call_range"}]},{"begin":"(?<=\\\\{|<%|\\\\?\\\\?<)","beginCaptures":{},"end":"}|%>|\\\\?\\\\?>","endCaptures":{"0":{"name":"punctuation.section.block.end.bracket.curly.union.cpp"}},"name":"meta.body.union.cpp","patterns":[{"include":"#function_pointer"},{"include":"#static_assert"},{"include":"#constructor_inline"},{"include":"#destructor_inline"},{"include":"$self"}]},{"begin":"(?<=}|%>|\\\\?\\\\?>)\\\\s*","beginCaptures":{},"end":"\\\\s*(?=;)","endCaptures":{},"name":"meta.tail.union.cpp","patterns":[{"include":"$self"}]}]},"union_declare":{"captures":{"1":{"name":"storage.type.union.declare.cpp"},"2":{"patterns":[{"include":"#inline_comment"}]},"3":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"4":{"name":"entity.name.type.union.cpp"},"5":{"patterns":[{"match":"\\\\*","name":"storage.modifier.pointer.cpp"},{"captures":{"1":{"patterns":[{"include":"#inline_comment"}]},"2":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"3":{"name":"comment.block.cpp"},"4":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"(?:&((?:\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+)+|\\\\s++|(?<=\\\\W)|(?=\\\\W)|^|\\\\n?$|\\\\A|\\\\Z)){2,}&","name":"invalid.illegal.reference-type.cpp"},{"match":"&","name":"storage.modifier.reference.cpp"}]},"6":{"patterns":[{"include":"#inline_comment"}]},"7":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"8":{"patterns":[{"include":"#inline_comment"}]},"9":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"10":{"patterns":[{"include":"#inline_comment"}]},"11":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]},"12":{"name":"variable.other.object.declare.cpp"},"13":{"patterns":[{"include":"#inline_comment"}]},"14":{"patterns":[{"captures":{"1":{"name":"comment.block.cpp punctuation.definition.comment.begin.cpp"},"2":{"name":"comment.block.cpp"},"3":{"name":"comment.block.cpp punctuation.definition.comment.end.cpp"}},"match":"\\\\s*+(/\\\\*)((?:[^*]++|\\\\*+(?!/))*+(\\\\*/))\\\\s*+"}]}},"match":"((?|(?:[^\\"'/<>]|/[^*])++)*>)\\\\s*+)?::)*\\\\s*+)?((?Ls(e,"name",{value:t,configurable:!0}),CI=(e,t)=>function(){return e&&(t=(0,e[Rd(e)[0]])(e=0)),t},H=(e,t)=>function(){return t||(0,e[Rd(e)[0]])((t={exports:{}}).exports,t),t.exports},Wr=(e,t)=>{for(var r in t)Ls(e,r,{get:t[r],enumerable:!0})},Ad=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Rd(t))!EI.call(e,a)&&a!==r&&Ls(e,a,{get:()=>t[a],enumerable:!(n=RI(t,a))||n.enumerable});return e},Ol=(e,t,r)=>(Ad(e,t,"default"),r),Ed=(e,t,r)=>(r=e!=null?$I(AI(e)):{},Ad(Ls(r,"default",{value:e,enumerable:!0}),e)),Cd=e=>Ad(Ls({},"__esModule",{value:!0}),e),Ll={};Wr(Ll,{AnnotatedTextEdit:()=>pr,ChangeAnnotation:()=>nn,ChangeAnnotationIdentifier:()=>Ke,CodeAction:()=>Qc,CodeActionContext:()=>Zc,CodeActionKind:()=>Jc,CodeActionTriggerKind:()=>Yi,CodeDescription:()=>Ic,CodeLens:()=>ef,Color:()=>Eo,ColorInformation:()=>Ec,ColorPresentation:()=>Cc,Command:()=>rn,CompletionItem:()=>Fc,CompletionItemKind:()=>Oc,CompletionItemLabelDetails:()=>Gc,CompletionItemTag:()=>Dc,CompletionList:()=>zc,CreateFile:()=>ha,DeleteFile:()=>ga,Diagnostic:()=>Wi,DiagnosticRelatedInformation:()=>Co,DiagnosticSeverity:()=>Sc,DiagnosticTag:()=>wc,DocumentHighlight:()=>Wc,DocumentHighlightKind:()=>Kc,DocumentLink:()=>rf,DocumentSymbol:()=>Xc,DocumentUri:()=>$c,EOL:()=>Fg,FoldingRange:()=>_c,FoldingRangeKind:()=>bc,FormattingOptions:()=>tf,Hover:()=>jc,InlayHint:()=>df,InlayHintKind:()=>So,InlayHintLabelPart:()=>wo,InlineCompletionContext:()=>vf,InlineCompletionItem:()=>mf,InlineCompletionList:()=>hf,InlineCompletionTriggerKind:()=>yf,InlineValueContext:()=>ff,InlineValueEvaluatableExpression:()=>cf,InlineValueText:()=>lf,InlineValueVariableLookup:()=>uf,InsertReplaceEdit:()=>xc,InsertTextFormat:()=>Lc,InsertTextMode:()=>Mc,Location:()=>Ki,LocationLink:()=>Ac,MarkedString:()=>Hi,MarkupContent:()=>va,MarkupKind:()=>_o,OptionalVersionedTextDocumentIdentifier:()=>Vi,ParameterInformation:()=>Bc,Position:()=>ie,Range:()=>Q,RenameFile:()=>ya,SelectedCompletionInfo:()=>gf,SelectionRange:()=>nf,SemanticTokenModifiers:()=>sf,SemanticTokenTypes:()=>af,SemanticTokens:()=>of,SignatureInformation:()=>Uc,StringValue:()=>pf,SymbolInformation:()=>Hc,SymbolKind:()=>qc,SymbolTag:()=>Vc,TextDocument:()=>$f,TextDocumentEdit:()=>qi,TextDocumentIdentifier:()=>Nc,TextDocumentItem:()=>kc,TextEdit:()=>Ht,URI:()=>Ao,VersionedTextDocumentIdentifier:()=>Pc,WorkspaceChange:()=>Gg,WorkspaceEdit:()=>bo,WorkspaceFolder:()=>Tf,WorkspaceSymbol:()=>Yc,integer:()=>Rc,uinteger:()=>Ui});var $c,Ao,Rc,Ui,ie,Q,Ki,Ac,Eo,Ec,Cc,bc,_c,Co,Sc,wc,Ic,Wi,rn,Ht,nn,Ke,pr,qi,ha,ya,ga,bo,Pi,Uu,Gg,Nc,Pc,Vi,kc,_o,va,Oc,Lc,Dc,xc,Mc,Gc,Fc,zc,Hi,jc,Bc,Uc,Kc,Wc,qc,Vc,Hc,Yc,Xc,Jc,Yi,Zc,Qc,ef,tf,rf,nf,af,sf,of,lf,uf,cf,ff,So,wo,df,pf,mf,hf,yf,gf,vf,Tf,Fg,$f,oh,A,Ds=CI({"../../node_modules/.pnpm/vscode-languageserver-types@3.17.5/node_modules/vscode-languageserver-types/lib/esm/main.js"(){(function(e){function t(r){return typeof r=="string"}i(t,"is"),e.is=t})($c||($c={})),(function(e){function t(r){return typeof r=="string"}i(t,"is"),e.is=t})(Ao||(Ao={})),(function(e){e.MIN_VALUE=-2147483648,e.MAX_VALUE=2147483647;function t(r){return typeof r=="number"&&e.MIN_VALUE<=r&&r<=e.MAX_VALUE}i(t,"is"),e.is=t})(Rc||(Rc={})),(function(e){e.MIN_VALUE=0,e.MAX_VALUE=2147483647;function t(r){return typeof r=="number"&&e.MIN_VALUE<=r&&r<=e.MAX_VALUE}i(t,"is"),e.is=t})(Ui||(Ui={})),(function(e){function t(n,a){return n===Number.MAX_VALUE&&(n=Ui.MAX_VALUE),a===Number.MAX_VALUE&&(a=Ui.MAX_VALUE),{line:n,character:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&A.uinteger(a.line)&&A.uinteger(a.character)}i(r,"is"),e.is=r})(ie||(ie={})),(function(e){function t(n,a,s,o){if(A.uinteger(n)&&A.uinteger(a)&&A.uinteger(s)&&A.uinteger(o))return{start:ie.create(n,a),end:ie.create(s,o)};if(ie.is(n)&&ie.is(a))return{start:n,end:a};throw new Error(`Range#create called with invalid arguments[${n}, ${a}, ${s}, ${o}]`)}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&ie.is(a.start)&&ie.is(a.end)}i(r,"is"),e.is=r})(Q||(Q={})),(function(e){function t(n,a){return{uri:n,range:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&Q.is(a.range)&&(A.string(a.uri)||A.undefined(a.uri))}i(r,"is"),e.is=r})(Ki||(Ki={})),(function(e){function t(n,a,s,o){return{targetUri:n,targetRange:a,targetSelectionRange:s,originSelectionRange:o}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&Q.is(a.targetRange)&&A.string(a.targetUri)&&Q.is(a.targetSelectionRange)&&(Q.is(a.originSelectionRange)||A.undefined(a.originSelectionRange))}i(r,"is"),e.is=r})(Ac||(Ac={})),(function(e){function t(n,a,s,o){return{red:n,green:a,blue:s,alpha:o}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.numberRange(a.red,0,1)&&A.numberRange(a.green,0,1)&&A.numberRange(a.blue,0,1)&&A.numberRange(a.alpha,0,1)}i(r,"is"),e.is=r})(Eo||(Eo={})),(function(e){function t(n,a){return{range:n,color:a}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&Q.is(a.range)&&Eo.is(a.color)}i(r,"is"),e.is=r})(Ec||(Ec={})),(function(e){function t(n,a,s){return{label:n,textEdit:a,additionalTextEdits:s}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.string(a.label)&&(A.undefined(a.textEdit)||Ht.is(a))&&(A.undefined(a.additionalTextEdits)||A.typedArray(a.additionalTextEdits,Ht.is))}i(r,"is"),e.is=r})(Cc||(Cc={})),(function(e){e.Comment="comment",e.Imports="imports",e.Region="region"})(bc||(bc={})),(function(e){function t(n,a,s,o,l,u){const c={startLine:n,endLine:a};return A.defined(s)&&(c.startCharacter=s),A.defined(o)&&(c.endCharacter=o),A.defined(l)&&(c.kind=l),A.defined(u)&&(c.collapsedText=u),c}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.uinteger(a.startLine)&&A.uinteger(a.startLine)&&(A.undefined(a.startCharacter)||A.uinteger(a.startCharacter))&&(A.undefined(a.endCharacter)||A.uinteger(a.endCharacter))&&(A.undefined(a.kind)||A.string(a.kind))}i(r,"is"),e.is=r})(_c||(_c={})),(function(e){function t(n,a){return{location:n,message:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Ki.is(a.location)&&A.string(a.message)}i(r,"is"),e.is=r})(Co||(Co={})),(function(e){e.Error=1,e.Warning=2,e.Information=3,e.Hint=4})(Sc||(Sc={})),(function(e){e.Unnecessary=1,e.Deprecated=2})(wc||(wc={})),(function(e){function t(r){const n=r;return A.objectLiteral(n)&&A.string(n.href)}i(t,"is"),e.is=t})(Ic||(Ic={})),(function(e){function t(n,a,s,o,l,u){let c={range:n,message:a};return A.defined(s)&&(c.severity=s),A.defined(o)&&(c.code=o),A.defined(l)&&(c.source=l),A.defined(u)&&(c.relatedInformation=u),c}i(t,"create"),e.create=t;function r(n){var a;let s=n;return A.defined(s)&&Q.is(s.range)&&A.string(s.message)&&(A.number(s.severity)||A.undefined(s.severity))&&(A.integer(s.code)||A.string(s.code)||A.undefined(s.code))&&(A.undefined(s.codeDescription)||A.string((a=s.codeDescription)===null||a===void 0?void 0:a.href))&&(A.string(s.source)||A.undefined(s.source))&&(A.undefined(s.relatedInformation)||A.typedArray(s.relatedInformation,Co.is))}i(r,"is"),e.is=r})(Wi||(Wi={})),(function(e){function t(n,a,...s){let o={title:n,command:a};return A.defined(s)&&s.length>0&&(o.arguments=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.title)&&A.string(a.command)}i(r,"is"),e.is=r})(rn||(rn={})),(function(e){function t(s,o){return{range:s,newText:o}}i(t,"replace"),e.replace=t;function r(s,o){return{range:{start:s,end:s},newText:o}}i(r,"insert"),e.insert=r;function n(s){return{range:s,newText:""}}i(n,"del"),e.del=n;function a(s){const o=s;return A.objectLiteral(o)&&A.string(o.newText)&&Q.is(o.range)}i(a,"is"),e.is=a})(Ht||(Ht={})),(function(e){function t(n,a,s){const o={label:n};return a!==void 0&&(o.needsConfirmation=a),s!==void 0&&(o.description=s),o}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.string(a.label)&&(A.boolean(a.needsConfirmation)||a.needsConfirmation===void 0)&&(A.string(a.description)||a.description===void 0)}i(r,"is"),e.is=r})(nn||(nn={})),(function(e){function t(r){const n=r;return A.string(n)}i(t,"is"),e.is=t})(Ke||(Ke={})),(function(e){function t(s,o,l){return{range:s,newText:o,annotationId:l}}i(t,"replace"),e.replace=t;function r(s,o,l){return{range:{start:s,end:s},newText:o,annotationId:l}}i(r,"insert"),e.insert=r;function n(s,o){return{range:s,newText:"",annotationId:o}}i(n,"del"),e.del=n;function a(s){const o=s;return Ht.is(o)&&(nn.is(o.annotationId)||Ke.is(o.annotationId))}i(a,"is"),e.is=a})(pr||(pr={})),(function(e){function t(n,a){return{textDocument:n,edits:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Vi.is(a.textDocument)&&Array.isArray(a.edits)}i(r,"is"),e.is=r})(qi||(qi={})),(function(e){function t(n,a,s){let o={kind:"create",uri:n};return a!==void 0&&(a.overwrite!==void 0||a.ignoreIfExists!==void 0)&&(o.options=a),s!==void 0&&(o.annotationId=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return a&&a.kind==="create"&&A.string(a.uri)&&(a.options===void 0||(a.options.overwrite===void 0||A.boolean(a.options.overwrite))&&(a.options.ignoreIfExists===void 0||A.boolean(a.options.ignoreIfExists)))&&(a.annotationId===void 0||Ke.is(a.annotationId))}i(r,"is"),e.is=r})(ha||(ha={})),(function(e){function t(n,a,s,o){let l={kind:"rename",oldUri:n,newUri:a};return s!==void 0&&(s.overwrite!==void 0||s.ignoreIfExists!==void 0)&&(l.options=s),o!==void 0&&(l.annotationId=o),l}i(t,"create"),e.create=t;function r(n){let a=n;return a&&a.kind==="rename"&&A.string(a.oldUri)&&A.string(a.newUri)&&(a.options===void 0||(a.options.overwrite===void 0||A.boolean(a.options.overwrite))&&(a.options.ignoreIfExists===void 0||A.boolean(a.options.ignoreIfExists)))&&(a.annotationId===void 0||Ke.is(a.annotationId))}i(r,"is"),e.is=r})(ya||(ya={})),(function(e){function t(n,a,s){let o={kind:"delete",uri:n};return a!==void 0&&(a.recursive!==void 0||a.ignoreIfNotExists!==void 0)&&(o.options=a),s!==void 0&&(o.annotationId=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return a&&a.kind==="delete"&&A.string(a.uri)&&(a.options===void 0||(a.options.recursive===void 0||A.boolean(a.options.recursive))&&(a.options.ignoreIfNotExists===void 0||A.boolean(a.options.ignoreIfNotExists)))&&(a.annotationId===void 0||Ke.is(a.annotationId))}i(r,"is"),e.is=r})(ga||(ga={})),(function(e){function t(r){let n=r;return n&&(n.changes!==void 0||n.documentChanges!==void 0)&&(n.documentChanges===void 0||n.documentChanges.every(a=>A.string(a.kind)?ha.is(a)||ya.is(a)||ga.is(a):qi.is(a)))}i(t,"is"),e.is=t})(bo||(bo={})),Pi=class{static{i(this,"TextEditChangeImpl")}constructor(e,t){this.edits=e,this.changeAnnotations=t}insert(e,t,r){let n,a;if(r===void 0?n=Ht.insert(e,t):Ke.is(r)?(a=r,n=pr.insert(e,t,r)):(this.assertChangeAnnotations(this.changeAnnotations),a=this.changeAnnotations.manage(r),n=pr.insert(e,t,a)),this.edits.push(n),a!==void 0)return a}replace(e,t,r){let n,a;if(r===void 0?n=Ht.replace(e,t):Ke.is(r)?(a=r,n=pr.replace(e,t,r)):(this.assertChangeAnnotations(this.changeAnnotations),a=this.changeAnnotations.manage(r),n=pr.replace(e,t,a)),this.edits.push(n),a!==void 0)return a}delete(e,t){let r,n;if(t===void 0?r=Ht.del(e):Ke.is(t)?(n=t,r=pr.del(e,t)):(this.assertChangeAnnotations(this.changeAnnotations),n=this.changeAnnotations.manage(t),r=pr.del(e,n)),this.edits.push(r),n!==void 0)return n}add(e){this.edits.push(e)}all(){return this.edits}clear(){this.edits.splice(0,this.edits.length)}assertChangeAnnotations(e){if(e===void 0)throw new Error("Text edit change is not configured to manage change annotations.")}},Uu=class{static{i(this,"ChangeAnnotations")}constructor(e){this._annotations=e===void 0?Object.create(null):e,this._counter=0,this._size=0}all(){return this._annotations}get size(){return this._size}manage(e,t){let r;if(Ke.is(e)?r=e:(r=this.nextId(),t=e),this._annotations[r]!==void 0)throw new Error(`Id ${r} is already in use.`);if(t===void 0)throw new Error(`No annotation provided for id ${r}`);return this._annotations[r]=t,this._size++,r}nextId(){return this._counter++,this._counter.toString()}},Gg=class{static{i(this,"WorkspaceChange")}constructor(e){this._textEditChanges=Object.create(null),e!==void 0?(this._workspaceEdit=e,e.documentChanges?(this._changeAnnotations=new Uu(e.changeAnnotations),e.changeAnnotations=this._changeAnnotations.all(),e.documentChanges.forEach(t=>{if(qi.is(t)){const r=new Pi(t.edits,this._changeAnnotations);this._textEditChanges[t.textDocument.uri]=r}})):e.changes&&Object.keys(e.changes).forEach(t=>{const r=new Pi(e.changes[t]);this._textEditChanges[t]=r})):this._workspaceEdit={}}get edit(){return this.initDocumentChanges(),this._changeAnnotations!==void 0&&(this._changeAnnotations.size===0?this._workspaceEdit.changeAnnotations=void 0:this._workspaceEdit.changeAnnotations=this._changeAnnotations.all()),this._workspaceEdit}getTextEditChange(e){if(Vi.is(e)){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");const t={uri:e.uri,version:e.version};let r=this._textEditChanges[t.uri];if(!r){const n=[],a={textDocument:t,edits:n};this._workspaceEdit.documentChanges.push(a),r=new Pi(n,this._changeAnnotations),this._textEditChanges[t.uri]=r}return r}else{if(this.initChanges(),this._workspaceEdit.changes===void 0)throw new Error("Workspace edit is not configured for normal text edit changes.");let t=this._textEditChanges[e];if(!t){let r=[];this._workspaceEdit.changes[e]=r,t=new Pi(r),this._textEditChanges[e]=t}return t}}initDocumentChanges(){this._workspaceEdit.documentChanges===void 0&&this._workspaceEdit.changes===void 0&&(this._changeAnnotations=new Uu,this._workspaceEdit.documentChanges=[],this._workspaceEdit.changeAnnotations=this._changeAnnotations.all())}initChanges(){this._workspaceEdit.documentChanges===void 0&&this._workspaceEdit.changes===void 0&&(this._workspaceEdit.changes=Object.create(null))}createFile(e,t,r){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");let n;nn.is(t)||Ke.is(t)?n=t:r=t;let a,s;if(n===void 0?a=ha.create(e,r):(s=Ke.is(n)?n:this._changeAnnotations.manage(n),a=ha.create(e,r,s)),this._workspaceEdit.documentChanges.push(a),s!==void 0)return s}renameFile(e,t,r,n){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");let a;nn.is(r)||Ke.is(r)?a=r:n=r;let s,o;if(a===void 0?s=ya.create(e,t,n):(o=Ke.is(a)?a:this._changeAnnotations.manage(a),s=ya.create(e,t,n,o)),this._workspaceEdit.documentChanges.push(s),o!==void 0)return o}deleteFile(e,t,r){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");let n;nn.is(t)||Ke.is(t)?n=t:r=t;let a,s;if(n===void 0?a=ga.create(e,r):(s=Ke.is(n)?n:this._changeAnnotations.manage(n),a=ga.create(e,r,s)),this._workspaceEdit.documentChanges.push(a),s!==void 0)return s}},(function(e){function t(n){return{uri:n}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)}i(r,"is"),e.is=r})(Nc||(Nc={})),(function(e){function t(n,a){return{uri:n,version:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)&&A.integer(a.version)}i(r,"is"),e.is=r})(Pc||(Pc={})),(function(e){function t(n,a){return{uri:n,version:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)&&(a.version===null||A.integer(a.version))}i(r,"is"),e.is=r})(Vi||(Vi={})),(function(e){function t(n,a,s,o){return{uri:n,languageId:a,version:s,text:o}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)&&A.string(a.languageId)&&A.integer(a.version)&&A.string(a.text)}i(r,"is"),e.is=r})(kc||(kc={})),(function(e){e.PlainText="plaintext",e.Markdown="markdown";function t(r){const n=r;return n===e.PlainText||n===e.Markdown}i(t,"is"),e.is=t})(_o||(_o={})),(function(e){function t(r){const n=r;return A.objectLiteral(r)&&_o.is(n.kind)&&A.string(n.value)}i(t,"is"),e.is=t})(va||(va={})),(function(e){e.Text=1,e.Method=2,e.Function=3,e.Constructor=4,e.Field=5,e.Variable=6,e.Class=7,e.Interface=8,e.Module=9,e.Property=10,e.Unit=11,e.Value=12,e.Enum=13,e.Keyword=14,e.Snippet=15,e.Color=16,e.File=17,e.Reference=18,e.Folder=19,e.EnumMember=20,e.Constant=21,e.Struct=22,e.Event=23,e.Operator=24,e.TypeParameter=25})(Oc||(Oc={})),(function(e){e.PlainText=1,e.Snippet=2})(Lc||(Lc={})),(function(e){e.Deprecated=1})(Dc||(Dc={})),(function(e){function t(n,a,s){return{newText:n,insert:a,replace:s}}i(t,"create"),e.create=t;function r(n){const a=n;return a&&A.string(a.newText)&&Q.is(a.insert)&&Q.is(a.replace)}i(r,"is"),e.is=r})(xc||(xc={})),(function(e){e.asIs=1,e.adjustIndentation=2})(Mc||(Mc={})),(function(e){function t(r){const n=r;return n&&(A.string(n.detail)||n.detail===void 0)&&(A.string(n.description)||n.description===void 0)}i(t,"is"),e.is=t})(Gc||(Gc={})),(function(e){function t(r){return{label:r}}i(t,"create"),e.create=t})(Fc||(Fc={})),(function(e){function t(r,n){return{items:r||[],isIncomplete:!!n}}i(t,"create"),e.create=t})(zc||(zc={})),(function(e){function t(n){return n.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")}i(t,"fromPlainText"),e.fromPlainText=t;function r(n){const a=n;return A.string(a)||A.objectLiteral(a)&&A.string(a.language)&&A.string(a.value)}i(r,"is"),e.is=r})(Hi||(Hi={})),(function(e){function t(r){let n=r;return!!n&&A.objectLiteral(n)&&(va.is(n.contents)||Hi.is(n.contents)||A.typedArray(n.contents,Hi.is))&&(r.range===void 0||Q.is(r.range))}i(t,"is"),e.is=t})(jc||(jc={})),(function(e){function t(r,n){return n?{label:r,documentation:n}:{label:r}}i(t,"create"),e.create=t})(Bc||(Bc={})),(function(e){function t(r,n,...a){let s={label:r};return A.defined(n)&&(s.documentation=n),A.defined(a)?s.parameters=a:s.parameters=[],s}i(t,"create"),e.create=t})(Uc||(Uc={})),(function(e){e.Text=1,e.Read=2,e.Write=3})(Kc||(Kc={})),(function(e){function t(r,n){let a={range:r};return A.number(n)&&(a.kind=n),a}i(t,"create"),e.create=t})(Wc||(Wc={})),(function(e){e.File=1,e.Module=2,e.Namespace=3,e.Package=4,e.Class=5,e.Method=6,e.Property=7,e.Field=8,e.Constructor=9,e.Enum=10,e.Interface=11,e.Function=12,e.Variable=13,e.Constant=14,e.String=15,e.Number=16,e.Boolean=17,e.Array=18,e.Object=19,e.Key=20,e.Null=21,e.EnumMember=22,e.Struct=23,e.Event=24,e.Operator=25,e.TypeParameter=26})(qc||(qc={})),(function(e){e.Deprecated=1})(Vc||(Vc={})),(function(e){function t(r,n,a,s,o){let l={name:r,kind:n,location:{uri:s,range:a}};return o&&(l.containerName=o),l}i(t,"create"),e.create=t})(Hc||(Hc={})),(function(e){function t(r,n,a,s){return s!==void 0?{name:r,kind:n,location:{uri:a,range:s}}:{name:r,kind:n,location:{uri:a}}}i(t,"create"),e.create=t})(Yc||(Yc={})),(function(e){function t(n,a,s,o,l,u){let c={name:n,detail:a,kind:s,range:o,selectionRange:l};return u!==void 0&&(c.children=u),c}i(t,"create"),e.create=t;function r(n){let a=n;return a&&A.string(a.name)&&A.number(a.kind)&&Q.is(a.range)&&Q.is(a.selectionRange)&&(a.detail===void 0||A.string(a.detail))&&(a.deprecated===void 0||A.boolean(a.deprecated))&&(a.children===void 0||Array.isArray(a.children))&&(a.tags===void 0||Array.isArray(a.tags))}i(r,"is"),e.is=r})(Xc||(Xc={})),(function(e){e.Empty="",e.QuickFix="quickfix",e.Refactor="refactor",e.RefactorExtract="refactor.extract",e.RefactorInline="refactor.inline",e.RefactorRewrite="refactor.rewrite",e.Source="source",e.SourceOrganizeImports="source.organizeImports",e.SourceFixAll="source.fixAll"})(Jc||(Jc={})),(function(e){e.Invoked=1,e.Automatic=2})(Yi||(Yi={})),(function(e){function t(n,a,s){let o={diagnostics:n};return a!=null&&(o.only=a),s!=null&&(o.triggerKind=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.typedArray(a.diagnostics,Wi.is)&&(a.only===void 0||A.typedArray(a.only,A.string))&&(a.triggerKind===void 0||a.triggerKind===Yi.Invoked||a.triggerKind===Yi.Automatic)}i(r,"is"),e.is=r})(Zc||(Zc={})),(function(e){function t(n,a,s){let o={title:n},l=!0;return typeof a=="string"?(l=!1,o.kind=a):rn.is(a)?o.command=a:o.edit=a,l&&s!==void 0&&(o.kind=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return a&&A.string(a.title)&&(a.diagnostics===void 0||A.typedArray(a.diagnostics,Wi.is))&&(a.kind===void 0||A.string(a.kind))&&(a.edit!==void 0||a.command!==void 0)&&(a.command===void 0||rn.is(a.command))&&(a.isPreferred===void 0||A.boolean(a.isPreferred))&&(a.edit===void 0||bo.is(a.edit))}i(r,"is"),e.is=r})(Qc||(Qc={})),(function(e){function t(n,a){let s={range:n};return A.defined(a)&&(s.data=a),s}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Q.is(a.range)&&(A.undefined(a.command)||rn.is(a.command))}i(r,"is"),e.is=r})(ef||(ef={})),(function(e){function t(n,a){return{tabSize:n,insertSpaces:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.uinteger(a.tabSize)&&A.boolean(a.insertSpaces)}i(r,"is"),e.is=r})(tf||(tf={})),(function(e){function t(n,a,s){return{range:n,target:a,data:s}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Q.is(a.range)&&(A.undefined(a.target)||A.string(a.target))}i(r,"is"),e.is=r})(rf||(rf={})),(function(e){function t(n,a){return{range:n,parent:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&Q.is(a.range)&&(a.parent===void 0||e.is(a.parent))}i(r,"is"),e.is=r})(nf||(nf={})),(function(e){e.namespace="namespace",e.type="type",e.class="class",e.enum="enum",e.interface="interface",e.struct="struct",e.typeParameter="typeParameter",e.parameter="parameter",e.variable="variable",e.property="property",e.enumMember="enumMember",e.event="event",e.function="function",e.method="method",e.macro="macro",e.keyword="keyword",e.modifier="modifier",e.comment="comment",e.string="string",e.number="number",e.regexp="regexp",e.operator="operator",e.decorator="decorator"})(af||(af={})),(function(e){e.declaration="declaration",e.definition="definition",e.readonly="readonly",e.static="static",e.deprecated="deprecated",e.abstract="abstract",e.async="async",e.modification="modification",e.documentation="documentation",e.defaultLibrary="defaultLibrary"})(sf||(sf={})),(function(e){function t(r){const n=r;return A.objectLiteral(n)&&(n.resultId===void 0||typeof n.resultId=="string")&&Array.isArray(n.data)&&(n.data.length===0||typeof n.data[0]=="number")}i(t,"is"),e.is=t})(of||(of={})),(function(e){function t(n,a){return{range:n,text:a}}i(t,"create"),e.create=t;function r(n){const a=n;return a!=null&&Q.is(a.range)&&A.string(a.text)}i(r,"is"),e.is=r})(lf||(lf={})),(function(e){function t(n,a,s){return{range:n,variableName:a,caseSensitiveLookup:s}}i(t,"create"),e.create=t;function r(n){const a=n;return a!=null&&Q.is(a.range)&&A.boolean(a.caseSensitiveLookup)&&(A.string(a.variableName)||a.variableName===void 0)}i(r,"is"),e.is=r})(uf||(uf={})),(function(e){function t(n,a){return{range:n,expression:a}}i(t,"create"),e.create=t;function r(n){const a=n;return a!=null&&Q.is(a.range)&&(A.string(a.expression)||a.expression===void 0)}i(r,"is"),e.is=r})(cf||(cf={})),(function(e){function t(n,a){return{frameId:n,stoppedLocation:a}}i(t,"create"),e.create=t;function r(n){const a=n;return A.defined(a)&&Q.is(n.stoppedLocation)}i(r,"is"),e.is=r})(ff||(ff={})),(function(e){e.Type=1,e.Parameter=2;function t(r){return r===1||r===2}i(t,"is"),e.is=t})(So||(So={})),(function(e){function t(n){return{value:n}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&(a.tooltip===void 0||A.string(a.tooltip)||va.is(a.tooltip))&&(a.location===void 0||Ki.is(a.location))&&(a.command===void 0||rn.is(a.command))}i(r,"is"),e.is=r})(wo||(wo={})),(function(e){function t(n,a,s){const o={position:n,label:a};return s!==void 0&&(o.kind=s),o}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&ie.is(a.position)&&(A.string(a.label)||A.typedArray(a.label,wo.is))&&(a.kind===void 0||So.is(a.kind))&&a.textEdits===void 0||A.typedArray(a.textEdits,Ht.is)&&(a.tooltip===void 0||A.string(a.tooltip)||va.is(a.tooltip))&&(a.paddingLeft===void 0||A.boolean(a.paddingLeft))&&(a.paddingRight===void 0||A.boolean(a.paddingRight))}i(r,"is"),e.is=r})(df||(df={})),(function(e){function t(r){return{kind:"snippet",value:r}}i(t,"createSnippet"),e.createSnippet=t})(pf||(pf={})),(function(e){function t(r,n,a,s){return{insertText:r,filterText:n,range:a,command:s}}i(t,"create"),e.create=t})(mf||(mf={})),(function(e){function t(r){return{items:r}}i(t,"create"),e.create=t})(hf||(hf={})),(function(e){e.Invoked=0,e.Automatic=1})(yf||(yf={})),(function(e){function t(r,n){return{range:r,text:n}}i(t,"create"),e.create=t})(gf||(gf={})),(function(e){function t(r,n){return{triggerKind:r,selectedCompletionInfo:n}}i(t,"create"),e.create=t})(vf||(vf={})),(function(e){function t(r){const n=r;return A.objectLiteral(n)&&Ao.is(n.uri)&&A.string(n.name)}i(t,"is"),e.is=t})(Tf||(Tf={})),Fg=[` +`,`\r +`,"\r"],(function(e){function t(s,o,l,u){return new oh(s,o,l,u)}i(t,"create"),e.create=t;function r(s){let o=s;return!!(A.defined(o)&&A.string(o.uri)&&(A.undefined(o.languageId)||A.string(o.languageId))&&A.uinteger(o.lineCount)&&A.func(o.getText)&&A.func(o.positionAt)&&A.func(o.offsetAt))}i(r,"is"),e.is=r;function n(s,o){let l=s.getText(),u=a(o,(f,d)=>{let m=f.range.start.line-d.range.start.line;return m===0?f.range.start.character-d.range.start.character:m}),c=l.length;for(let f=u.length-1;f>=0;f--){let d=u[f],m=s.offsetAt(d.range.start),g=s.offsetAt(d.range.end);if(g<=c)l=l.substring(0,m)+d.newText+l.substring(g,l.length);else throw new Error("Overlapping edit");c=m}return l}i(n,"applyEdits"),e.applyEdits=n;function a(s,o){if(s.length<=1)return s;const l=s.length/2|0,u=s.slice(0,l),c=s.slice(l);a(u,o),a(c,o);let f=0,d=0,m=0;for(;f0&&e.push(t.length),this._lineOffsets=e}return this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);let t=this.getLineOffsets(),r=0,n=t.length;if(n===0)return ie.create(0,e);for(;re?n=s:r=s+1}let a=r-1;return ie.create(a,e-t[a])}offsetAt(e){let t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;let r=t[e.line],n=e.line+1"u"}i(n,"undefined"),e.undefined=n;function a(g){return g===!0||g===!1}i(a,"boolean"),e.boolean=a;function s(g){return t.call(g)==="[object String]"}i(s,"string"),e.string=s;function o(g){return t.call(g)==="[object Number]"}i(o,"number"),e.number=o;function l(g,v,b){return t.call(g)==="[object Number]"&&v<=g&&g<=b}i(l,"numberRange"),e.numberRange=l;function u(g){return t.call(g)==="[object Number]"&&-2147483648<=g&&g<=2147483647}i(u,"integer"),e.integer=u;function c(g){return t.call(g)==="[object Number]"&&0<=g&&g<=2147483647}i(c,"uinteger"),e.uinteger=c;function f(g){return t.call(g)==="[object Function]"}i(f,"func"),e.func=f;function d(g){return g!==null&&typeof g=="object"}i(d,"objectLiteral"),e.objectLiteral=d;function m(g,v){return Array.isArray(g)&&g.every(v)}i(m,"typedArray"),e.typedArray=m})(A||(A={}))}}),Ln=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/ral.js"(e){Object.defineProperty(e,"__esModule",{value:!0});var t;function r(){if(t===void 0)throw new Error("No runtime abstraction layer installed");return t}i(r,"RAL"),(function(n){function a(s){if(s===void 0)throw new Error("No runtime abstraction layer provided");t=s}i(a,"install"),n.install=a})(r||(r={})),e.default=r}}),xs=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/is.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.stringArray=e.array=e.func=e.error=e.number=e.string=e.boolean=void 0;function t(u){return u===!0||u===!1}i(t,"boolean"),e.boolean=t;function r(u){return typeof u=="string"||u instanceof String}i(r,"string"),e.string=r;function n(u){return typeof u=="number"||u instanceof Number}i(n,"number"),e.number=n;function a(u){return u instanceof Error}i(a,"error"),e.error=a;function s(u){return typeof u=="function"}i(s,"func"),e.func=s;function o(u){return Array.isArray(u)}i(o,"array"),e.array=o;function l(u){return o(u)&&u.every(c=>r(c))}i(l,"stringArray"),e.stringArray=l}}),Qa=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/events.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Emitter=e.Event=void 0;var t=Ln(),r;(function(s){const o={dispose(){}};s.None=function(){return o}})(r||(e.Event=r={}));var n=class{static{i(this,"CallbackList")}add(s,o=null,l){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(s),this._contexts.push(o),Array.isArray(l)&&l.push({dispose:i(()=>this.remove(s,o),"dispose")})}remove(s,o=null){if(!this._callbacks)return;let l=!1;for(let u=0,c=this._callbacks.length;u{this._callbacks||(this._callbacks=new n),this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(o,l);const c={dispose:i(()=>{this._callbacks&&(this._callbacks.remove(o,l),c.dispose=zg._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))},"dispose")};return Array.isArray(u)&&u.push(c),c}),this._event}fire(o){this._callbacks&&this._callbacks.invoke.call(this._callbacks,o)}dispose(){this._callbacks&&(this._callbacks.dispose(),this._callbacks=void 0)}};e.Emitter=a,a._noop=function(){}}}),Dl=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/cancellation.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.CancellationTokenSource=e.CancellationToken=void 0;var t=Ln(),r=xs(),n=Qa(),a;(function(u){u.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:n.Event.None}),u.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:n.Event.None});function c(f){const d=f;return d&&(d===u.None||d===u.Cancelled||r.boolean(d.isCancellationRequested)&&!!d.onCancellationRequested)}i(c,"is"),u.is=c})(a||(e.CancellationToken=a={}));var s=Object.freeze(function(u,c){const f=(0,t.default)().timer.setTimeout(u.bind(c),0);return{dispose(){f.dispose()}}}),o=class{static{i(this,"MutableToken")}constructor(){this._isCancelled=!1}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?s:(this._emitter||(this._emitter=new n.Emitter),this._emitter.event)}dispose(){this._emitter&&(this._emitter.dispose(),this._emitter=void 0)}},l=class{static{i(this,"CancellationTokenSource")}get token(){return this._token||(this._token=new o),this._token}cancel(){this._token?this._token.cancel():this._token=a.Cancelled}dispose(){this._token?this._token instanceof o&&this._token.dispose():this._token=a.None}};e.CancellationTokenSource=l}}),jg=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messages.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Message=e.NotificationType9=e.NotificationType8=e.NotificationType7=e.NotificationType6=e.NotificationType5=e.NotificationType4=e.NotificationType3=e.NotificationType2=e.NotificationType1=e.NotificationType0=e.NotificationType=e.RequestType9=e.RequestType8=e.RequestType7=e.RequestType6=e.RequestType5=e.RequestType4=e.RequestType3=e.RequestType2=e.RequestType1=e.RequestType=e.RequestType0=e.AbstractMessageSignature=e.ParameterStructures=e.ResponseError=e.ErrorCodes=void 0;var t=xs(),r;(function(y){y.ParseError=-32700,y.InvalidRequest=-32600,y.MethodNotFound=-32601,y.InvalidParams=-32602,y.InternalError=-32603,y.jsonrpcReservedErrorRangeStart=-32099,y.serverErrorStart=-32099,y.MessageWriteError=-32099,y.MessageReadError=-32098,y.PendingResponseRejected=-32097,y.ConnectionInactive=-32096,y.ServerNotInitialized=-32002,y.UnknownErrorCode=-32001,y.jsonrpcReservedErrorRangeEnd=-32e3,y.serverErrorEnd=-32e3})(r||(e.ErrorCodes=r={}));var n=class Bg extends Error{static{i(this,"ResponseError")}constructor(E,T,$){super(T),this.code=t.number(E)?E:r.UnknownErrorCode,this.data=$,Object.setPrototypeOf(this,Bg.prototype)}toJson(){const E={code:this.code,message:this.message};return this.data!==void 0&&(E.data=this.data),E}};e.ResponseError=n;var a=class Io{static{i(this,"ParameterStructures")}constructor(E){this.kind=E}static is(E){return E===Io.auto||E===Io.byName||E===Io.byPosition}toString(){return this.kind}};e.ParameterStructures=a,a.auto=new a("auto"),a.byPosition=new a("byPosition"),a.byName=new a("byName");var s=class{static{i(this,"AbstractMessageSignature")}constructor(y,E){this.method=y,this.numberOfParams=E}get parameterStructures(){return a.auto}};e.AbstractMessageSignature=s;var o=class extends s{static{i(this,"RequestType0")}constructor(y){super(y,0)}};e.RequestType0=o;var l=class extends s{static{i(this,"RequestType")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.RequestType=l;var u=class extends s{static{i(this,"RequestType1")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.RequestType1=u;var c=class extends s{static{i(this,"RequestType2")}constructor(y){super(y,2)}};e.RequestType2=c;var f=class extends s{static{i(this,"RequestType3")}constructor(y){super(y,3)}};e.RequestType3=f;var d=class extends s{static{i(this,"RequestType4")}constructor(y){super(y,4)}};e.RequestType4=d;var m=class extends s{static{i(this,"RequestType5")}constructor(y){super(y,5)}};e.RequestType5=m;var g=class extends s{static{i(this,"RequestType6")}constructor(y){super(y,6)}};e.RequestType6=g;var v=class extends s{static{i(this,"RequestType7")}constructor(y){super(y,7)}};e.RequestType7=v;var b=class extends s{static{i(this,"RequestType8")}constructor(y){super(y,8)}};e.RequestType8=b;var S=class extends s{static{i(this,"RequestType9")}constructor(y){super(y,9)}};e.RequestType9=S;var w=class extends s{static{i(this,"NotificationType")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.NotificationType=w;var I=class extends s{static{i(this,"NotificationType0")}constructor(y){super(y,0)}};e.NotificationType0=I;var R=class extends s{static{i(this,"NotificationType1")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.NotificationType1=R;var P=class extends s{static{i(this,"NotificationType2")}constructor(y){super(y,2)}};e.NotificationType2=P;var z=class extends s{static{i(this,"NotificationType3")}constructor(y){super(y,3)}};e.NotificationType3=z;var X=class extends s{static{i(this,"NotificationType4")}constructor(y){super(y,4)}};e.NotificationType4=X;var Z=class extends s{static{i(this,"NotificationType5")}constructor(y){super(y,5)}};e.NotificationType5=Z;var ce=class extends s{static{i(this,"NotificationType6")}constructor(y){super(y,6)}};e.NotificationType6=ce;var se=class extends s{static{i(this,"NotificationType7")}constructor(y){super(y,7)}};e.NotificationType7=se;var Se=class extends s{static{i(this,"NotificationType8")}constructor(y){super(y,8)}};e.NotificationType8=Se;var k=class extends s{static{i(this,"NotificationType9")}constructor(y){super(y,9)}};e.NotificationType9=k;var C;(function(y){function E(_){const O=_;return O&&t.string(O.method)&&(t.string(O.id)||t.number(O.id))}i(E,"isRequest"),y.isRequest=E;function T(_){const O=_;return O&&t.string(O.method)&&_.id===void 0}i(T,"isNotification"),y.isNotification=T;function $(_){const O=_;return O&&(O.result!==void 0||!!O.error)&&(t.string(O.id)||t.number(O.id)||O.id===null)}i($,"isResponse"),y.isResponse=$})(C||(e.Message=C={}))}}),Ug=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/linkedMap.js"(e){var t;Object.defineProperty(e,"__esModule",{value:!0}),e.LRUCache=e.LinkedMap=e.Touch=void 0;var r;(function(s){s.None=0,s.First=1,s.AsOld=s.First,s.Last=2,s.AsNew=s.Last})(r||(e.Touch=r={}));var n=class{static{i(this,"LinkedMap")}constructor(){this[t]="LinkedMap",this._map=new Map,this._head=void 0,this._tail=void 0,this._size=0,this._state=0}clear(){this._map.clear(),this._head=void 0,this._tail=void 0,this._size=0,this._state++}isEmpty(){return!this._head&&!this._tail}get size(){return this._size}get first(){return this._head?.value}get last(){return this._tail?.value}has(s){return this._map.has(s)}get(s,o=r.None){const l=this._map.get(s);if(l)return o!==r.None&&this.touch(l,o),l.value}set(s,o,l=r.None){let u=this._map.get(s);if(u)u.value=o,l!==r.None&&this.touch(u,l);else{switch(u={key:s,value:o,next:void 0,previous:void 0},l){case r.None:this.addItemLast(u);break;case r.First:this.addItemFirst(u);break;case r.Last:this.addItemLast(u);break;default:this.addItemLast(u);break}this._map.set(s,u),this._size++}return this}delete(s){return!!this.remove(s)}remove(s){const o=this._map.get(s);if(o)return this._map.delete(s),this.removeItem(o),this._size--,o.value}shift(){if(!this._head&&!this._tail)return;if(!this._head||!this._tail)throw new Error("Invalid list");const s=this._head;return this._map.delete(s.key),this.removeItem(s),this._size--,s.value}forEach(s,o){const l=this._state;let u=this._head;for(;u;){if(o?s.bind(o)(u.value,u.key,this):s(u.value,u.key,this),this._state!==l)throw new Error("LinkedMap got modified during iteration.");u=u.next}}keys(){const s=this._state;let o=this._head;const l={[Symbol.iterator]:()=>l,next:i(()=>{if(this._state!==s)throw new Error("LinkedMap got modified during iteration.");if(o){const u={value:o.key,done:!1};return o=o.next,u}else return{value:void 0,done:!0}},"next")};return l}values(){const s=this._state;let o=this._head;const l={[Symbol.iterator]:()=>l,next:i(()=>{if(this._state!==s)throw new Error("LinkedMap got modified during iteration.");if(o){const u={value:o.value,done:!1};return o=o.next,u}else return{value:void 0,done:!0}},"next")};return l}entries(){const s=this._state;let o=this._head;const l={[Symbol.iterator]:()=>l,next:i(()=>{if(this._state!==s)throw new Error("LinkedMap got modified during iteration.");if(o){const u={value:[o.key,o.value],done:!1};return o=o.next,u}else return{value:void 0,done:!0}},"next")};return l}[(t=Symbol.toStringTag,Symbol.iterator)](){return this.entries()}trimOld(s){if(s>=this.size)return;if(s===0){this.clear();return}let o=this._head,l=this.size;for(;o&&l>s;)this._map.delete(o.key),o=o.next,l--;this._head=o,this._size=l,o&&(o.previous=void 0),this._state++}addItemFirst(s){if(!this._head&&!this._tail)this._tail=s;else if(this._head)s.next=this._head,this._head.previous=s;else throw new Error("Invalid list");this._head=s,this._state++}addItemLast(s){if(!this._head&&!this._tail)this._head=s;else if(this._tail)s.previous=this._tail,this._tail.next=s;else throw new Error("Invalid list");this._tail=s,this._state++}removeItem(s){if(s===this._head&&s===this._tail)this._head=void 0,this._tail=void 0;else if(s===this._head){if(!s.next)throw new Error("Invalid list");s.next.previous=void 0,this._head=s.next}else if(s===this._tail){if(!s.previous)throw new Error("Invalid list");s.previous.next=void 0,this._tail=s.previous}else{const o=s.next,l=s.previous;if(!o||!l)throw new Error("Invalid list");o.previous=l,l.next=o}s.next=void 0,s.previous=void 0,this._state++}touch(s,o){if(!this._head||!this._tail)throw new Error("Invalid list");if(!(o!==r.First&&o!==r.Last)){if(o===r.First){if(s===this._head)return;const l=s.next,u=s.previous;s===this._tail?(u.next=void 0,this._tail=u):(l.previous=u,u.next=l),s.previous=void 0,s.next=this._head,this._head.previous=s,this._head=s,this._state++}else if(o===r.Last){if(s===this._tail)return;const l=s.next,u=s.previous;s===this._head?(l.previous=void 0,this._head=l):(l.previous=u,u.next=l),s.next=void 0,s.previous=this._tail,this._tail.next=s,this._tail=s,this._state++}}}toJSON(){const s=[];return this.forEach((o,l)=>{s.push([l,o])}),s}fromJSON(s){this.clear();for(const[o,l]of s)this.set(o,l)}};e.LinkedMap=n;var a=class extends n{static{i(this,"LRUCache")}constructor(s,o=1){super(),this._limit=s,this._ratio=Math.min(Math.max(0,o),1)}get limit(){return this._limit}set limit(s){this._limit=s,this.checkTrim()}get ratio(){return this._ratio}set ratio(s){this._ratio=Math.min(Math.max(0,s),1),this.checkTrim()}get(s,o=r.AsNew){return super.get(s,o)}peek(s){return super.get(s,r.None)}set(s,o){return super.set(s,o,r.Last),this.checkTrim(),this}checkTrim(){this.size>this._limit&&this.trimOld(Math.round(this._limit*this._ratio))}};e.LRUCache=a}}),bI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/disposable.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Disposable=void 0;var t;(function(r){function n(a){return{dispose:a}}i(n,"create"),r.create=n})(t||(e.Disposable=t={}))}}),_I=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/sharedArrayCancellation.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.SharedArrayReceiverStrategy=e.SharedArraySenderStrategy=void 0;var t=Dl(),r;(function(l){l.Continue=0,l.Cancelled=1})(r||(r={}));var n=class{static{i(this,"SharedArraySenderStrategy")}constructor(){this.buffers=new Map}enableCancellation(l){if(l.id===null)return;const u=new SharedArrayBuffer(4),c=new Int32Array(u,0,1);c[0]=r.Continue,this.buffers.set(l.id,u),l.$cancellationData=u}async sendCancellation(l,u){const c=this.buffers.get(u);if(c===void 0)return;const f=new Int32Array(c,0,1);Atomics.store(f,0,r.Cancelled)}cleanup(l){this.buffers.delete(l)}dispose(){this.buffers.clear()}};e.SharedArraySenderStrategy=n;var a=class{static{i(this,"SharedArrayBufferCancellationToken")}constructor(l){this.data=new Int32Array(l,0,1)}get isCancellationRequested(){return Atomics.load(this.data,0)===r.Cancelled}get onCancellationRequested(){throw new Error("Cancellation over SharedArrayBuffer doesn't support cancellation events")}},s=class{static{i(this,"SharedArrayBufferCancellationTokenSource")}constructor(l){this.token=new a(l)}cancel(){}dispose(){}},o=class{static{i(this,"SharedArrayReceiverStrategy")}constructor(){this.kind="request"}createCancellationTokenSource(l){const u=l.$cancellationData;return u===void 0?new t.CancellationTokenSource:new s(u)}};e.SharedArrayReceiverStrategy=o}}),Kg=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/semaphore.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Semaphore=void 0;var t=Ln(),r=class{static{i(this,"Semaphore")}constructor(n=1){if(n<=0)throw new Error("Capacity must be greater than 0");this._capacity=n,this._active=0,this._waiting=[]}lock(n){return new Promise((a,s)=>{this._waiting.push({thunk:n,resolve:a,reject:s}),this.runNext()})}get active(){return this._active}runNext(){this._waiting.length===0||this._active===this._capacity||(0,t.default)().timer.setImmediate(()=>this.doRunNext())}doRunNext(){if(this._waiting.length===0||this._active===this._capacity)return;const n=this._waiting.shift();if(this._active++,this._active>this._capacity)throw new Error("To many thunks active");try{const a=n.thunk();a instanceof Promise?a.then(s=>{this._active--,n.resolve(s),this.runNext()},s=>{this._active--,n.reject(s),this.runNext()}):(this._active--,n.resolve(a),this.runNext())}catch(a){this._active--,n.reject(a),this.runNext()}}};e.Semaphore=r}}),SI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messageReader.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ReadableStreamMessageReader=e.AbstractMessageReader=e.MessageReader=void 0;var t=Ln(),r=xs(),n=Qa(),a=Kg(),s;(function(c){function f(d){let m=d;return m&&r.func(m.listen)&&r.func(m.dispose)&&r.func(m.onError)&&r.func(m.onClose)&&r.func(m.onPartialMessage)}i(f,"is"),c.is=f})(s||(e.MessageReader=s={}));var o=class{static{i(this,"AbstractMessageReader")}constructor(){this.errorEmitter=new n.Emitter,this.closeEmitter=new n.Emitter,this.partialMessageEmitter=new n.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(c){this.errorEmitter.fire(this.asError(c))}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}get onPartialMessage(){return this.partialMessageEmitter.event}firePartialMessage(c){this.partialMessageEmitter.fire(c)}asError(c){return c instanceof Error?c:new Error(`Reader received error. Reason: ${r.string(c.message)?c.message:"unknown"}`)}};e.AbstractMessageReader=o;var l;(function(c){function f(d){let m,g;const v=new Map;let b;const S=new Map;if(d===void 0||typeof d=="string")m=d??"utf-8";else{if(m=d.charset??"utf-8",d.contentDecoder!==void 0&&(g=d.contentDecoder,v.set(g.name,g)),d.contentDecoders!==void 0)for(const w of d.contentDecoders)v.set(w.name,w);if(d.contentTypeDecoder!==void 0&&(b=d.contentTypeDecoder,S.set(b.name,b)),d.contentTypeDecoders!==void 0)for(const w of d.contentTypeDecoders)S.set(w.name,w)}return b===void 0&&(b=(0,t.default)().applicationJson.decoder,S.set(b.name,b)),{charset:m,contentDecoder:g,contentDecoders:v,contentTypeDecoder:b,contentTypeDecoders:S}}i(f,"fromOptions"),c.fromOptions=f})(l||(l={}));var u=class extends o{static{i(this,"ReadableStreamMessageReader")}constructor(c,f){super(),this.readable=c,this.options=l.fromOptions(f),this.buffer=(0,t.default)().messageBuffer.create(this.options.charset),this._partialMessageTimeout=1e4,this.nextMessageLength=-1,this.messageToken=0,this.readSemaphore=new a.Semaphore(1)}set partialMessageTimeout(c){this._partialMessageTimeout=c}get partialMessageTimeout(){return this._partialMessageTimeout}listen(c){this.nextMessageLength=-1,this.messageToken=0,this.partialMessageTimer=void 0,this.callback=c;const f=this.readable.onData(d=>{this.onData(d)});return this.readable.onError(d=>this.fireError(d)),this.readable.onClose(()=>this.fireClose()),f}onData(c){try{for(this.buffer.append(c);;){if(this.nextMessageLength===-1){const d=this.buffer.tryReadHeaders(!0);if(!d)return;const m=d.get("content-length");if(!m){this.fireError(new Error(`Header must provide a Content-Length property. +${JSON.stringify(Object.fromEntries(d))}`));return}const g=parseInt(m);if(isNaN(g)){this.fireError(new Error(`Content-Length value must be a number. Got ${m}`));return}this.nextMessageLength=g}const f=this.buffer.tryReadBody(this.nextMessageLength);if(f===void 0){this.setPartialMessageTimer();return}this.clearPartialMessageTimer(),this.nextMessageLength=-1,this.readSemaphore.lock(async()=>{const d=this.options.contentDecoder!==void 0?await this.options.contentDecoder.decode(f):f,m=await this.options.contentTypeDecoder.decode(d,this.options);this.callback(m)}).catch(d=>{this.fireError(d)})}}catch(f){this.fireError(f)}}clearPartialMessageTimer(){this.partialMessageTimer&&(this.partialMessageTimer.dispose(),this.partialMessageTimer=void 0)}setPartialMessageTimer(){this.clearPartialMessageTimer(),!(this._partialMessageTimeout<=0)&&(this.partialMessageTimer=(0,t.default)().timer.setTimeout((c,f)=>{this.partialMessageTimer=void 0,c===this.messageToken&&(this.firePartialMessage({messageToken:c,waitingTime:f}),this.setPartialMessageTimer())},this._partialMessageTimeout,this.messageToken,this._partialMessageTimeout))}};e.ReadableStreamMessageReader=u}}),wI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messageWriter.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.WriteableStreamMessageWriter=e.AbstractMessageWriter=e.MessageWriter=void 0;var t=Ln(),r=xs(),n=Kg(),a=Qa(),s="Content-Length: ",o=`\r +`,l;(function(d){function m(g){let v=g;return v&&r.func(v.dispose)&&r.func(v.onClose)&&r.func(v.onError)&&r.func(v.write)}i(m,"is"),d.is=m})(l||(e.MessageWriter=l={}));var u=class{static{i(this,"AbstractMessageWriter")}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(d,m,g){this.errorEmitter.fire([this.asError(d),m,g])}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}asError(d){return d instanceof Error?d:new Error(`Writer received error. Reason: ${r.string(d.message)?d.message:"unknown"}`)}};e.AbstractMessageWriter=u;var c;(function(d){function m(g){return g===void 0||typeof g=="string"?{charset:g??"utf-8",contentTypeEncoder:(0,t.default)().applicationJson.encoder}:{charset:g.charset??"utf-8",contentEncoder:g.contentEncoder,contentTypeEncoder:g.contentTypeEncoder??(0,t.default)().applicationJson.encoder}}i(m,"fromOptions"),d.fromOptions=m})(c||(c={}));var f=class extends u{static{i(this,"WriteableStreamMessageWriter")}constructor(d,m){super(),this.writable=d,this.options=c.fromOptions(m),this.errorCount=0,this.writeSemaphore=new n.Semaphore(1),this.writable.onError(g=>this.fireError(g)),this.writable.onClose(()=>this.fireClose())}async write(d){return this.writeSemaphore.lock(async()=>this.options.contentTypeEncoder.encode(d,this.options).then(g=>this.options.contentEncoder!==void 0?this.options.contentEncoder.encode(g):g).then(g=>{const v=[];return v.push(s,g.byteLength.toString(),o),v.push(o),this.doWrite(d,v,g)},g=>{throw this.fireError(g),g}))}async doWrite(d,m,g){try{return await this.writable.write(m.join(""),"ascii"),this.writable.write(g)}catch(v){return this.handleError(v,d),Promise.reject(v)}}handleError(d,m){this.errorCount++,this.fireError(d,m,this.errorCount)}end(){this.writable.end()}};e.WriteableStreamMessageWriter=f}}),II=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messageBuffer.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractMessageBuffer=void 0;var t=13,r=10,n=`\r +`,a=class{static{i(this,"AbstractMessageBuffer")}constructor(s="utf-8"){this._encoding=s,this._chunks=[],this._totalLength=0}get encoding(){return this._encoding}append(s){const o=typeof s=="string"?this.fromString(s,this._encoding):s;this._chunks.push(o),this._totalLength+=o.byteLength}tryReadHeaders(s=!1){if(this._chunks.length===0)return;let o=0,l=0,u=0,c=0;e:for(;lthis._totalLength)throw new Error("Cannot read so many bytes!");if(this._chunks[0].byteLength===s){const c=this._chunks[0];return this._chunks.shift(),this._totalLength-=s,this.asNative(c)}if(this._chunks[0].byteLength>s){const c=this._chunks[0],f=this.asNative(c,s);return this._chunks[0]=c.slice(s),this._totalLength-=s,f}const o=this.allocNative(s);let l=0,u=0;for(;s>0;){const c=this._chunks[u];if(c.byteLength>s){const f=c.slice(0,s);o.set(f,l),l+=s,this._chunks[u]=c.slice(s),this._totalLength-=s,s-=s}else o.set(c,l),l+=c.byteLength,this._chunks.shift(),this._totalLength-=c.byteLength,s-=c.byteLength}return o}};e.AbstractMessageBuffer=a}}),NI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/connection.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.createMessageConnection=e.ConnectionOptions=e.MessageStrategy=e.CancellationStrategy=e.CancellationSenderStrategy=e.CancellationReceiverStrategy=e.RequestCancellationReceiverStrategy=e.IdCancellationReceiverStrategy=e.ConnectionStrategy=e.ConnectionError=e.ConnectionErrors=e.LogTraceNotification=e.SetTraceNotification=e.TraceFormat=e.TraceValues=e.Trace=e.NullLogger=e.ProgressType=e.ProgressToken=void 0;var t=Ln(),r=xs(),n=jg(),a=Ug(),s=Qa(),o=Dl(),l;(function(y){y.type=new n.NotificationType("$/cancelRequest")})(l||(l={}));var u;(function(y){function E(T){return typeof T=="string"||typeof T=="number"}i(E,"is"),y.is=E})(u||(e.ProgressToken=u={}));var c;(function(y){y.type=new n.NotificationType("$/progress")})(c||(c={}));var f=class{static{i(this,"ProgressType")}constructor(){}};e.ProgressType=f;var d;(function(y){function E(T){return r.func(T)}i(E,"is"),y.is=E})(d||(d={})),e.NullLogger=Object.freeze({error:i(()=>{},"error"),warn:i(()=>{},"warn"),info:i(()=>{},"info"),log:i(()=>{},"log")});var m;(function(y){y[y.Off=0]="Off",y[y.Messages=1]="Messages",y[y.Compact=2]="Compact",y[y.Verbose=3]="Verbose"})(m||(e.Trace=m={}));var g;(function(y){y.Off="off",y.Messages="messages",y.Compact="compact",y.Verbose="verbose"})(g||(e.TraceValues=g={})),(function(y){function E($){if(!r.string($))return y.Off;switch($=$.toLowerCase(),$){case"off":return y.Off;case"messages":return y.Messages;case"compact":return y.Compact;case"verbose":return y.Verbose;default:return y.Off}}i(E,"fromString"),y.fromString=E;function T($){switch($){case y.Off:return"off";case y.Messages:return"messages";case y.Compact:return"compact";case y.Verbose:return"verbose";default:return"off"}}i(T,"toString"),y.toString=T})(m||(e.Trace=m={}));var v;(function(y){y.Text="text",y.JSON="json"})(v||(e.TraceFormat=v={})),(function(y){function E(T){return r.string(T)?(T=T.toLowerCase(),T==="json"?y.JSON:y.Text):y.Text}i(E,"fromString"),y.fromString=E})(v||(e.TraceFormat=v={}));var b;(function(y){y.type=new n.NotificationType("$/setTrace")})(b||(e.SetTraceNotification=b={}));var S;(function(y){y.type=new n.NotificationType("$/logTrace")})(S||(e.LogTraceNotification=S={}));var w;(function(y){y[y.Closed=1]="Closed",y[y.Disposed=2]="Disposed",y[y.AlreadyListening=3]="AlreadyListening"})(w||(e.ConnectionErrors=w={}));var I=class Wg extends Error{static{i(this,"ConnectionError")}constructor(E,T){super(T),this.code=E,Object.setPrototypeOf(this,Wg.prototype)}};e.ConnectionError=I;var R;(function(y){function E(T){const $=T;return $&&r.func($.cancelUndispatched)}i(E,"is"),y.is=E})(R||(e.ConnectionStrategy=R={}));var P;(function(y){function E(T){const $=T;return $&&($.kind===void 0||$.kind==="id")&&r.func($.createCancellationTokenSource)&&($.dispose===void 0||r.func($.dispose))}i(E,"is"),y.is=E})(P||(e.IdCancellationReceiverStrategy=P={}));var z;(function(y){function E(T){const $=T;return $&&$.kind==="request"&&r.func($.createCancellationTokenSource)&&($.dispose===void 0||r.func($.dispose))}i(E,"is"),y.is=E})(z||(e.RequestCancellationReceiverStrategy=z={}));var X;(function(y){y.Message=Object.freeze({createCancellationTokenSource(T){return new o.CancellationTokenSource}});function E(T){return P.is(T)||z.is(T)}i(E,"is"),y.is=E})(X||(e.CancellationReceiverStrategy=X={}));var Z;(function(y){y.Message=Object.freeze({sendCancellation(T,$){return T.sendNotification(l.type,{id:$})},cleanup(T){}});function E(T){const $=T;return $&&r.func($.sendCancellation)&&r.func($.cleanup)}i(E,"is"),y.is=E})(Z||(e.CancellationSenderStrategy=Z={}));var ce;(function(y){y.Message=Object.freeze({receiver:X.Message,sender:Z.Message});function E(T){const $=T;return $&&X.is($.receiver)&&Z.is($.sender)}i(E,"is"),y.is=E})(ce||(e.CancellationStrategy=ce={}));var se;(function(y){function E(T){const $=T;return $&&r.func($.handleMessage)}i(E,"is"),y.is=E})(se||(e.MessageStrategy=se={}));var Se;(function(y){function E(T){const $=T;return $&&(ce.is($.cancellationStrategy)||R.is($.connectionStrategy)||se.is($.messageStrategy))}i(E,"is"),y.is=E})(Se||(e.ConnectionOptions=Se={}));var k;(function(y){y[y.New=1]="New",y[y.Listening=2]="Listening",y[y.Closed=3]="Closed",y[y.Disposed=4]="Disposed"})(k||(k={}));function C(y,E,T,$){const _=T!==void 0?T:e.NullLogger;let O=0,x=0,D=0;const G="2.0";let W;const Y=new Map;let q;const Pe=new Map,oe=new Map;let Le,De=new a.LinkedMap,ke=new Map,Ze=new Set,Je=new Map,ne=m.Off,Ut=v.Text,Ee,Pt=k.New;const ta=new s.Emitter,ci=new s.Emitter,fi=new s.Emitter,di=new s.Emitter,pi=new s.Emitter,kt=$&&$.cancellationStrategy?$.cancellationStrategy:ce.Message;function ra(h){if(h===null)throw new Error("Can't send requests with id null since the response can't be correlated.");return"req-"+h.toString()}i(ra,"createRequestQueueKey");function mi(h){return h===null?"res-unknown-"+(++D).toString():"res-"+h.toString()}i(mi,"createResponseQueueKey");function hi(){return"not-"+(++x).toString()}i(hi,"createNotificationQueueKey");function yi(h,N){n.Message.isRequest(N)?h.set(ra(N.id),N):n.Message.isResponse(N)?h.set(mi(N.id),N):h.set(hi(),N)}i(yi,"addMessageToQueue");function gi(h){}i(gi,"cancelUndispatched");function na(){return Pt===k.Listening}i(na,"isListening");function aa(){return Pt===k.Closed}i(aa,"isClosed");function Kt(){return Pt===k.Disposed}i(Kt,"isDisposed");function ia(){(Pt===k.New||Pt===k.Listening)&&(Pt=k.Closed,ci.fire(void 0))}i(ia,"closeHandler");function vi(h){ta.fire([h,void 0,void 0])}i(vi,"readErrorHandler");function Ti(h){ta.fire(h)}i(Ti,"writeErrorHandler"),y.onClose(ia),y.onError(vi),E.onClose(ia),E.onError(Ti);function sa(){Le||De.size===0||(Le=(0,t.default)().timer.setImmediate(()=>{Le=void 0,$i()}))}i(sa,"triggerMessageQueue");function oa(h){n.Message.isRequest(h)?Ri(h):n.Message.isNotification(h)?Ei(h):n.Message.isResponse(h)?Ai(h):Ci(h)}i(oa,"handleMessage");function $i(){if(De.size===0)return;const h=De.shift();try{const N=$?.messageStrategy;se.is(N)?N.handleMessage(h,oa):oa(h)}finally{sa()}}i($i,"processMessageQueue");const ro=i(h=>{try{if(n.Message.isNotification(h)&&h.method===l.type.method){const N=h.params.id,L=ra(N),M=De.get(L);if(n.Message.isRequest(M)){const fe=$?.connectionStrategy,Ce=fe&&fe.cancelUndispatched?fe.cancelUndispatched(M,gi):void 0;if(Ce&&(Ce.error!==void 0||Ce.result!==void 0)){De.delete(L),Je.delete(N),Ce.id=M.id,Or(Ce,h.method,Date.now()),E.write(Ce).catch(()=>_.error("Sending response for canceled message failed."));return}}const he=Je.get(N);if(he!==void 0){he.cancel(),Xr(h);return}else Ze.add(N)}yi(De,h)}finally{sa()}},"callback");function Ri(h){if(Kt())return;function N(te,$e,le){const xe={jsonrpc:G,id:h.id};te instanceof n.ResponseError?xe.error=te.toJson():xe.result=te===void 0?null:te,Or(xe,$e,le),E.write(xe).catch(()=>_.error("Sending response failed."))}i(N,"reply");function L(te,$e,le){const xe={jsonrpc:G,id:h.id,error:te.toJson()};Or(xe,$e,le),E.write(xe).catch(()=>_.error("Sending response failed."))}i(L,"replyError");function M(te,$e,le){te===void 0&&(te=null);const xe={jsonrpc:G,id:h.id,result:te};Or(xe,$e,le),E.write(xe).catch(()=>_.error("Sending response failed."))}i(M,"replySuccess"),Si(h);const he=Y.get(h.method);let fe,Ce;he&&(fe=he.type,Ce=he.handler);const we=Date.now();if(Ce||W){const te=h.id??String(Date.now()),$e=P.is(kt.receiver)?kt.receiver.createCancellationTokenSource(te):kt.receiver.createCancellationTokenSource(h);h.id!==null&&Ze.has(h.id)&&$e.cancel(),h.id!==null&&Je.set(te,$e);try{let le;if(Ce)if(h.params===void 0){if(fe!==void 0&&fe.numberOfParams!==0){L(new n.ResponseError(n.ErrorCodes.InvalidParams,`Request ${h.method} defines ${fe.numberOfParams} params but received none.`),h.method,we);return}le=Ce($e.token)}else if(Array.isArray(h.params)){if(fe!==void 0&&fe.parameterStructures===n.ParameterStructures.byName){L(new n.ResponseError(n.ErrorCodes.InvalidParams,`Request ${h.method} defines parameters by name but received parameters by position`),h.method,we);return}le=Ce(...h.params,$e.token)}else{if(fe!==void 0&&fe.parameterStructures===n.ParameterStructures.byPosition){L(new n.ResponseError(n.ErrorCodes.InvalidParams,`Request ${h.method} defines parameters by position but received parameters by name`),h.method,we);return}le=Ce(h.params,$e.token)}else W&&(le=W(h.method,h.params,$e.token));const xe=le;le?xe.then?xe.then(Qe=>{Je.delete(te),N(Qe,h.method,we)},Qe=>{Je.delete(te),Qe instanceof n.ResponseError?L(Qe,h.method,we):Qe&&r.string(Qe.message)?L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed with message: ${Qe.message}`),h.method,we):L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed unexpectedly without providing any details.`),h.method,we)}):(Je.delete(te),N(le,h.method,we)):(Je.delete(te),M(le,h.method,we))}catch(le){Je.delete(te),le instanceof n.ResponseError?N(le,h.method,we):le&&r.string(le.message)?L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed with message: ${le.message}`),h.method,we):L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed unexpectedly without providing any details.`),h.method,we)}}else L(new n.ResponseError(n.ErrorCodes.MethodNotFound,`Unhandled method ${h.method}`),h.method,we)}i(Ri,"handleRequest");function Ai(h){if(!Kt())if(h.id===null)h.error?_.error(`Received response message without id: Error is: +${JSON.stringify(h.error,void 0,4)}`):_.error("Received response message without id. No further error information provided.");else{const N=h.id,L=ke.get(N);if(wi(h,L),L!==void 0){ke.delete(N);try{if(h.error){const M=h.error;L.reject(new n.ResponseError(M.code,M.message,M.data))}else if(h.result!==void 0)L.resolve(h.result);else throw new Error("Should never happen.")}catch(M){M.message?_.error(`Response handler '${L.method}' failed with message: ${M.message}`):_.error(`Response handler '${L.method}' failed unexpectedly.`)}}}}i(Ai,"handleResponse");function Ei(h){if(Kt())return;let N,L;if(h.method===l.type.method){const M=h.params.id;Ze.delete(M),Xr(h);return}else{const M=Pe.get(h.method);M&&(L=M.handler,N=M.type)}if(L||q)try{if(Xr(h),L)if(h.params===void 0)N!==void 0&&N.numberOfParams!==0&&N.parameterStructures!==n.ParameterStructures.byName&&_.error(`Notification ${h.method} defines ${N.numberOfParams} params but received none.`),L();else if(Array.isArray(h.params)){const M=h.params;h.method===c.type.method&&M.length===2&&u.is(M[0])?L({token:M[0],value:M[1]}):(N!==void 0&&(N.parameterStructures===n.ParameterStructures.byName&&_.error(`Notification ${h.method} defines parameters by name but received parameters by position`),N.numberOfParams!==h.params.length&&_.error(`Notification ${h.method} defines ${N.numberOfParams} params but received ${M.length} arguments`)),L(...M))}else N!==void 0&&N.parameterStructures===n.ParameterStructures.byPosition&&_.error(`Notification ${h.method} defines parameters by position but received parameters by name`),L(h.params);else q&&q(h.method,h.params)}catch(M){M.message?_.error(`Notification handler '${h.method}' failed with message: ${M.message}`):_.error(`Notification handler '${h.method}' failed unexpectedly.`)}else fi.fire(h)}i(Ei,"handleNotification");function Ci(h){if(!h){_.error("Received empty message.");return}_.error(`Received message which is neither a response nor a notification message: +${JSON.stringify(h,null,4)}`);const N=h;if(r.string(N.id)||r.number(N.id)){const L=N.id,M=ke.get(L);M&&M.reject(new Error("The received response has neither a result nor an error property."))}}i(Ci,"handleInvalidMessage");function Ct(h){if(h!=null)switch(ne){case m.Verbose:return JSON.stringify(h,null,4);case m.Compact:return JSON.stringify(h);default:return}}i(Ct,"stringifyTrace");function bi(h){if(!(ne===m.Off||!Ee))if(Ut===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&h.params&&(N=`Params: ${Ct(h.params)} + +`),Ee.log(`Sending request '${h.method} - (${h.id})'.`,N)}else Wt("send-request",h)}i(bi,"traceSendingRequest");function _i(h){if(!(ne===m.Off||!Ee))if(Ut===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&(h.params?N=`Params: ${Ct(h.params)} + +`:N=`No parameters provided. + +`),Ee.log(`Sending notification '${h.method}'.`,N)}else Wt("send-notification",h)}i(_i,"traceSendingNotification");function Or(h,N,L){if(!(ne===m.Off||!Ee))if(Ut===v.Text){let M;(ne===m.Verbose||ne===m.Compact)&&(h.error&&h.error.data?M=`Error data: ${Ct(h.error.data)} + +`:h.result?M=`Result: ${Ct(h.result)} + +`:h.error===void 0&&(M=`No result returned. + +`)),Ee.log(`Sending response '${N} - (${h.id})'. Processing request took ${Date.now()-L}ms`,M)}else Wt("send-response",h)}i(Or,"traceSendingResponse");function Si(h){if(!(ne===m.Off||!Ee))if(Ut===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&h.params&&(N=`Params: ${Ct(h.params)} + +`),Ee.log(`Received request '${h.method} - (${h.id})'.`,N)}else Wt("receive-request",h)}i(Si,"traceReceivedRequest");function Xr(h){if(!(ne===m.Off||!Ee||h.method===S.type.method))if(Ut===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&(h.params?N=`Params: ${Ct(h.params)} + +`:N=`No parameters provided. + +`),Ee.log(`Received notification '${h.method}'.`,N)}else Wt("receive-notification",h)}i(Xr,"traceReceivedNotification");function wi(h,N){if(!(ne===m.Off||!Ee))if(Ut===v.Text){let L;if((ne===m.Verbose||ne===m.Compact)&&(h.error&&h.error.data?L=`Error data: ${Ct(h.error.data)} + +`:h.result?L=`Result: ${Ct(h.result)} + +`:h.error===void 0&&(L=`No result returned. + +`)),N){const M=h.error?` Request failed: ${h.error.message} (${h.error.code}).`:"";Ee.log(`Received response '${N.method} - (${h.id})' in ${Date.now()-N.timerStart}ms.${M}`,L)}else Ee.log(`Received response ${h.id} without active response promise.`,L)}else Wt("receive-response",h)}i(wi,"traceReceivedResponse");function Wt(h,N){if(!Ee||ne===m.Off)return;const L={isLSPMessage:!0,type:h,message:N,timestamp:Date.now()};Ee.log(L)}i(Wt,"logLSPMessage");function ur(){if(aa())throw new I(w.Closed,"Connection is closed.");if(Kt())throw new I(w.Disposed,"Connection is disposed.")}i(ur,"throwIfClosedOrDisposed");function Ii(){if(na())throw new I(w.AlreadyListening,"Connection is already listening")}i(Ii,"throwIfListening");function Ni(){if(!na())throw new Error("Call listen() first.")}i(Ni,"throwIfNotListening");function cr(h){return h===void 0?null:h}i(cr,"undefinedToNull");function la(h){if(h!==null)return h}i(la,"nullToUndefined");function p(h){return h!=null&&!Array.isArray(h)&&typeof h=="object"}i(p,"isNamedParam");function ae(h,N){switch(h){case n.ParameterStructures.auto:return p(N)?la(N):[cr(N)];case n.ParameterStructures.byName:if(!p(N))throw new Error("Received parameters by name but param is not an object literal.");return la(N);case n.ParameterStructures.byPosition:return[cr(N)];default:throw new Error(`Unknown parameter structure ${h.toString()}`)}}i(ae,"computeSingleParam");function Te(h,N){let L;const M=h.numberOfParams;switch(M){case 0:L=void 0;break;case 1:L=ae(h.parameterStructures,N[0]);break;default:L=[];for(let he=0;he{ur();let L,M;if(r.string(h)){L=h;const fe=N[0];let Ce=0,we=n.ParameterStructures.auto;n.ParameterStructures.is(fe)&&(Ce=1,we=fe);let te=N.length;const $e=te-Ce;switch($e){case 0:M=void 0;break;case 1:M=ae(we,N[Ce]);break;default:if(we===n.ParameterStructures.byName)throw new Error(`Received ${$e} parameters for 'by Name' notification parameter structure.`);M=N.slice(Ce,te).map(le=>cr(le));break}}else{const fe=N;L=h.method,M=Te(h,fe)}const he={jsonrpc:G,method:L,params:M};return _i(he),E.write(he).catch(fe=>{throw _.error("Sending notification failed."),fe})},"sendNotification"),onNotification:i((h,N)=>{ur();let L;return r.func(h)?q=h:N&&(r.string(h)?(L=h,Pe.set(h,{type:void 0,handler:N})):(L=h.method,Pe.set(h.method,{type:h,handler:N}))),{dispose:i(()=>{L!==void 0?Pe.delete(L):q=void 0},"dispose")}},"onNotification"),onProgress:i((h,N,L)=>{if(oe.has(N))throw new Error(`Progress handler for token ${N} already registered`);return oe.set(N,L),{dispose:i(()=>{oe.delete(N)},"dispose")}},"onProgress"),sendProgress:i((h,N,L)=>V.sendNotification(c.type,{token:N,value:L}),"sendProgress"),onUnhandledProgress:di.event,sendRequest:i((h,...N)=>{ur(),Ni();let L,M,he;if(r.string(h)){L=h;const te=N[0],$e=N[N.length-1];let le=0,xe=n.ParameterStructures.auto;n.ParameterStructures.is(te)&&(le=1,xe=te);let Qe=N.length;o.CancellationToken.is($e)&&(Qe=Qe-1,he=$e);const qt=Qe-le;switch(qt){case 0:M=void 0;break;case 1:M=ae(xe,N[le]);break;default:if(xe===n.ParameterStructures.byName)throw new Error(`Received ${qt} parameters for 'by Name' request parameter structure.`);M=N.slice(le,Qe).map(TI=>cr(TI));break}}else{const te=N;L=h.method,M=Te(h,te);const $e=h.numberOfParams;he=o.CancellationToken.is(te[$e])?te[$e]:void 0}const fe=O++;let Ce;he&&(Ce=he.onCancellationRequested(()=>{const te=kt.sender.sendCancellation(V,fe);return te===void 0?(_.log(`Received no promise from cancellation strategy when cancelling id ${fe}`),Promise.resolve()):te.catch(()=>{_.log(`Sending cancellation messages for id ${fe} failed`)})}));const we={jsonrpc:G,id:fe,method:L,params:M};return bi(we),typeof kt.sender.enableCancellation=="function"&&kt.sender.enableCancellation(we),new Promise(async(te,$e)=>{const le=i(qt=>{te(qt),kt.sender.cleanup(fe),Ce?.dispose()},"resolveWithCleanup"),xe=i(qt=>{$e(qt),kt.sender.cleanup(fe),Ce?.dispose()},"rejectWithCleanup"),Qe={method:L,timerStart:Date.now(),resolve:le,reject:xe};try{await E.write(we),ke.set(fe,Qe)}catch(qt){throw _.error("Sending request failed."),Qe.reject(new n.ResponseError(n.ErrorCodes.MessageWriteError,qt.message?qt.message:"Unknown reason")),qt}})},"sendRequest"),onRequest:i((h,N)=>{ur();let L=null;return d.is(h)?(L=void 0,W=h):r.string(h)?(L=null,N!==void 0&&(L=h,Y.set(h,{handler:N,type:void 0}))):N!==void 0&&(L=h.method,Y.set(h.method,{type:h,handler:N})),{dispose:i(()=>{L!==null&&(L!==void 0?Y.delete(L):W=void 0)},"dispose")}},"onRequest"),hasPendingResponse:i(()=>ke.size>0,"hasPendingResponse"),trace:i(async(h,N,L)=>{let M=!1,he=v.Text;L!==void 0&&(r.boolean(L)?M=L:(M=L.sendNotification||!1,he=L.traceFormat||v.Text)),ne=h,Ut=he,ne===m.Off?Ee=void 0:Ee=N,M&&!aa()&&!Kt()&&await V.sendNotification(b.type,{value:m.toString(h)})},"trace"),onError:ta.event,onClose:ci.event,onUnhandledNotification:fi.event,onDispose:pi.event,end:i(()=>{E.end()},"end"),dispose:i(()=>{if(Kt())return;Pt=k.Disposed,pi.fire(void 0);const h=new n.ResponseError(n.ErrorCodes.PendingResponseRejected,"Pending response rejected since connection got disposed");for(const N of ke.values())N.reject(h);ke=new Map,Je=new Map,Ze=new Set,De=new a.LinkedMap,r.func(E.dispose)&&E.dispose(),r.func(y.dispose)&&y.dispose()},"dispose"),listen:i(()=>{ur(),Ii(),Pt=k.Listening,y.listen(ro)},"listen"),inspect:i(()=>{(0,t.default)().console.log("inspect")},"inspect")};return V.onNotification(S.type,h=>{if(ne===m.Off||!Ee)return;const N=ne===m.Verbose||ne===m.Compact;Ee.log(h.message,N?h.verbose:void 0)}),V.onNotification(c.type,h=>{const N=oe.get(h.token);N?N(h.value):di.fire(h)}),V}i(C,"createMessageConnection"),e.createMessageConnection=C}}),Rf=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/api.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ProgressType=e.ProgressToken=e.createMessageConnection=e.NullLogger=e.ConnectionOptions=e.ConnectionStrategy=e.AbstractMessageBuffer=e.WriteableStreamMessageWriter=e.AbstractMessageWriter=e.MessageWriter=e.ReadableStreamMessageReader=e.AbstractMessageReader=e.MessageReader=e.SharedArrayReceiverStrategy=e.SharedArraySenderStrategy=e.CancellationToken=e.CancellationTokenSource=e.Emitter=e.Event=e.Disposable=e.LRUCache=e.Touch=e.LinkedMap=e.ParameterStructures=e.NotificationType9=e.NotificationType8=e.NotificationType7=e.NotificationType6=e.NotificationType5=e.NotificationType4=e.NotificationType3=e.NotificationType2=e.NotificationType1=e.NotificationType0=e.NotificationType=e.ErrorCodes=e.ResponseError=e.RequestType9=e.RequestType8=e.RequestType7=e.RequestType6=e.RequestType5=e.RequestType4=e.RequestType3=e.RequestType2=e.RequestType1=e.RequestType0=e.RequestType=e.Message=e.RAL=void 0,e.MessageStrategy=e.CancellationStrategy=e.CancellationSenderStrategy=e.CancellationReceiverStrategy=e.ConnectionError=e.ConnectionErrors=e.LogTraceNotification=e.SetTraceNotification=e.TraceFormat=e.TraceValues=e.Trace=void 0;var t=jg();Object.defineProperty(e,"Message",{enumerable:!0,get:i(function(){return t.Message},"get")}),Object.defineProperty(e,"RequestType",{enumerable:!0,get:i(function(){return t.RequestType},"get")}),Object.defineProperty(e,"RequestType0",{enumerable:!0,get:i(function(){return t.RequestType0},"get")}),Object.defineProperty(e,"RequestType1",{enumerable:!0,get:i(function(){return t.RequestType1},"get")}),Object.defineProperty(e,"RequestType2",{enumerable:!0,get:i(function(){return t.RequestType2},"get")}),Object.defineProperty(e,"RequestType3",{enumerable:!0,get:i(function(){return t.RequestType3},"get")}),Object.defineProperty(e,"RequestType4",{enumerable:!0,get:i(function(){return t.RequestType4},"get")}),Object.defineProperty(e,"RequestType5",{enumerable:!0,get:i(function(){return t.RequestType5},"get")}),Object.defineProperty(e,"RequestType6",{enumerable:!0,get:i(function(){return t.RequestType6},"get")}),Object.defineProperty(e,"RequestType7",{enumerable:!0,get:i(function(){return t.RequestType7},"get")}),Object.defineProperty(e,"RequestType8",{enumerable:!0,get:i(function(){return t.RequestType8},"get")}),Object.defineProperty(e,"RequestType9",{enumerable:!0,get:i(function(){return t.RequestType9},"get")}),Object.defineProperty(e,"ResponseError",{enumerable:!0,get:i(function(){return t.ResponseError},"get")}),Object.defineProperty(e,"ErrorCodes",{enumerable:!0,get:i(function(){return t.ErrorCodes},"get")}),Object.defineProperty(e,"NotificationType",{enumerable:!0,get:i(function(){return t.NotificationType},"get")}),Object.defineProperty(e,"NotificationType0",{enumerable:!0,get:i(function(){return t.NotificationType0},"get")}),Object.defineProperty(e,"NotificationType1",{enumerable:!0,get:i(function(){return t.NotificationType1},"get")}),Object.defineProperty(e,"NotificationType2",{enumerable:!0,get:i(function(){return t.NotificationType2},"get")}),Object.defineProperty(e,"NotificationType3",{enumerable:!0,get:i(function(){return t.NotificationType3},"get")}),Object.defineProperty(e,"NotificationType4",{enumerable:!0,get:i(function(){return t.NotificationType4},"get")}),Object.defineProperty(e,"NotificationType5",{enumerable:!0,get:i(function(){return t.NotificationType5},"get")}),Object.defineProperty(e,"NotificationType6",{enumerable:!0,get:i(function(){return t.NotificationType6},"get")}),Object.defineProperty(e,"NotificationType7",{enumerable:!0,get:i(function(){return t.NotificationType7},"get")}),Object.defineProperty(e,"NotificationType8",{enumerable:!0,get:i(function(){return t.NotificationType8},"get")}),Object.defineProperty(e,"NotificationType9",{enumerable:!0,get:i(function(){return t.NotificationType9},"get")}),Object.defineProperty(e,"ParameterStructures",{enumerable:!0,get:i(function(){return t.ParameterStructures},"get")});var r=Ug();Object.defineProperty(e,"LinkedMap",{enumerable:!0,get:i(function(){return r.LinkedMap},"get")}),Object.defineProperty(e,"LRUCache",{enumerable:!0,get:i(function(){return r.LRUCache},"get")}),Object.defineProperty(e,"Touch",{enumerable:!0,get:i(function(){return r.Touch},"get")});var n=bI();Object.defineProperty(e,"Disposable",{enumerable:!0,get:i(function(){return n.Disposable},"get")});var a=Qa();Object.defineProperty(e,"Event",{enumerable:!0,get:i(function(){return a.Event},"get")}),Object.defineProperty(e,"Emitter",{enumerable:!0,get:i(function(){return a.Emitter},"get")});var s=Dl();Object.defineProperty(e,"CancellationTokenSource",{enumerable:!0,get:i(function(){return s.CancellationTokenSource},"get")}),Object.defineProperty(e,"CancellationToken",{enumerable:!0,get:i(function(){return s.CancellationToken},"get")});var o=_I();Object.defineProperty(e,"SharedArraySenderStrategy",{enumerable:!0,get:i(function(){return o.SharedArraySenderStrategy},"get")}),Object.defineProperty(e,"SharedArrayReceiverStrategy",{enumerable:!0,get:i(function(){return o.SharedArrayReceiverStrategy},"get")});var l=SI();Object.defineProperty(e,"MessageReader",{enumerable:!0,get:i(function(){return l.MessageReader},"get")}),Object.defineProperty(e,"AbstractMessageReader",{enumerable:!0,get:i(function(){return l.AbstractMessageReader},"get")}),Object.defineProperty(e,"ReadableStreamMessageReader",{enumerable:!0,get:i(function(){return l.ReadableStreamMessageReader},"get")});var u=wI();Object.defineProperty(e,"MessageWriter",{enumerable:!0,get:i(function(){return u.MessageWriter},"get")}),Object.defineProperty(e,"AbstractMessageWriter",{enumerable:!0,get:i(function(){return u.AbstractMessageWriter},"get")}),Object.defineProperty(e,"WriteableStreamMessageWriter",{enumerable:!0,get:i(function(){return u.WriteableStreamMessageWriter},"get")});var c=II();Object.defineProperty(e,"AbstractMessageBuffer",{enumerable:!0,get:i(function(){return c.AbstractMessageBuffer},"get")});var f=NI();Object.defineProperty(e,"ConnectionStrategy",{enumerable:!0,get:i(function(){return f.ConnectionStrategy},"get")}),Object.defineProperty(e,"ConnectionOptions",{enumerable:!0,get:i(function(){return f.ConnectionOptions},"get")}),Object.defineProperty(e,"NullLogger",{enumerable:!0,get:i(function(){return f.NullLogger},"get")}),Object.defineProperty(e,"createMessageConnection",{enumerable:!0,get:i(function(){return f.createMessageConnection},"get")}),Object.defineProperty(e,"ProgressToken",{enumerable:!0,get:i(function(){return f.ProgressToken},"get")}),Object.defineProperty(e,"ProgressType",{enumerable:!0,get:i(function(){return f.ProgressType},"get")}),Object.defineProperty(e,"Trace",{enumerable:!0,get:i(function(){return f.Trace},"get")}),Object.defineProperty(e,"TraceValues",{enumerable:!0,get:i(function(){return f.TraceValues},"get")}),Object.defineProperty(e,"TraceFormat",{enumerable:!0,get:i(function(){return f.TraceFormat},"get")}),Object.defineProperty(e,"SetTraceNotification",{enumerable:!0,get:i(function(){return f.SetTraceNotification},"get")}),Object.defineProperty(e,"LogTraceNotification",{enumerable:!0,get:i(function(){return f.LogTraceNotification},"get")}),Object.defineProperty(e,"ConnectionErrors",{enumerable:!0,get:i(function(){return f.ConnectionErrors},"get")}),Object.defineProperty(e,"ConnectionError",{enumerable:!0,get:i(function(){return f.ConnectionError},"get")}),Object.defineProperty(e,"CancellationReceiverStrategy",{enumerable:!0,get:i(function(){return f.CancellationReceiverStrategy},"get")}),Object.defineProperty(e,"CancellationSenderStrategy",{enumerable:!0,get:i(function(){return f.CancellationSenderStrategy},"get")}),Object.defineProperty(e,"CancellationStrategy",{enumerable:!0,get:i(function(){return f.CancellationStrategy},"get")}),Object.defineProperty(e,"MessageStrategy",{enumerable:!0,get:i(function(){return f.MessageStrategy},"get")});var d=Ln();e.RAL=d.default}}),PI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/browser/ril.js"(e){Object.defineProperty(e,"__esModule",{value:!0});var t=Rf(),r=class qg extends t.AbstractMessageBuffer{static{i(this,"MessageBuffer")}constructor(c="utf-8"){super(c),this.asciiDecoder=new TextDecoder("ascii")}emptyBuffer(){return qg.emptyBuffer}fromString(c,f){return new TextEncoder().encode(c)}toString(c,f){return f==="ascii"?this.asciiDecoder.decode(c):new TextDecoder(f).decode(c)}asNative(c,f){return f===void 0?c:c.slice(0,f)}allocNative(c){return new Uint8Array(c)}};r.emptyBuffer=new Uint8Array(0);var n=class{static{i(this,"ReadableStreamWrapper")}constructor(u){this.socket=u,this._onData=new t.Emitter,this._messageListener=c=>{c.data.arrayBuffer().then(d=>{this._onData.fire(new Uint8Array(d))},()=>{(0,t.RAL)().console.error("Converting blob to array buffer failed.")})},this.socket.addEventListener("message",this._messageListener)}onClose(u){return this.socket.addEventListener("close",u),t.Disposable.create(()=>this.socket.removeEventListener("close",u))}onError(u){return this.socket.addEventListener("error",u),t.Disposable.create(()=>this.socket.removeEventListener("error",u))}onEnd(u){return this.socket.addEventListener("end",u),t.Disposable.create(()=>this.socket.removeEventListener("end",u))}onData(u){return this._onData.event(u)}},a=class{static{i(this,"WritableStreamWrapper")}constructor(u){this.socket=u}onClose(u){return this.socket.addEventListener("close",u),t.Disposable.create(()=>this.socket.removeEventListener("close",u))}onError(u){return this.socket.addEventListener("error",u),t.Disposable.create(()=>this.socket.removeEventListener("error",u))}onEnd(u){return this.socket.addEventListener("end",u),t.Disposable.create(()=>this.socket.removeEventListener("end",u))}write(u,c){if(typeof u=="string"){if(c!==void 0&&c!=="utf-8")throw new Error(`In a Browser environments only utf-8 text encoding is supported. But got encoding: ${c}`);this.socket.send(u)}else this.socket.send(u);return Promise.resolve()}end(){this.socket.close()}},s=new TextEncoder,o=Object.freeze({messageBuffer:Object.freeze({create:i(u=>new r(u),"create")}),applicationJson:Object.freeze({encoder:Object.freeze({name:"application/json",encode:i((u,c)=>{if(c.charset!=="utf-8")throw new Error(`In a Browser environments only utf-8 text encoding is supported. But got encoding: ${c.charset}`);return Promise.resolve(s.encode(JSON.stringify(u,void 0,0)))},"encode")}),decoder:Object.freeze({name:"application/json",decode:i((u,c)=>{if(!(u instanceof Uint8Array))throw new Error("In a Browser environments only Uint8Arrays are supported.");return Promise.resolve(JSON.parse(new TextDecoder(c.charset).decode(u)))},"decode")})}),stream:Object.freeze({asReadableStream:i(u=>new n(u),"asReadableStream"),asWritableStream:i(u=>new a(u),"asWritableStream")}),console,timer:Object.freeze({setTimeout(u,c,...f){const d=setTimeout(u,c,...f);return{dispose:i(()=>clearTimeout(d),"dispose")}},setImmediate(u,...c){const f=setTimeout(u,0,...c);return{dispose:i(()=>clearTimeout(f),"dispose")}},setInterval(u,c,...f){const d=setInterval(u,c,...f);return{dispose:i(()=>clearInterval(d),"dispose")}}})});function l(){return o}i(l,"RIL"),(function(u){function c(){t.RAL.install(o)}i(c,"install"),u.install=c})(l||(l={})),e.default=l}}),ei=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/browser/main.js"(e){var t=e&&e.__createBinding||(Object.create?(function(u,c,f,d){d===void 0&&(d=f);var m=Object.getOwnPropertyDescriptor(c,f);(!m||("get"in m?!c.__esModule:m.writable||m.configurable))&&(m={enumerable:!0,get:i(function(){return c[f]},"get")}),Object.defineProperty(u,d,m)}):(function(u,c,f,d){d===void 0&&(d=f),u[d]=c[f]})),r=e&&e.__exportStar||function(u,c){for(var f in u)f!=="default"&&!Object.prototype.hasOwnProperty.call(c,f)&&t(c,u,f)};Object.defineProperty(e,"__esModule",{value:!0}),e.createMessageConnection=e.BrowserMessageWriter=e.BrowserMessageReader=void 0;var n=PI();n.default.install();var a=Rf();r(Rf(),e);var s=class extends a.AbstractMessageReader{static{i(this,"BrowserMessageReader")}constructor(u){super(),this._onData=new a.Emitter,this._messageListener=c=>{this._onData.fire(c.data)},u.addEventListener("error",c=>this.fireError(c)),u.onmessage=this._messageListener}listen(u){return this._onData.event(u)}};e.BrowserMessageReader=s;var o=class extends a.AbstractMessageWriter{static{i(this,"BrowserMessageWriter")}constructor(u){super(),this.port=u,this.errorCount=0,u.addEventListener("error",c=>this.fireError(c))}write(u){try{return this.port.postMessage(u),Promise.resolve()}catch(c){return this.handleError(c,u),Promise.reject(c)}}handleError(u,c){this.errorCount++,this.fireError(u,c,this.errorCount)}end(){}};e.BrowserMessageWriter=o;function l(u,c,f,d){return f===void 0&&(f=a.NullLogger),a.ConnectionStrategy.is(d)&&(d={connectionStrategy:d}),(0,a.createMessageConnection)(u,c,f,d)}i(l,"createMessageConnection"),e.createMessageConnection=l}}),lh=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/browser.js"(e,t){t.exports=ei()}}),Ae=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/messages.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ProtocolNotificationType=e.ProtocolNotificationType0=e.ProtocolRequestType=e.ProtocolRequestType0=e.RegistrationType=e.MessageDirection=void 0;var t=ei(),r;(function(u){u.clientToServer="clientToServer",u.serverToClient="serverToClient",u.both="both"})(r||(e.MessageDirection=r={}));var n=class{static{i(this,"RegistrationType")}constructor(u){this.method=u}};e.RegistrationType=n;var a=class extends t.RequestType0{static{i(this,"ProtocolRequestType0")}constructor(u){super(u)}};e.ProtocolRequestType0=a;var s=class extends t.RequestType{static{i(this,"ProtocolRequestType")}constructor(u){super(u,t.ParameterStructures.byName)}};e.ProtocolRequestType=s;var o=class extends t.NotificationType0{static{i(this,"ProtocolNotificationType0")}constructor(u){super(u)}};e.ProtocolNotificationType0=o;var l=class extends t.NotificationType{static{i(this,"ProtocolNotificationType")}constructor(u){super(u,t.ParameterStructures.byName)}};e.ProtocolNotificationType=l}}),bd=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/utils/is.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.objectLiteral=e.typedArray=e.stringArray=e.array=e.func=e.error=e.number=e.string=e.boolean=void 0;function t(f){return f===!0||f===!1}i(t,"boolean"),e.boolean=t;function r(f){return typeof f=="string"||f instanceof String}i(r,"string"),e.string=r;function n(f){return typeof f=="number"||f instanceof Number}i(n,"number"),e.number=n;function a(f){return f instanceof Error}i(a,"error"),e.error=a;function s(f){return typeof f=="function"}i(s,"func"),e.func=s;function o(f){return Array.isArray(f)}i(o,"array"),e.array=o;function l(f){return o(f)&&f.every(d=>r(d))}i(l,"stringArray"),e.stringArray=l;function u(f,d){return Array.isArray(f)&&f.every(d)}i(u,"typedArray"),e.typedArray=u;function c(f){return f!==null&&typeof f=="object"}i(c,"objectLiteral"),e.objectLiteral=c}}),kI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.implementation.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ImplementationRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/implementation",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.ImplementationRequest=r={}))}}),OI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeDefinition.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.TypeDefinitionRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/typeDefinition",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.TypeDefinitionRequest=r={}))}}),LI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.workspaceFolder.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DidChangeWorkspaceFoldersNotification=e.WorkspaceFoldersRequest=void 0;var t=Ae(),r;(function(a){a.method="workspace/workspaceFolders",a.messageDirection=t.MessageDirection.serverToClient,a.type=new t.ProtocolRequestType0(a.method)})(r||(e.WorkspaceFoldersRequest=r={}));var n;(function(a){a.method="workspace/didChangeWorkspaceFolders",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolNotificationType(a.method)})(n||(e.DidChangeWorkspaceFoldersNotification=n={}))}}),DI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.configuration.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ConfigurationRequest=void 0;var t=Ae(),r;(function(n){n.method="workspace/configuration",n.messageDirection=t.MessageDirection.serverToClient,n.type=new t.ProtocolRequestType(n.method)})(r||(e.ConfigurationRequest=r={}))}}),xI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.colorProvider.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ColorPresentationRequest=e.DocumentColorRequest=void 0;var t=Ae(),r;(function(a){a.method="textDocument/documentColor",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(r||(e.DocumentColorRequest=r={}));var n;(function(a){a.method="textDocument/colorPresentation",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(n||(e.ColorPresentationRequest=n={}))}}),MI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.foldingRange.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.FoldingRangeRefreshRequest=e.FoldingRangeRequest=void 0;var t=Ae(),r;(function(a){a.method="textDocument/foldingRange",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(r||(e.FoldingRangeRequest=r={}));var n;(function(a){a.method="workspace/foldingRange/refresh",a.messageDirection=t.MessageDirection.serverToClient,a.type=new t.ProtocolRequestType0(a.method)})(n||(e.FoldingRangeRefreshRequest=n={}))}}),GI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.declaration.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DeclarationRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/declaration",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.DeclarationRequest=r={}))}}),FI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.selectionRange.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.SelectionRangeRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/selectionRange",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.SelectionRangeRequest=r={}))}}),zI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.progress.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.WorkDoneProgressCancelNotification=e.WorkDoneProgressCreateRequest=e.WorkDoneProgress=void 0;var t=ei(),r=Ae(),n;(function(o){o.type=new t.ProgressType;function l(u){return u===o.type}i(l,"is"),o.is=l})(n||(e.WorkDoneProgress=n={}));var a;(function(o){o.method="window/workDoneProgress/create",o.messageDirection=r.MessageDirection.serverToClient,o.type=new r.ProtocolRequestType(o.method)})(a||(e.WorkDoneProgressCreateRequest=a={}));var s;(function(o){o.method="window/workDoneProgress/cancel",o.messageDirection=r.MessageDirection.clientToServer,o.type=new r.ProtocolNotificationType(o.method)})(s||(e.WorkDoneProgressCancelNotification=s={}))}}),jI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.callHierarchy.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.CallHierarchyOutgoingCallsRequest=e.CallHierarchyIncomingCallsRequest=e.CallHierarchyPrepareRequest=void 0;var t=Ae(),r;(function(s){s.method="textDocument/prepareCallHierarchy",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(r||(e.CallHierarchyPrepareRequest=r={}));var n;(function(s){s.method="callHierarchy/incomingCalls",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(n||(e.CallHierarchyIncomingCallsRequest=n={}));var a;(function(s){s.method="callHierarchy/outgoingCalls",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(a||(e.CallHierarchyOutgoingCallsRequest=a={}))}}),BI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.semanticTokens.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.SemanticTokensRefreshRequest=e.SemanticTokensRangeRequest=e.SemanticTokensDeltaRequest=e.SemanticTokensRequest=e.SemanticTokensRegistrationType=e.TokenFormat=void 0;var t=Ae(),r;(function(u){u.Relative="relative"})(r||(e.TokenFormat=r={}));var n;(function(u){u.method="textDocument/semanticTokens",u.type=new t.RegistrationType(u.method)})(n||(e.SemanticTokensRegistrationType=n={}));var a;(function(u){u.method="textDocument/semanticTokens/full",u.messageDirection=t.MessageDirection.clientToServer,u.type=new t.ProtocolRequestType(u.method),u.registrationMethod=n.method})(a||(e.SemanticTokensRequest=a={}));var s;(function(u){u.method="textDocument/semanticTokens/full/delta",u.messageDirection=t.MessageDirection.clientToServer,u.type=new t.ProtocolRequestType(u.method),u.registrationMethod=n.method})(s||(e.SemanticTokensDeltaRequest=s={}));var o;(function(u){u.method="textDocument/semanticTokens/range",u.messageDirection=t.MessageDirection.clientToServer,u.type=new t.ProtocolRequestType(u.method),u.registrationMethod=n.method})(o||(e.SemanticTokensRangeRequest=o={}));var l;(function(u){u.method="workspace/semanticTokens/refresh",u.messageDirection=t.MessageDirection.serverToClient,u.type=new t.ProtocolRequestType0(u.method)})(l||(e.SemanticTokensRefreshRequest=l={}))}}),UI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.showDocument.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ShowDocumentRequest=void 0;var t=Ae(),r;(function(n){n.method="window/showDocument",n.messageDirection=t.MessageDirection.serverToClient,n.type=new t.ProtocolRequestType(n.method)})(r||(e.ShowDocumentRequest=r={}))}}),KI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.linkedEditingRange.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.LinkedEditingRangeRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/linkedEditingRange",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.LinkedEditingRangeRequest=r={}))}}),WI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.fileOperations.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.WillDeleteFilesRequest=e.DidDeleteFilesNotification=e.DidRenameFilesNotification=e.WillRenameFilesRequest=e.DidCreateFilesNotification=e.WillCreateFilesRequest=e.FileOperationPatternKind=void 0;var t=Ae(),r;(function(c){c.file="file",c.folder="folder"})(r||(e.FileOperationPatternKind=r={}));var n;(function(c){c.method="workspace/willCreateFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolRequestType(c.method)})(n||(e.WillCreateFilesRequest=n={}));var a;(function(c){c.method="workspace/didCreateFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolNotificationType(c.method)})(a||(e.DidCreateFilesNotification=a={}));var s;(function(c){c.method="workspace/willRenameFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolRequestType(c.method)})(s||(e.WillRenameFilesRequest=s={}));var o;(function(c){c.method="workspace/didRenameFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolNotificationType(c.method)})(o||(e.DidRenameFilesNotification=o={}));var l;(function(c){c.method="workspace/didDeleteFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolNotificationType(c.method)})(l||(e.DidDeleteFilesNotification=l={}));var u;(function(c){c.method="workspace/willDeleteFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolRequestType(c.method)})(u||(e.WillDeleteFilesRequest=u={}))}}),qI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.moniker.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.MonikerRequest=e.MonikerKind=e.UniquenessLevel=void 0;var t=Ae(),r;(function(s){s.document="document",s.project="project",s.group="group",s.scheme="scheme",s.global="global"})(r||(e.UniquenessLevel=r={}));var n;(function(s){s.$import="import",s.$export="export",s.local="local"})(n||(e.MonikerKind=n={}));var a;(function(s){s.method="textDocument/moniker",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(a||(e.MonikerRequest=a={}))}}),VI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeHierarchy.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.TypeHierarchySubtypesRequest=e.TypeHierarchySupertypesRequest=e.TypeHierarchyPrepareRequest=void 0;var t=Ae(),r;(function(s){s.method="textDocument/prepareTypeHierarchy",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(r||(e.TypeHierarchyPrepareRequest=r={}));var n;(function(s){s.method="typeHierarchy/supertypes",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(n||(e.TypeHierarchySupertypesRequest=n={}));var a;(function(s){s.method="typeHierarchy/subtypes",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(a||(e.TypeHierarchySubtypesRequest=a={}))}}),HI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineValue.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.InlineValueRefreshRequest=e.InlineValueRequest=void 0;var t=Ae(),r;(function(a){a.method="textDocument/inlineValue",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(r||(e.InlineValueRequest=r={}));var n;(function(a){a.method="workspace/inlineValue/refresh",a.messageDirection=t.MessageDirection.serverToClient,a.type=new t.ProtocolRequestType0(a.method)})(n||(e.InlineValueRefreshRequest=n={}))}}),YI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayHint.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.InlayHintRefreshRequest=e.InlayHintResolveRequest=e.InlayHintRequest=void 0;var t=Ae(),r;(function(s){s.method="textDocument/inlayHint",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(r||(e.InlayHintRequest=r={}));var n;(function(s){s.method="inlayHint/resolve",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(n||(e.InlayHintResolveRequest=n={}));var a;(function(s){s.method="workspace/inlayHint/refresh",s.messageDirection=t.MessageDirection.serverToClient,s.type=new t.ProtocolRequestType0(s.method)})(a||(e.InlayHintRefreshRequest=a={}))}}),XI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DiagnosticRefreshRequest=e.WorkspaceDiagnosticRequest=e.DocumentDiagnosticRequest=e.DocumentDiagnosticReportKind=e.DiagnosticServerCancellationData=void 0;var t=ei(),r=bd(),n=Ae(),a;(function(c){function f(d){const m=d;return m&&r.boolean(m.retriggerRequest)}i(f,"is"),c.is=f})(a||(e.DiagnosticServerCancellationData=a={}));var s;(function(c){c.Full="full",c.Unchanged="unchanged"})(s||(e.DocumentDiagnosticReportKind=s={}));var o;(function(c){c.method="textDocument/diagnostic",c.messageDirection=n.MessageDirection.clientToServer,c.type=new n.ProtocolRequestType(c.method),c.partialResult=new t.ProgressType})(o||(e.DocumentDiagnosticRequest=o={}));var l;(function(c){c.method="workspace/diagnostic",c.messageDirection=n.MessageDirection.clientToServer,c.type=new n.ProtocolRequestType(c.method),c.partialResult=new t.ProgressType})(l||(e.WorkspaceDiagnosticRequest=l={}));var u;(function(c){c.method="workspace/diagnostic/refresh",c.messageDirection=n.MessageDirection.serverToClient,c.type=new n.ProtocolRequestType0(c.method)})(u||(e.DiagnosticRefreshRequest=u={}))}}),JI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.notebook.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DidCloseNotebookDocumentNotification=e.DidSaveNotebookDocumentNotification=e.DidChangeNotebookDocumentNotification=e.NotebookCellArrayChange=e.DidOpenNotebookDocumentNotification=e.NotebookDocumentSyncRegistrationType=e.NotebookDocument=e.NotebookCell=e.ExecutionSummary=e.NotebookCellKind=void 0;var t=(Ds(),Cd(Ll)),r=bd(),n=Ae(),a;(function(v){v.Markup=1,v.Code=2;function b(S){return S===1||S===2}i(b,"is"),v.is=b})(a||(e.NotebookCellKind=a={}));var s;(function(v){function b(I,R){const P={executionOrder:I};return(R===!0||R===!1)&&(P.success=R),P}i(b,"create"),v.create=b;function S(I){const R=I;return r.objectLiteral(R)&&t.uinteger.is(R.executionOrder)&&(R.success===void 0||r.boolean(R.success))}i(S,"is"),v.is=S;function w(I,R){return I===R?!0:I==null||R===null||R===void 0?!1:I.executionOrder===R.executionOrder&&I.success===R.success}i(w,"equals"),v.equals=w})(s||(e.ExecutionSummary=s={}));var o;(function(v){function b(R,P){return{kind:R,document:P}}i(b,"create"),v.create=b;function S(R){const P=R;return r.objectLiteral(P)&&a.is(P.kind)&&t.DocumentUri.is(P.document)&&(P.metadata===void 0||r.objectLiteral(P.metadata))}i(S,"is"),v.is=S;function w(R,P){const z=new Set;return R.document!==P.document&&z.add("document"),R.kind!==P.kind&&z.add("kind"),R.executionSummary!==P.executionSummary&&z.add("executionSummary"),(R.metadata!==void 0||P.metadata!==void 0)&&!I(R.metadata,P.metadata)&&z.add("metadata"),(R.executionSummary!==void 0||P.executionSummary!==void 0)&&!s.equals(R.executionSummary,P.executionSummary)&&z.add("executionSummary"),z}i(w,"diff"),v.diff=w;function I(R,P){if(R===P)return!0;if(R==null||P===null||P===void 0||typeof R!=typeof P||typeof R!="object")return!1;const z=Array.isArray(R),X=Array.isArray(P);if(z!==X)return!1;if(z&&X){if(R.length!==P.length)return!1;for(let Z=0;Z0}i(ae,"hasId"),p.hasId=ae})(O||(e.StaticRegistrationOptions=O={}));var x;(function(p){function ae(Te){const V=Te;return V&&(V.documentSelector===null||C.is(V.documentSelector))}i(ae,"is"),p.is=ae})(x||(e.TextDocumentRegistrationOptions=x={}));var D;(function(p){function ae(V){const h=V;return n.objectLiteral(h)&&(h.workDoneProgress===void 0||n.boolean(h.workDoneProgress))}i(ae,"is"),p.is=ae;function Te(V){const h=V;return h&&n.boolean(h.workDoneProgress)}i(Te,"hasWorkDoneProgress"),p.hasWorkDoneProgress=Te})(D||(e.WorkDoneProgressOptions=D={}));var G;(function(p){p.method="initialize",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(G||(e.InitializeRequest=G={}));var W;(function(p){p.unknownProtocolVersion=1})(W||(e.InitializeErrorCodes=W={}));var Y;(function(p){p.method="initialized",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(Y||(e.InitializedNotification=Y={}));var q;(function(p){p.method="shutdown",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType0(p.method)})(q||(e.ShutdownRequest=q={}));var Pe;(function(p){p.method="exit",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType0(p.method)})(Pe||(e.ExitNotification=Pe={}));var oe;(function(p){p.method="workspace/didChangeConfiguration",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(oe||(e.DidChangeConfigurationNotification=oe={}));var Le;(function(p){p.Error=1,p.Warning=2,p.Info=3,p.Log=4,p.Debug=5})(Le||(e.MessageType=Le={}));var De;(function(p){p.method="window/showMessage",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(De||(e.ShowMessageNotification=De={}));var ke;(function(p){p.method="window/showMessageRequest",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolRequestType(p.method)})(ke||(e.ShowMessageRequest=ke={}));var Ze;(function(p){p.method="window/logMessage",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(Ze||(e.LogMessageNotification=Ze={}));var Je;(function(p){p.method="telemetry/event",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(Je||(e.TelemetryEventNotification=Je={}));var ne;(function(p){p.None=0,p.Full=1,p.Incremental=2})(ne||(e.TextDocumentSyncKind=ne={}));var Ut;(function(p){p.method="textDocument/didOpen",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(Ut||(e.DidOpenTextDocumentNotification=Ut={}));var Ee;(function(p){function ae(V){let h=V;return h!=null&&typeof h.text=="string"&&h.range!==void 0&&(h.rangeLength===void 0||typeof h.rangeLength=="number")}i(ae,"isIncremental"),p.isIncremental=ae;function Te(V){let h=V;return h!=null&&typeof h.text=="string"&&h.range===void 0&&h.rangeLength===void 0}i(Te,"isFull"),p.isFull=Te})(Ee||(e.TextDocumentContentChangeEvent=Ee={}));var Pt;(function(p){p.method="textDocument/didChange",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(Pt||(e.DidChangeTextDocumentNotification=Pt={}));var ta;(function(p){p.method="textDocument/didClose",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(ta||(e.DidCloseTextDocumentNotification=ta={}));var ci;(function(p){p.method="textDocument/didSave",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(ci||(e.DidSaveTextDocumentNotification=ci={}));var fi;(function(p){p.Manual=1,p.AfterDelay=2,p.FocusOut=3})(fi||(e.TextDocumentSaveReason=fi={}));var di;(function(p){p.method="textDocument/willSave",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(di||(e.WillSaveTextDocumentNotification=di={}));var pi;(function(p){p.method="textDocument/willSaveWaitUntil",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(pi||(e.WillSaveTextDocumentWaitUntilRequest=pi={}));var kt;(function(p){p.method="workspace/didChangeWatchedFiles",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(kt||(e.DidChangeWatchedFilesNotification=kt={}));var ra;(function(p){p.Created=1,p.Changed=2,p.Deleted=3})(ra||(e.FileChangeType=ra={}));var mi;(function(p){function ae(Te){const V=Te;return n.objectLiteral(V)&&(r.URI.is(V.baseUri)||r.WorkspaceFolder.is(V.baseUri))&&n.string(V.pattern)}i(ae,"is"),p.is=ae})(mi||(e.RelativePattern=mi={}));var hi;(function(p){p.Create=1,p.Change=2,p.Delete=4})(hi||(e.WatchKind=hi={}));var yi;(function(p){p.method="textDocument/publishDiagnostics",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(yi||(e.PublishDiagnosticsNotification=yi={}));var gi;(function(p){p.Invoked=1,p.TriggerCharacter=2,p.TriggerForIncompleteCompletions=3})(gi||(e.CompletionTriggerKind=gi={}));var na;(function(p){p.method="textDocument/completion",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(na||(e.CompletionRequest=na={}));var aa;(function(p){p.method="completionItem/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(aa||(e.CompletionResolveRequest=aa={}));var Kt;(function(p){p.method="textDocument/hover",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Kt||(e.HoverRequest=Kt={}));var ia;(function(p){p.Invoked=1,p.TriggerCharacter=2,p.ContentChange=3})(ia||(e.SignatureHelpTriggerKind=ia={}));var vi;(function(p){p.method="textDocument/signatureHelp",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(vi||(e.SignatureHelpRequest=vi={}));var Ti;(function(p){p.method="textDocument/definition",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ti||(e.DefinitionRequest=Ti={}));var sa;(function(p){p.method="textDocument/references",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(sa||(e.ReferencesRequest=sa={}));var oa;(function(p){p.method="textDocument/documentHighlight",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(oa||(e.DocumentHighlightRequest=oa={}));var $i;(function(p){p.method="textDocument/documentSymbol",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})($i||(e.DocumentSymbolRequest=$i={}));var ro;(function(p){p.method="textDocument/codeAction",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(ro||(e.CodeActionRequest=ro={}));var Ri;(function(p){p.method="codeAction/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ri||(e.CodeActionResolveRequest=Ri={}));var Ai;(function(p){p.method="workspace/symbol",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ai||(e.WorkspaceSymbolRequest=Ai={}));var Ei;(function(p){p.method="workspaceSymbol/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ei||(e.WorkspaceSymbolResolveRequest=Ei={}));var Ci;(function(p){p.method="textDocument/codeLens",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ci||(e.CodeLensRequest=Ci={}));var Ct;(function(p){p.method="codeLens/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ct||(e.CodeLensResolveRequest=Ct={}));var bi;(function(p){p.method="workspace/codeLens/refresh",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolRequestType0(p.method)})(bi||(e.CodeLensRefreshRequest=bi={}));var _i;(function(p){p.method="textDocument/documentLink",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(_i||(e.DocumentLinkRequest=_i={}));var Or;(function(p){p.method="documentLink/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Or||(e.DocumentLinkResolveRequest=Or={}));var Si;(function(p){p.method="textDocument/formatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Si||(e.DocumentFormattingRequest=Si={}));var Xr;(function(p){p.method="textDocument/rangeFormatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Xr||(e.DocumentRangeFormattingRequest=Xr={}));var wi;(function(p){p.method="textDocument/rangesFormatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(wi||(e.DocumentRangesFormattingRequest=wi={}));var Wt;(function(p){p.method="textDocument/onTypeFormatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Wt||(e.DocumentOnTypeFormattingRequest=Wt={}));var ur;(function(p){p.Identifier=1})(ur||(e.PrepareSupportDefaultBehavior=ur={}));var Ii;(function(p){p.method="textDocument/rename",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ii||(e.RenameRequest=Ii={}));var Ni;(function(p){p.method="textDocument/prepareRename",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ni||(e.PrepareRenameRequest=Ni={}));var cr;(function(p){p.method="workspace/executeCommand",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(cr||(e.ExecuteCommandRequest=cr={}));var la;(function(p){p.method="workspace/applyEdit",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolRequestType("workspace/applyEdit")})(la||(e.ApplyWorkspaceEditRequest=la={}))}}),eN=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/connection.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.createProtocolConnection=void 0;var t=ei();function r(n,a,s,o){return t.ConnectionStrategy.is(o)&&(o={connectionStrategy:o}),(0,t.createMessageConnection)(n,a,s,o)}i(r,"createProtocolConnection"),e.createProtocolConnection=r}}),tN=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/api.js"(e){var t=e&&e.__createBinding||(Object.create?(function(s,o,l,u){u===void 0&&(u=l);var c=Object.getOwnPropertyDescriptor(o,l);(!c||("get"in c?!o.__esModule:c.writable||c.configurable))&&(c={enumerable:!0,get:i(function(){return o[l]},"get")}),Object.defineProperty(s,u,c)}):(function(s,o,l,u){u===void 0&&(u=l),s[u]=o[l]})),r=e&&e.__exportStar||function(s,o){for(var l in s)l!=="default"&&!Object.prototype.hasOwnProperty.call(o,l)&&t(o,s,l)};Object.defineProperty(e,"__esModule",{value:!0}),e.LSPErrorCodes=e.createProtocolConnection=void 0,r(ei(),e),r((Ds(),Cd(Ll)),e),r(Ae(),e),r(QI(),e);var n=eN();Object.defineProperty(e,"createProtocolConnection",{enumerable:!0,get:i(function(){return n.createProtocolConnection},"get")});var a;(function(s){s.lspReservedErrorRangeStart=-32899,s.RequestFailed=-32803,s.ServerCancelled=-32802,s.ContentModified=-32801,s.RequestCancelled=-32800,s.lspReservedErrorRangeEnd=-32800})(a||(e.LSPErrorCodes=a={}))}}),rN=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/browser/main.js"(e){var t=e&&e.__createBinding||(Object.create?(function(s,o,l,u){u===void 0&&(u=l);var c=Object.getOwnPropertyDescriptor(o,l);(!c||("get"in c?!o.__esModule:c.writable||c.configurable))&&(c={enumerable:!0,get:i(function(){return o[l]},"get")}),Object.defineProperty(s,u,c)}):(function(s,o,l,u){u===void 0&&(u=l),s[u]=o[l]})),r=e&&e.__exportStar||function(s,o){for(var l in s)l!=="default"&&!Object.prototype.hasOwnProperty.call(o,l)&&t(o,s,l)};Object.defineProperty(e,"__esModule",{value:!0}),e.createProtocolConnection=void 0;var n=lh();r(lh(),e),r(tN(),e);function a(s,o,l,u){return(0,n.createMessageConnection)(s,o,l,u)}i(a,"createProtocolConnection"),e.createProtocolConnection=a}}),Vg={};Wr(Vg,{AbstractAstReflection:()=>wd,AbstractCstNode:()=>Nm,AbstractLangiumParser:()=>km,AbstractParserErrorMessageProvider:()=>xS,AbstractThreadedAsyncParser:()=>_F,AstUtils:()=>Id,BiMap:()=>Il,Cancellation:()=>pe,CompositeCstNodeImpl:()=>Pu,ContextCache:()=>Gu,CstNodeBuilder:()=>kS,CstUtils:()=>_d,DEFAULT_TOKENIZE_OPTIONS:()=>Xm,DONE_RESULT:()=>et,DatatypeSymbol:()=>bl,DefaultAstNodeDescriptionProvider:()=>dw,DefaultAstNodeLocator:()=>mw,DefaultAsyncParser:()=>kw,DefaultCommentProvider:()=>Pw,DefaultConfigurationProvider:()=>hw,DefaultDocumentBuilder:()=>yw,DefaultDocumentValidator:()=>fw,DefaultHydrator:()=>Lw,DefaultIndexManager:()=>gw,DefaultJsonSerializer:()=>ow,DefaultLangiumDocumentFactory:()=>ZS,DefaultLangiumDocuments:()=>QS,DefaultLangiumProfiler:()=>PF,DefaultLexer:()=>Jm,DefaultLexerErrorMessageProvider:()=>Tw,DefaultLinker:()=>ew,DefaultNameProvider:()=>tw,DefaultReferenceDescriptionProvider:()=>pw,DefaultReferences:()=>rw,DefaultScopeComputation:()=>nw,DefaultScopeProvider:()=>sw,DefaultServiceRegistry:()=>lw,DefaultTokenBuilder:()=>Lu,DefaultValueConverter:()=>Fm,DefaultWorkspaceLock:()=>Ow,DefaultWorkspaceManager:()=>vw,Deferred:()=>Sr,Disposable:()=>In,DisposableCache:()=>Mu,DocumentCache:()=>iw,DocumentState:()=>J,DocumentValidator:()=>bt,EMPTY_SCOPE:()=>AF,EMPTY_STREAM:()=>Ba,EmptyFileSystem:()=>Xe,EmptyFileSystemProvider:()=>Mw,ErrorWithLocation:()=>Kl,GrammarAST:()=>Xg,GrammarUtils:()=>ip,IndentationAwareLexer:()=>wF,IndentationAwareTokenBuilder:()=>xw,JSDocDocumentationProvider:()=>Nw,LangiumCompletionParser:()=>MS,LangiumParser:()=>DS,LangiumParserErrorMessageProvider:()=>Om,LeafCstNodeImpl:()=>Cl,LexingMode:()=>Sn,MapScope:()=>RF,Module:()=>rd,MultiMap:()=>wr,MultiMapScope:()=>aw,OperationCancelled:()=>er,ParserWorker:()=>SF,ProfilingTask:()=>Fw,Reduction:()=>vs,RefResolving:()=>ln,RegExpUtils:()=>op,RootCstNodeImpl:()=>Pm,SimpleCache:()=>Wm,StreamImpl:()=>Qt,StreamScope:()=>Zf,TextDocument:()=>Sl,TreeStreamImpl:()=>Ua,URI:()=>vt,UriTrie:()=>Um,UriUtils:()=>rt,VALIDATE_EACH_NODE:()=>cw,ValidationCategory:()=>Nl,ValidationRegistry:()=>uw,ValueConverter:()=>Jt,WorkspaceCache:()=>qm,assertCondition:()=>sp,assertUnreachable:()=>qr,createCompletionParser:()=>xm,createDefaultCoreModule:()=>je,createDefaultSharedCoreModule:()=>Be,createGrammarConfig:()=>bp,createLangiumParser:()=>Mm,createParser:()=>ku,delayNextTick:()=>Du,diagnosticData:()=>_n,eagerLoad:()=>ah,getDiagnosticRange:()=>Hm,indentationBuilderDefaultOptions:()=>ad,inject:()=>ee,interruptAndCheck:()=>ze,isAstNode:()=>Oe,isAstNodeDescription:()=>Sd,isAstNodeWithComment:()=>Vm,isCompositeCstNode:()=>Tr,isIMultiModeLexerDefinition:()=>ju,isJSDoc:()=>Qm,isLeafCstNode:()=>Dn,isLinkingError:()=>dn,isMultiReference:()=>tr,isNamed:()=>Km,isOperationCancelled:()=>ea,isReference:()=>tt,isRootCstNode:()=>xl,isTokenTypeArray:()=>zu,isTokenTypeDictionary:()=>Pl,loadGrammarFromJson:()=>Ue,parseJSDoc:()=>Zm,prepareLangiumParser:()=>Gm,setInterruptionPeriod:()=>zm,startCancelableOperation:()=>xu,stream:()=>ue,toDiagnosticData:()=>Ym,toDiagnosticSeverity:()=>ys});var _d={};Wr(_d,{DefaultNameRegexp:()=>ep,RangeComparison:()=>Zt,compareRange:()=>Zd,findCommentNode:()=>tp,findDeclarationNodeAtOffset:()=>hv,findLeafNodeAtOffset:()=>Ul,findLeafNodeBeforeOffset:()=>rp,flattenCst:()=>mv,getDatatypeNode:()=>pv,getInteriorNodes:()=>vv,getNextNode:()=>yv,getPreviousNode:()=>ap,getStartlineNode:()=>gv,inRange:()=>Qd,isChildNode:()=>Jd,isCommentNode:()=>ll,streamCst:()=>Va,toDocumentSegment:()=>Ha,tokenToRange:()=>Ts});function Oe(e){return typeof e=="object"&&e!==null&&typeof e.$type=="string"}i(Oe,"isAstNode");function tt(e){return typeof e=="object"&&e!==null&&typeof e.$refText=="string"&&"ref"in e}i(tt,"isReference");function tr(e){return typeof e=="object"&&e!==null&&typeof e.$refText=="string"&&"items"in e}i(tr,"isMultiReference");function Sd(e){return typeof e=="object"&&e!==null&&typeof e.name=="string"&&typeof e.type=="string"&&typeof e.path=="string"}i(Sd,"isAstNodeDescription");function dn(e){return typeof e=="object"&&e!==null&&typeof e.info=="object"&&typeof e.message=="string"}i(dn,"isLinkingError");var wd=class{static{i(this,"AbstractAstReflection")}constructor(){this.subtypes={},this.allSubtypes={}}getAllTypes(){return Object.keys(this.types)}getReferenceType(e){const t=this.types[e.container.$type];if(!t)throw new Error(`Type ${e.container.$type||"undefined"} not found.`);const r=t.properties[e.property]?.referenceType;if(!r)throw new Error(`Property ${e.property||"undefined"} of type ${e.container.$type} is not a reference.`);return r}getTypeMetaData(e){const t=this.types[e];return t||{name:e,properties:{},superTypes:[]}}isInstance(e,t){return Oe(e)&&this.isSubtype(e.$type,t)}isSubtype(e,t){if(e===t)return!0;let r=this.subtypes[e];r||(r=this.subtypes[e]={});const n=r[t];if(n!==void 0)return n;{const a=this.types[e],s=a?a.superTypes.some(o=>this.isSubtype(o,t)):!1;return r[t]=s,s}}getAllSubTypes(e){const t=this.allSubtypes[e];if(t)return t;{const r=this.getAllTypes(),n=[];for(const a of r)this.isSubtype(a,e)&&n.push(a);return this.allSubtypes[e]=n,n}}};function Tr(e){return typeof e=="object"&&e!==null&&Array.isArray(e.content)}i(Tr,"isCompositeCstNode");function Dn(e){return typeof e=="object"&&e!==null&&typeof e.tokenType=="object"}i(Dn,"isLeafCstNode");function xl(e){return Tr(e)&&typeof e.fullText=="string"}i(xl,"isRootCstNode");var Qt=class mr{static{i(this,"StreamImpl")}constructor(t,r){this.startFn=t,this.nextFn=r}iterator(){const t={state:this.startFn(),next:i(()=>this.nextFn(t.state),"next"),[Symbol.iterator]:()=>t};return t}[Symbol.iterator](){return this.iterator()}isEmpty(){return!!this.iterator().next().done}count(){const t=this.iterator();let r=0,n=t.next();for(;!n.done;)r++,n=t.next();return r}toArray(){const t=[],r=this.iterator();let n;do n=r.next(),n.value!==void 0&&t.push(n.value);while(!n.done);return t}toSet(){return new Set(this)}toMap(t,r){const n=this.map(a=>[t?t(a):a,r?r(a):a]);return new Map(n)}toString(){return this.join()}concat(t){return new mr(()=>({first:this.startFn(),firstDone:!1,iterator:t[Symbol.iterator]()}),r=>{let n;if(!r.firstDone){do if(n=this.nextFn(r.first),!n.done)return n;while(!n.done);r.firstDone=!0}do if(n=r.iterator.next(),!n.done)return n;while(!n.done);return et})}join(t=","){const r=this.iterator();let n="",a,s=!1;do a=r.next(),a.done||(s&&(n+=t),n+=Hg(a.value)),s=!0;while(!a.done);return n}indexOf(t,r=0){const n=this.iterator();let a=0,s=n.next();for(;!s.done;){if(a>=r&&s.value===t)return a;s=n.next(),a++}return-1}every(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(!t(n.value))return!1;n=r.next()}return!0}some(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(t(n.value))return!0;n=r.next()}return!1}forEach(t){const r=this.iterator();let n=0,a=r.next();for(;!a.done;)t(a.value,n),a=r.next(),n++}map(t){return new mr(this.startFn,r=>{const{done:n,value:a}=this.nextFn(r);return n?et:{done:!1,value:t(a)}})}filter(t){return new mr(this.startFn,r=>{let n;do if(n=this.nextFn(r),!n.done&&t(n.value))return n;while(!n.done);return et})}nonNullable(){return this.filter(t=>t!=null)}reduce(t,r){const n=this.iterator();let a=r,s=n.next();for(;!s.done;)a===void 0?a=s.value:a=t(a,s.value),s=n.next();return a}reduceRight(t,r){return this.recursiveReduce(this.iterator(),t,r)}recursiveReduce(t,r,n){const a=t.next();if(a.done)return n;const s=this.recursiveReduce(t,r,n);return s===void 0?a.value:r(s,a.value)}find(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(t(n.value))return n.value;n=r.next()}}findIndex(t){const r=this.iterator();let n=0,a=r.next();for(;!a.done;){if(t(a.value))return n;a=r.next(),n++}return-1}includes(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(n.value===t)return!0;n=r.next()}return!1}flatMap(t){return new mr(()=>({this:this.startFn()}),r=>{do{if(r.iterator){const s=r.iterator.next();if(s.done)r.iterator=void 0;else return s}const{done:n,value:a}=this.nextFn(r.this);if(!n){const s=t(a);if(gs(s))r.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}}while(r.iterator);return et})}flat(t){if(t===void 0&&(t=1),t<=0)return this;const r=t>1?this.flat(t-1):this;return new mr(()=>({this:r.startFn()}),n=>{do{if(n.iterator){const o=n.iterator.next();if(o.done)n.iterator=void 0;else return o}const{done:a,value:s}=r.nextFn(n.this);if(!a)if(gs(s))n.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}while(n.iterator);return et})}head(){const r=this.iterator().next();if(!r.done)return r.value}tail(t=1){return new mr(()=>{const r=this.startFn();for(let n=0;n({size:0,state:this.startFn()}),r=>(r.size++,r.size>t?et:this.nextFn(r.state)))}distinct(t){return new mr(()=>({set:new Set,internalState:this.startFn()}),r=>{let n;do if(n=this.nextFn(r.internalState),!n.done){const a=t?t(n.value):n.value;if(!r.set.has(a))return r.set.add(a),n}while(!n.done);return et})}exclude(t,r){const n=new Set;for(const a of t){const s=r?r(a):a;n.add(s)}return this.filter(a=>{const s=r?r(a):a;return!n.has(s)})}};function Hg(e){return typeof e=="string"?e:typeof e>"u"?"undefined":typeof e.toString=="function"?e.toString():Object.prototype.toString.call(e)}i(Hg,"toString");function gs(e){return!!e&&typeof e[Symbol.iterator]=="function"}i(gs,"isIterable");var Ba=new Qt(()=>{},()=>et),et=Object.freeze({done:!0,value:void 0});function ue(...e){if(e.length===1){const t=e[0];if(t instanceof Qt)return t;if(gs(t))return new Qt(()=>t[Symbol.iterator](),r=>r.next());if(typeof t.length=="number")return new Qt(()=>({index:0}),r=>r.index1?new Qt(()=>({collIndex:0,arrIndex:0}),t=>{do{if(t.iterator){const r=t.iterator.next();if(!r.done)return r;t.iterator=void 0}if(t.array){if(t.arrIndex({iterators:r?.includeRoot?[[e][Symbol.iterator]()]:[t(e)[Symbol.iterator]()],pruned:!1}),n=>{for(n.pruned&&(n.iterators.pop(),n.pruned=!1);n.iterators.length>0;){const s=n.iterators[n.iterators.length-1].next();if(s.done)n.iterators.pop();else return n.iterators.push(t(s.value)[Symbol.iterator]()),s}return et})}iterator(){const e={state:this.startFn(),next:i(()=>this.nextFn(e.state),"next"),prune:i(()=>{e.state.pruned=!0},"prune"),[Symbol.iterator]:()=>e};return e}},vs;(function(e){function t(s){return s.reduce((o,l)=>o+l,0)}i(t,"sum"),e.sum=t;function r(s){return s.reduce((o,l)=>o*l,0)}i(r,"product"),e.product=r;function n(s){return s.reduce((o,l)=>Math.min(o,l))}i(n,"min"),e.min=n;function a(s){return s.reduce((o,l)=>Math.max(o,l))}i(a,"max"),e.max=a})(vs||(vs={}));var Id={};Wr(Id,{assignMandatoryProperties:()=>Nd,copyAstNode:()=>Ho,findRootNode:()=>Ga,getContainerOfType:()=>xn,getDocument:()=>xt,getReferenceNodes:()=>qo,hasContainerOfType:()=>Yg,linkContentToContainer:()=>Ka,streamAllContents:()=>Ir,streamAst:()=>Mt,streamContents:()=>Ms,streamReferences:()=>Wa});function Ka(e,t={}){for(const[r,n]of Object.entries(e))r.startsWith("$")||(Array.isArray(n)?n.forEach((a,s)=>{Oe(a)&&(a.$container=e,a.$containerProperty=r,a.$containerIndex=s,t.deep&&Ka(a,t))}):Oe(n)&&(n.$container=e,n.$containerProperty=r,t.deep&&Ka(n,t)))}i(Ka,"linkContentToContainer");function xn(e,t){let r=e;for(;r;){if(t(r))return r;r=r.$container}}i(xn,"getContainerOfType");function Yg(e,t){let r=e;for(;r;){if(t(r))return!0;r=r.$container}return!1}i(Yg,"hasContainerOfType");function xt(e){const r=Ga(e).$document;if(!r)throw new Error("AST node has no document.");return r}i(xt,"getDocument");function Ga(e){for(;e.$container;)e=e.$container;return e}i(Ga,"findRootNode");function qo(e){return tt(e)?e.ref?[e.ref]:[]:tr(e)?e.items.map(t=>t.ref):[]}i(qo,"getReferenceNodes");function Ms(e,t){if(!e)throw new Error("Node must be an AstNode.");const r=t?.range;return new Qt(()=>({keys:Object.keys(e),keyIndex:0,arrayIndex:0}),n=>{for(;n.keyIndexMs(r,t))}i(Ir,"streamAllContents");function Mt(e,t){if(e){if(t?.range&&!Vo(e,t.range))return new Ua(e,()=>[])}else throw new Error("Root node must be an AstNode.");return new Ua(e,r=>Ms(r,t),{includeRoot:!0})}i(Mt,"streamAst");function Vo(e,t){if(!t)return!0;const r=e.$cstNode?.range;return r?Qd(r,t):!1}i(Vo,"isAstNodeInRange");function Wa(e){return new Qt(()=>({keys:Object.keys(e),keyIndex:0,arrayIndex:0}),t=>{for(;t.keyIndexft,AbstractParserRule:()=>rs,AbstractRule:()=>Na,AbstractType:()=>gt,Action:()=>Dr,Alternatives:()=>ns,ArrayLiteral:()=>Yo,ArrayType:()=>Xo,Assignment:()=>xr,BooleanLiteral:()=>Jo,CharacterRange:()=>Mr,Condition:()=>Gr,Conjunction:()=>as,CrossReference:()=>Fr,Disjunction:()=>is,EndOfFile:()=>Zo,Grammar:()=>yr,GrammarImport:()=>Qo,Group:()=>pn,InferredType:()=>el,InfixRule:()=>Xt,InfixRuleOperatorList:()=>ss,InfixRuleOperators:()=>tl,Interface:()=>Pa,Keyword:()=>ka,LangiumGrammarAstReflection:()=>Xd,LangiumGrammarTerminals:()=>nN,NamedArgument:()=>Oa,NegatedToken:()=>mn,Negation:()=>rl,NumberLiteral:()=>nl,Parameter:()=>La,ParameterReference:()=>al,ParserRule:()=>Ot,ReferenceType:()=>os,RegexToken:()=>hn,ReturnType:()=>il,RuleCall:()=>yn,SimpleType:()=>Da,StringLiteral:()=>sl,TerminalAlternatives:()=>gn,TerminalElement:()=>dt,TerminalGroup:()=>vn,TerminalRule:()=>gr,TerminalRuleCall:()=>Tn,Type:()=>ls,TypeAttribute:()=>$n,TypeDefinition:()=>Rn,UnionType:()=>ol,UnorderedGroup:()=>us,UntilToken:()=>An,ValueLiteral:()=>En,Wildcard:()=>xa,isAbstractElement:()=>Ml,isAbstractParserRule:()=>Mn,isAbstractRule:()=>Jg,isAbstractType:()=>Zg,isAction:()=>zr,isAlternatives:()=>Gl,isArrayLiteral:()=>Qg,isArrayType:()=>kd,isAssignment:()=>$r,isBooleanLiteral:()=>Od,isCharacterRange:()=>Ld,isCondition:()=>ev,isConjunction:()=>Dd,isCrossReference:()=>Gn,isDisjunction:()=>xd,isEndOfFile:()=>Md,isGrammar:()=>tv,isGrammarImport:()=>rv,isGroup:()=>Fn,isInferredType:()=>Gs,isInfixRule:()=>qa,isInfixRuleOperatorList:()=>nv,isInfixRuleOperators:()=>av,isInterface:()=>Gd,isKeyword:()=>Rr,isNamedArgument:()=>iv,isNegatedToken:()=>Fd,isNegation:()=>zd,isNumberLiteral:()=>sv,isParameter:()=>ov,isParameterReference:()=>jd,isParserRule:()=>at,isReferenceType:()=>Bd,isRegexToken:()=>Ud,isReturnType:()=>Kd,isRuleCall:()=>Ar,isSimpleType:()=>Fl,isStringLiteral:()=>lv,isTerminalAlternatives:()=>Wd,isTerminalElement:()=>uv,isTerminalGroup:()=>qd,isTerminalRule:()=>It,isTerminalRuleCall:()=>zl,isType:()=>jl,isTypeAttribute:()=>cv,isTypeDefinition:()=>fv,isUnionType:()=>Vd,isUnorderedGroup:()=>Bl,isUntilToken:()=>Hd,isValueLiteral:()=>dv,isWildcard:()=>Yd,reflection:()=>j});var nN={ID:/\^?[_a-zA-Z][\w_]*/,STRING:/"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/,NUMBER:/NaN|-?((\d*\.\d+|\d+)([Ee][+-]?\d+)?|Infinity)/,RegexLiteral:/\/(?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\/[a-z]*/,WS:/\s+/,ML_COMMENT:/\/\*[\s\S]*?\*\//,SL_COMMENT:/\/\/[^\n\r]*/},ft={$type:"AbstractElement",cardinality:"cardinality"};function Ml(e){return j.isInstance(e,ft.$type)}i(Ml,"isAbstractElement");var rs={$type:"AbstractParserRule"};function Mn(e){return j.isInstance(e,rs.$type)}i(Mn,"isAbstractParserRule");var Na={$type:"AbstractRule"};function Jg(e){return j.isInstance(e,Na.$type)}i(Jg,"isAbstractRule");var gt={$type:"AbstractType"};function Zg(e){return j.isInstance(e,gt.$type)}i(Zg,"isAbstractType");var Dr={$type:"Action",cardinality:"cardinality",feature:"feature",inferredType:"inferredType",operator:"operator",type:"type"};function zr(e){return j.isInstance(e,Dr.$type)}i(zr,"isAction");var ns={$type:"Alternatives",cardinality:"cardinality",elements:"elements"};function Gl(e){return j.isInstance(e,ns.$type)}i(Gl,"isAlternatives");var Yo={$type:"ArrayLiteral",elements:"elements"};function Qg(e){return j.isInstance(e,Yo.$type)}i(Qg,"isArrayLiteral");var Xo={$type:"ArrayType",elementType:"elementType"};function kd(e){return j.isInstance(e,Xo.$type)}i(kd,"isArrayType");var xr={$type:"Assignment",cardinality:"cardinality",feature:"feature",operator:"operator",predicate:"predicate",terminal:"terminal"};function $r(e){return j.isInstance(e,xr.$type)}i($r,"isAssignment");var Jo={$type:"BooleanLiteral",true:"true"};function Od(e){return j.isInstance(e,Jo.$type)}i(Od,"isBooleanLiteral");var Mr={$type:"CharacterRange",cardinality:"cardinality",left:"left",lookahead:"lookahead",parenthesized:"parenthesized",right:"right"};function Ld(e){return j.isInstance(e,Mr.$type)}i(Ld,"isCharacterRange");var Gr={$type:"Condition"};function ev(e){return j.isInstance(e,Gr.$type)}i(ev,"isCondition");var as={$type:"Conjunction",left:"left",right:"right"};function Dd(e){return j.isInstance(e,as.$type)}i(Dd,"isConjunction");var Fr={$type:"CrossReference",cardinality:"cardinality",deprecatedSyntax:"deprecatedSyntax",isMulti:"isMulti",terminal:"terminal",type:"type"};function Gn(e){return j.isInstance(e,Fr.$type)}i(Gn,"isCrossReference");var is={$type:"Disjunction",left:"left",right:"right"};function xd(e){return j.isInstance(e,is.$type)}i(xd,"isDisjunction");var Zo={$type:"EndOfFile",cardinality:"cardinality"};function Md(e){return j.isInstance(e,Zo.$type)}i(Md,"isEndOfFile");var yr={$type:"Grammar",imports:"imports",interfaces:"interfaces",isDeclared:"isDeclared",name:"name",rules:"rules",types:"types"};function tv(e){return j.isInstance(e,yr.$type)}i(tv,"isGrammar");var Qo={$type:"GrammarImport",path:"path"};function rv(e){return j.isInstance(e,Qo.$type)}i(rv,"isGrammarImport");var pn={$type:"Group",cardinality:"cardinality",elements:"elements",guardCondition:"guardCondition",predicate:"predicate"};function Fn(e){return j.isInstance(e,pn.$type)}i(Fn,"isGroup");var el={$type:"InferredType",name:"name"};function Gs(e){return j.isInstance(e,el.$type)}i(Gs,"isInferredType");var Xt={$type:"InfixRule",call:"call",dataType:"dataType",inferredType:"inferredType",name:"name",operators:"operators",parameters:"parameters",returnType:"returnType"};function qa(e){return j.isInstance(e,Xt.$type)}i(qa,"isInfixRule");var ss={$type:"InfixRuleOperatorList",associativity:"associativity",operators:"operators"};function nv(e){return j.isInstance(e,ss.$type)}i(nv,"isInfixRuleOperatorList");var tl={$type:"InfixRuleOperators",precedences:"precedences"};function av(e){return j.isInstance(e,tl.$type)}i(av,"isInfixRuleOperators");var Pa={$type:"Interface",attributes:"attributes",name:"name",superTypes:"superTypes"};function Gd(e){return j.isInstance(e,Pa.$type)}i(Gd,"isInterface");var ka={$type:"Keyword",cardinality:"cardinality",predicate:"predicate",value:"value"};function Rr(e){return j.isInstance(e,ka.$type)}i(Rr,"isKeyword");var Oa={$type:"NamedArgument",calledByName:"calledByName",parameter:"parameter",value:"value"};function iv(e){return j.isInstance(e,Oa.$type)}i(iv,"isNamedArgument");var mn={$type:"NegatedToken",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",terminal:"terminal"};function Fd(e){return j.isInstance(e,mn.$type)}i(Fd,"isNegatedToken");var rl={$type:"Negation",value:"value"};function zd(e){return j.isInstance(e,rl.$type)}i(zd,"isNegation");var nl={$type:"NumberLiteral",value:"value"};function sv(e){return j.isInstance(e,nl.$type)}i(sv,"isNumberLiteral");var La={$type:"Parameter",name:"name"};function ov(e){return j.isInstance(e,La.$type)}i(ov,"isParameter");var al={$type:"ParameterReference",parameter:"parameter"};function jd(e){return j.isInstance(e,al.$type)}i(jd,"isParameterReference");var Ot={$type:"ParserRule",dataType:"dataType",definition:"definition",entry:"entry",fragment:"fragment",inferredType:"inferredType",name:"name",parameters:"parameters",returnType:"returnType"};function at(e){return j.isInstance(e,Ot.$type)}i(at,"isParserRule");var os={$type:"ReferenceType",isMulti:"isMulti",referenceType:"referenceType"};function Bd(e){return j.isInstance(e,os.$type)}i(Bd,"isReferenceType");var hn={$type:"RegexToken",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",regex:"regex"};function Ud(e){return j.isInstance(e,hn.$type)}i(Ud,"isRegexToken");var il={$type:"ReturnType",name:"name"};function Kd(e){return j.isInstance(e,il.$type)}i(Kd,"isReturnType");var yn={$type:"RuleCall",arguments:"arguments",cardinality:"cardinality",predicate:"predicate",rule:"rule"};function Ar(e){return j.isInstance(e,yn.$type)}i(Ar,"isRuleCall");var Da={$type:"SimpleType",primitiveType:"primitiveType",stringType:"stringType",typeRef:"typeRef"};function Fl(e){return j.isInstance(e,Da.$type)}i(Fl,"isSimpleType");var sl={$type:"StringLiteral",value:"value"};function lv(e){return j.isInstance(e,sl.$type)}i(lv,"isStringLiteral");var gn={$type:"TerminalAlternatives",cardinality:"cardinality",elements:"elements",lookahead:"lookahead",parenthesized:"parenthesized"};function Wd(e){return j.isInstance(e,gn.$type)}i(Wd,"isTerminalAlternatives");var dt={$type:"TerminalElement",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized"};function uv(e){return j.isInstance(e,dt.$type)}i(uv,"isTerminalElement");var vn={$type:"TerminalGroup",cardinality:"cardinality",elements:"elements",lookahead:"lookahead",parenthesized:"parenthesized"};function qd(e){return j.isInstance(e,vn.$type)}i(qd,"isTerminalGroup");var gr={$type:"TerminalRule",definition:"definition",fragment:"fragment",hidden:"hidden",name:"name",type:"type"};function It(e){return j.isInstance(e,gr.$type)}i(It,"isTerminalRule");var Tn={$type:"TerminalRuleCall",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",rule:"rule"};function zl(e){return j.isInstance(e,Tn.$type)}i(zl,"isTerminalRuleCall");var ls={$type:"Type",name:"name",type:"type"};function jl(e){return j.isInstance(e,ls.$type)}i(jl,"isType");var $n={$type:"TypeAttribute",defaultValue:"defaultValue",isOptional:"isOptional",name:"name",type:"type"};function cv(e){return j.isInstance(e,$n.$type)}i(cv,"isTypeAttribute");var Rn={$type:"TypeDefinition"};function fv(e){return j.isInstance(e,Rn.$type)}i(fv,"isTypeDefinition");var ol={$type:"UnionType",types:"types"};function Vd(e){return j.isInstance(e,ol.$type)}i(Vd,"isUnionType");var us={$type:"UnorderedGroup",cardinality:"cardinality",elements:"elements"};function Bl(e){return j.isInstance(e,us.$type)}i(Bl,"isUnorderedGroup");var An={$type:"UntilToken",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",terminal:"terminal"};function Hd(e){return j.isInstance(e,An.$type)}i(Hd,"isUntilToken");var En={$type:"ValueLiteral"};function dv(e){return j.isInstance(e,En.$type)}i(dv,"isValueLiteral");var xa={$type:"Wildcard",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized"};function Yd(e){return j.isInstance(e,xa.$type)}i(Yd,"isWildcard");var Xd=class extends wd{static{i(this,"LangiumGrammarAstReflection")}constructor(){super(...arguments),this.types={AbstractElement:{name:ft.$type,properties:{cardinality:{name:ft.cardinality}},superTypes:[]},AbstractParserRule:{name:rs.$type,properties:{},superTypes:[Na.$type,gt.$type]},AbstractRule:{name:Na.$type,properties:{},superTypes:[]},AbstractType:{name:gt.$type,properties:{},superTypes:[]},Action:{name:Dr.$type,properties:{cardinality:{name:Dr.cardinality},feature:{name:Dr.feature},inferredType:{name:Dr.inferredType},operator:{name:Dr.operator},type:{name:Dr.type,referenceType:gt.$type}},superTypes:[ft.$type]},Alternatives:{name:ns.$type,properties:{cardinality:{name:ns.cardinality},elements:{name:ns.elements,defaultValue:[]}},superTypes:[ft.$type]},ArrayLiteral:{name:Yo.$type,properties:{elements:{name:Yo.elements,defaultValue:[]}},superTypes:[En.$type]},ArrayType:{name:Xo.$type,properties:{elementType:{name:Xo.elementType}},superTypes:[Rn.$type]},Assignment:{name:xr.$type,properties:{cardinality:{name:xr.cardinality},feature:{name:xr.feature},operator:{name:xr.operator},predicate:{name:xr.predicate},terminal:{name:xr.terminal}},superTypes:[ft.$type]},BooleanLiteral:{name:Jo.$type,properties:{true:{name:Jo.true,defaultValue:!1}},superTypes:[Gr.$type,En.$type]},CharacterRange:{name:Mr.$type,properties:{cardinality:{name:Mr.cardinality},left:{name:Mr.left},lookahead:{name:Mr.lookahead},parenthesized:{name:Mr.parenthesized,defaultValue:!1},right:{name:Mr.right}},superTypes:[dt.$type]},Condition:{name:Gr.$type,properties:{},superTypes:[]},Conjunction:{name:as.$type,properties:{left:{name:as.left},right:{name:as.right}},superTypes:[Gr.$type]},CrossReference:{name:Fr.$type,properties:{cardinality:{name:Fr.cardinality},deprecatedSyntax:{name:Fr.deprecatedSyntax,defaultValue:!1},isMulti:{name:Fr.isMulti,defaultValue:!1},terminal:{name:Fr.terminal},type:{name:Fr.type,referenceType:gt.$type}},superTypes:[ft.$type]},Disjunction:{name:is.$type,properties:{left:{name:is.left},right:{name:is.right}},superTypes:[Gr.$type]},EndOfFile:{name:Zo.$type,properties:{cardinality:{name:Zo.cardinality}},superTypes:[ft.$type]},Grammar:{name:yr.$type,properties:{imports:{name:yr.imports,defaultValue:[]},interfaces:{name:yr.interfaces,defaultValue:[]},isDeclared:{name:yr.isDeclared,defaultValue:!1},name:{name:yr.name},rules:{name:yr.rules,defaultValue:[]},types:{name:yr.types,defaultValue:[]}},superTypes:[]},GrammarImport:{name:Qo.$type,properties:{path:{name:Qo.path}},superTypes:[]},Group:{name:pn.$type,properties:{cardinality:{name:pn.cardinality},elements:{name:pn.elements,defaultValue:[]},guardCondition:{name:pn.guardCondition},predicate:{name:pn.predicate}},superTypes:[ft.$type]},InferredType:{name:el.$type,properties:{name:{name:el.name}},superTypes:[gt.$type]},InfixRule:{name:Xt.$type,properties:{call:{name:Xt.call},dataType:{name:Xt.dataType},inferredType:{name:Xt.inferredType},name:{name:Xt.name},operators:{name:Xt.operators},parameters:{name:Xt.parameters,defaultValue:[]},returnType:{name:Xt.returnType,referenceType:gt.$type}},superTypes:[rs.$type]},InfixRuleOperatorList:{name:ss.$type,properties:{associativity:{name:ss.associativity},operators:{name:ss.operators,defaultValue:[]}},superTypes:[]},InfixRuleOperators:{name:tl.$type,properties:{precedences:{name:tl.precedences,defaultValue:[]}},superTypes:[]},Interface:{name:Pa.$type,properties:{attributes:{name:Pa.attributes,defaultValue:[]},name:{name:Pa.name},superTypes:{name:Pa.superTypes,defaultValue:[],referenceType:gt.$type}},superTypes:[gt.$type]},Keyword:{name:ka.$type,properties:{cardinality:{name:ka.cardinality},predicate:{name:ka.predicate},value:{name:ka.value}},superTypes:[ft.$type]},NamedArgument:{name:Oa.$type,properties:{calledByName:{name:Oa.calledByName,defaultValue:!1},parameter:{name:Oa.parameter,referenceType:La.$type},value:{name:Oa.value}},superTypes:[]},NegatedToken:{name:mn.$type,properties:{cardinality:{name:mn.cardinality},lookahead:{name:mn.lookahead},parenthesized:{name:mn.parenthesized,defaultValue:!1},terminal:{name:mn.terminal}},superTypes:[dt.$type]},Negation:{name:rl.$type,properties:{value:{name:rl.value}},superTypes:[Gr.$type]},NumberLiteral:{name:nl.$type,properties:{value:{name:nl.value}},superTypes:[En.$type]},Parameter:{name:La.$type,properties:{name:{name:La.name}},superTypes:[]},ParameterReference:{name:al.$type,properties:{parameter:{name:al.parameter,referenceType:La.$type}},superTypes:[Gr.$type]},ParserRule:{name:Ot.$type,properties:{dataType:{name:Ot.dataType},definition:{name:Ot.definition},entry:{name:Ot.entry,defaultValue:!1},fragment:{name:Ot.fragment,defaultValue:!1},inferredType:{name:Ot.inferredType},name:{name:Ot.name},parameters:{name:Ot.parameters,defaultValue:[]},returnType:{name:Ot.returnType,referenceType:gt.$type}},superTypes:[rs.$type]},ReferenceType:{name:os.$type,properties:{isMulti:{name:os.isMulti,defaultValue:!1},referenceType:{name:os.referenceType}},superTypes:[Rn.$type]},RegexToken:{name:hn.$type,properties:{cardinality:{name:hn.cardinality},lookahead:{name:hn.lookahead},parenthesized:{name:hn.parenthesized,defaultValue:!1},regex:{name:hn.regex}},superTypes:[dt.$type]},ReturnType:{name:il.$type,properties:{name:{name:il.name}},superTypes:[]},RuleCall:{name:yn.$type,properties:{arguments:{name:yn.arguments,defaultValue:[]},cardinality:{name:yn.cardinality},predicate:{name:yn.predicate},rule:{name:yn.rule,referenceType:Na.$type}},superTypes:[ft.$type]},SimpleType:{name:Da.$type,properties:{primitiveType:{name:Da.primitiveType},stringType:{name:Da.stringType},typeRef:{name:Da.typeRef,referenceType:gt.$type}},superTypes:[Rn.$type]},StringLiteral:{name:sl.$type,properties:{value:{name:sl.value}},superTypes:[En.$type]},TerminalAlternatives:{name:gn.$type,properties:{cardinality:{name:gn.cardinality},elements:{name:gn.elements,defaultValue:[]},lookahead:{name:gn.lookahead},parenthesized:{name:gn.parenthesized,defaultValue:!1}},superTypes:[dt.$type]},TerminalElement:{name:dt.$type,properties:{cardinality:{name:dt.cardinality},lookahead:{name:dt.lookahead},parenthesized:{name:dt.parenthesized,defaultValue:!1}},superTypes:[ft.$type]},TerminalGroup:{name:vn.$type,properties:{cardinality:{name:vn.cardinality},elements:{name:vn.elements,defaultValue:[]},lookahead:{name:vn.lookahead},parenthesized:{name:vn.parenthesized,defaultValue:!1}},superTypes:[dt.$type]},TerminalRule:{name:gr.$type,properties:{definition:{name:gr.definition},fragment:{name:gr.fragment,defaultValue:!1},hidden:{name:gr.hidden,defaultValue:!1},name:{name:gr.name},type:{name:gr.type}},superTypes:[Na.$type]},TerminalRuleCall:{name:Tn.$type,properties:{cardinality:{name:Tn.cardinality},lookahead:{name:Tn.lookahead},parenthesized:{name:Tn.parenthesized,defaultValue:!1},rule:{name:Tn.rule,referenceType:gr.$type}},superTypes:[dt.$type]},Type:{name:ls.$type,properties:{name:{name:ls.name},type:{name:ls.type}},superTypes:[gt.$type]},TypeAttribute:{name:$n.$type,properties:{defaultValue:{name:$n.defaultValue},isOptional:{name:$n.isOptional,defaultValue:!1},name:{name:$n.name},type:{name:$n.type}},superTypes:[]},TypeDefinition:{name:Rn.$type,properties:{},superTypes:[]},UnionType:{name:ol.$type,properties:{types:{name:ol.types,defaultValue:[]}},superTypes:[Rn.$type]},UnorderedGroup:{name:us.$type,properties:{cardinality:{name:us.cardinality},elements:{name:us.elements,defaultValue:[]}},superTypes:[ft.$type]},UntilToken:{name:An.$type,properties:{cardinality:{name:An.cardinality},lookahead:{name:An.lookahead},parenthesized:{name:An.parenthesized,defaultValue:!1},terminal:{name:An.terminal}},superTypes:[dt.$type]},ValueLiteral:{name:En.$type,properties:{},superTypes:[]},Wildcard:{name:xa.$type,properties:{cardinality:{name:xa.cardinality},lookahead:{name:xa.lookahead},parenthesized:{name:xa.parenthesized,defaultValue:!1}},superTypes:[dt.$type]}}}},j=new Xd;function pv(e){let t=e,r=!1;for(;t;){const n=xn(t.grammarSource,at);if(n&&n.dataType)t=t.container,r=!0;else return r?t:void 0}}i(pv,"getDatatypeNode");function Va(e){return new Ua(e,t=>Tr(t)?t.content:[],{includeRoot:!0})}i(Va,"streamCst");function mv(e){return Va(e).filter(Dn)}i(mv,"flattenCst");function Jd(e,t){for(;e.container;)if(e=e.container,e===t)return!0;return!1}i(Jd,"isChildNode");function Ts(e){return{start:{character:e.startColumn-1,line:e.startLine-1},end:{character:e.endColumn,line:e.endLine-1}}}i(Ts,"tokenToRange");function Ha(e){if(!e)return;const{offset:t,end:r,range:n}=e;return{range:n,offset:t,end:r,length:r-t}}i(Ha,"toDocumentSegment");var Zt;(function(e){e[e.Before=0]="Before",e[e.After=1]="After",e[e.OverlapFront=2]="OverlapFront",e[e.OverlapBack=3]="OverlapBack",e[e.Inside=4]="Inside",e[e.Outside=5]="Outside"})(Zt||(Zt={}));function Zd(e,t){if(e.end.linet.end.line||e.start.line===t.end.line&&e.start.character>=t.end.character)return Zt.After;const r=e.start.line>t.start.line||e.start.line===t.start.line&&e.start.character>=t.start.character,n=e.end.lineZt.After}i(Qd,"inRange");var ep=/^[\w\p{L}]$/u;function hv(e,t,r=ep){if(e){if(t>0){const n=t-e.offset,a=e.text.charAt(n);r.test(a)||t--}return Ul(e,t)}}i(hv,"findDeclarationNodeAtOffset");function tp(e,t){if(e){const r=ap(e,!0);if(r&&ll(r,t))return r;if(xl(e)){const n=e.content.findIndex(a=>!a.hidden);for(let a=n-1;a>=0;a--){const s=e.content[a];if(ll(s,t))return s}}}}i(tp,"findCommentNode");function ll(e,t){return Dn(e)&&t.includes(e.tokenType.name)}i(ll,"isCommentNode");function Ul(e,t){if(Dn(e))return e;if(Tr(e)){const r=np(e,t,!1);if(r)return Ul(r,t)}}i(Ul,"findLeafNodeAtOffset");function rp(e,t){if(Dn(e))return e;if(Tr(e)){const r=np(e,t,!0);if(r)return rp(r,t)}}i(rp,"findLeafNodeBeforeOffset");function np(e,t,r){let n=0,a=e.content.length-1,s;for(;n<=a;){const o=Math.floor((n+a)/2),l=e.content[o];if(l.offset<=t&&l.end>t)return l;l.end<=t?(s=r?l:void 0,n=o+1):a=o-1}return s}i(np,"binarySearch");function ap(e,t=!0){for(;e.container;){const r=e.container;let n=r.content.indexOf(e);for(;n>0;){n--;const a=r.content[n];if(t||!a.hidden)return a}e=r}}i(ap,"getPreviousNode");function yv(e,t=!0){for(;e.container;){const r=e.container;let n=r.content.indexOf(e);const a=r.content.length-1;for(;nvp,findNameAssignment:()=>Jl,findNodeForKeyword:()=>gp,findNodeForProperty:()=>Hl,findNodesForKeyword:()=>Sv,findNodesForKeywordInternal:()=>Xl,findNodesForProperty:()=>yp,getActionAtElement:()=>$p,getActionType:()=>Ap,getAllReachableRules:()=>Vl,getAllRulesUsedForCrossReferences:()=>_v,getCrossReferenceTerminal:()=>mp,getEntryRule:()=>fp,getExplicitRuleType:()=>zs,getHiddenRules:()=>dp,getRuleType:()=>Ep,getRuleTypeName:()=>kv,getTypeName:()=>Nn,isArrayCardinality:()=>Iv,isArrayOperator:()=>Nv,isCommentTerminal:()=>hp,isDataType:()=>Pv,isDataTypeRule:()=>Fs,isOptionalCardinality:()=>wv,terminalRegex:()=>js});var Kl=class extends Error{static{i(this,"ErrorWithLocation")}constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}};function qr(e,t="Error: Got unexpected value."){throw new Error(t)}i(qr,"assertUnreachable");function sp(e,t="Error: Condition is violated."){if(!e)throw new Error(t)}i(sp,"assertCondition");var op={};Wr(op,{NEWLINE_REGEXP:()=>Av,escapeRegExp:()=>ti,getTerminalParts:()=>Cv,isMultilineComment:()=>lp,isWhitespace:()=>ql,partialMatches:()=>up,partialRegExp:()=>cp,whitespaceCharacters:()=>bv});function U(e){return e.charCodeAt(0)}i(U,"cc");function No(e,t){Array.isArray(e)?e.forEach(function(r){t.push(r)}):t.push(e)}i(No,"insertToSet");function Ta(e,t){if(e[t]===!0)throw"duplicate flag "+t;e[t],e[t]=!0}i(Ta,"addFlag");function an(e){if(e===void 0)throw Error("Internal Error - Should never get here!");return!0}i(an,"ASSERT_EXISTS");function $v(){throw Error("Internal Error - Should never get here!")}i($v,"ASSERT_NEVER_REACH_HERE");function Ef(e){return e.type==="Character"}i(Ef,"isCharacter");var ul=[];for(let e=U("0");e<=U("9");e++)ul.push(e);var cl=[U("_")].concat(ul);for(let e=U("a");e<=U("z");e++)cl.push(e);for(let e=U("A");e<=U("Z");e++)cl.push(e);var uh=[U(" "),U("\f"),U(` +`),U("\r"),U(" "),U("\v"),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U("\u2028"),U("\u2029"),U(" "),U(" "),U(" "),U("\uFEFF")],aN=/[0-9a-fA-F]/,no=/[0-9]/,iN=/[1-9]/,Rv=class{static{i(this,"RegExpParser")}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 t=this.disjunction();this.consumeChar("/");const r={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":Ta(r,"global");break;case"i":Ta(r,"ignoreCase");break;case"m":Ta(r,"multiLine");break;case"u":Ta(r,"unicode");break;case"y":Ta(r,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:r,value:t,loc:this.loc(0)}}disjunction(){const e=[],t=this.idx;for(e.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),e.push(this.alternative());return{type:"Disjunction",value:e,loc:this.loc(t)}}alternative(){const e=[],t=this.idx;for(;this.isTerm();)e.push(this.term());return{type:"Alternative",value:e,loc:this.loc(t)}}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 t;switch(this.popChar()){case"=":t="Lookahead";break;case"!":t="NegativeLookahead";break;case"<":{switch(this.popChar()){case"=":t="Lookbehind";break;case"!":t="NegativeLookbehind"}break}}an(t);const r=this.disjunction();return this.consumeChar(")"),{type:t,value:r,loc:this.loc(e)}}return $v()}quantifier(e=!1){let t;const r=this.idx;switch(this.popChar()){case"*":t={atLeast:0,atMost:1/0};break;case"+":t={atLeast:1,atMost:1/0};break;case"?":t={atLeast:0,atMost:1};break;case"{":const n=this.integerIncludingZero();switch(this.popChar()){case"}":t={atLeast:n,atMost:n};break;case",":let a;this.isDigit()?(a=this.integerIncludingZero(),t={atLeast:n,atMost:a}):t={atLeast:n,atMost:1/0},this.consumeChar("}");break}if(e===!0&&t===void 0)return;an(t);break}if(!(e===!0&&t===void 0)&&an(t))return this.peekChar(0)==="?"?(this.consumeChar("?"),t.greedy=!1):t.greedy=!0,t.type="Quantifier",t.loc=this.loc(r),t}atom(){let e;const t=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()),an(e))return e.loc=this.loc(t),this.isQuantifier()&&(e.quantifier=this.quantifier()),e}dotAll(){return this.consumeChar("."),{type:"Set",complement:!0,value:[U(` +`),U("\r"),U("\u2028"),U("\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,t=!1;switch(this.popChar()){case"d":e=ul;break;case"D":e=ul,t=!0;break;case"s":e=uh;break;case"S":e=uh,t=!0;break;case"w":e=cl;break;case"W":e=cl,t=!0;break}if(an(e))return{type:"Set",value:e,complement:t}}controlEscapeAtom(){let e;switch(this.popChar()){case"f":e=U("\f");break;case"n":e=U(` +`);break;case"r":e=U("\r");break;case"t":e=U(" ");break;case"v":e=U("\v");break}if(an(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:U("\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:U(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:U(e)}}}characterClass(){const e=[];let t=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),t=!0);this.isClassAtom();){const r=this.classAtom();if(r.type,Ef(r)&&this.isRangeDash()){this.consumeChar("-");const n=this.classAtom();if(n.type,Ef(n)){if(n.value=this.input.length)throw Error("Unexpected end of input");this.idx++}loc(e){return{begin:e,end:this.idx}}},Wl=class{static{i(this,"BaseRegExpVisitor")}visitChildren(e){for(const t in e){const r=e[t];e.hasOwnProperty(t)&&(r.type!==void 0?this.visit(r):Array.isArray(r)&&r.forEach(n=>{this.visit(n)},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){}},Av=/\r?\n/gm,Ev=new Rv,sN=class extends Wl{static{i(this,"TerminalRegExpVisitor")}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 t=String.fromCharCode(e.value);if(!this.multiline&&t===` +`&&(this.multiline=!0),e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const r=ti(t);this.endRegexpStack.push(r),this.isStarting&&(this.startRegexp+=r)}}visitSet(e){if(!this.multiline){const t=this.regex.substring(e.loc.begin,e.loc.end),r=new RegExp(t);this.multiline=!!` +`.match(r)}if(e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const t=this.regex.substring(e.loc.begin,e.loc.end);this.endRegexpStack.push(t),this.isStarting&&(this.startRegexp+=t)}}visitChildren(e){e.type==="Group"&&e.quantifier||super.visitChildren(e)}},Cn=new sN;function Cv(e){try{typeof e!="string"&&(e=e.source),e=`/${e}/`;const t=Ev.pattern(e),r=[];for(const n of t.value.value)Cn.reset(e),Cn.visit(n),r.push({start:Cn.startRegexp,end:Cn.endRegex});return r}catch{return[]}}i(Cv,"getTerminalParts");function lp(e){try{return typeof e=="string"&&(e=new RegExp(e)),e=e.toString(),Cn.reset(e),Cn.visit(Ev.pattern(e)),Cn.multiline}catch{return!1}}i(lp,"isMultilineComment");var bv=`\f +\r \v              \u2028\u2029   \uFEFF`.split("");function ql(e){const t=typeof e=="string"?new RegExp(e):e;return bv.some(r=>t.test(r))}i(ql,"isWhitespace");function ti(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}i(ti,"escapeRegExp");function up(e,t){const r=cp(e),n=t.match(r);return!!n&&n[0].length>0}i(up,"partialMatches");function cp(e){typeof e=="string"&&(e=new RegExp(e));const t=e,r=e.source;let n=0;function a(){let s="",o;function l(c){s+=r.substr(n,c),n+=c}i(l,"appendRaw");function u(c){s+="(?:"+r.substr(n,c)+"|$)",n+=c}for(i(u,"appendOptional");n",n)-n+1);break;default:u(2);break}break;case"[":o=/\[(?:\\.|.)*?\]/g,o.lastIndex=n,o=o.exec(r)||[],u(o[0].length);break;case"|":case"^":case"$":case"*":case"+":case"?":l(1);break;case"{":o=/\{\d+,?\d*\}/g,o.lastIndex=n,o=o.exec(r),o?l(o[0].length):u(1);break;case"(":if(r[n+1]==="?")switch(r[n+2]){case":":s+="(?:",n+=3,s+=a()+"|$)";break;case"=":s+="(?=",n+=3,s+=a()+")";break;case"!":o=n,n+=3,a(),s+=r.substr(o,n-o);break;case"<":switch(r[n+3]){case"=":case"!":o=n,n+=4,a(),s+=r.substr(o,n-o);break;default:l(r.indexOf(">",n)-n+1),s+=a()+"|$)";break}break}else l(1),s+=a()+"|$)";break;case")":return++n,s;default:u(1);break}return s}return i(a,"process"),new RegExp(a(),e.flags)}i(cp,"partialRegExp");function fp(e){return e.rules.find(t=>at(t)&&t.entry)}i(fp,"getEntryRule");function dp(e){return e.rules.filter(t=>It(t)&&t.hidden)}i(dp,"getHiddenRules");function Vl(e,t){const r=new Set,n=fp(e);if(!n)return new Set(e.rules);const a=[n].concat(dp(e));for(const o of a)pp(o,r,t);const s=new Set;for(const o of e.rules)(r.has(o.name)||It(o)&&o.hidden)&&s.add(o);return s}i(Vl,"getAllReachableRules");function pp(e,t,r){t.add(e.name),Ir(e).forEach(n=>{if(Ar(n)||r&&zl(n)){const a=n.rule.ref;a&&!t.has(a.name)&&pp(a,t,r)}})}i(pp,"ruleDfs");function _v(e){const t=new Set;return Ir(e).forEach(r=>{Gn(r)&&(at(r.type.ref)&&t.add(r.type.ref),Gs(r.type.ref)&&at(r.type.ref.$container)&&t.add(r.type.ref.$container))}),t}i(_v,"getAllRulesUsedForCrossReferences");function mp(e){if(e.terminal)return e.terminal;if(e.type.ref)return Jl(e.type.ref)?.terminal}i(mp,"getCrossReferenceTerminal");function hp(e){return e.hidden&&!ql(js(e))}i(hp,"isCommentTerminal");function yp(e,t){return!e||!t?[]:Yl(e,t,e.astNode,!0)}i(yp,"findNodesForProperty");function Hl(e,t,r){if(!e||!t)return;const n=Yl(e,t,e.astNode,!0);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}i(Hl,"findNodeForProperty");function Yl(e,t,r,n){if(!n){const a=xn(e.grammarSource,$r);if(a&&a.feature===t)return[e]}return Tr(e)&&e.astNode===r?e.content.flatMap(a=>Yl(a,t,r,!1)):[]}i(Yl,"findNodesForPropertyInternal");function Sv(e,t){return e?Xl(e,t,e?.astNode):[]}i(Sv,"findNodesForKeyword");function gp(e,t,r){if(!e)return;const n=Xl(e,t,e?.astNode);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}i(gp,"findNodeForKeyword");function Xl(e,t,r){if(e.astNode!==r)return[];if(Rr(e.grammarSource)&&e.grammarSource.value===t)return[e];const n=Va(e).iterator();let a;const s=[];do if(a=n.next(),!a.done){const o=a.value;o.astNode===r?Rr(o.grammarSource)&&o.grammarSource.value===t&&s.push(o):n.prune()}while(!a.done);return s}i(Xl,"findNodesForKeywordInternal");function vp(e){const t=e.astNode;for(;t===e.container?.astNode;){const r=xn(e.grammarSource,$r);if(r)return r;e=e.container}}i(vp,"findAssignment");function Jl(e){let t=e;return Gs(t)&&(zr(t.$container)?t=t.$container.$container:Mn(t.$container)?t=t.$container:qr(t.$container)),Tp(e,t,new Map)}i(Jl,"findNameAssignment");function Tp(e,t,r){function n(a,s){let o;return xn(a,$r)||(o=Tp(s,s,r)),r.set(e,o),o}if(i(n,"go"),r.has(e))return r.get(e);r.set(e,void 0);for(const a of Ir(t)){if($r(a)&&a.feature.toLowerCase()==="name")return r.set(e,a),a;if(Ar(a)&&at(a.rule.ref))return n(a,a.rule.ref);if(Fl(a)&&a.typeRef?.ref)return n(a,a.typeRef.ref)}}i(Tp,"findNameAssignmentInternal");function $p(e){const t=e.$container;if(Fn(t)){const r=t.elements,n=r.indexOf(e);for(let a=n-1;a>=0;a--){const s=r[a];if(zr(s))return s;{const o=Ir(r[a]).find(zr);if(o)return o}}}if(Ml(t))return $p(t)}i($p,"getActionAtElement");function wv(e,t){return e==="?"||e==="*"||Fn(t)&&!!t.guardCondition}i(wv,"isOptionalCardinality");function Iv(e){return e==="*"||e==="+"}i(Iv,"isArrayCardinality");function Nv(e){return e==="+="}i(Nv,"isArrayOperator");function Fs(e){return Rp(e,new Set)}i(Fs,"isDataTypeRule");function Rp(e,t){if(t.has(e))return!0;t.add(e);for(const r of Ir(e))if(Ar(r)){if(!r.rule.ref||at(r.rule.ref)&&!Rp(r.rule.ref,t)||qa(r.rule.ref))return!1}else{if($r(r))return!1;if(zr(r))return!1}return!!e.definition}i(Rp,"isDataTypeRuleInternal");function Pv(e){return fl(e.type,new Set)}i(Pv,"isDataType");function fl(e,t){if(t.has(e))return!0;if(t.add(e),kd(e))return!1;if(Bd(e))return!1;if(Vd(e))return e.types.every(r=>fl(r,t));if(Fl(e)){if(e.primitiveType!==void 0)return!0;if(e.stringType!==void 0)return!0;if(e.typeRef!==void 0){const r=e.typeRef.ref;return jl(r)?fl(r.type,t):!1}else return!1}else return!1}i(fl,"isDataTypeInternal");function zs(e){if(!It(e)){if(e.inferredType)return e.inferredType.name;if(e.dataType)return e.dataType;if(e.returnType){const t=e.returnType.ref;if(t)return t.name}}}i(zs,"getExplicitRuleType");function Nn(e){if(Mn(e))return at(e)&&Fs(e)?e.name:zs(e)??e.name;if(Gd(e)||jl(e)||Kd(e))return e.name;if(zr(e)){const t=Ap(e);if(t)return t}else if(Gs(e))return e.name;throw new Error("Cannot get name of Unknown Type")}i(Nn,"getTypeName");function Ap(e){if(e.inferredType)return e.inferredType.name;if(e.type?.ref)return Nn(e.type.ref)}i(Ap,"getActionType");function kv(e){return It(e)?e.type?.name??"string":at(e)&&Fs(e)?e.name:zs(e)??e.name}i(kv,"getRuleTypeName");function Ep(e){return It(e)?e.type?.name??"string":zs(e)??e.name}i(Ep,"getRuleType");function js(e){const t={s:!1,i:!1,u:!1},r=zn(e.definition,t),n=Object.entries(t).filter(([,a])=>a).map(([a])=>a).join("");return new RegExp(r,n)}i(js,"terminalRegex");var Cp=/[\s\S]/.source;function zn(e,t){if(Wd(e))return Ov(e);if(qd(e))return Lv(e);if(Ld(e))return Mv(e);if(zl(e)){const r=e.rule.ref;if(!r)throw new Error("Missing rule reference.");return rr(zn(r.definition),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized})}else{if(Fd(e))return xv(e);if(Hd(e))return Dv(e);if(Ud(e)){const r=e.regex.lastIndexOf("/"),n=e.regex.substring(1,r),a=e.regex.substring(r+1);return t&&(t.i=a.includes("i"),t.s=a.includes("s"),t.u=a.includes("u")),rr(n,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}else{if(Yd(e))return rr(Cp,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized});throw new Error(`Invalid terminal element: ${e?.$type}, ${e?.$cstNode?.text}`)}}}i(zn,"abstractElementToRegex");function Ov(e){return rr(e.elements.map(t=>zn(t)).join("|"),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}i(Ov,"terminalAlternativesToRegex");function Lv(e){return rr(e.elements.map(t=>zn(t)).join(""),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}i(Lv,"terminalGroupToRegex");function Dv(e){return rr(`${Cp}*?${zn(e.terminal)}`,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized})}i(Dv,"untilTokenToRegex");function xv(e){return rr(`(?!${zn(e.terminal)})${Cp}*?`,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized})}i(xv,"negateTokenToRegex");function Mv(e){return e.right?rr(`[${Po(e.left)}-${Po(e.right)}]`,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1}):rr(Po(e.left),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}i(Mv,"characterRangeToRegex");function Po(e){return ti(e.value)}i(Po,"keywordToRegex");function rr(e,t){return(t.parenthesized||t.lookahead||t.wrap!==!1)&&(e=`(${t.lookahead??(t.parenthesized?"":"?:")}${e})`),t.cardinality?`${e}${t.cardinality}`:e}i(rr,"withCardinality");function bp(e){const t=[],r=e.Grammar;for(const n of r.rules)It(n)&&hp(n)&&lp(js(n))&&t.push(n.name);return{multilineCommentRules:t,nameRegexp:ep}}i(bp,"createGrammarConfig");var oN=typeof global=="object"&&global&&global.Object===Object&&global,Gv=oN,lN=typeof self=="object"&&self&&self.Object===Object&&self,uN=Gv||lN||Function("return this")(),ar=uN,cN=ar.Symbol,St=cN,Fv=Object.prototype,fN=Fv.hasOwnProperty,dN=Fv.toString,ki=St?St.toStringTag:void 0;function zv(e){var t=fN.call(e,ki),r=e[ki];try{e[ki]=void 0;var n=!0}catch{}var a=dN.call(e);return n&&(t?e[ki]=r:delete e[ki]),a}i(zv,"getRawTag");var pN=zv,mN=Object.prototype,hN=mN.toString;function jv(e){return hN.call(e)}i(jv,"objectToString");var yN=jv,gN="[object Null]",vN="[object Undefined]",ch=St?St.toStringTag:void 0;function Bv(e){return e==null?e===void 0?vN:gN:ch&&ch in Object(e)?pN(e):yN(e)}i(Bv,"baseGetTag");var Vr=Bv;function Uv(e){return e!=null&&typeof e=="object"}i(Uv,"isObjectLike");var zt=Uv,TN="[object Symbol]";function Kv(e){return typeof e=="symbol"||zt(e)&&Vr(e)==TN}i(Kv,"isSymbol");var Zl=Kv;function Wv(e,t){for(var r=-1,n=e==null?0:e.length,a=Array(n);++r0){if(++t>=tP)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}i(lT,"shortOut");var aP=lT;function uT(e){return function(){return e}}i(uT,"constant");var iP=uT,sP=(function(){try{var e=Bn(Object,"defineProperty");return e({},"",{}),e}catch{}})(),dl=sP,oP=dl?function(e,t){return dl(e,"toString",{configurable:!0,enumerable:!1,value:iP(t),writable:!0})}:Ks,lP=oP,uP=aP(lP),cP=uP;function cT(e,t){for(var r=-1,n=e==null?0:e.length;++r-1}i(gT,"arrayIncludes");var vT=gT,pP=9007199254740991,mP=/^(?:0|[1-9]\d*)$/;function TT(e,t){var r=typeof e;return t=t??pP,!!t&&(r=="number"||r!="symbol"&&mP.test(e))&&e>-1&&e%1==0&&e-1&&e%1==0&&e<=vP}i(_T,"isLength");var Np=_T;function ST(e){return e!=null&&Np(e.length)&&!Nr(e)}i(ST,"isArrayLike");var ir=ST;function wT(e,t,r){if(!wt(r))return!1;var n=typeof t;return(n=="number"?ir(r)&&Ql(t,r.length):n=="string"&&t in r)?Ws(r[t],e):!1}i(wT,"isIterateeCall");var tu=wT;function IT(e){return Ip(function(t,r){var n=-1,a=r.length,s=a>1?r[a-1]:void 0,o=a>2?r[2]:void 0;for(s=e.length>3&&typeof s=="function"?(a--,s):void 0,o&&tu(r[0],r[1],o)&&(s=a<3?void 0:s,a=1),t=Object(t);++n-1}i(i$,"listCacheHas");var xk=i$;function s$(e,t){var r=this.__data__,n=au(r,e);return n<0?(++this.size,r.push([e,t])):r[n][1]=t,this}i(s$,"listCacheSet");var Mk=s$;function Kn(e){var t=-1,r=e==null?0:e.length;for(this.clear();++t0&&r(l)?t>1?Dp(l,t-1,r,n,a):Lp(a,l):n||(a[a.length]=l)}return a}i(Dp,"baseFlatten");var xp=Dp;function A$(e){var t=e==null?0:e.length;return t?xp(e,1):[]}i(A$,"flatten");var Gt=A$,rO=BT(Object.getPrototypeOf,Object),E$=rO;function C$(e,t,r){var n=-1,a=e.length;t<0&&(t=-t>a?0:a+t),r=r>a?a:r,r<0&&(r+=a),a=t>r?0:r-t>>>0,t>>>=0;for(var s=Array(a);++nl))return!1;var c=s.get(e),f=s.get(t);if(c&&f)return c==t&&f==e;var d=-1,m=!0,g=r&q0?new zp:void 0;for(s.set(e,t),s.set(t,e);++d2?t[2]:void 0;for(a&&tu(t[0],t[1],a)&&(n=1);++r=FL&&(s=jp,o=!1,t=new zp(t));e:for(;++a-1?a[s?t[o]:o]:void 0}}i(iA,"createFind");var WL=iA,qL=Math.max;function sA(e,t,r){var n=e==null?0:e.length;if(!n)return-1;var a=r==null?0:Us(r);return a<0&&(a=qL(n+a,0)),pT(e,sr(t),a)}i(sA,"findIndex");var VL=sA,HL=WL(VL),Xa=HL;function oA(e){return e&&e.length?e[0]:void 0}i(oA,"head");var jt=oA;function lA(e,t){var r=-1,n=ir(e)?Array(e.length):[];return Vn(e,function(a,s,o){n[++r]=t(a,s,o)}),n}i(lA,"baseMap");var YL=lA;function uA(e,t){var r=re(e)?Bs:YL;return r(e,sr(t))}i(uA,"map");var F=uA;function cA(e,t){return xp(F(e,t),1)}i(cA,"flatMap");var _t=cA,XL=Object.prototype,JL=XL.hasOwnProperty,ZL=xL(function(e,t,r){JL.call(e,r)?e[r].push(t):wp(e,r,[t])}),QL=ZL,eD=Object.prototype,tD=eD.hasOwnProperty;function fA(e,t){return e!=null&&tD.call(e,t)}i(fA,"baseHas");var rD=fA;function dA(e,t){return e!=null&&NR(e,t,rD)}i(dA,"has");var B=dA,nD="[object String]";function pA(e){return typeof e=="string"||!re(e)&&zt(e)&&Vr(e)==nD}i(pA,"isString");var pt=pA;function mA(e,t){return Bs(t,function(r){return e[r]})}i(mA,"baseValues");var aD=mA;function hA(e){return e==null?[]:aD(e,Tt(e))}i(hA,"values");var Me=hA,iD=Math.max;function yA(e,t,r,n){e=ir(e)?e:Me(e),r=r&&!n?Us(r):0;var a=e.length;return r<0&&(r=iD(a+r,0)),pt(e)?r<=a&&e.indexOf(t,r)>-1:!!a&&Sp(e,t,r)>-1}i(yA,"includes");var lt=yA,sD=Math.max;function gA(e,t,r){var n=e==null?0:e.length;if(!n)return-1;var a=r==null?0:Us(r);return a<0&&(a=sD(n+a,0)),Sp(e,t,a)}i(gA,"indexOf");var Bh=gA,oD="[object Map]",lD="[object Set]",uD=Object.prototype,cD=uD.hasOwnProperty;function vA(e){if(e==null)return!0;if(ir(e)&&(re(e)||typeof e=="string"||typeof e.splice=="function"||$s(e)||Pp(e)||ru(e)))return!e.length;var t=Ya(e);if(t==oD||t==lD)return!e.size;if(Vs(e))return!KT(e).length;for(var r in e)if(cD.call(e,r))return!1;return!0}i(vA,"isEmpty");var me=vA,fD="[object RegExp]";function TA(e){return zt(e)&&Vr(e)==fD}i(TA,"baseIsRegExp");var dD=TA,Uh=jr&&jr.isRegExp,pD=Uh?Hs(Uh):dD,Er=pD;function $A(e){return e===void 0}i($A,"isUndefined");var Cr=$A,mD="Expected a function";function RA(e){if(typeof e!="function")throw new TypeError(mD);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}i(RA,"negate");var hD=RA;function AA(e,t,r,n){if(!wt(e))return e;t=uu(t,e);for(var a=-1,s=t.length,o=s-1,l=e;l!=null&&++a=ED){var c=t?null:AD(e);if(c)return Bp(c);o=!1,a=jp,u=new zp}else u=t?[]:l;e:for(;++n{t.accept(e)})}},it=class extends or{static{i(this,"NonTerminal")}constructor(e){super([]),this.idx=1,$t(this,Bt(e,t=>t!==void 0))}set definition(e){}get definition(){return this.referencedRule!==void 0?this.referencedRule.definition:[]}accept(e){e.visit(this)}},ri=class extends or{static{i(this,"Rule")}constructor(e){super(e.definition),this.orgText="",$t(this,Bt(e,t=>t!==void 0))}},mt=class extends or{static{i(this,"Alternative")}constructor(e){super(e.definition),this.ignoreAmbiguities=!1,$t(this,Bt(e,t=>t!==void 0))}},He=class extends or{static{i(this,"Option")}constructor(e){super(e.definition),this.idx=1,$t(this,Bt(e,t=>t!==void 0))}},At=class extends or{static{i(this,"RepetitionMandatory")}constructor(e){super(e.definition),this.idx=1,$t(this,Bt(e,t=>t!==void 0))}},Et=class extends or{static{i(this,"RepetitionMandatoryWithSeparator")}constructor(e){super(e.definition),this.idx=1,$t(this,Bt(e,t=>t!==void 0))}},be=class extends or{static{i(this,"Repetition")}constructor(e){super(e.definition),this.idx=1,$t(this,Bt(e,t=>t!==void 0))}},ht=class extends or{static{i(this,"RepetitionWithSeparator")}constructor(e){super(e.definition),this.idx=1,$t(this,Bt(e,t=>t!==void 0))}},yt=class extends or{static{i(this,"Alternation")}get definition(){return this._definition}set definition(e){this._definition=e}constructor(e){super(e.definition),this.idx=1,this.ignoreAmbiguities=!1,this.hasPredicates=!1,$t(this,Bt(e,t=>t!==void 0))}},ve=class{static{i(this,"Terminal")}constructor(e){this.idx=1,$t(this,Bt(e,t=>t!==void 0))}accept(e){e.visit(this)}};function DA(e){return F(e,ps)}i(DA,"serializeGrammar");function ps(e){function t(r){return F(r,ps)}if(i(t,"convertDefinition"),e instanceof it){const r={type:"NonTerminal",name:e.nonTerminalName,idx:e.idx};return pt(e.label)&&(r.label=e.label),r}else{if(e instanceof mt)return{type:"Alternative",definition:t(e.definition)};if(e instanceof He)return{type:"Option",idx:e.idx,definition:t(e.definition)};if(e instanceof At)return{type:"RepetitionMandatory",idx:e.idx,definition:t(e.definition)};if(e instanceof Et)return{type:"RepetitionMandatoryWithSeparator",idx:e.idx,separator:ps(new ve({terminalType:e.separator})),definition:t(e.definition)};if(e instanceof ht)return{type:"RepetitionWithSeparator",idx:e.idx,separator:ps(new ve({terminalType:e.separator})),definition:t(e.definition)};if(e instanceof be)return{type:"Repetition",idx:e.idx,definition:t(e.definition)};if(e instanceof yt)return{type:"Alternation",idx:e.idx,definition:t(e.definition)};if(e instanceof ve){const r={type:"Terminal",name:e.terminalType.name,label:OA(e.terminalType),idx:e.idx};pt(e.label)&&(r.terminalLabel=e.label);const n=e.terminalType.PATTERN;return e.terminalType.PATTERN&&(r.pattern=Er(n)?n.source:n),r}else{if(e instanceof ri)return{type:"Rule",name:e.name,orgText:e.orgText,definition:t(e.definition)};throw Error("non exhaustive match")}}}i(ps,"serializeProduction");var ni=class{static{i(this,"GAstVisitor")}visit(e){const t=e;switch(t.constructor){case it:return this.visitNonTerminal(t);case mt:return this.visitAlternative(t);case He:return this.visitOption(t);case At:return this.visitRepetitionMandatory(t);case Et:return this.visitRepetitionMandatoryWithSeparator(t);case ht:return this.visitRepetitionWithSeparator(t);case be:return this.visitRepetition(t);case yt:return this.visitAlternation(t);case ve:return this.visitTerminal(t);case ri:return this.visitRule(t);default:throw Error("non exhaustive match")}}visitNonTerminal(e){}visitAlternative(e){}visitOption(e){}visitRepetition(e){}visitRepetitionMandatory(e){}visitRepetitionMandatoryWithSeparator(e){}visitRepetitionWithSeparator(e){}visitAlternation(e){}visitTerminal(e){}visitRule(e){}};function xA(e){return e instanceof mt||e instanceof He||e instanceof be||e instanceof At||e instanceof Et||e instanceof ht||e instanceof ve||e instanceof ri}i(xA,"isSequenceProd");function bs(e,t=[]){return e instanceof He||e instanceof be||e instanceof ht?!0:e instanceof yt?NA(e.definition,n=>bs(n,t)):e instanceof it&<(t,e)?!1:e instanceof or?(e instanceof it&&t.push(e),Ft(e.definition,n=>bs(n,t))):!1}i(bs,"isOptionalProd");function MA(e){return e instanceof yt}i(MA,"isBranchingProd");function Lt(e){if(e instanceof it)return"SUBRULE";if(e instanceof He)return"OPTION";if(e instanceof yt)return"OR";if(e instanceof At)return"AT_LEAST_ONE";if(e instanceof Et)return"AT_LEAST_ONE_SEP";if(e instanceof ht)return"MANY_SEP";if(e instanceof be)return"MANY";if(e instanceof ve)return"CONSUME";throw Error("non exhaustive match")}i(Lt,"getProductionDslName");var du=class{static{i(this,"RestWalker")}walk(e,t=[]){K(e.definition,(r,n)=>{const a=Ve(e.definition,n+1);if(r instanceof it)this.walkProdRef(r,a,t);else if(r instanceof ve)this.walkTerminal(r,a,t);else if(r instanceof mt)this.walkFlat(r,a,t);else if(r instanceof He)this.walkOption(r,a,t);else if(r instanceof At)this.walkAtLeastOne(r,a,t);else if(r instanceof Et)this.walkAtLeastOneSep(r,a,t);else if(r instanceof ht)this.walkManySep(r,a,t);else if(r instanceof be)this.walkMany(r,a,t);else if(r instanceof yt)this.walkOr(r,a,t);else throw Error("non exhaustive match")})}walkTerminal(e,t,r){}walkProdRef(e,t,r){}walkFlat(e,t,r){const n=t.concat(r);this.walk(e,n)}walkOption(e,t,r){const n=t.concat(r);this.walk(e,n)}walkAtLeastOne(e,t,r){const n=[new He({definition:e.definition})].concat(t,r);this.walk(e,n)}walkAtLeastOneSep(e,t,r){const n=wf(e,t,r);this.walk(e,n)}walkMany(e,t,r){const n=[new He({definition:e.definition})].concat(t,r);this.walk(e,n)}walkManySep(e,t,r){const n=wf(e,t,r);this.walk(e,n)}walkOr(e,t,r){const n=t.concat(r);K(e.definition,a=>{const s=new mt({definition:[a]});this.walk(s,n)})}};function wf(e,t,r){return[new He({definition:[new ve({terminalType:e.separator})].concat(e.definition)})].concat(t,r)}i(wf,"restForRepetitionWithSeparator");function ai(e){if(e instanceof it)return ai(e.referencedRule);if(e instanceof ve)return zA(e);if(xA(e))return GA(e);if(MA(e))return FA(e);throw Error("non exhaustive match")}i(ai,"first");function GA(e){let t=[];const r=e.definition;let n=0,a=r.length>n,s,o=!0;for(;a&&o;)s=r[n],o=bs(s),t=t.concat(ai(s)),n=n+1,a=r.length>n;return Wp(t)}i(GA,"firstForSequence");function FA(e){const t=F(e.definition,r=>ai(r));return Wp(Gt(t))}i(FA,"firstForBranching");function zA(e){return[e.terminalType]}i(zA,"firstForTerminal");var jA="_~IN~_",bD=class extends du{static{i(this,"ResyncFollowsWalker")}constructor(e){super(),this.topProd=e,this.follows={}}startWalking(){return this.walk(this.topProd),this.follows}walkTerminal(e,t,r){}walkProdRef(e,t,r){const n=UA(e.referencedRule,e.idx)+this.topProd.name,a=t.concat(r),s=new mt({definition:a}),o=ai(s);this.follows[n]=o}};function BA(e){const t={};return K(e,r=>{const n=new bD(r).startWalking();$t(t,n)}),t}i(BA,"computeAllProdsFollows");function UA(e,t){return e.name+t+jA}i(UA,"buildBetweenProdsFollowPrefix");var ko={},_D=new Rv;function Js(e){const t=e.toString();if(ko.hasOwnProperty(t))return ko[t];{const r=_D.pattern(t);return ko[t]=r,r}}i(Js,"getRegExpAst");function KA(){ko={}}i(KA,"clearRegExpParserCache");var WA="Complement Sets are not supported for first char optimization",hl=`Unable to use "first char" lexer optimizations: +`;function qA(e,t=!1){try{const r=Js(e);return yl(r.value,{},r.flags.ignoreCase)}catch(r){if(r.message===WA)t&&qp(`${hl} Unable to optimize: < ${e.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="";t&&(n=` + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),ml(`${hl} + Failed parsing: < ${e.toString()} > + Using the @chevrotain/regexp-to-ast library + Please open an issue at: https://github.com/chevrotain/chevrotain/issues`+n)}}return[]}i(qA,"getOptimizedStartCodesIndices");function yl(e,t,r){switch(e.type){case"Disjunction":for(let a=0;a{if(typeof u=="number")Xi(u,t,r);else{const c=u;if(r===!0)for(let f=c.from;f<=c.to;f++)Xi(f,t,r);else{for(let f=c.from;f<=c.to&&f=Zi){const f=c.from>=Zi?c.from:Zi,d=c.to,m=br(f),g=br(d);for(let v=m;v<=g;v++)t[v]=v}}}});break;case"Group":yl(o.value,t,r);break;default:throw Error("Non Exhaustive Match")}const l=o.quantifier!==void 0&&o.quantifier.atLeast===0;if(o.type==="Group"&&gl(o)===!1||o.type!=="Group"&&l===!1)break}break;default:throw Error("non exhaustive match!")}return Me(t)}i(yl,"firstCharOptimizedIndices");function Xi(e,t,r){const n=br(e);t[n]=n,r===!0&&VA(e,t)}i(Xi,"addOptimizedIdxToResult");function VA(e,t){const r=String.fromCharCode(e),n=r.toUpperCase();if(n!==r){const a=br(n.charCodeAt(0));t[a]=a}else{const a=r.toLowerCase();if(a!==r){const s=br(a.charCodeAt(0));t[s]=s}}}i(VA,"handleIgnoreCase");function If(e,t){return Xa(e.value,r=>{if(typeof r=="number")return lt(t,r);{const n=r;return Xa(t,a=>n.from<=a&&a<=n.to)!==void 0}})}i(If,"findCode");function gl(e){const t=e.quantifier;return t&&t.atLeast===0?!0:e.value?re(e.value)?Ft(e.value,gl):gl(e.value):!1}i(gl,"isWholeOptional");var SD=class extends Wl{static{i(this,"CharCodeFinder")}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){lt(this.targetCharCodes,e.value)&&(this.found=!0)}visitSet(e){e.complement?If(e,this.targetCharCodes)===void 0&&(this.found=!0):If(e,this.targetCharCodes)!==void 0&&(this.found=!0)}};function pu(e,t){if(t instanceof RegExp){const r=Js(t),n=new SD(e);return n.visit(r),n.found}else return Xa(t,r=>lt(e,r.charCodeAt(0)))!==void 0}i(pu,"canMatchCharCode");var kn="PATTERN",Ji="defaultMode",io="modes";function HA(e,t){t=Kp(t,{debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",` +`],tracer:i((I,R)=>R(),"tracer")});const r=t.tracer;r("initCharCodeToOptimizedIndexMap",()=>{hE()});let n;r("Reject Lexer.NA",()=>{n=fu(e,I=>I[kn]===nt.NA)});let a=!1,s;r("Transform Patterns",()=>{a=!1,s=F(n,I=>{const R=I[kn];if(Er(R)){const P=R.source;return P.length===1&&P!=="^"&&P!=="$"&&P!=="."&&!R.ignoreCase?P:P.length===2&&P[0]==="\\"&&!lt(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],P[1])?P[1]:Nf(R)}else{if(Nr(R))return a=!0,{exec:R};if(typeof R=="object")return a=!0,R;if(typeof R=="string"){if(R.length===1)return R;{const P=R.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),z=new RegExp(P);return Nf(z)}}else throw Error("non exhaustive match")}})});let o,l,u,c,f;r("misc mapping",()=>{o=F(n,I=>I.tokenTypeIdx),l=F(n,I=>{const R=I.GROUP;if(R!==nt.SKIPPED){if(pt(R))return R;if(Cr(R))return!1;throw Error("non exhaustive match")}}),u=F(n,I=>{const R=I.LONGER_ALT;if(R)return re(R)?F(R,z=>Bh(n,z)):[Bh(n,R)]}),c=F(n,I=>I.PUSH_MODE),f=F(n,I=>B(I,"POP_MODE"))});let d;r("Line Terminator Handling",()=>{const I=Jp(t.lineTerminatorCharacters);d=F(n,R=>!1),t.positionTracking!=="onlyOffset"&&(d=F(n,R=>B(R,"LINE_BREAKS")?!!R.LINE_BREAKS:Xp(R,I)===!1&&pu(I,R.PATTERN)))});let m,g,v,b;r("Misc Mapping #2",()=>{m=F(n,Yp),g=F(s,pE),v=Rt(n,(I,R)=>{const P=R.GROUP;return pt(P)&&P!==nt.SKIPPED&&(I[P]=[]),I},{}),b=F(s,(I,R)=>({pattern:s[R],longerAlt:u[R],canLineTerminator:d[R],isCustom:m[R],short:g[R],group:l[R],push:c[R],pop:f[R],tokenTypeIdx:o[R],tokenType:n[R]}))});let S=!0,w=[];return t.safeMode||r("First Char Optimization",()=>{w=Rt(n,(I,R,P)=>{if(typeof R.PATTERN=="string"){const z=R.PATTERN.charCodeAt(0),X=br(z);Oo(I,X,b[P])}else if(re(R.START_CHARS_HINT)){let z;K(R.START_CHARS_HINT,X=>{const Z=typeof X=="string"?X.charCodeAt(0):X,ce=br(Z);z!==ce&&(z=ce,Oo(I,ce,b[P]))})}else if(Er(R.PATTERN))if(R.PATTERN.unicode)S=!1,t.ensureOptimizations&&ml(`${hl} Unable to analyze < ${R.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 z=qA(R.PATTERN,t.ensureOptimizations);me(z)&&(S=!1),K(z,X=>{Oo(I,X,b[P])})}else t.ensureOptimizations&&ml(`${hl} TokenType: <${R.name}> is using a custom token pattern without providing parameter. + This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),S=!1;return I},[])}),{emptyGroups:v,patternIdxToConfig:b,charCodeToPatternIdxToConfig:w,hasCustom:a,canBeOptimized:S}}i(HA,"analyzeTokenTypes");function YA(e,t){let r=[];const n=JA(e);r=r.concat(n.errors);const a=ZA(n.valid),s=a.valid;return r=r.concat(a.errors),r=r.concat(XA(s)),r=r.concat(aE(s)),r=r.concat(iE(s,t)),r=r.concat(sE(s)),r}i(YA,"validatePatterns");function XA(e){let t=[];const r=Nt(e,n=>Er(n[kn]));return t=t.concat(QA(r)),t=t.concat(tE(r)),t=t.concat(rE(r)),t=t.concat(nE(r)),t=t.concat(eE(r)),t}i(XA,"validateRegExpPattern");function JA(e){const t=Nt(e,a=>!B(a,kn)),r=F(t,a=>({message:"Token Type: ->"+a.name+"<- missing static 'PATTERN' property",type:_e.MISSING_PATTERN,tokenTypes:[a]})),n=cu(e,t);return{errors:r,valid:n}}i(JA,"findMissingPatterns");function ZA(e){const t=Nt(e,a=>{const s=a[kn];return!Er(s)&&!Nr(s)&&!B(s,"exec")&&!pt(s)}),r=F(t,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:_e.INVALID_PATTERN,tokenTypes:[a]})),n=cu(e,t);return{errors:r,valid:n}}i(ZA,"findInvalidPatterns");var wD=/[^\\][$]/;function QA(e){class t extends Wl{static{i(this,"EndAnchorFinder")}constructor(){super(...arguments),this.found=!1}visitEndAnchor(s){this.found=!0}}const r=Nt(e,a=>{const s=a.PATTERN;try{const o=Js(s),l=new t;return l.visit(o),l.found}catch{return wD.test(s.source)}});return F(r,a=>({message:`Unexpected RegExp Anchor Error: + Token Type: ->`+a.name+`<- static 'PATTERN' cannot contain end of input anchor '$' + See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:_e.EOI_ANCHOR_FOUND,tokenTypes:[a]}))}i(QA,"findEndOfInputAnchor");function eE(e){const t=Nt(e,n=>n.PATTERN.test(""));return F(t,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' must not match an empty string",type:_e.EMPTY_MATCH_PATTERN,tokenTypes:[n]}))}i(eE,"findEmptyMatchRegExps");var ID=/[^\\[][\^]|^\^/;function tE(e){class t extends Wl{static{i(this,"StartAnchorFinder")}constructor(){super(...arguments),this.found=!1}visitStartAnchor(s){this.found=!0}}const r=Nt(e,a=>{const s=a.PATTERN;try{const o=Js(s),l=new t;return l.visit(o),l.found}catch{return ID.test(s.source)}});return F(r,a=>({message:`Unexpected RegExp Anchor Error: + Token Type: ->`+a.name+`<- static 'PATTERN' cannot contain start of input anchor '^' + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:_e.SOI_ANCHOR_FOUND,tokenTypes:[a]}))}i(tE,"findStartOfInputAnchor");function rE(e){const t=Nt(e,n=>{const a=n[kn];return a instanceof RegExp&&(a.multiline||a.global)});return F(t,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:_e.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[n]}))}i(rE,"findUnsupportedFlags");function nE(e){const t=[];let r=F(e,s=>Rt(e,(o,l)=>(s.PATTERN.source===l.PATTERN.source&&!lt(t,l)&&l.PATTERN!==nt.NA&&(t.push(l),o.push(l)),o),[]));r=Xs(r);const n=Nt(r,s=>s.length>1);return F(n,s=>{const o=F(s,u=>u.name);return{message:`The same RegExp pattern ->${jt(s).PATTERN}<-has been used in all of the following Token Types: ${o.join(", ")} <-`,type:_e.DUPLICATE_PATTERNS_FOUND,tokenTypes:s}})}i(nE,"findDuplicatePatterns");function aE(e){const t=Nt(e,n=>{if(!B(n,"GROUP"))return!1;const a=n.GROUP;return a!==nt.SKIPPED&&a!==nt.NA&&!pt(a)});return F(t,n=>({message:"Token Type: ->"+n.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:_e.INVALID_GROUP_TYPE_FOUND,tokenTypes:[n]}))}i(aE,"findInvalidGroupType");function iE(e,t){const r=Nt(e,a=>a.PUSH_MODE!==void 0&&!lt(t,a.PUSH_MODE));return F(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:_e.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[a]}))}i(iE,"findModesThatDoNotExist");function sE(e){const t=[],r=Rt(e,(n,a,s)=>{const o=a.PATTERN;return o===nt.NA||(pt(o)?n.push({str:o,idx:s,tokenType:a}):Er(o)&&lE(o)&&n.push({str:o.source,idx:s,tokenType:a})),n},[]);return K(e,(n,a)=>{K(r,({str:s,idx:o,tokenType:l})=>{if(a${l.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`;t.push({message:u,type:_e.UNREACHABLE_PATTERN,tokenTypes:[n,l]})}})}),t}i(sE,"findUnreachablePatterns");function oE(e,t){if(Er(t)){if(uE(t))return!1;const r=t.exec(e);return r!==null&&r.index===0}else{if(Nr(t))return t(e,0,[],{});if(B(t,"exec"))return t.exec(e,0,[],{});if(typeof t=="string")return t===e;throw Error("non exhaustive match")}}i(oE,"tryToMatchStrToPattern");function lE(e){return Xa([".","\\","[","]","|","^","$","(",")","?","*","+","{"],r=>e.source.indexOf(r)!==-1)===void 0}i(lE,"noMetaChar");function uE(e){return/(\(\?=)|(\(\?!)|(\(\?<=)|(\(\? property in its definition +`,type:_e.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),B(e,io)||n.push({message:"A MultiMode Lexer cannot be initialized without a <"+io+`> property in its definition +`,type:_e.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),B(e,io)&&B(e,Ji)&&!B(e.modes,e.defaultMode)&&n.push({message:`A MultiMode Lexer cannot be initialized with a ${Ji}: <${e.defaultMode}>which does not exist +`,type:_e.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),B(e,io)&&K(e.modes,(a,s)=>{K(a,(o,l)=>{if(Cr(o))n.push({message:`A Lexer cannot be initialized using an undefined Token Type. Mode:<${s}> at index: <${l}> +`,type:_e.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED});else if(B(o,"LONGER_ALT")){const u=re(o.LONGER_ALT)?o.LONGER_ALT:[o.LONGER_ALT];K(u,c=>{!Cr(c)&&!lt(a,c)&&n.push({message:`A MultiMode Lexer cannot be initialized with a longer_alt <${c.name}> on token <${o.name}> outside of mode <${s}> +`,type:_e.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE})})}})}),n}i(cE,"performRuntimeChecks");function fE(e,t,r){const n=[];let a=!1;const s=Xs(Gt(Me(e.modes))),o=fu(s,u=>u[kn]===nt.NA),l=Jp(r);return t&&K(o,u=>{const c=Xp(u,l);if(c!==!1){const d={message:mE(u,c),type:c.issue,tokenType:u};n.push(d)}else B(u,"LINE_BREAKS")?u.LINE_BREAKS===!0&&(a=!0):pu(l,u.PATTERN)&&(a=!0)}),t&&!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:_e.NO_LINE_BREAKS_FLAGS}),n}i(fE,"performWarningRuntimeChecks");function dE(e){const t={},r=Tt(e);return K(r,n=>{const a=e[n];if(re(a))t[n]=[];else throw Error("non exhaustive match")}),t}i(dE,"cloneEmptyGroups");function Yp(e){const t=e.PATTERN;if(Er(t))return!1;if(Nr(t))return!0;if(B(t,"exec"))return!0;if(pt(t))return!1;throw Error("non exhaustive match")}i(Yp,"isCustomPattern");function pE(e){return pt(e)&&e.length===1?e.charCodeAt(0):!1}i(pE,"isShortPattern");var ND={test:i(function(e){const t=e.length;for(let r=this.lastIndex;r Token Type + Root cause: ${t.errMsg}. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR`;if(t.issue===_e.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the option. + The problem is in the <${e.name}> Token Type + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK`;throw Error("non exhaustive match")}i(mE,"buildLineBreakIssueMessage");function Jp(e){return F(e,r=>pt(r)?r.charCodeAt(0):r)}i(Jp,"getCharCodes");function Oo(e,t,r){e[t]===void 0?e[t]=[r]:e[t].push(r)}i(Oo,"addToMapOfArrays");var Zi=256,Lo=[];function br(e){return e255?255+~~(e/255):e}}i(hE,"initCharCodeToOptimizedIndexMap");function ii(e,t){const r=e.tokenTypeIdx;return r===t.tokenTypeIdx?!0:t.isParent===!0&&t.categoryMatchesMap[r]===!0}i(ii,"tokenStructuredMatcher");function _s(e,t){return e.tokenTypeIdx===t.tokenTypeIdx}i(_s,"tokenStructuredMatcherNoCategories");var Kh=1,yE={};function si(e){const t=gE(e);vE(t),$E(t),TE(t),K(t,r=>{r.isParent=r.categoryMatches.length>0})}i(si,"augmentTokenTypes");function gE(e){let t=Ye(e),r=e,n=!0;for(;n;){r=Xs(Gt(F(r,s=>s.CATEGORIES)));const a=cu(r,t);t=t.concat(a),me(a)?n=!1:r=a}return t}i(gE,"expandCategories");function vE(e){K(e,t=>{Qp(t)||(yE[Kh]=t,t.tokenTypeIdx=Kh++),Pf(t)&&!re(t.CATEGORIES)&&(t.CATEGORIES=[t.CATEGORIES]),Pf(t)||(t.CATEGORIES=[]),RE(t)||(t.categoryMatches=[]),AE(t)||(t.categoryMatchesMap={})})}i(vE,"assignTokenDefaultProps");function TE(e){K(e,t=>{t.categoryMatches=[],K(t.categoryMatchesMap,(r,n)=>{t.categoryMatches.push(yE[n].tokenTypeIdx)})})}i(TE,"assignCategoriesTokensProp");function $E(e){K(e,t=>{Zp([],t)})}i($E,"assignCategoriesMapProp");function Zp(e,t){K(e,r=>{t.categoryMatchesMap[r.tokenTypeIdx]=!0}),K(t.CATEGORIES,r=>{const n=e.concat(t);lt(n,r)||Zp(n,r)})}i(Zp,"singleAssignCategoriesToksMap");function Qp(e){return B(e,"tokenTypeIdx")}i(Qp,"hasShortKeyProperty");function Pf(e){return B(e,"CATEGORIES")}i(Pf,"hasCategoriesProperty");function RE(e){return B(e,"categoryMatches")}i(RE,"hasExtendingTokensTypesProperty");function AE(e){return B(e,"categoryMatchesMap")}i(AE,"hasExtendingTokensTypesMapProperty");function EE(e){return B(e,"tokenTypeIdx")}i(EE,"isTokenType");var kf={buildUnableToPopLexerModeMessage(e){return`Unable to pop Lexer Mode after encountering Token ->${e.image}<- The Mode Stack is empty`},buildUnexpectedCharactersMessage(e,t,r,n,a,s){return`unexpected character: ->${e.charAt(t)}<- at offset: ${t}, skipped ${r} characters.`}},_e;(function(e){e[e.MISSING_PATTERN=0]="MISSING_PATTERN",e[e.INVALID_PATTERN=1]="INVALID_PATTERN",e[e.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",e[e.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",e[e.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",e[e.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",e[e.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",e[e.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",e[e.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",e[e.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",e[e.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",e[e.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",e[e.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",e[e.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",e[e.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",e[e.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",e[e.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK",e[e.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE=17]="MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE"})(_e||(_e={}));var Qi={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[` +`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:kf,traceInitPerf:!1,skipValidations:!1,recoveryEnabled:!0};Object.freeze(Qi);var nt=class{static{i(this,"Lexer")}constructor(e,t=Qi){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=(n,a)=>{if(this.traceInitPerf===!0){this.traceInitIndent++;const s=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <${n}>`);const{time:o,value:l}=Vp(a),u=o>10?console.warn:console.log;return this.traceInitIndent time: ${o}ms`),this.traceInitIndent--,l}else return a()},typeof t=="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=$t({},Qi,t);const r=this.config.traceInitPerf;r===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof r=="number"&&(this.traceInitMaxIdent=r,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",()=>{let n,a=!0;this.TRACE_INIT("Lexer Config handling",()=>{if(this.config.lineTerminatorsPattern===Qi.lineTerminatorsPattern)this.config.lineTerminatorsPattern=ND;else if(this.config.lineTerminatorCharacters===Qi.lineTerminatorCharacters)throw Error(`Error: Missing property on the Lexer config. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(t.safeMode&&t.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),re(e)?n={modes:{defaultMode:Ye(e)},defaultMode:Ji}:(a=!1,n=Ye(e))}),this.config.skipValidations===!1&&(this.TRACE_INIT("performRuntimeChecks",()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(cE(n,this.trackStartLines,this.config.lineTerminatorCharacters))}),this.TRACE_INIT("performWarningRuntimeChecks",()=>{this.lexerDefinitionWarning=this.lexerDefinitionWarning.concat(fE(n,this.trackStartLines,this.config.lineTerminatorCharacters))})),n.modes=n.modes?n.modes:{},K(n.modes,(o,l)=>{n.modes[l]=fu(o,u=>Cr(u))});const s=Tt(n.modes);if(K(n.modes,(o,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(YA(o,s))}),me(this.lexerDefinitionErrors)){si(o);let u;this.TRACE_INIT("analyzeTokenTypes",()=>{u=HA(o,{lineTerminatorCharacters:this.config.lineTerminatorCharacters,positionTracking:t.positionTracking,ensureOptimizations:t.ensureOptimizations,safeMode:t.safeMode,tracer:this.TRACE_INIT})}),this.patternIdxToConfig[l]=u.patternIdxToConfig,this.charCodeToPatternIdxToConfig[l]=u.charCodeToPatternIdxToConfig,this.emptyGroups=$t({},this.emptyGroups,u.emptyGroups),this.hasCustom=u.hasCustom||this.hasCustom,this.canModeBeOptimized[l]=u.canBeOptimized}})}),this.defaultMode=n.defaultMode,!me(this.lexerDefinitionErrors)&&!this.config.deferDefinitionErrorsHandling){const l=F(this.lexerDefinitionErrors,u=>u.message).join(`----------------------- +`);throw new Error(`Errors detected in definition of Lexer: +`+l)}K(this.lexerDefinitionWarning,o=>{qp(o.message)}),this.TRACE_INIT("Choosing sub-methods implementations",()=>{if(a&&(this.handleModes=Fe),this.trackStartLines===!1&&(this.computeNewColumn=Ks),this.trackEndLines===!1&&(this.updateTokenEndLineColumnLocation=Fe),/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 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 o=Rt(this.canModeBeOptimized,(l,u,c)=>(u===!1&&l.push(c),l),[]);if(t.ensureOptimizations&&!me(o))throw Error(`Lexer Modes: < ${o.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",()=>{KA()}),this.TRACE_INIT("toFastProperties",()=>{Hp(this)})})}tokenize(e,t=this.defaultMode){if(!me(this.lexerDefinitionErrors)){const n=F(this.lexerDefinitionErrors,a=>a.message).join(`----------------------- +`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer: +`+n)}return this.tokenizeInternal(e,t)}tokenizeInternal(e,t){let r,n,a,s,o,l,u,c,f,d,m,g,v,b,S;const w=e,I=w.length;let R=0,P=0;const z=this.hasCustom?0:Math.floor(e.length/10),X=new Array(z),Z=[];let ce=this.trackStartLines?1:void 0,se=this.trackStartLines?1:void 0;const Se=dE(this.emptyGroups),k=this.trackStartLines,C=this.config.lineTerminatorsPattern;let y=0,E=[],T=[];const $=[],_=[];Object.freeze(_);let O=!1;const x=i(Y=>{if($.length===1&&Y.tokenType.PUSH_MODE===void 0){const q=this.config.errorMessageProvider.buildUnableToPopLexerModeMessage(Y);Z.push({offset:Y.startOffset,line:Y.startLine,column:Y.startColumn,length:Y.image.length,message:q})}else{$.pop();const q=Pn($);E=this.patternIdxToConfig[q],T=this.charCodeToPatternIdxToConfig[q],y=E.length;const Pe=this.canModeBeOptimized[q]&&this.config.safeMode===!1;T&&Pe?O=!0:O=!1}},"pop_mode");function D(Y){$.push(Y),T=this.charCodeToPatternIdxToConfig[Y],E=this.patternIdxToConfig[Y],y=E.length,y=E.length;const q=this.canModeBeOptimized[Y]&&this.config.safeMode===!1;T&&q?O=!0:O=!1}i(D,"push_mode"),D.call(this,t);let G;const W=this.config.recoveryEnabled;for(;Rl.length){l=s,f=s.length,u=c,G=ke;break}}}break}}if(f!==-1){if(d=G.group,d!==void 0&&(l=l!==null?l:e.substring(R,R+f),m=G.tokenTypeIdx,g=this.createTokenInstance(l,R,m,G.tokenType,ce,se,f),this.handlePayload(g,u),d===!1?P=this.addToken(X,P,g):Se[d].push(g)),k===!0&&G.canLineTerminator===!0){let oe=0,Le,De;C.lastIndex=0;do l=l!==null?l:e.substring(R,R+f),Le=C.test(l),Le===!0&&(De=C.lastIndex-1,oe++);while(Le===!0);oe!==0?(ce=ce+oe,se=f-De,this.updateTokenEndLineColumnLocation(g,d,De,oe,ce,se,f)):se=this.computeNewColumn(se,f)}else se=this.computeNewColumn(se,f);R=R+f,this.handleModes(G,x,D,g)}else{const oe=R,Le=ce,De=se;let ke=W===!1;for(;ke===!1&&R ${wn(e)} <--`:`token of type --> ${e.name} <--`} but found --> '${t.image}' <--`},buildNotAllInputParsedMessage({firstRedundant:e,ruleName:t}){return"Redundant input, expecting EOF but found: "+e.image},buildNoViableAltMessage({expectedPathsPerAlt:e,actual:t,previous:r,customUserDescription:n,ruleName:a}){const s="Expecting: ",l=` +but found: '`+jt(t).image+"'";if(n)return s+n+l;{const u=Rt(e,(m,g)=>m.concat(g),[]),c=F(u,m=>`[${F(m,g=>wn(g)).join(", ")}]`),d=`one of these possible Token sequences: +${F(c,(m,g)=>` ${g+1}. ${m}`).join(` +`)}`;return s+d+l}},buildEarlyExitMessage({expectedIterationPaths:e,actual:t,customUserDescription:r,ruleName:n}){const a="Expecting: ",o=` +but found: '`+jt(t).image+"'";if(r)return a+r+o;{const u=`expecting at least one iteration which starts with one of these possible Token sequences:: + <${F(e,c=>`[${F(c,f=>wn(f)).join(",")}]`).join(" ,")}>`;return a+u+o}}};Object.freeze(Ma);var kD={buildRuleNotFoundError(e,t){return"Invalid grammar, reference to a rule which is not defined: ->"+t.nonTerminalName+`<- +inside top level rule: ->`+e.name+"<-"}},bn={buildDuplicateFoundError(e,t){function r(f){return f instanceof ve?f.terminalType.name:f instanceof it?f.nonTerminalName:""}i(r,"getExtraProductionArgument");const n=e.name,a=jt(t),s=a.idx,o=Lt(a),l=r(a),u=s>0;let c=`->${o}${u?s:""}<- ${l?`with argument: ->${l}<-`:""} + appears more than once (${t.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(e){return`Namespace conflict found in grammar. +The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <${e.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(e){const t=F(e.prefixPath,a=>wn(a)).join(", "),r=e.alternation.idx===0?"":e.alternation.idx;return`Ambiguous alternatives: <${e.ambiguityIndices.join(" ,")}> due to common lookahead prefix +in inside <${e.topLevelRule.name}> Rule, +<${t}> 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(e){const t=e.alternation.idx===0?"":e.alternation.idx,r=e.prefixPath.length===0;let n=`Ambiguous Alternatives Detected: <${e.ambiguityIndices.join(" ,")}> in inside <${e.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=F(e.prefixPath,s=>wn(s)).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(e){let t=Lt(e.repetition);return e.repetition.idx!==0&&(t+=e.repetition.idx),`The repetition <${t}> within Rule <${e.topLevelRule.name}> can never consume any tokens. +This could lead to an infinite loop.`},buildTokenNameError(e){return"deprecated"},buildEmptyAlternationError(e){return`Ambiguous empty alternative: <${e.emptyChoiceIdx+1}> in inside <${e.topLevelRule.name}> Rule. +Only the last alternative may be an empty alternative.`},buildTooManyAlternativesError(e){return`An Alternation cannot have more than 256 alternatives: + inside <${e.topLevelRule.name}> Rule. + has ${e.alternation.definition.length+1} alternatives.`},buildLeftRecursionError(e){const t=e.topLevelRule.name,r=F(e.leftRecursionPath,s=>s.name),n=`${t} --> ${r.concat([t]).join(" --> ")}`;return`Left Recursion found in grammar. +rule: <${t}> 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(e){return"deprecated"},buildDuplicateRuleNameError(e){let t;return e.topLevelRule instanceof ri?t=e.topLevelRule.name:t=e.topLevelRule,`Duplicate definition, rule: ->${t}<- is already defined in the grammar: ->${e.grammarName}<-`}};function bE(e,t){const r=new OD(e,t);return r.resolveRefs(),r.errors}i(bE,"resolveGrammar");var OD=class extends ni{static{i(this,"GastRefResolverVisitor")}constructor(e,t){super(),this.nameToTopRule=e,this.errMsgProvider=t,this.errors=[]}resolveRefs(){K(Me(this.nameToTopRule),e=>{this.currTopLevel=e,e.accept(this)})}visitNonTerminal(e){const t=this.nameToTopRule[e.nonTerminalName];if(t)e.referencedRule=t;else{const r=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,e);this.errors.push({message:r,type:st.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:e.nonTerminalName})}}},LD=class extends du{static{i(this,"AbstractNextPossibleTokensWalker")}constructor(e,t){super(),this.topProd=e,this.path=t,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=Ye(this.path.ruleStack).reverse(),this.occurrenceStack=Ye(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes}walk(e,t=[]){this.found||super.walk(e,t)}walkProdRef(e,t,r){if(e.referencedRule.name===this.nextProductionName&&e.idx===this.nextProductionOccurrence){const n=t.concat(r);this.updateExpectedNext(),this.walk(e.referencedRule,n)}}updateExpectedNext(){me(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())}},DD=class extends LD{static{i(this,"NextAfterTokenWalker")}constructor(e,t){super(e,t),this.path=t,this.nextTerminalName="",this.nextTerminalOccurrence=0,this.nextTerminalName=this.path.lastTok.name,this.nextTerminalOccurrence=this.path.lastTokOccurrence}walkTerminal(e,t,r){if(this.isAtEndOfPath&&e.terminalType.name===this.nextTerminalName&&e.idx===this.nextTerminalOccurrence&&!this.found){const n=t.concat(r),a=new mt({definition:n});this.possibleTokTypes=ai(a),this.found=!0}}},mu=class extends du{static{i(this,"AbstractNextTerminalAfterProductionWalker")}constructor(e,t){super(),this.topRule=e,this.occurrence=t,this.result={token:void 0,occurrence:void 0,isEndOfRule:void 0}}startWalking(){return this.walk(this.topRule),this.result}},xD=class extends mu{static{i(this,"NextTerminalAfterManyWalker")}walkMany(e,t,r){if(e.idx===this.occurrence){const n=jt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkMany(e,t,r)}},Qh=class extends mu{static{i(this,"NextTerminalAfterManySepWalker")}walkManySep(e,t,r){if(e.idx===this.occurrence){const n=jt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkManySep(e,t,r)}},MD=class extends mu{static{i(this,"NextTerminalAfterAtLeastOneWalker")}walkAtLeastOne(e,t,r){if(e.idx===this.occurrence){const n=jt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkAtLeastOne(e,t,r)}},ey=class extends mu{static{i(this,"NextTerminalAfterAtLeastOneSepWalker")}walkAtLeastOneSep(e,t,r){if(e.idx===this.occurrence){const n=jt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkAtLeastOneSep(e,t,r)}};function vl(e,t,r=[]){r=Ye(r);let n=[],a=0;function s(l){return l.concat(Ve(e,a+1))}i(s,"remainingPathWith");function o(l){const u=vl(s(l),t,r);return n.concat(u)}for(i(o,"getAlternativesForProd");r.length{me(u.definition)===!1&&(n=o(u.definition))}),n;if(l instanceof ve)r.push(l.terminalType);else throw Error("non exhaustive match")}a++}return n.push({partialPath:r,suffixDef:Ve(e,a)}),n}i(vl,"possiblePathsFrom");function rm(e,t,r,n){const a="EXIT_NONE_TERMINAL",s=[a],o="EXIT_ALTERNATIVE";let l=!1;const u=t.length,c=u-n-1,f=[],d=[];for(d.push({idx:-1,def:e,ruleStack:[],occurrenceStack:[]});!me(d);){const m=d.pop();if(m===o){l&&Pn(d).idx<=c&&d.pop();continue}const g=m.def,v=m.idx,b=m.ruleStack,S=m.occurrenceStack;if(me(g))continue;const w=g[0];if(w===a){const I={idx:v,def:Ve(g),ruleStack:Cs(b),occurrenceStack:Cs(S)};d.push(I)}else if(w instanceof ve)if(v=0;I--){const R=w.definition[I],P={idx:v,def:R.definition.concat(Ve(g)),ruleStack:b,occurrenceStack:S};d.push(P),d.push(o)}else if(w instanceof mt)d.push({idx:v,def:w.definition.concat(Ve(g)),ruleStack:b,occurrenceStack:S});else if(w instanceof ri)d.push(_E(w,v,b,S));else throw Error("non exhaustive match")}return f}i(rm,"nextPossibleTokensAfter");function _E(e,t,r,n){const a=Ye(r);a.push(e.name);const s=Ye(n);return s.push(1),{idx:t,def:e.definition,ruleStack:a,occurrenceStack:s}}i(_E,"expandTopLevelRule");var Re;(function(e){e[e.OPTION=0]="OPTION",e[e.REPETITION=1]="REPETITION",e[e.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",e[e.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",e[e.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",e[e.ALTERNATION=5]="ALTERNATION"})(Re||(Re={}));function hu(e){if(e instanceof He||e==="Option")return Re.OPTION;if(e instanceof be||e==="Repetition")return Re.REPETITION;if(e instanceof At||e==="RepetitionMandatory")return Re.REPETITION_MANDATORY;if(e instanceof Et||e==="RepetitionMandatoryWithSeparator")return Re.REPETITION_MANDATORY_WITH_SEPARATOR;if(e instanceof ht||e==="RepetitionWithSeparator")return Re.REPETITION_WITH_SEPARATOR;if(e instanceof yt||e==="Alternation")return Re.ALTERNATION;throw Error("non exhaustive match")}i(hu,"getProdType");function Of(e){const{occurrence:t,rule:r,prodType:n,maxLookahead:a}=e,s=hu(n);return s===Re.ALTERNATION?Qs(t,r,a):eo(t,r,s,a)}i(Of,"getLookaheadPaths");function SE(e,t,r,n,a,s){const o=Qs(e,t,r),l=am(o)?_s:ii;return s(o,n,l,a)}i(SE,"buildLookaheadFuncForOr");function wE(e,t,r,n,a,s){const o=eo(e,t,a,r),l=am(o)?_s:ii;return s(o[0],l,n)}i(wE,"buildLookaheadFuncForOptionalProd");function IE(e,t,r,n){const a=e.length,s=Ft(e,o=>Ft(o,l=>l.length===1));if(t)return function(o){const l=F(o,u=>u.GATE);for(let u=0;uGt(u)),l=Rt(o,(u,c,f)=>(K(c,d=>{B(u,d.tokenTypeIdx)||(u[d.tokenTypeIdx]=f),K(d.categoryMatches,m=>{B(u,m)||(u[m]=f)})}),u),{});return function(){const u=this.LA(1);return l[u.tokenTypeIdx]}}else return function(){for(let o=0;os.length===1),a=e.length;if(n&&!r){const s=Gt(e);if(s.length===1&&me(s[0].categoryMatches)){const l=s[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===l}}else{const o=Rt(s,(l,u,c)=>(l[u.tokenTypeIdx]=!0,K(u.categoryMatches,f=>{l[f]=!0}),l),[]);return function(){const l=this.LA(1);return o[l.tokenTypeIdx]===!0}}}else return function(){e:for(let s=0;svl([o],1)),n=Lf(r.length),a=F(r,o=>{const l={};return K(o,u=>{const c=Do(u.partialPath);K(c,f=>{l[f]=!0})}),l});let s=r;for(let o=1;o<=t;o++){const l=s;s=Lf(l.length);for(let u=0;u{const w=Do(S.partialPath);K(w,I=>{a[u][I]=!0})})}}}}return n}i(nm,"lookAheadSequenceFromAlternatives");function Qs(e,t,r,n){const a=new PE(e,Re.ALTERNATION,n);return t.accept(a),nm(a.result,r)}i(Qs,"getLookaheadPathsForOr");function eo(e,t,r,n){const a=new PE(e,r);t.accept(a);const s=a.result,l=new GD(t,e,r).startWalking(),u=new mt({definition:s}),c=new mt({definition:l});return nm([u,c],n)}i(eo,"getLookaheadPathsForOptionalProd");function Tl(e,t){e:for(let r=0;r{const a=t[n];return r===a||a.categoryMatchesMap[r.tokenTypeIdx]})}i(OE,"isStrictPrefixOfPath");function am(e){return Ft(e,t=>Ft(t,r=>Ft(r,n=>me(n.categoryMatches))))}i(am,"areTokenCategoriesNotUsed");function LE(e){const t=e.lookaheadStrategy.validate({rules:e.rules,tokenTypes:e.tokenTypes,grammarName:e.grammarName});return F(t,r=>Object.assign({type:st.CUSTOM_LOOKAHEAD_VALIDATION},r))}i(LE,"validateLookahead");function DE(e,t,r,n){const a=_t(e,u=>xE(u,r)),s=qE(e,t,r),o=_t(e,u=>BE(u,r)),l=_t(e,u=>GE(u,e,n,r));return a.concat(s,o,l)}i(DE,"validateGrammar");function xE(e,t){const r=new FD;e.accept(r);const n=r.allProductions,a=QL(n,ME),s=Bt(a,l=>l.length>1);return F(Me(s),l=>{const u=jt(l),c=t.buildDuplicateFoundError(e,l),f=Lt(u),d={message:c,type:st.DUPLICATE_PRODUCTIONS,ruleName:e.name,dslName:f,occurrence:u.idx},m=im(u);return m&&(d.parameter=m),d})}i(xE,"validateDuplicateProductions");function ME(e){return`${Lt(e)}_#_${e.idx}_#_${im(e)}`}i(ME,"identifyProductionForDuplicates");function im(e){return e instanceof ve?e.terminalType.name:e instanceof it?e.nonTerminalName:""}i(im,"getExtraProductionArgument");var FD=class extends ni{static{i(this,"OccurrenceValidationCollector")}constructor(){super(...arguments),this.allProductions=[]}visitNonTerminal(e){this.allProductions.push(e)}visitOption(e){this.allProductions.push(e)}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}visitAlternation(e){this.allProductions.push(e)}visitTerminal(e){this.allProductions.push(e)}};function GE(e,t,r,n){const a=[];if(Rt(t,(o,l)=>l.name===e.name?o+1:o,0)>1){const o=n.buildDuplicateRuleNameError({topLevelRule:e,grammarName:r});a.push({message:o,type:st.DUPLICATE_RULE_NAME,ruleName:e.name})}return a}i(GE,"validateRuleDoesNotAlreadyExist");function FE(e,t,r){const n=[];let a;return lt(t,e)||(a=`Invalid rule override, rule: ->${e}<- cannot be overridden in the grammar: ->${r}<-as it is not defined in any of the super grammars `,n.push({message:a,type:st.INVALID_RULE_OVERRIDE,ruleName:e})),n}i(FE,"validateRuleIsOverridden");function sm(e,t,r,n=[]){const a=[],s=ms(t.definition);if(me(s))return[];{const o=e.name;lt(s,e)&&a.push({message:r.buildLeftRecursionError({topLevelRule:e,leftRecursionPath:n}),type:st.LEFT_RECURSION,ruleName:o});const u=cu(s,n.concat([e])),c=_t(u,f=>{const d=Ye(n);return d.push(f),sm(e,f,r,d)});return a.concat(c)}}i(sm,"validateNoLeftRecursion");function ms(e){let t=[];if(me(e))return t;const r=jt(e);if(r instanceof it)t.push(r.referencedRule);else if(r instanceof mt||r instanceof He||r instanceof At||r instanceof Et||r instanceof ht||r instanceof be)t=t.concat(ms(r.definition));else if(r instanceof yt)t=Gt(F(r.definition,s=>ms(s.definition)));else if(!(r instanceof ve))throw Error("non exhaustive match");const n=bs(r),a=e.length>1;if(n&&a){const s=Ve(e);return t.concat(ms(s))}else return t}i(ms,"getFirstNoneTerminal");var om=class extends ni{static{i(this,"OrCollector")}constructor(){super(...arguments),this.alternations=[]}visitAlternation(e){this.alternations.push(e)}};function zE(e,t){const r=new om;e.accept(r);const n=r.alternations;return _t(n,s=>{const o=Cs(s.definition);return _t(o,(l,u)=>{const c=rm([l],[],ii,1);return me(c)?[{message:t.buildEmptyAlternationError({topLevelRule:e,alternation:s,emptyChoiceIdx:u}),type:st.NONE_LAST_EMPTY_ALT,ruleName:e.name,occurrence:s.idx,alternative:u+1}]:[]})})}i(zE,"validateEmptyOrAlternative");function jE(e,t,r){const n=new om;e.accept(n);let a=n.alternations;return a=fu(a,o=>o.ignoreAmbiguities===!0),_t(a,o=>{const l=o.idx,u=o.maxLookahead||t,c=Qs(l,e,u,o),f=KE(c,o,e,r),d=WE(c,o,e,r);return f.concat(d)})}i(jE,"validateAmbiguousAlternationAlternatives");var zD=class extends ni{static{i(this,"RepetitionCollector")}constructor(){super(...arguments),this.allProductions=[]}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}};function BE(e,t){const r=new om;e.accept(r);const n=r.alternations;return _t(n,s=>s.definition.length>255?[{message:t.buildTooManyAlternativesError({topLevelRule:e,alternation:s}),type:st.TOO_MANY_ALTS,ruleName:e.name,occurrence:s.idx}]:[])}i(BE,"validateTooManyAlts");function UE(e,t,r){const n=[];return K(e,a=>{const s=new zD;a.accept(s);const o=s.allProductions;K(o,l=>{const u=hu(l),c=l.maxLookahead||t,f=l.idx,m=eo(f,a,u,c)[0];if(me(Gt(m))){const g=r.buildEmptyRepetitionError({topLevelRule:a,repetition:l});n.push({message:g,type:st.NO_NON_EMPTY_LOOKAHEAD,ruleName:a.name})}})}),n}i(UE,"validateSomeNonEmptyLookaheadPath");function KE(e,t,r,n){const a=[],s=Rt(e,(l,u,c)=>(t.definition[c].ignoreAmbiguities===!0||K(u,f=>{const d=[c];K(e,(m,g)=>{c!==g&&Tl(m,f)&&t.definition[g].ignoreAmbiguities!==!0&&d.push(g)}),d.length>1&&!Tl(a,f)&&(a.push(f),l.push({alts:d,path:f}))}),l),[]);return F(s,l=>{const u=F(l.alts,f=>f+1);return{message:n.buildAlternationAmbiguityError({topLevelRule:r,alternation:t,ambiguityIndices:u,prefixPath:l.path}),type:st.AMBIGUOUS_ALTS,ruleName:r.name,occurrence:t.idx,alternatives:l.alts}})}i(KE,"checkAlternativesAmbiguities");function WE(e,t,r,n){const a=Rt(e,(o,l,u)=>{const c=F(l,f=>({idx:u,path:f}));return o.concat(c)},[]);return Xs(_t(a,o=>{if(t.definition[o.idx].ignoreAmbiguities===!0)return[];const u=o.idx,c=o.path,f=Nt(a,m=>t.definition[m.idx].ignoreAmbiguities!==!0&&m.idx{const g=[m.idx+1,u+1],v=t.idx===0?"":t.idx;return{message:n.buildAlternationPrefixAmbiguityError({topLevelRule:r,alternation:t,ambiguityIndices:g,prefixPath:m.path}),type:st.AMBIGUOUS_PREFIX_ALTS,ruleName:r.name,occurrence:v,alternatives:g}})}))}i(WE,"checkPrefixAlternativesAmbiguities");function qE(e,t,r){const n=[],a=F(t,s=>s.name);return K(e,s=>{const o=s.name;if(lt(a,o)){const l=r.buildNamespaceConflictError(s);n.push({message:l,type:st.CONFLICT_TOKENS_RULES_NAMESPACE,ruleName:o})}}),n}i(qE,"checkTerminalAndNoneTerminalsNameSpace");function VE(e){const t=Kp(e,{errMsgProvider:kD}),r={};return K(e.rules,n=>{r[n.name]=n}),bE(r,t.errMsgProvider)}i(VE,"resolveGrammar");function HE(e){return e=Kp(e,{errMsgProvider:bn}),DE(e.rules,e.tokenTypes,e.errMsgProvider,e.grammarName)}i(HE,"validateGrammar");var YE="MismatchedTokenException",XE="NoViableAltException",JE="EarlyExitException",ZE="NotAllInputParsedException",QE=[YE,XE,JE,ZE];Object.freeze(QE);function Ss(e){return lt(QE,e.name)}i(Ss,"isRecognitionException");var yu=class extends Error{static{i(this,"RecognitionException")}constructor(e,t){super(e),this.token=t,this.resyncedTokens=[],Object.setPrototypeOf(this,new.target.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},eC=class extends yu{static{i(this,"MismatchedTokenException")}constructor(e,t,r){super(e,t),this.previousToken=r,this.name=YE}},jD=class extends yu{static{i(this,"NoViableAltException")}constructor(e,t,r){super(e,t),this.previousToken=r,this.name=XE}},BD=class extends yu{static{i(this,"NotAllInputParsedException")}constructor(e,t){super(e,t),this.name=ZE}},UD=class extends yu{static{i(this,"EarlyExitException")}constructor(e,t,r){super(e,t),this.previousToken=r,this.name=JE}},Vu={},tC="InRuleRecoveryException",KD=class extends Error{static{i(this,"InRuleRecoveryException")}constructor(e){super(e),this.name=tC}},WD=class{static{i(this,"Recoverable")}initRecoverable(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=B(e,"recoveryEnabled")?e.recoveryEnabled:_r.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=rC)}getTokenToInsert(e){const t=Zs(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return t.isInsertedInRecovery=!0,t}canTokenTypeBeInsertedInRecovery(e){return!0}canTokenTypeBeDeletedInRecovery(e){return!0}tryInRepetitionRecovery(e,t,r,n){const a=this.findReSyncTokenType(),s=this.exportLexerState(),o=[];let l=!1;const u=this.LA(1);let c=this.LA(1);const f=i(()=>{const d=this.LA(0),m=this.errorMessageProvider.buildMismatchTokenMessage({expected:n,actual:u,previous:d,ruleName:this.getCurrRuleFullName()}),g=new eC(m,u,this.LA(0));g.resyncedTokens=Cs(o),this.SAVE_ERROR(g)},"generateErrorMessage");for(;!l;)if(this.tokenMatcher(c,n)){f();return}else if(r.call(this)){f(),e.apply(this,t);return}else this.tokenMatcher(c,a)?l=!0:(c=this.SKIP_TOKEN(),this.addToResyncTokens(c,o));this.importLexerState(s)}shouldInRepetitionRecoveryBeTried(e,t,r){return!(r===!1||this.tokenMatcher(this.LA(1),e)||this.isBackTracking()||this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,t)))}getFollowsForInRuleRecovery(e,t){const r=this.getCurrentGrammarPath(e,t);return this.getNextPossibleTokenTypes(r)}tryInRuleRecovery(e,t){if(this.canRecoverWithSingleTokenInsertion(e,t))return this.getTokenToInsert(e);if(this.canRecoverWithSingleTokenDeletion(e)){const r=this.SKIP_TOKEN();return this.consumeToken(),r}throw new KD("sad sad panda")}canPerformInRuleRecovery(e,t){return this.canRecoverWithSingleTokenInsertion(e,t)||this.canRecoverWithSingleTokenDeletion(e)}canRecoverWithSingleTokenInsertion(e,t){if(!this.canTokenTypeBeInsertedInRecovery(e)||me(t))return!1;const r=this.LA(1);return Xa(t,a=>this.tokenMatcher(r,a))!==void 0}canRecoverWithSingleTokenDeletion(e){return this.canTokenTypeBeDeletedInRecovery(e)?this.tokenMatcher(this.LA(2),e):!1}isInCurrentRuleReSyncSet(e){const t=this.getCurrFollowKey(),r=this.getFollowSetFromFollowKey(t);return lt(r,e)}findReSyncTokenType(){const e=this.flattenFollowSet();let t=this.LA(1),r=2;for(;;){const n=Xa(e,a=>tm(t,a));if(n!==void 0)return n;t=this.LA(r),r++}}getCurrFollowKey(){if(this.RULE_STACK.length===1)return Vu;const e=this.getLastExplicitRuleShortName(),t=this.getLastExplicitRuleOccurrenceIndex(),r=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:t,inRule:this.shortRuleNameToFullName(r)}}buildFullFollowKeyStack(){const e=this.RULE_STACK,t=this.RULE_OCCURRENCE_STACK;return F(e,(r,n)=>n===0?Vu:{ruleName:this.shortRuleNameToFullName(r),idxInCallingRule:t[n],inRule:this.shortRuleNameToFullName(e[n-1])})}flattenFollowSet(){const e=F(this.buildFullFollowKeyStack(),t=>this.getFollowSetFromFollowKey(t));return Gt(e)}getFollowSetFromFollowKey(e){if(e===Vu)return[Br];const t=e.ruleName+e.idxInCallingRule+jA+e.inRule;return this.resyncFollows[t]}addToResyncTokens(e,t){return this.tokenMatcher(e,Br)||t.push(e),t}reSyncTo(e){const t=[];let r=this.LA(1);for(;this.tokenMatcher(r,e)===!1;)r=this.SKIP_TOKEN(),this.addToResyncTokens(r,t);return Cs(t)}attemptInRepetitionRecovery(e,t,r,n,a,s,o){}getCurrentGrammarPath(e,t){const r=this.getHumanReadableRuleStack(),n=Ye(this.RULE_OCCURRENCE_STACK);return{ruleStack:r,occurrenceStack:n,lastTok:e,lastTokOccurrence:t}}getHumanReadableRuleStack(){return F(this.RULE_STACK,e=>this.shortRuleNameToFullName(e))}};function rC(e,t,r,n,a,s,o){const l=this.getKeyForAutomaticLookahead(n,a);let u=this.firstAfterRepMap[l];if(u===void 0){const m=this.getCurrRuleFullName(),g=this.getGAstProductions()[m];u=new s(g,a).startWalking(),this.firstAfterRepMap[l]=u}let c=u.token,f=u.occurrence;const d=u.isEndOfRule;this.RULE_STACK.length===1&&d&&c===void 0&&(c=Br,f=1),!(c===void 0||f===void 0)&&this.shouldInRepetitionRecoveryBeTried(c,f,o)&&this.tryInRepetitionRecovery(e,t,r,c)}i(rC,"attemptInRepetitionRecovery");var qD=4,Hr=8,nC=1<sm(t,t,bn))}validateEmptyOrAlternatives(e){return _t(e,t=>zE(t,bn))}validateAmbiguousAlternationAlternatives(e,t){return _t(e,r=>jE(r,t,bn))}validateSomeNonEmptyLookaheadPath(e,t){return UE(e,t,bn)}buildLookaheadForAlternation(e){return SE(e.prodOccurrence,e.rule,e.maxLookahead,e.hasPredicates,e.dynamicTokensEnabled,IE)}buildLookaheadForOptional(e){return wE(e.prodOccurrence,e.rule,e.maxLookahead,e.dynamicTokensEnabled,hu(e.prodType),NE)}},VD=class{static{i(this,"LooksAhead")}initLooksAhead(e){this.dynamicTokensEnabled=B(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:_r.dynamicTokensEnabled,this.maxLookahead=B(e,"maxLookahead")?e.maxLookahead:_r.maxLookahead,this.lookaheadStrategy=B(e,"lookaheadStrategy")?e.lookaheadStrategy:new lm({maxLookahead:this.maxLookahead}),this.lookAheadFuncsCache=new Map}preComputeLookaheadFunctions(e){K(e,t=>{this.TRACE_INIT(`${t.name} Rule Lookahead`,()=>{const{alternation:r,repetition:n,option:a,repetitionMandatory:s,repetitionMandatoryWithSeparator:o,repetitionWithSeparator:l}=iC(t);K(r,u=>{const c=u.idx===0?"":u.idx;this.TRACE_INIT(`${Lt(u)}${c}`,()=>{const f=this.lookaheadStrategy.buildLookaheadForAlternation({prodOccurrence:u.idx,rule:t,maxLookahead:u.maxLookahead||this.maxLookahead,hasPredicates:u.hasPredicates,dynamicTokensEnabled:this.dynamicTokensEnabled}),d=Mo(this.fullRuleNameToShort[t.name],nC,u.idx);this.setLaFuncCache(d,f)})}),K(n,u=>{this.computeLookaheadFunc(t,u.idx,Df,"Repetition",u.maxLookahead,Lt(u))}),K(a,u=>{this.computeLookaheadFunc(t,u.idx,aC,"Option",u.maxLookahead,Lt(u))}),K(s,u=>{this.computeLookaheadFunc(t,u.idx,xf,"RepetitionMandatory",u.maxLookahead,Lt(u))}),K(o,u=>{this.computeLookaheadFunc(t,u.idx,xo,"RepetitionMandatoryWithSeparator",u.maxLookahead,Lt(u))}),K(l,u=>{this.computeLookaheadFunc(t,u.idx,Mf,"RepetitionWithSeparator",u.maxLookahead,Lt(u))})})})}computeLookaheadFunc(e,t,r,n,a,s){this.TRACE_INIT(`${s}${t===0?"":t}`,()=>{const o=this.lookaheadStrategy.buildLookaheadForOptional({prodOccurrence:t,rule:e,maxLookahead:a||this.maxLookahead,dynamicTokensEnabled:this.dynamicTokensEnabled,prodType:n}),l=Mo(this.fullRuleNameToShort[e.name],r,t);this.setLaFuncCache(l,o)})}getKeyForAutomaticLookahead(e,t){const r=this.getLastExplicitRuleShortName();return Mo(r,e,t)}getLaFuncFromCache(e){return this.lookAheadFuncsCache.get(e)}setLaFuncCache(e,t){this.lookAheadFuncsCache.set(e,t)}},HD=class extends ni{static{i(this,"DslMethodsCollectorVisitor")}constructor(){super(...arguments),this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}reset(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}visitOption(e){this.dslMethods.option.push(e)}visitRepetitionWithSeparator(e){this.dslMethods.repetitionWithSeparator.push(e)}visitRepetitionMandatory(e){this.dslMethods.repetitionMandatory.push(e)}visitRepetitionMandatoryWithSeparator(e){this.dslMethods.repetitionMandatoryWithSeparator.push(e)}visitRepetition(e){this.dslMethods.repetition.push(e)}visitAlternation(e){this.dslMethods.alternation.push(e)}},so=new HD;function iC(e){so.reset(),e.accept(so);const t=so.dslMethods;return so.reset(),t}i(iC,"collectMethods");function Gf(e,t){isNaN(e.startOffset)===!0?(e.startOffset=t.startOffset,e.endOffset=t.endOffset):e.endOffseto.msg);throw Error(`Errors Detected in CST Visitor <${this.constructor.name}>: + ${s.join(` + +`).replace(/\n/g,` + `)}`)}},"validateVisitor")};return r.prototype=n,r.prototype.constructor=r,r._RULE_NAMES=t,r}i(uC,"createBaseSemanticVisitorConstructor");function cC(e,t,r){const n=i(function(){},"derivedConstructor");um(n,e+"BaseSemanticsWithDefaults");const a=Object.create(r.prototype);return K(t,s=>{a[s]=lC}),n.prototype=a,n.prototype.constructor=n,n}i(cC,"createBaseVisitorConstructorWithDefaults");var zf;(function(e){e[e.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",e[e.MISSING_METHOD=1]="MISSING_METHOD"})(zf||(zf={}));function fC(e,t){return dC(e,t)}i(fC,"validateVisitor");function dC(e,t){const r=Nt(t,a=>Nr(e[a])===!1),n=F(r,a=>({msg:`Missing visitor method: <${a}> on ${e.constructor.name} CST Visitor.`,type:zf.MISSING_METHOD,methodName:a}));return Xs(n)}i(dC,"validateMissingCstMethods");var XD=class{static{i(this,"TreeBuilder")}initTreeBuilder(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=B(e,"nodeLocationTracking")?e.nodeLocationTracking:_r.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=Fe,this.cstFinallyStateUpdate=Fe,this.cstPostTerminal=Fe,this.cstPostNonTerminal=Fe,this.cstPostRule=Fe;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=Ff,this.setNodeLocationFromNode=Ff,this.cstPostRule=Fe,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=Fe,this.setNodeLocationFromNode=Fe,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=Gf,this.setNodeLocationFromNode=Gf,this.cstPostRule=Fe,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=Fe,this.setNodeLocationFromNode=Fe,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=Fe,this.setNodeLocationFromNode=Fe,this.cstPostRule=Fe,this.setInitialNodeLocation=Fe;else throw Error(`Invalid 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 t=this.LA(1);e.location={startOffset:t.startOffset,startLine:t.startLine,startColumn:t.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}}cstInvocationStateUpdate(e){const t={name:e,children:Object.create(null)};this.setInitialNodeLocation(t),this.CST_STACK.push(t)}cstFinallyStateUpdate(){this.CST_STACK.pop()}cstPostRuleFull(e){const t=this.LA(0),r=e.location;r.startOffset<=t.startOffset?(r.endOffset=t.endOffset,r.endLine=t.endLine,r.endColumn=t.endColumn):(r.startOffset=NaN,r.startLine=NaN,r.startColumn=NaN)}cstPostRuleOnlyOffset(e){const t=this.LA(0),r=e.location;r.startOffset<=t.startOffset?r.endOffset=t.endOffset:r.startOffset=NaN}cstPostTerminal(e,t){const r=this.CST_STACK[this.CST_STACK.length-1];sC(r,t,e),this.setNodeLocationFromToken(r.location,t)}cstPostNonTerminal(e,t){const r=this.CST_STACK[this.CST_STACK.length-1];oC(r,t,e),this.setNodeLocationFromNode(r.location,e.location)}getBaseCstVisitorConstructor(){if(Cr(this.baseCstVisitorConstructor)){const e=uC(this.className,Tt(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor}getBaseCstVisitorConstructorWithDefaults(){if(Cr(this.baseCstVisitorWithDefaultsConstructor)){const e=cC(this.className,Tt(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]}},JD=class{static{i(this,"LexerAdapter")}initLexerAdapter(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1}set input(e){if(this.selfAnalysisDone!==!0)throw Error("Missing 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)):$l}LA(e){const t=this.currIdx+e;return t<0||this.tokVectorLength<=t?$l:this.tokVector[t]}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()}},ZD=class{static{i(this,"RecognizerApi")}ACTION(e){return e.call(this)}consume(e,t,r){return this.consumeInternal(t,e,r)}subrule(e,t,r){return this.subruleInternal(t,e,r)}option(e,t){return this.optionInternal(t,e)}or(e,t){return this.orInternal(t,e)}many(e,t){return this.manyInternal(e,t)}atLeastOne(e,t){return this.atLeastOneInternal(e,t)}CONSUME(e,t){return this.consumeInternal(e,0,t)}CONSUME1(e,t){return this.consumeInternal(e,1,t)}CONSUME2(e,t){return this.consumeInternal(e,2,t)}CONSUME3(e,t){return this.consumeInternal(e,3,t)}CONSUME4(e,t){return this.consumeInternal(e,4,t)}CONSUME5(e,t){return this.consumeInternal(e,5,t)}CONSUME6(e,t){return this.consumeInternal(e,6,t)}CONSUME7(e,t){return this.consumeInternal(e,7,t)}CONSUME8(e,t){return this.consumeInternal(e,8,t)}CONSUME9(e,t){return this.consumeInternal(e,9,t)}SUBRULE(e,t){return this.subruleInternal(e,0,t)}SUBRULE1(e,t){return this.subruleInternal(e,1,t)}SUBRULE2(e,t){return this.subruleInternal(e,2,t)}SUBRULE3(e,t){return this.subruleInternal(e,3,t)}SUBRULE4(e,t){return this.subruleInternal(e,4,t)}SUBRULE5(e,t){return this.subruleInternal(e,5,t)}SUBRULE6(e,t){return this.subruleInternal(e,6,t)}SUBRULE7(e,t){return this.subruleInternal(e,7,t)}SUBRULE8(e,t){return this.subruleInternal(e,8,t)}SUBRULE9(e,t){return this.subruleInternal(e,9,t)}OPTION(e){return this.optionInternal(e,0)}OPTION1(e){return this.optionInternal(e,1)}OPTION2(e){return this.optionInternal(e,2)}OPTION3(e){return this.optionInternal(e,3)}OPTION4(e){return this.optionInternal(e,4)}OPTION5(e){return this.optionInternal(e,5)}OPTION6(e){return this.optionInternal(e,6)}OPTION7(e){return this.optionInternal(e,7)}OPTION8(e){return this.optionInternal(e,8)}OPTION9(e){return this.optionInternal(e,9)}OR(e){return this.orInternal(e,0)}OR1(e){return this.orInternal(e,1)}OR2(e){return this.orInternal(e,2)}OR3(e){return this.orInternal(e,3)}OR4(e){return this.orInternal(e,4)}OR5(e){return this.orInternal(e,5)}OR6(e){return this.orInternal(e,6)}OR7(e){return this.orInternal(e,7)}OR8(e){return this.orInternal(e,8)}OR9(e){return this.orInternal(e,9)}MANY(e){this.manyInternal(0,e)}MANY1(e){this.manyInternal(1,e)}MANY2(e){this.manyInternal(2,e)}MANY3(e){this.manyInternal(3,e)}MANY4(e){this.manyInternal(4,e)}MANY5(e){this.manyInternal(5,e)}MANY6(e){this.manyInternal(6,e)}MANY7(e){this.manyInternal(7,e)}MANY8(e){this.manyInternal(8,e)}MANY9(e){this.manyInternal(9,e)}MANY_SEP(e){this.manySepFirstInternal(0,e)}MANY_SEP1(e){this.manySepFirstInternal(1,e)}MANY_SEP2(e){this.manySepFirstInternal(2,e)}MANY_SEP3(e){this.manySepFirstInternal(3,e)}MANY_SEP4(e){this.manySepFirstInternal(4,e)}MANY_SEP5(e){this.manySepFirstInternal(5,e)}MANY_SEP6(e){this.manySepFirstInternal(6,e)}MANY_SEP7(e){this.manySepFirstInternal(7,e)}MANY_SEP8(e){this.manySepFirstInternal(8,e)}MANY_SEP9(e){this.manySepFirstInternal(9,e)}AT_LEAST_ONE(e){this.atLeastOneInternal(0,e)}AT_LEAST_ONE1(e){return this.atLeastOneInternal(1,e)}AT_LEAST_ONE2(e){this.atLeastOneInternal(2,e)}AT_LEAST_ONE3(e){this.atLeastOneInternal(3,e)}AT_LEAST_ONE4(e){this.atLeastOneInternal(4,e)}AT_LEAST_ONE5(e){this.atLeastOneInternal(5,e)}AT_LEAST_ONE6(e){this.atLeastOneInternal(6,e)}AT_LEAST_ONE7(e){this.atLeastOneInternal(7,e)}AT_LEAST_ONE8(e){this.atLeastOneInternal(8,e)}AT_LEAST_ONE9(e){this.atLeastOneInternal(9,e)}AT_LEAST_ONE_SEP(e){this.atLeastOneSepFirstInternal(0,e)}AT_LEAST_ONE_SEP1(e){this.atLeastOneSepFirstInternal(1,e)}AT_LEAST_ONE_SEP2(e){this.atLeastOneSepFirstInternal(2,e)}AT_LEAST_ONE_SEP3(e){this.atLeastOneSepFirstInternal(3,e)}AT_LEAST_ONE_SEP4(e){this.atLeastOneSepFirstInternal(4,e)}AT_LEAST_ONE_SEP5(e){this.atLeastOneSepFirstInternal(5,e)}AT_LEAST_ONE_SEP6(e){this.atLeastOneSepFirstInternal(6,e)}AT_LEAST_ONE_SEP7(e){this.atLeastOneSepFirstInternal(7,e)}AT_LEAST_ONE_SEP8(e){this.atLeastOneSepFirstInternal(8,e)}AT_LEAST_ONE_SEP9(e){this.atLeastOneSepFirstInternal(9,e)}RULE(e,t,r=Rl){if(lt(this.definedRulesNames,e)){const s={message:bn.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),type:st.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(s)}this.definedRulesNames.push(e);const n=this.defineRule(e,t,r);return this[e]=n,n}OVERRIDE_RULE(e,t,r=Rl){const n=FE(e,this.definedRulesNames,this.className);this.definitionErrors=this.definitionErrors.concat(n);const a=this.defineRule(e,t,r);return this[e]=a,a}BACKTRACK(e,t){return function(){this.isBackTrackingStack.push(1);const r=this.saveRecogState();try{return e.apply(this,t),!0}catch(n){if(Ss(n))return!1;throw n}finally{this.reloadRecogState(r),this.isBackTrackingStack.pop()}}}getGAstProductions(){return this.gastProductionsCache}getSerializedGastProductions(){return DA(Me(this.gastProductionsCache))}},QD=class{static{i(this,"RecognizerEngine")}initRecognizerEngine(e,t){if(this.className=this.constructor.name,this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=_s,this.subruleIdx=0,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},B(t,"serializedGrammar"))throw Error(`The Parser's configuration can no longer contain a property. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0 + For Further details.`);if(re(e)){if(me(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(re(e))this.tokensMap=Rt(e,(a,s)=>(a[s.name]=s,a),{});else if(B(e,"modes")&&Ft(Gt(Me(e.modes)),EE)){const a=Gt(Me(e.modes)),s=Wp(a);this.tokensMap=Rt(s,(o,l)=>(o[l.name]=l,o),{})}else if(wt(e))this.tokensMap=Ye(e);else throw new Error(" argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=Br;const r=B(e,"modes")?Gt(Me(e.modes)):Me(e),n=Ft(r,a=>me(a.categoryMatches));this.tokenMatcher=n?_s:ii,si(Me(this.tokensMap))}defineRule(e,t,r){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 n=B(r,"resyncEnabled")?r.resyncEnabled:Rl.resyncEnabled,a=B(r,"recoveryValueFunc")?r.recoveryValueFunc:Rl.recoveryValueFunc,s=this.ruleShortNameIdx<s.call(this)&&o.call(this),"lookAheadFunc")}}else a=e;if(n.call(this)===!0)return a.call(this)}atLeastOneInternal(e,t){const r=this.getKeyForAutomaticLookahead(xf,e);return this.atLeastOneInternalLogic(e,t,r)}atLeastOneInternalLogic(e,t,r){let n=this.getLaFuncFromCache(r),a;if(typeof t!="function"){a=t.DEF;const s=t.GATE;if(s!==void 0){const o=n;n=i(()=>s.call(this)&&o.call(this),"lookAheadFunc")}}else a=t;if(n.call(this)===!0){let s=this.doSingleRepetition(a);for(;n.call(this)===!0&&s===!0;)s=this.doSingleRepetition(a)}else throw this.raiseEarlyExitException(e,Re.REPETITION_MANDATORY,t.ERR_MSG);this.attemptInRepetitionRecovery(this.atLeastOneInternal,[e,t],n,xf,e,MD)}atLeastOneSepFirstInternal(e,t){const r=this.getKeyForAutomaticLookahead(xo,e);this.atLeastOneSepFirstInternalLogic(e,t,r)}atLeastOneSepFirstInternalLogic(e,t,r){const n=t.DEF,a=t.SEP;if(this.getLaFuncFromCache(r).call(this)===!0){n.call(this);const o=i(()=>this.tokenMatcher(this.LA(1),a),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),a)===!0;)this.CONSUME(a),n.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,a,o,n,ey],o,xo,e,ey)}else throw this.raiseEarlyExitException(e,Re.REPETITION_MANDATORY_WITH_SEPARATOR,t.ERR_MSG)}manyInternal(e,t){const r=this.getKeyForAutomaticLookahead(Df,e);return this.manyInternalLogic(e,t,r)}manyInternalLogic(e,t,r){let n=this.getLaFuncFromCache(r),a;if(typeof t!="function"){a=t.DEF;const o=t.GATE;if(o!==void 0){const l=n;n=i(()=>o.call(this)&&l.call(this),"lookaheadFunction")}}else a=t;let s=!0;for(;n.call(this)===!0&&s===!0;)s=this.doSingleRepetition(a);this.attemptInRepetitionRecovery(this.manyInternal,[e,t],n,Df,e,xD,s)}manySepFirstInternal(e,t){const r=this.getKeyForAutomaticLookahead(Mf,e);this.manySepFirstInternalLogic(e,t,r)}manySepFirstInternalLogic(e,t,r){const n=t.DEF,a=t.SEP;if(this.getLaFuncFromCache(r).call(this)===!0){n.call(this);const o=i(()=>this.tokenMatcher(this.LA(1),a),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),a)===!0;)this.CONSUME(a),n.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,a,o,n,Qh],o,Mf,e,Qh)}}repetitionSepSecondInternal(e,t,r,n,a){for(;r();)this.CONSUME(t),n.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,t,r,n,a],r,xo,e,a)}doSingleRepetition(e){const t=this.getLexerPosition();return e.call(this),this.getLexerPosition()>t}orInternal(e,t){const r=this.getKeyForAutomaticLookahead(nC,t),n=re(e)?e:e.DEF,s=this.getLaFuncFromCache(r).call(this,n);if(s!==void 0)return n[s].ALT.call(this);this.raiseNoAltException(t,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),t=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new BD(t,e))}}subruleInternal(e,t,r){let n;try{const a=r!==void 0?r.ARGS:void 0;return this.subruleIdx=t,n=e.apply(this,a),this.cstPostNonTerminal(n,r!==void 0&&r.LABEL!==void 0?r.LABEL:e.ruleName),n}catch(a){throw this.subruleInternalError(a,r,e.ruleName)}}subruleInternalError(e,t,r){throw Ss(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstResult,t!==void 0&&t.LABEL!==void 0?t.LABEL:r),delete e.partialCstResult),e}consumeInternal(e,t,r){let n;try{const a=this.LA(1);this.tokenMatcher(a,e)===!0?(this.consumeToken(),n=a):this.consumeInternalError(e,a,r)}catch(a){n=this.consumeInternalRecovery(e,t,a)}return this.cstPostTerminal(r!==void 0&&r.LABEL!==void 0?r.LABEL:e.name,n),n}consumeInternalError(e,t,r){let n;const a=this.LA(0);throw r!==void 0&&r.ERR_MSG?n=r.ERR_MSG:n=this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:t,previous:a,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new eC(n,t,a))}consumeInternalRecovery(e,t,r){if(this.recoveryEnabled&&r.name==="MismatchedTokenException"&&!this.isBackTracking()){const n=this.getFollowsForInRuleRecovery(e,t);try{return this.tryInRuleRecovery(e,n)}catch(a){throw a.name===tC?r:a}}else throw r}saveRecogState(){const e=this.errors,t=Ye(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:t,CST_STACK:this.CST_STACK}}reloadRecogState(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK}ruleInvocationStateUpdate(e,t,r){this.RULE_OCCURRENCE_STACK.push(r),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(t)}isBackTracking(){return this.isBackTrackingStack.length!==0}getCurrRuleFullName(){const e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]}shortRuleNameToFullName(e){return this.shortRuleNameToFull[e]}isAtEndOfInput(){return this.tokenMatcher(this.LA(1),Br)}reset(){this.resetLexerState(),this.subruleIdx=0,this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]}},ex=class{static{i(this,"ErrorHandler")}initErrorHandler(e){this._errors=[],this.errorMessageProvider=B(e,"errorMessageProvider")?e.errorMessageProvider:_r.errorMessageProvider}SAVE_ERROR(e){if(Ss(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:Ye(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")}get errors(){return Ye(this._errors)}set errors(e){this._errors=e}raiseEarlyExitException(e,t,r){const n=this.getCurrRuleFullName(),a=this.getGAstProductions()[n],o=eo(e,a,t,this.maxLookahead)[0],l=[];for(let c=1;c<=this.maxLookahead;c++)l.push(this.LA(c));const u=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:o,actual:l,previous:this.LA(0),customUserDescription:r,ruleName:n});throw this.SAVE_ERROR(new UD(u,this.LA(1),this.LA(0)))}raiseNoAltException(e,t){const r=this.getCurrRuleFullName(),n=this.getGAstProductions()[r],a=Qs(e,n,this.maxLookahead),s=[];for(let u=1;u<=this.maxLookahead;u++)s.push(this.LA(u));const o=this.LA(0),l=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:a,actual:s,previous:o,customUserDescription:t,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new jD(l,this.LA(1),o))}},tx=class{static{i(this,"ContentAssist")}initContentAssist(){}computeContentAssist(e,t){const r=this.gastProductionsCache[e];if(Cr(r))throw Error(`Rule ->${e}<- does not exist in this grammar.`);return rm([r],t,this.tokenMatcher,this.maxLookahead)}getNextPossibleTokenTypes(e){const t=jt(e.ruleStack),n=this.getGAstProductions()[t];return new DD(n,e).startWalking()}},gu={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(gu);var ty=!0,ry=Math.pow(2,Hr)-1,pC=za({name:"RECORDING_PHASE_TOKEN",pattern:nt.NA});si([pC]);var mC=Zs(pC,`This IToken indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze(mC);var rx={name:`This CSTNode indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},nx=class{static{i(this,"GastRecorder")}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 t=e>0?e:"";this[`CONSUME${t}`]=function(r,n){return this.consumeInternalRecord(r,e,n)},this[`SUBRULE${t}`]=function(r,n){return this.subruleInternalRecord(r,e,n)},this[`OPTION${t}`]=function(r){return this.optionInternalRecord(r,e)},this[`OR${t}`]=function(r){return this.orInternalRecord(r,e)},this[`MANY${t}`]=function(r){this.manyInternalRecord(e,r)},this[`MANY_SEP${t}`]=function(r){this.manySepFirstInternalRecord(e,r)},this[`AT_LEAST_ONE${t}`]=function(r){this.atLeastOneInternalRecord(e,r)},this[`AT_LEAST_ONE_SEP${t}`]=function(r){this.atLeastOneSepFirstInternalRecord(e,r)}}this.consume=function(e,t,r){return this.consumeInternalRecord(t,e,r)},this.subrule=function(e,t,r){return this.subruleInternalRecord(t,e,r)},this.option=function(e,t){return this.optionInternalRecord(t,e)},this.or=function(e,t){return this.orInternalRecord(t,e)},this.many=function(e,t){this.manyInternalRecord(e,t)},this.atLeastOne=function(e,t){this.atLeastOneInternalRecord(e,t)},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 t=0;t<10;t++){const r=t>0?t:"";delete e[`CONSUME${r}`],delete e[`SUBRULE${r}`],delete e[`OPTION${r}`],delete e[`OR${r}`],delete e[`MANY${r}`],delete e[`MANY_SEP${r}`],delete e[`AT_LEAST_ONE${r}`],delete e[`AT_LEAST_ONE_SEP${r}`]}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,t){return()=>!0}LA_RECORD(e){return $l}topLevelRuleRecord(e,t){try{const r=new ri({definition:[],name:e});return r.name=e,this.recordingProdStack.push(r),t.call(this),this.recordingProdStack.pop(),r}catch(r){if(r.KNOWN_RECORDER_ERROR!==!0)try{r.message=r.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 r}throw r}}optionInternalRecord(e,t){return $a.call(this,He,e,t)}atLeastOneInternalRecord(e,t){$a.call(this,At,t,e)}atLeastOneSepFirstInternalRecord(e,t){$a.call(this,Et,t,e,ty)}manyInternalRecord(e,t){$a.call(this,be,t,e)}manySepFirstInternalRecord(e,t){$a.call(this,ht,t,e,ty)}orInternalRecord(e,t){return hC.call(this,e,t)}subruleInternalRecord(e,t,r){if(ws(t),!e||B(e,"ruleName")===!1){const o=new Error(` argument is invalid expecting a Parser method reference but got: <${JSON.stringify(e)}> + inside top level rule: <${this.recordingProdStack[0].name}>`);throw o.KNOWN_RECORDER_ERROR=!0,o}const n=Pn(this.recordingProdStack),a=e.ruleName,s=new it({idx:t,nonTerminalName:a,label:r?.LABEL,referencedRule:void 0});return n.definition.push(s),this.outputCst?rx:gu}consumeInternalRecord(e,t,r){if(ws(t),!Qp(e)){const s=new Error(` argument is invalid expecting a TokenType reference but got: <${JSON.stringify(e)}> + inside top level rule: <${this.recordingProdStack[0].name}>`);throw s.KNOWN_RECORDER_ERROR=!0,s}const n=Pn(this.recordingProdStack),a=new ve({idx:t,terminalType:e,label:r?.LABEL});return n.definition.push(a),mC}};function $a(e,t,r,n=!1){ws(r);const a=Pn(this.recordingProdStack),s=Nr(t)?t:t.DEF,o=new e({definition:[],idx:r});return n&&(o.separator=t.SEP),B(t,"MAX_LOOKAHEAD")&&(o.maxLookahead=t.MAX_LOOKAHEAD),this.recordingProdStack.push(o),s.call(this),a.definition.push(o),this.recordingProdStack.pop(),gu}i($a,"recordProd");function hC(e,t){ws(t);const r=Pn(this.recordingProdStack),n=re(e)===!1,a=n===!1?e:e.DEF,s=new yt({definition:[],idx:t,ignoreAmbiguities:n&&e.IGNORE_AMBIGUITIES===!0});B(e,"MAX_LOOKAHEAD")&&(s.maxLookahead=e.MAX_LOOKAHEAD);const o=NA(a,l=>Nr(l.GATE));return s.hasPredicates=o,r.definition.push(s),K(a,l=>{const u=new mt({definition:[]});s.definition.push(u),B(l,"IGNORE_AMBIGUITIES")?u.ignoreAmbiguities=l.IGNORE_AMBIGUITIES:B(l,"GATE")&&(u.ignoreAmbiguities=!0),this.recordingProdStack.push(u),l.ALT.call(this),this.recordingProdStack.pop()}),gu}i(hC,"recordOrProd");function jf(e){return e===0?"":`${e}`}i(jf,"getIdxSuffix");function ws(e){if(e<0||e>ry){const t=new Error(`Invalid DSL Method idx value: <${e}> + Idx value must be a none negative value smaller than ${ry+1}`);throw t.KNOWN_RECORDER_ERROR=!0,t}}i(ws,"assertMethodIdxIsValid");var ax=class{static{i(this,"PerformanceTracer")}initPerformanceTracer(e){if(B(e,"traceInitPerf")){const t=e.traceInitPerf,r=typeof t=="number";this.traceInitMaxIdent=r?t:1/0,this.traceInitPerf=r?t>0:t}else this.traceInitMaxIdent=0,this.traceInitPerf=_r.traceInitPerf;this.traceInitIndent=-1}TRACE_INIT(e,t){if(this.traceInitPerf===!0){this.traceInitIndent++;const r=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <${e}>`);const{time:n,value:a}=Vp(t),s=n>10?console.warn:console.log;return this.traceInitIndent time: ${n}ms`),this.traceInitIndent--,a}else return t()}};function yC(e,t){t.forEach(r=>{const n=r.prototype;Object.getOwnPropertyNames(n).forEach(a=>{if(a==="constructor")return;const s=Object.getOwnPropertyDescriptor(n,a);s&&(s.get||s.set)?Object.defineProperty(e.prototype,a,s):e.prototype[a]=r.prototype[a]})})}i(yC,"applyMixins");var $l=Zs(Br,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze($l);var _r=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:Ma,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1}),Rl=Object.freeze({recoveryValueFunc:i(()=>{},"recoveryValueFunc"),resyncEnabled:!0}),st;(function(e){e[e.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",e[e.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",e[e.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",e[e.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",e[e.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",e[e.LEFT_RECURSION=5]="LEFT_RECURSION",e[e.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",e[e.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",e[e.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",e[e.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",e[e.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",e[e.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",e[e.TOO_MANY_ALTS=12]="TOO_MANY_ALTS",e[e.CUSTOM_LOOKAHEAD_VALIDATION=13]="CUSTOM_LOOKAHEAD_VALIDATION"})(st||(st={}));function Bf(e=void 0){return function(){return e}}i(Bf,"EMPTY_ALT");var cm=class gC{static{i(this,"Parser")}static performSelfAnalysis(t){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")}performSelfAnalysis(){this.TRACE_INIT("performSelfAnalysis",()=>{let t;this.selfAnalysisDone=!0;const r=this.className;this.TRACE_INIT("toFastProps",()=>{Hp(this)}),this.TRACE_INIT("Grammar Recording",()=>{try{this.enableRecording(),K(this.definedRulesNames,a=>{const o=this[a].originalGrammarAction;let l;this.TRACE_INIT(`${a} Rule`,()=>{l=this.topLevelRuleRecord(a,o)}),this.gastProductionsCache[a]=l})}finally{this.disableRecording()}});let n=[];if(this.TRACE_INIT("Grammar Resolving",()=>{n=VE({rules:Me(this.gastProductionsCache)}),this.definitionErrors=this.definitionErrors.concat(n)}),this.TRACE_INIT("Grammar Validations",()=>{if(me(n)&&this.skipValidations===!1){const a=HE({rules:Me(this.gastProductionsCache),tokenTypes:Me(this.tokensMap),errMsgProvider:bn,grammarName:r}),s=LE({lookaheadStrategy:this.lookaheadStrategy,rules:Me(this.gastProductionsCache),tokenTypes:Me(this.tokensMap),grammarName:r});this.definitionErrors=this.definitionErrors.concat(a,s)}}),me(this.definitionErrors)&&(this.recoveryEnabled&&this.TRACE_INIT("computeAllProdsFollows",()=>{const a=BA(Me(this.gastProductionsCache));this.resyncFollows=a}),this.TRACE_INIT("ComputeLookaheadFunctions",()=>{var a,s;(s=(a=this.lookaheadStrategy).initialize)===null||s===void 0||s.call(a,{rules:Me(this.gastProductionsCache)}),this.preComputeLookaheadFunctions(Me(this.gastProductionsCache))})),!gC.DEFER_DEFINITION_ERRORS_HANDLING&&!me(this.definitionErrors))throw t=F(this.definitionErrors,a=>a.message),new Error(`Parser Definition Errors detected: + ${t.join(` +------------------------------- +`)}`)})}constructor(t,r){this.definitionErrors=[],this.selfAnalysisDone=!1;const n=this;if(n.initErrorHandler(r),n.initLexerAdapter(),n.initLooksAhead(r),n.initRecognizerEngine(t,r),n.initRecoverable(r),n.initTreeBuilder(r),n.initContentAssist(),n.initGastRecorder(r),n.initPerformanceTracer(r),B(r,"ignoredIssues"))throw new Error(`The IParserConfig property has been deprecated. + Please use the flag on the relevant DSL method instead. + See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES + For further details.`);this.skipValidations=B(r,"skipValidations")?r.skipValidations:_r.skipValidations}};cm.DEFER_DEFINITION_ERRORS_HANDLING=!1;yC(cm,[WD,VD,XD,JD,QD,ZD,ex,tx,nx,ax]);var ix=class extends cm{static{i(this,"EmbeddedActionsParser")}constructor(e,t=_r){const r=Ye(t);r.outputCst=!1,super(e,r)}};function vC(e,t){for(var r=-1,n=e==null?0:e.length,a=Array(n);++r-1}i(_C,"listCacheHas");var fx=_C;function SC(e,t){var r=this.__data__,n=vu(r,e);return n<0?(++this.size,r.push([e,t])):r[n][1]=t,this}i(SC,"listCacheSet");var dx=SC;function Hn(e){var t=-1,r=e==null?0:e.length;for(this.clear();++tl))return!1;var c=s.get(e),f=s.get(t);if(c&&f)return c==t&&f==e;var d=-1,m=!0,g=r&vM?new sb:void 0;for(s.set(e,t),s.set(t,e);++d-1&&e%1==0&&e-1&&e%1==0&&e<=QM}i(Ib,"isLength");var pm=Ib,e1="[object Arguments]",t1="[object Array]",r1="[object Boolean]",n1="[object Date]",a1="[object Error]",i1="[object Function]",s1="[object Map]",o1="[object Number]",l1="[object Object]",u1="[object RegExp]",c1="[object Set]",f1="[object String]",d1="[object WeakMap]",p1="[object ArrayBuffer]",m1="[object DataView]",h1="[object Float32Array]",y1="[object Float64Array]",g1="[object Int8Array]",v1="[object Int16Array]",T1="[object Int32Array]",$1="[object Uint8Array]",R1="[object Uint8ClampedArray]",A1="[object Uint16Array]",E1="[object Uint32Array]",ge={};ge[h1]=ge[y1]=ge[g1]=ge[v1]=ge[T1]=ge[$1]=ge[R1]=ge[A1]=ge[E1]=!0;ge[e1]=ge[t1]=ge[p1]=ge[r1]=ge[m1]=ge[n1]=ge[a1]=ge[i1]=ge[s1]=ge[o1]=ge[l1]=ge[u1]=ge[c1]=ge[f1]=ge[d1]=!1;function Nb(e){return Ja(e)&&pm(e.length)&&!!ge[oi(e)]}i(Nb,"baseIsTypedArray");var C1=Nb;function Pb(e){return function(t){return e(t)}}i(Pb,"baseUnary");var b1=Pb,kb=typeof exports=="object"&&exports&&!exports.nodeType&&exports,hs=kb&&typeof module=="object"&&module&&!module.nodeType&&module,_1=hs&&hs.exports===kb,Xu=_1&&kC.process,S1=(function(){try{var e=hs&&hs.require&&hs.require("util").types;return e||Xu&&Xu.binding&&Xu.binding("util")}catch{}})(),dy=S1,py=dy&&dy.isTypedArray,w1=py?b1(py):C1,mm=w1,I1=Object.prototype,N1=I1.hasOwnProperty;function Ob(e,t){var r=ot(e),n=!r&&Au(e),a=!r&&!n&&Al(e),s=!r&&!n&&!a&&mm(e),o=r||n||a||s,l=o?BM(e.length,String):[],u=l.length;for(var c in e)(t||N1.call(e,c))&&!(o&&(c=="length"||a&&(c=="offset"||c=="parent")||s&&(c=="buffer"||c=="byteLength"||c=="byteOffset")||wb(c,u)))&&l.push(c);return l}i(Ob,"arrayLikeKeys");var P1=Ob,k1=Object.prototype;function Lb(e){var t=e&&e.constructor,r=typeof t=="function"&&t.prototype||k1;return e===r}i(Lb,"isPrototype");var Db=Lb;function xb(e,t){return function(r){return e(t(r))}}i(xb,"overArg");var O1=xb,L1=O1(Object.keys,Object),D1=L1,x1=Object.prototype,M1=x1.hasOwnProperty;function Mb(e){if(!Db(e))return D1(e);var t=[];for(var r in Object(e))M1.call(e,r)&&r!="constructor"&&t.push(r);return t}i(Mb,"baseKeys");var Gb=Mb;function Fb(e){return e!=null&&pm(e.length)&&!FC(e)}i(Fb,"isArrayLike");var Eu=Fb;function zb(e){return Eu(e)?P1(e):Gb(e)}i(zb,"keys");var hm=zb;function jb(e){return xM(e,hm,jM)}i(jb,"getAllKeys");var my=jb,G1=1,F1=Object.prototype,z1=F1.hasOwnProperty;function Bb(e,t,r,n,a,s){var o=r&G1,l=my(e),u=l.length,c=my(t),f=c.length;if(u!=f&&!o)return!1;for(var d=u;d--;){var m=l[d];if(!(o?m in t:z1.call(t,m)))return!1}var g=s.get(e),v=s.get(t);if(g&&v)return g==t&&v==e;var b=!0;s.set(e,t),s.set(t,e);for(var S=o;++dEm(e,t,o));return Qn(e,t,n,r,...a)}i(L_,"alternation");function D_(e,t,r){const n=Ge(e,t,r,{type:Ur});kr(e,n);const a=Qn(e,t,n,r,Yr(e,t,r));return x_(e,t,r,a)}i(D_,"option");function Yr(e,t,r){const n=MG(vr(r.definition,a=>Em(e,t,a)),a=>a!==void 0);return n.length===1?n[0]:n.length===0?void 0:G_(e,n)}i(Yr,"block");function Cm(e,t,r,n,a){const s=n.left,o=n.right,l=Ge(e,t,r,{type:BG});kr(e,l);const u=Ge(e,t,r,{type:__});return s.loopback=l,u.loopback=l,e.decisionMap[On(t,a?"RepetitionMandatoryWithSeparator":"RepetitionMandatory",r.idx)]=l,Ie(o,l),a===void 0?(Ie(l,s),Ie(l,u)):(Ie(l,u),Ie(l,a.left),Ie(a.right,s)),{left:s,right:u}}i(Cm,"plus");function bm(e,t,r,n,a){const s=n.left,o=n.right,l=Ge(e,t,r,{type:jG});kr(e,l);const u=Ge(e,t,r,{type:__}),c=Ge(e,t,r,{type:zG});return l.loopback=c,u.loopback=c,Ie(l,s),Ie(l,u),Ie(o,c),a!==void 0?(Ie(c,u),Ie(c,a.left),Ie(a.right,s)):Ie(c,l),e.decisionMap[On(t,a?"RepetitionWithSeparator":"Repetition",r.idx)]=l,{left:l,right:u}}i(bm,"star");function x_(e,t,r,n){const a=n.left,s=n.right;return Ie(a,s),e.decisionMap[On(t,"Option",r.idx)]=a,n}i(x_,"optional");function kr(e,t){return e.decisionStates.push(t),t.decision=e.decisionStates.length-1,t.decision}i(kr,"defineDecisionState");function Qn(e,t,r,n,...a){const s=Ge(e,t,n,{type:FG,start:r});r.end=s;for(const l of a)l!==void 0?(Ie(r,l.left),Ie(l.right,s)):Ie(r,s);const o={left:r,right:s};return e.decisionMap[On(t,M_(n),n.idx)]=r,o}i(Qn,"makeAlts");function M_(e){if(e instanceof yt)return"Alternation";if(e instanceof He)return"Option";if(e instanceof be)return"Repetition";if(e instanceof ht)return"RepetitionWithSeparator";if(e instanceof At)return"RepetitionMandatory";if(e instanceof Et)return"RepetitionMandatoryWithSeparator";throw new Error("Invalid production type encountered")}i(M_,"getProdType");function G_(e,t){const r=t.length;for(let s=0;se.alt)}get key(){let e="";for(const t in this.map)e+=t+":";return e}};function _m(e,t=!0){return`${t?`a${e.alt}`:""}s${e.state.stateNumber}:${e.stack.map(r=>r.stateNumber.toString()).join("_")}`}i(_m,"getATNConfigKey");function B_(e,t,r){for(var n=-1,a=e.length;++n0&&r(l)?t>1?Sm(l,t-1,r,n,a):yb(a,l):n||(a[a.length]=l)}return a}i(Sm,"baseFlatten");var q_=Sm;function V_(e,t){return q_(vr(e,t),1)}i(V_,"flatMap");var VG=V_;function H_(e,t,r,n){for(var a=e.length,s=r+(n?1:-1);n?s--:++s-1}i(Z_,"arrayIncludes");var ZG=Z_;function Q_(e,t,r){for(var n=-1,a=e==null?0:e.length;++n=aF){var c=t?null:nF(e);if(c)return dm(c);o=!1,a=ub,u=new sb}else u=t?[]:l;e:for(;++n{const a=n.toString();let s=r[a];return s!==void 0||(s={atnStartState:e,decision:t,states:{}},r[a]=s),s}}i(fS,"createDFACache");var dS=class{static{i(this,"PredicateSet")}constructor(){this.predicates=[]}is(e){return e>=this.predicates.length||this.predicates[e]}set(e,t){this.predicates[e]=t}toString(){let e="";const t=this.predicates.length;for(let r=0;rconsole.log(r))}initialize(e){this.atn=w_(e.rules),this.dfas=pS(this.atn)}validateAmbiguousAlternationAlternatives(){return[]}validateEmptyOrAlternatives(){return[]}buildLookaheadForAlternation(e){const{prodOccurrence:t,rule:r,hasPredicates:n,dynamicTokensEnabled:a}=e,s=this.dfas,o=this.logging,l=On(r,"Alternation",t),c=this.atn.decisionMap[l].decision,f=vr(Of({maxLookahead:1,occurrence:t,prodType:"Alternation",rule:r}),d=>vr(d,m=>m[0]));if(Hf(f,!1)&&!a){const d=_y(f,(m,g,v)=>(Ju(g,b=>{b&&(m[b.tokenTypeIdx]=v,Ju(b.categoryMatches,S=>{m[S]=v}))}),m),{});return n?function(m){var g;const v=this.LA(1),b=d[v.tokenTypeIdx];if(m!==void 0&&b!==void 0){const S=(g=m[b])===null||g===void 0?void 0:g.GATE;if(S!==void 0&&S.call(this)===!1)return}return b}:function(){const m=this.LA(1);return d[m.tokenTypeIdx]}}else return n?function(d){const m=new dS,g=d===void 0?0:d.length;for(let b=0;bvr(d,m=>m[0]));if(Hf(f)&&f[0][0]&&!a){const d=f[0],m=oF(d);if(m.length===1&&mF(m[0].categoryMatches)){const v=m[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===v}}else{const g=_y(m,(v,b)=>(b!==void 0&&(v[b.tokenTypeIdx]=!0,Ju(b.categoryMatches,S=>{v[S]=!0})),v),{});return function(){const v=this.LA(1);return g[v.tokenTypeIdx]===!0}}}return function(){const d=Fo.call(this,s,c,Sy,o);return typeof d=="object"?!1:d===0}}};function Hf(e,t=!0){const r=new Set;for(const n of e){const a=new Set;for(const s of n){if(s===void 0){if(t)break;return!1}const o=[s.tokenTypeIdx].concat(s.categoryMatches);for(const l of o)if(r.has(l)){if(!a.has(l))return!1}else r.add(l),a.add(l)}}return!0}i(Hf,"isLL1Sequence");function pS(e){const t=e.decisionStates.length,r=Array(t);for(let n=0;nwn(a)).join(", "),r=e.production.idx===0?"":e.production.idx;let n=`Ambiguous Alternatives Detected: <${e.ambiguityIndices.join(", ")}> in <${vS(e.production)}${r}> inside <${e.topLevelRule.name}> Rule, +<${t}> 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}i(gS,"buildAmbiguityError");function vS(e){if(e instanceof it)return"SUBRULE";if(e instanceof He)return"OPTION";if(e instanceof yt)return"OR";if(e instanceof At)return"AT_LEAST_ONE";if(e instanceof Et)return"AT_LEAST_ONE_SEP";if(e instanceof ht)return"MANY_SEP";if(e instanceof be)return"MANY";if(e instanceof ve)return"CONSUME";throw Error("non exhaustive match")}i(vS,"getProductionDslName");function TS(e,t,r){const n=VG(t.configs.elements,s=>s.state.transitions),a=sF(n.filter(s=>s instanceof Rm).map(s=>s.tokenType),s=>s.tokenTypeIdx);return{actualToken:r,possibleTokenTypes:a,tokenPath:e}}i(TS,"buildAdaptivePredictError");function $S(e,t){return e.edges[t.tokenTypeIdx]}i($S,"getExistingTargetState");function RS(e,t,r){const n=new Vf,a=[];for(const o of e.elements){if(r.is(o.alt)===!1)continue;if(o.state.type===to){a.push(o);continue}const l=o.state.transitions.length;for(let u=0;u0&&!_S(s))for(const o of a)s.add(o);return s}i(RS,"computeReachSet");function AS(e,t){if(e instanceof Rm&&tm(t,e.tokenType))return e.target}i(AS,"getReachableTarget");function ES(e,t){let r;for(const n of e.elements)if(t.is(n.alt)===!0){if(r===void 0)r=n.alt;else if(r!==n.alt)return}return r}i(ES,"getUniqueAlt");function wm(e){return{configs:e,edges:{},isAcceptState:!1,prediction:-1}}i(wm,"newDFAState");function Yf(e,t,r,n){return n=Im(e,n),t.edges[r.tokenTypeIdx]=n,n}i(Yf,"addDFAEdge");function Im(e,t){if(t===El)return t;const r=t.configs.key,n=e.states[r];return n!==void 0?n:(t.configs.finalize(),e.states[r]=t,t)}i(Im,"addDFAState");function CS(e){const t=new Vf,r=e.transitions.length;for(let n=0;n0){const a=[...e.stack],o={state:a.pop(),alt:e.alt,stack:a};ks(o,t)}else t.add(e);return}r.epsilonOnlyTransitions||t.add(e);const n=r.transitions.length;for(let a=0;a1)return!0;return!1}i(NS,"hasConflictingAltSet");function PS(e){for(const t of Array.from(e.values()))if(Object.keys(t).length===1)return!0;return!1}i(PS,"hasStateAssociatedWithOneAlt");Ds();var kS=class{static{i(this,"CstNodeBuilder")}constructor(){this.nodeStack=[]}get current(){return this.nodeStack[this.nodeStack.length-1]??this.rootNode}buildRootNode(e){return this.rootNode=new Pm(e),this.rootNode.root=this.rootNode,this.nodeStack=[this.rootNode],this.rootNode}buildCompositeNode(e){const t=new Pu;return t.grammarSource=e,t.root=this.rootNode,this.current.content.push(t),this.nodeStack.push(t),t}buildLeafNode(e,t){const r=new Cl(e.startOffset,e.image.length,Ts(e),e.tokenType,!t);return r.grammarSource=t,r.root=this.rootNode,this.current.content.push(r),r}removeNode(e){const t=e.container;if(t){const r=t.content.indexOf(e);r>=0&&t.content.splice(r,1)}}addHiddenNodes(e){const t=[];for(const a of e){const s=new Cl(a.startOffset,a.image.length,Ts(a),a.tokenType,!0);s.root=this.rootNode,t.push(s)}let r=this.current,n=!1;if(r.content.length>0){r.content.push(...t);return}for(;r.container;){const a=r.container.content.indexOf(r);if(a>0){r.container.content.splice(a,0,...t),n=!0;break}r=r.container}n||this.rootNode.content.unshift(...t)}construct(e){const t=this.current;typeof e.$type=="string"&&!e.$infix&&(this.current.astNode=e),e.$cstNode=t;const r=this.nodeStack.pop();r?.content.length===0&&this.removeNode(r)}},Nm=class{static{i(this,"AbstractCstNode")}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)}},Cl=class extends Nm{static{i(this,"LeafCstNodeImpl")}get offset(){return this._offset}get length(){return this._length}get end(){return this._offset+this._length}get hidden(){return this._hidden}get tokenType(){return this._tokenType}get range(){return this._range}constructor(e,t,r,n,a=!1){super(),this._hidden=a,this._offset=e,this._tokenType=n,this._length=t,this._range=r}},Pu=class extends Nm{static{i(this,"CompositeCstNodeImpl")}constructor(){super(...arguments),this.content=new vF(this)}get offset(){return this.firstNonHiddenNode?.offset??0}get length(){return this.end-this.offset}get end(){return this.lastNonHiddenNode?.end??0}get range(){const e=this.firstNonHiddenNode,t=this.lastNonHiddenNode;if(e&&t){if(this._rangeCache===void 0){const{range:r}=e,{range:n}=t;this._rangeCache={start:r.start,end:n.end.line=0;e--){const t=this.content[e];if(!t.hidden)return t}return this.content[this.content.length-1]}},vF=class OS extends Array{static{i(this,"CstNodeContainer")}constructor(t){super(),this.parent=t,Object.setPrototypeOf(this,OS.prototype)}push(...t){return this.addParents(t),super.push(...t)}unshift(...t){return this.addParents(t),super.unshift(...t)}splice(t,r,...n){return this.addParents(n),super.splice(t,r,...n)}addParents(t){for(const r of t)r.container=this.parent}},Pm=class extends Pu{static{i(this,"RootCstNodeImpl")}get text(){return this._text.substring(this.offset,this.end)}get fullText(){return this._text}constructor(e){super(),this._text="",this._text=e??""}},bl=Symbol("Datatype");function zo(e){return e.$type===bl}i(zo,"isDataTypeNode");var wy="​",LS=i(e=>e.endsWith(wy)?e:e+wy,"withRuleSuffix"),km=class{static{i(this,"AbstractLangiumParser")}constructor(e){this._unorderedGroups=new Map,this.allRules=new Map,this.lexer=e.parser.Lexer;const t=this.lexer.definition,r=e.LanguageMetaData.mode==="production";e.shared.profilers.LangiumProfiler?.isActive("parsing")?this.wrapper=new $F(t,{...e.parser.ParserConfig,skipValidations:r,errorMessageProvider:e.parser.ParserErrorMessageProvider},e.shared.profilers.LangiumProfiler.createTask("parsing",e.LanguageMetaData.languageId)):this.wrapper=new GS(t,{...e.parser.ParserConfig,skipValidations:r,errorMessageProvider:e.parser.ParserErrorMessageProvider})}alternatives(e,t){this.wrapper.wrapOr(e,t)}optional(e,t){this.wrapper.wrapOption(e,t)}many(e,t){this.wrapper.wrapMany(e,t)}atLeastOne(e,t){this.wrapper.wrapAtLeastOne(e,t)}getRule(e){return this.allRules.get(e)}isRecording(){return this.wrapper.IS_RECORDING}get unorderedGroups(){return this._unorderedGroups}getRuleStack(){return this.wrapper.RULE_STACK}finalize(){this.wrapper.wrapSelfAnalysis()}},DS=class extends km{static{i(this,"LangiumParser")}get current(){return this.stack[this.stack.length-1]}constructor(e){super(e),this.nodeBuilder=new kS,this.stack=[],this.assignmentMap=new Map,this.operatorPrecedence=new Map,this.linker=e.references.Linker,this.converter=e.parser.ValueConverter,this.astReflection=e.shared.AstReflection}rule(e,t){const r=this.computeRuleType(e);let n;qa(e)&&(n=e.name,this.registerPrecedenceMap(e));const a=this.wrapper.DEFINE_RULE(LS(e.name),this.startImplementation(r,n,t).bind(this));return this.allRules.set(e.name,a),at(e)&&e.entry&&(this.mainRule=a),a}registerPrecedenceMap(e){const t=e.name,r=new Map;for(let n=0;n0&&(t=this.construct()),t===void 0)throw new Error("No result from parser");if(this.stack.length>0)throw new Error("Parser stack is not empty after parsing");return t}startImplementation(e,t,r){return n=>{const a=!this.isRecording()&&e!==void 0;if(a){const s={$type:e};this.stack.push(s),e===bl?s.value="":t!==void 0&&(s.$infixName=t)}return r(n),a?this.construct():void 0}}extractHiddenTokens(e){const t=this.lexerResult.hidden;if(!t.length)return[];const r=e.startOffset;for(let n=0;nr)return t.splice(0,n);return t.splice(0,t.length)}consume(e,t,r){const n=this.wrapper.wrapConsume(e,t);if(!this.isRecording()&&this.isValidToken(n)){const a=this.extractHiddenTokens(n);this.nodeBuilder.addHiddenNodes(a);const s=this.nodeBuilder.buildLeafNode(n,r),{assignment:o,crossRef:l}=this.getAssignment(r),u=this.current;if(o){const c=Rr(r)?n.image:this.converter.convert(n.image,s);this.assign(o.operator,o.feature,c,s,l)}else if(zo(u)){let c=n.image;Rr(r)||(c=this.converter.convert(c,s).toString()),u.value+=c}}}isValidToken(e){return!e.isInsertedInRecovery&&!isNaN(e.startOffset)&&typeof e.endOffset=="number"&&!isNaN(e.endOffset)}subrule(e,t,r,n,a){let s;!this.isRecording()&&!r&&(s=this.nodeBuilder.buildCompositeNode(n));let o;try{o=this.wrapper.wrapSubrule(e,t,a)}finally{this.isRecording()||(o===void 0&&!r&&(o=this.construct()),o!==void 0&&s&&s.length>0&&this.performSubruleAssignment(o,n,s))}}performSubruleAssignment(e,t,r){const{assignment:n,crossRef:a}=this.getAssignment(t);if(n)this.assign(n.operator,n.feature,e,r,a);else if(!n){const s=this.current;if(zo(s))s.value+=e.toString();else if(typeof e=="object"&&e){const l=this.assignWithoutOverride(e,s);this.stack.pop(),this.stack.push(l)}}}action(e,t){if(!this.isRecording()){let r=this.current;if(t.feature&&t.operator){r=this.construct(),this.nodeBuilder.removeNode(r.$cstNode),this.nodeBuilder.buildCompositeNode(t).content.push(r.$cstNode);const a={$type:e};this.stack.push(a),this.assign(t.operator,t.feature,r,r.$cstNode)}else r.$type=e}}construct(){if(this.isRecording())return;const e=this.stack.pop();return this.nodeBuilder.construct(e),"$infixName"in e?this.constructInfix(e,this.operatorPrecedence.get(e.$infixName)):zo(e)?this.converter.convert(e.value,e.$cstNode):(Nd(this.astReflection,e),e)}constructInfix(e,t){const r=e.parts;if(!Array.isArray(r)||r.length===0)return;const n=e.operators;if(!Array.isArray(n)||r.length<2)return r[0];let a=0,s=-1;for(let v=0;vs?(s=S.precedence,a=v):S.precedence===s&&(S.rightAssoc||(a=v))}const o=n.slice(0,a),l=n.slice(a+1),u=r.slice(0,a+1),c=r.slice(a+1),f={$infixName:e.$infixName,$type:e.$type,$cstNode:e.$cstNode,parts:u,operators:o},d={$infixName:e.$infixName,$type:e.$type,$cstNode:e.$cstNode,parts:c,operators:l},m=this.constructInfix(f,t),g=this.constructInfix(d,t);return{$type:e.$type,$cstNode:e.$cstNode,left:m,operator:n[a],right:g}}getAssignment(e){if(!this.assignmentMap.has(e)){const t=xn(e,$r);this.assignmentMap.set(e,{assignment:t,crossRef:t&&Gn(t.terminal)?t.terminal.isMulti?"multi":"single":void 0})}return this.assignmentMap.get(e)}assign(e,t,r,n,a){const s=this.current;let o;switch(a==="single"&&typeof r=="string"?o=this.linker.buildReference(s,t,n,r):a==="multi"&&typeof r=="string"?o=this.linker.buildMultiReference(s,t,n,r):o=r,e){case"=":{s[t]=o;break}case"?=":{s[t]=!0;break}case"+=":Array.isArray(s[t])||(s[t]=[]),s[t].push(o)}}assignWithoutOverride(e,t){for(const[n,a]of Object.entries(t)){const s=e[n];s===void 0?e[n]=a:Array.isArray(s)&&Array.isArray(a)&&(a.push(...s),e[n]=a)}const r=e.$cstNode;return r&&(r.astNode=void 0,e.$cstNode=void 0),e}get definitionErrors(){return this.wrapper.definitionErrors}},xS=class{static{i(this,"AbstractParserErrorMessageProvider")}buildMismatchTokenMessage(e){return Ma.buildMismatchTokenMessage(e)}buildNotAllInputParsedMessage(e){return Ma.buildNotAllInputParsedMessage(e)}buildNoViableAltMessage(e){return Ma.buildNoViableAltMessage(e)}buildEarlyExitMessage(e){return Ma.buildEarlyExitMessage(e)}},Om=class extends xS{static{i(this,"LangiumParserErrorMessageProvider")}buildMismatchTokenMessage({expected:e,actual:t}){return`Expecting ${e.LABEL?"`"+e.LABEL+"`":e.name.endsWith(":KW")?`keyword '${e.name.substring(0,e.name.length-3)}'`:`token of type '${e.name}'`} but found \`${t.image}\`.`}buildNotAllInputParsedMessage({firstRedundant:e}){return`Expecting end of file but found \`${e.image}\`.`}},MS=class extends km{static{i(this,"LangiumCompletionParser")}constructor(){super(...arguments),this.tokens=[],this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}action(){}construct(){}parse(e){this.resetState();const t=this.lexer.tokenize(e,{mode:"partial"});return this.tokens=t.tokens,this.wrapper.input=[...this.tokens],this.mainRule.call(this.wrapper,{}),this.unorderedGroups.clear(),{tokens:this.tokens,elementStack:[...this.lastElementStack],tokenIndex:this.nextTokenIndex}}rule(e,t){const r=this.wrapper.DEFINE_RULE(LS(e.name),this.startImplementation(t).bind(this));return this.allRules.set(e.name,r),e.entry&&(this.mainRule=r),r}resetState(){this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}startImplementation(e){return t=>{const r=this.keepStackSize();try{e(t)}finally{this.resetStackSize(r)}}}removeUnexpectedElements(){this.elementStack.splice(this.stackSize)}keepStackSize(){const e=this.elementStack.length;return this.stackSize=e,e}resetStackSize(e){this.removeUnexpectedElements(),this.stackSize=e}consume(e,t,r){this.wrapper.wrapConsume(e,t),this.isRecording()||(this.lastElementStack=[...this.elementStack,r],this.nextTokenIndex=this.currIdx+1)}subrule(e,t,r,n,a){this.before(n),this.wrapper.wrapSubrule(e,t,a),this.after(n)}before(e){this.isRecording()||this.elementStack.push(e)}after(e){if(!this.isRecording()){const t=this.elementStack.lastIndexOf(e);t>=0&&this.elementStack.splice(t)}}get currIdx(){return this.wrapper.currIdx}},TF={recoveryEnabled:!0,nodeLocationTracking:"full",skipValidations:!0,errorMessageProvider:new Om},GS=class extends ix{static{i(this,"ChevrotainWrapper")}constructor(e,t){const r=t&&"maxLookahead"in t;super(e,{...TF,lookaheadStrategy:r?new lm({maxLookahead:t.maxLookahead}):new gF({logging:t.skipValidations?()=>{}:void 0}),...t})}get IS_RECORDING(){return this.RECORDING_PHASE}DEFINE_RULE(e,t,r){return this.RULE(e,t,r)}wrapSelfAnalysis(){this.performSelfAnalysis()}wrapConsume(e,t){return this.consume(e,t,void 0)}wrapSubrule(e,t,r){return this.subrule(e,t,{ARGS:[r]})}wrapOr(e,t){this.or(e,t)}wrapOption(e,t){this.option(e,t)}wrapMany(e,t){this.many(e,t)}wrapAtLeastOne(e,t){this.atLeastOne(e,t)}rule(e){return e.call(this,{})}},$F=class extends GS{static{i(this,"ProfilerWrapper")}constructor(e,t,r){super(e,t),this.task=r}rule(e){this.task.start(),this.task.startSubTask(this.ruleName(e));try{return super.rule(e)}finally{this.task.stopSubTask(this.ruleName(e)),this.task.stop()}}ruleName(e){return e.ruleName}subrule(e,t,r){this.task.startSubTask(this.ruleName(t));try{return super.subrule(e,t,r)}finally{this.task.stopSubTask(this.ruleName(t))}}};function ku(e,t,r){return FS({parser:t,tokens:r,ruleNames:new Map},e),t}i(ku,"createParser");function FS(e,t){const r=Vl(t,!1),n=ue(t.rules).filter(at).filter(s=>r.has(s));for(const s of n){const o={...e,consume:1,optional:1,subrule:1,many:1,or:1};e.parser.rule(s,Kr(o,s.definition))}const a=ue(t.rules).filter(qa).filter(s=>r.has(s));for(const s of a)e.parser.rule(s,zS(e,s))}i(FS,"buildRules");function zS(e,t){const r=t.call.rule.ref;if(!r)throw new Error("Could not resolve reference to infix operator rule: "+t.call.rule.$refText);if(It(r))throw new Error("Cannot use terminal rule in infix expression");const n=t.operators.precedences.flatMap(g=>g.operators),a={$type:"Group",elements:[]},s={$container:a,$type:"Assignment",feature:"parts",operator:"+=",terminal:t.call},o={$container:a,$type:"Group",elements:[],cardinality:"*"};a.elements.push(s,o);const u={$container:o,$type:"Assignment",feature:"operators",operator:"+=",terminal:{$type:"Alternatives",elements:n}},c={...s,$container:o};o.elements.push(u,c);const d=n.map(g=>e.tokens[g.value]).map((g,v)=>({ALT:i(()=>e.parser.consume(v,g,u),"ALT")}));let m;return g=>{m??(m=Ou(e,r)),e.parser.subrule(0,m,!1,s,g),e.parser.many(0,{DEF:i(()=>{e.parser.alternatives(0,d),e.parser.subrule(1,m,!1,c,g)},"DEF")})}}i(zS,"buildInfixRule");function Kr(e,t,r=!1){let n;if(Rr(t))n=VS(e,t);else if(zr(t))n=jS(e,t);else if($r(t))n=Kr(e,t.terminal);else if(Gn(t))n=Lm(e,t);else if(Ar(t))n=BS(e,t);else if(Gl(t))n=KS(e,t);else if(Bl(t))n=WS(e,t);else if(Fn(t))n=qS(e,t);else if(Md(t)){const a=e.consume++;n=i(()=>e.parser.consume(a,Br,t),"method")}else throw new Kl(t.$cstNode,`Unexpected element type: ${t.$type}`);return Dm(e,r?void 0:Os(t),n,t.cardinality)}i(Kr,"buildElement");function jS(e,t){const r=Nn(t);return()=>e.parser.action(r,t)}i(jS,"buildAction");function BS(e,t){const r=t.rule.ref;if(Mn(r)){const n=e.subrule++,a=at(r)&&r.fragment,s=t.arguments.length>0?US(r,t.arguments):()=>({});let o;return l=>{o??(o=Ou(e,r)),e.parser.subrule(n,o,a,t,s(l))}}else if(It(r)){const n=e.consume++,a=_l(e,r.name);return()=>e.parser.consume(n,a,t)}else if(r)qr();else throw new Kl(t.$cstNode,`Undefined rule: ${t.rule.$refText}`)}i(BS,"buildRuleCall");function US(e,t){if(t.some(n=>n.calledByName)){const n=t.map(a=>({parameterName:a.parameter?.ref?.name,predicate:Dt(a.value)}));return a=>{const s={};for(const{parameterName:o,predicate:l}of n)o&&(s[o]=l(a));return s}}else{const n=t.map(a=>Dt(a.value));return a=>{const s={};for(let o=0;ot(n)||r(n)}else if(Dd(e)){const t=Dt(e.left),r=Dt(e.right);return n=>t(n)&&r(n)}else if(zd(e)){const t=Dt(e.value);return r=>!t(r)}else if(jd(e)){const t=e.parameter.ref.name;return r=>r!==void 0&&r[t]===!0}else if(Od(e)){const t=!!e.true;return()=>t}qr()}i(Dt,"buildPredicate");function KS(e,t){if(t.elements.length===1)return Kr(e,t.elements[0]);{const r=[];for(const a of t.elements){const s={ALT:Kr(e,a,!0)},o=Os(a);o&&(s.GATE=Dt(o)),r.push(s)}const n=e.or++;return a=>e.parser.alternatives(n,r.map(s=>{const o={ALT:i(()=>s.ALT(a),"ALT")},l=s.GATE;return l&&(o.GATE=()=>l(a)),o}))}}i(KS,"buildAlternatives");function WS(e,t){if(t.elements.length===1)return Kr(e,t.elements[0]);const r=[];for(const l of t.elements){const u={ALT:Kr(e,l,!0)},c=Os(l);c&&(u.GATE=Dt(c)),r.push(u)}const n=e.or++,a=i((l,u)=>{const c=u.getRuleStack().join("-");return`uGroup_${l}_${c}`},"idFunc"),s=i(l=>e.parser.alternatives(n,r.map((u,c)=>{const f={ALT:i(()=>!0,"ALT")},d=e.parser;f.ALT=()=>{if(u.ALT(l),!d.isRecording()){const g=a(n,d);d.unorderedGroups.get(g)||d.unorderedGroups.set(g,[]);const v=d.unorderedGroups.get(g);typeof v?.[c]>"u"&&(v[c]=!0)}};const m=u.GATE;return m?f.GATE=()=>m(l):f.GATE=()=>!d.unorderedGroups.get(a(n,d))?.[c],f})),"alternatives"),o=Dm(e,Os(t),s,"*");return l=>{o(l),e.parser.isRecording()||e.parser.unorderedGroups.delete(a(n,e.parser))}}i(WS,"buildUnorderedGroup");function qS(e,t){const r=t.elements.map(n=>Kr(e,n));return n=>r.forEach(a=>a(n))}i(qS,"buildGroup");function Os(e){if(Fn(e))return e.guardCondition}i(Os,"getGuardCondition");function Lm(e,t,r=t.terminal){if(r)if(Ar(r)&&at(r.rule.ref)){const n=r.rule.ref,a=e.subrule++;let s;return o=>{s??(s=Ou(e,n)),e.parser.subrule(a,s,!1,t,o)}}else if(Ar(r)&&It(r.rule.ref)){const n=e.consume++,a=_l(e,r.rule.ref.name);return()=>e.parser.consume(n,a,t)}else if(Rr(r)){const n=e.consume++,a=_l(e,r.value);return()=>e.parser.consume(n,a,t)}else throw new Error("Could not build cross reference parser");else{if(!t.type.ref)throw new Error("Could not resolve reference to type: "+t.type.$refText);const a=Jl(t.type.ref)?.terminal;if(!a)throw new Error("Could not find name assignment for type: "+Nn(t.type.ref));return Lm(e,t,a)}}i(Lm,"buildCrossReference");function VS(e,t){const r=e.consume++,n=e.tokens[t.value];if(!n)throw new Error("Could not find token for keyword: "+t.value);return()=>e.parser.consume(r,n,t)}i(VS,"buildKeyword");function Dm(e,t,r,n){const a=t&&Dt(t);if(!n)if(a){const s=e.or++;return o=>e.parser.alternatives(s,[{ALT:i(()=>r(o),"ALT"),GATE:i(()=>a(o),"GATE")},{ALT:Bf(),GATE:i(()=>!a(o),"GATE")}])}else return r;if(n==="*"){const s=e.many++;return o=>e.parser.many(s,{DEF:i(()=>r(o),"DEF"),GATE:a?()=>a(o):void 0})}else if(n==="+"){const s=e.many++;if(a){const o=e.or++;return l=>e.parser.alternatives(o,[{ALT:i(()=>e.parser.atLeastOne(s,{DEF:i(()=>r(l),"DEF")}),"ALT"),GATE:i(()=>a(l),"GATE")},{ALT:Bf(),GATE:i(()=>!a(l),"GATE")}])}else return o=>e.parser.atLeastOne(s,{DEF:i(()=>r(o),"DEF")})}else if(n==="?"){const s=e.optional++;return o=>e.parser.optional(s,{DEF:i(()=>r(o),"DEF"),GATE:a?()=>a(o):void 0})}else qr()}i(Dm,"wrap");function Ou(e,t){const r=HS(e,t),n=e.parser.getRule(r);if(!n)throw new Error(`Rule "${r}" not found."`);return n}i(Ou,"getRule");function HS(e,t){if(Mn(t))return t.name;if(e.ruleNames.has(t))return e.ruleNames.get(t);{let r=t,n=r.$container,a=t.$type;for(;!at(n);)(Fn(n)||Gl(n)||Bl(n))&&(a=n.elements.indexOf(r).toString()+":"+a),r=n,n=n.$container;return a=n.name+":"+a,e.ruleNames.set(t,a),a}}i(HS,"getRuleName");function _l(e,t){const r=e.tokens[t];if(!r)throw new Error(`Token "${t}" not found."`);return r}i(_l,"getToken");function xm(e){const t=e.Grammar,r=e.parser.Lexer,n=new MS(e);return ku(t,n,r.definition),n.finalize(),n}i(xm,"createCompletionParser");function Mm(e){const t=Gm(e);return t.finalize(),t}i(Mm,"createLangiumParser");function Gm(e){const t=e.Grammar,r=e.parser.Lexer,n=new DS(e);return ku(t,n,r.definition)}i(Gm,"prepareLangiumParser");var Lu=class{static{i(this,"DefaultTokenBuilder")}constructor(){this.diagnostics=[]}buildTokens(e,t){const r=ue(Vl(e,!1)),n=this.buildTerminalTokens(r),a=this.buildKeywordTokens(r,n,t);return a.push(...n),a}flushLexingReport(e){return{diagnostics:this.popDiagnostics()}}popDiagnostics(){const e=[...this.diagnostics];return this.diagnostics=[],e}buildTerminalTokens(e){return e.filter(It).filter(t=>!t.fragment).map(t=>this.buildTerminalToken(t)).toArray()}buildTerminalToken(e){const t=js(e),r=this.requiresCustomPattern(t)?this.regexPatternFunction(t):t,n={name:e.name,PATTERN:r};return typeof r=="function"&&(n.LINE_BREAKS=!0),e.hidden&&(n.GROUP=ql(t)?nt.SKIPPED:"hidden"),n}requiresCustomPattern(e){return!!(e.flags.includes("u")||e.flags.includes("s"))}regexPatternFunction(e){const t=new RegExp(e,e.flags+"y");return(r,n)=>(t.lastIndex=n,t.exec(r))}buildKeywordTokens(e,t,r){return e.filter(Mn).flatMap(n=>Ir(n).filter(Rr)).distinct(n=>n.value).toArray().sort((n,a)=>a.value.length-n.value.length).map(n=>this.buildKeywordToken(n,t,!!r?.caseInsensitive))}buildKeywordToken(e,t,r){const n=this.buildKeywordPattern(e,r),a={name:e.value,PATTERN:n,LONGER_ALT:this.findLongerAlt(e,t)};return typeof n=="function"&&(a.LINE_BREAKS=!0),a}buildKeywordPattern(e,t){return t?new RegExp(ti(e.value),"i"):e.value}findLongerAlt(e,t){return t.reduce((r,n)=>{const a=n?.PATTERN;return a?.source&&up("^"+a.source+"$",e.value)&&r.push(n),r},[])}},Fm=class{static{i(this,"DefaultValueConverter")}convert(e,t){let r=t.grammarSource;if(Gn(r)&&(r=mp(r)),Ar(r)){const n=r.rule.ref;if(!n)throw new Error("This cst node was not parsed by a rule.");return this.runConverter(n,e,t)}return e}runConverter(e,t,r){switch(e.name.toUpperCase()){case"INT":return Jt.convertInt(t);case"STRING":return Jt.convertString(t);case"ID":return Jt.convertID(t)}switch(Ep(e)?.toLowerCase()){case"number":return Jt.convertNumber(t);case"boolean":return Jt.convertBoolean(t);case"bigint":return Jt.convertBigint(t);case"date":return Jt.convertDate(t);default:return t}}},Jt;(function(e){function t(c){let f="";for(let d=1;d{typeof setImmediate>"u"?setTimeout(e,0):setImmediate(e)})}i(Du,"delayNextTick");var jo=0,YS=10;function xu(){return jo=performance.now(),new pe.CancellationTokenSource}i(xu,"startCancelableOperation");function zm(e){YS=e}i(zm,"setInterruptionPeriod");var er=Symbol("OperationCancelled");function ea(e){return e===er}i(ea,"isOperationCancelled");async function ze(e){if(e===pe.CancellationToken.None)return;const t=performance.now();if(t-jo>=YS&&(jo=t,await Du(),jo=performance.now()),e.isCancellationRequested)throw er}i(ze,"interruptAndCheck");var Sr=class{static{i(this,"Deferred")}constructor(){this.promise=new Promise((e,t)=>{this.resolve=r=>(e(r),this),this.reject=r=>(t(r),this)})}},Iy=class Xf{static{i(this,"FullTextDocument")}constructor(t,r,n,a){this._uri=t,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(t){if(t){const r=this.offsetAt(t.start),n=this.offsetAt(t.end);return this._content.substring(r,n)}return this._content}update(t,r){for(const n of t)if(Xf.isIncremental(n)){const a=Bm(n.range),s=this.offsetAt(a.start),o=this.offsetAt(a.end);this._content=this._content.substring(0,s)+n.text+this._content.substring(o,this._content.length);const l=Math.max(a.start.line,0),u=Math.max(a.end.line,0);let c=this._lineOffsets;const f=Jf(n.text,!1,s);if(u-l===f.length)for(let m=0,g=f.length;mt?a=o:n=o+1}const s=n-1;return t=this.ensureBeforeEOL(t,r[s]),{line:s,character:t-r[s]}}offsetAt(t){const r=this.getLineOffsets();if(t.line>=r.length)return this._content.length;if(t.line<0)return 0;const n=r[t.line];if(t.character<=0)return n;const a=t.line+1r&&jm(this._content.charCodeAt(t-1));)t--;return t}get lineCount(){return this.getLineOffsets().length}static isIncremental(t){const r=t;return r!=null&&typeof r.text=="string"&&r.range!==void 0&&(r.rangeLength===void 0||typeof r.rangeLength=="number")}static isFull(t){const r=t;return r!=null&&typeof r.text=="string"&&r.range===void 0&&r.rangeLength===void 0}},Sl;(function(e){function t(a,s,o,l){return new Iy(a,s,o,l)}i(t,"create"),e.create=t;function r(a,s,o){if(a instanceof Iy)return a.update(s,o),a;throw new Error("TextDocument.update: document must be created by TextDocument.create")}i(r,"update"),e.update=r;function n(a,s){const o=a.getText(),l=wl(s.map(XS),(f,d)=>{const m=f.range.start.line-d.range.start.line;return m===0?f.range.start.character-d.range.start.character:m});let u=0;const c=[];for(const f of l){const d=a.offsetAt(f.range.start);if(du&&c.push(o.substring(u,d)),f.newText.length&&c.push(f.newText),u=a.offsetAt(f.range.end)}return c.push(o.substr(u)),c.join("")}i(n,"applyEdits"),e.applyEdits=n})(Sl||(Sl={}));function wl(e,t){if(e.length<=1)return e;const r=e.length/2|0,n=e.slice(0,r),a=e.slice(r);wl(n,t),wl(a,t);let s=0,o=0,l=0;for(;sr.line||t.line===r.line&&t.character>r.character?{start:r,end:t}:e}i(Bm,"getWellformedRange");function XS(e){const t=Bm(e.range);return t!==e.range?{newText:e.newText,range:t}:e}i(XS,"getWellformedEdit");var JS;(()=>{var e={975:k=>{function C(T){if(typeof T!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(T))}i(C,"e");function y(T,$){for(var _,O="",x=0,D=-1,G=0,W=0;W<=T.length;++W){if(W2){var Y=O.lastIndexOf("/");if(Y!==O.length-1){Y===-1?(O="",x=0):x=(O=O.slice(0,Y)).length-1-O.lastIndexOf("/"),D=W,G=0;continue}}else if(O.length===2||O.length===1){O="",x=0,D=W,G=0;continue}}$&&(O.length>0?O+="/..":O="..",x=2)}else O.length>0?O+="/"+T.slice(D+1,W):O=T.slice(D+1,W),x=W-D-1;D=W,G=0}else _===46&&G!==-1?++G:G=-1}return O}i(y,"r");var E={resolve:i(function(){for(var T,$="",_=!1,O=arguments.length-1;O>=-1&&!_;O--){var x;O>=0?x=arguments[O]:(T===void 0&&(T=process.cwd()),x=T),C(x),x.length!==0&&($=x+"/"+$,_=x.charCodeAt(0)===47)}return $=y($,!_),_?$.length>0?"/"+$:"/":$.length>0?$:"."},"resolve"),normalize:i(function(T){if(C(T),T.length===0)return".";var $=T.charCodeAt(0)===47,_=T.charCodeAt(T.length-1)===47;return(T=y(T,!$)).length!==0||$||(T="."),T.length>0&&_&&(T+="/"),$?"/"+T:T},"normalize"),isAbsolute:i(function(T){return C(T),T.length>0&&T.charCodeAt(0)===47},"isAbsolute"),join:i(function(){if(arguments.length===0)return".";for(var T,$=0;$0&&(T===void 0?T=_:T+="/"+_)}return T===void 0?".":E.normalize(T)},"join"),relative:i(function(T,$){if(C(T),C($),T===$||(T=E.resolve(T))===($=E.resolve($)))return"";for(var _=1;_W){if($.charCodeAt(D+q)===47)return $.slice(D+q+1);if(q===0)return $.slice(D+q)}else x>W&&(T.charCodeAt(_+q)===47?Y=q:q===0&&(Y=0));break}var Pe=T.charCodeAt(_+q);if(Pe!==$.charCodeAt(D+q))break;Pe===47&&(Y=q)}var oe="";for(q=_+Y+1;q<=O;++q)q!==O&&T.charCodeAt(q)!==47||(oe.length===0?oe+="..":oe+="/..");return oe.length>0?oe+$.slice(D+Y):(D+=Y,$.charCodeAt(D)===47&&++D,$.slice(D))},"relative"),_makeLong:i(function(T){return T},"_makeLong"),dirname:i(function(T){if(C(T),T.length===0)return".";for(var $=T.charCodeAt(0),_=$===47,O=-1,x=!0,D=T.length-1;D>=1;--D)if(($=T.charCodeAt(D))===47){if(!x){O=D;break}}else x=!1;return O===-1?_?"/":".":_&&O===1?"//":T.slice(0,O)},"dirname"),basename:i(function(T,$){if($!==void 0&&typeof $!="string")throw new TypeError('"ext" argument must be a string');C(T);var _,O=0,x=-1,D=!0;if($!==void 0&&$.length>0&&$.length<=T.length){if($.length===T.length&&$===T)return"";var G=$.length-1,W=-1;for(_=T.length-1;_>=0;--_){var Y=T.charCodeAt(_);if(Y===47){if(!D){O=_+1;break}}else W===-1&&(D=!1,W=_+1),G>=0&&(Y===$.charCodeAt(G)?--G==-1&&(x=_):(G=-1,x=W))}return O===x?x=W:x===-1&&(x=T.length),T.slice(O,x)}for(_=T.length-1;_>=0;--_)if(T.charCodeAt(_)===47){if(!D){O=_+1;break}}else x===-1&&(D=!1,x=_+1);return x===-1?"":T.slice(O,x)},"basename"),extname:i(function(T){C(T);for(var $=-1,_=0,O=-1,x=!0,D=0,G=T.length-1;G>=0;--G){var W=T.charCodeAt(G);if(W!==47)O===-1&&(x=!1,O=G+1),W===46?$===-1?$=G:D!==1&&(D=1):$!==-1&&(D=-1);else if(!x){_=G+1;break}}return $===-1||O===-1||D===0||D===1&&$===O-1&&$===_+1?"":T.slice($,O)},"extname"),format:i(function(T){if(T===null||typeof T!="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof T);return(function($,_){var O=_.dir||_.root,x=_.base||(_.name||"")+(_.ext||"");return O?O===_.root?O+x:O+"/"+x:x})(0,T)},"format"),parse:i(function(T){C(T);var $={root:"",dir:"",base:"",ext:"",name:""};if(T.length===0)return $;var _,O=T.charCodeAt(0),x=O===47;x?($.root="/",_=1):_=0;for(var D=-1,G=0,W=-1,Y=!0,q=T.length-1,Pe=0;q>=_;--q)if((O=T.charCodeAt(q))!==47)W===-1&&(Y=!1,W=q+1),O===46?D===-1?D=q:Pe!==1&&(Pe=1):D!==-1&&(Pe=-1);else if(!Y){G=q+1;break}return D===-1||W===-1||Pe===0||Pe===1&&D===W-1&&D===G+1?W!==-1&&($.base=$.name=G===0&&x?T.slice(1,W):T.slice(G,W)):(G===0&&x?($.name=T.slice(1,D),$.base=T.slice(1,W)):($.name=T.slice(G,D),$.base=T.slice(G,W)),$.ext=T.slice(D,W)),G>0?$.dir=T.slice(0,G-1):x&&($.dir="/"),$},"parse"),sep:"/",delimiter:":",win32:null,posix:null};E.posix=E,k.exports=E}},t={};function r(k){var C=t[k];if(C!==void 0)return C.exports;var y=t[k]={exports:{}};return e[k](y,y.exports,r),y.exports}i(r,"r"),r.d=(k,C)=>{for(var y in C)r.o(C,y)&&!r.o(k,y)&&Object.defineProperty(k,y,{enumerable:!0,get:C[y]})},r.o=(k,C)=>Object.prototype.hasOwnProperty.call(k,C),r.r=k=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(k,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(k,"__esModule",{value:!0})};var n={};let a;r.r(n),r.d(n,{URI:i(()=>m,"URI"),Utils:i(()=>Se,"Utils")}),typeof process=="object"?a=process.platform==="win32":typeof navigator=="object"&&(a=navigator.userAgent.indexOf("Windows")>=0);const s=/^\w[\w\d+.-]*$/,o=/^\//,l=/^\/\//;function u(k,C){if(!k.scheme&&C)throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${k.authority}", path: "${k.path}", query: "${k.query}", fragment: "${k.fragment}"}`);if(k.scheme&&!s.test(k.scheme))throw new Error("[UriError]: Scheme contains illegal characters.");if(k.path){if(k.authority){if(!o.test(k.path))throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character')}else if(l.test(k.path))throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")')}}i(u,"a");const c="",f="/",d=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;class m{static{i(this,"l")}static isUri(C){return C instanceof m||!!C&&typeof C.authority=="string"&&typeof C.fragment=="string"&&typeof C.path=="string"&&typeof C.query=="string"&&typeof C.scheme=="string"&&typeof C.fsPath=="string"&&typeof C.with=="function"&&typeof C.toString=="function"}scheme;authority;path;query;fragment;constructor(C,y,E,T,$,_=!1){typeof C=="object"?(this.scheme=C.scheme||c,this.authority=C.authority||c,this.path=C.path||c,this.query=C.query||c,this.fragment=C.fragment||c):(this.scheme=(function(O,x){return O||x?O:"file"})(C,_),this.authority=y||c,this.path=(function(O,x){switch(O){case"https":case"http":case"file":x?x[0]!==f&&(x=f+x):x=f}return x})(this.scheme,E||c),this.query=T||c,this.fragment=$||c,u(this,_))}get fsPath(){return I(this,!1)}with(C){if(!C)return this;let{scheme:y,authority:E,path:T,query:$,fragment:_}=C;return y===void 0?y=this.scheme:y===null&&(y=c),E===void 0?E=this.authority:E===null&&(E=c),T===void 0?T=this.path:T===null&&(T=c),$===void 0?$=this.query:$===null&&($=c),_===void 0?_=this.fragment:_===null&&(_=c),y===this.scheme&&E===this.authority&&T===this.path&&$===this.query&&_===this.fragment?this:new v(y,E,T,$,_)}static parse(C,y=!1){const E=d.exec(C);return E?new v(E[2]||c,X(E[4]||c),X(E[5]||c),X(E[7]||c),X(E[9]||c),y):new v(c,c,c,c,c)}static file(C){let y=c;if(a&&(C=C.replace(/\\/g,f)),C[0]===f&&C[1]===f){const E=C.indexOf(f,2);E===-1?(y=C.substring(2),C=f):(y=C.substring(2,E),C=C.substring(E)||f)}return new v("file",y,C,c,c)}static from(C){const y=new v(C.scheme,C.authority,C.path,C.query,C.fragment);return u(y,!0),y}toString(C=!1){return R(this,C)}toJSON(){return this}static revive(C){if(C){if(C instanceof m)return C;{const y=new v(C);return y._formatted=C.external,y._fsPath=C._sep===g?C.fsPath:null,y}}return C}}const g=a?1:void 0;class v extends m{static{i(this,"d")}_formatted=null;_fsPath=null;get fsPath(){return this._fsPath||(this._fsPath=I(this,!1)),this._fsPath}toString(C=!1){return C?R(this,!0):(this._formatted||(this._formatted=R(this,!1)),this._formatted)}toJSON(){const C={$mid:1};return this._fsPath&&(C.fsPath=this._fsPath,C._sep=g),this._formatted&&(C.external=this._formatted),this.path&&(C.path=this.path),this.scheme&&(C.scheme=this.scheme),this.authority&&(C.authority=this.authority),this.query&&(C.query=this.query),this.fragment&&(C.fragment=this.fragment),C}}const b={58:"%3A",47:"%2F",63:"%3F",35:"%23",91:"%5B",93:"%5D",64:"%40",33:"%21",36:"%24",38:"%26",39:"%27",40:"%28",41:"%29",42:"%2A",43:"%2B",44:"%2C",59:"%3B",61:"%3D",32:"%20"};function S(k,C,y){let E,T=-1;for(let $=0;$=97&&_<=122||_>=65&&_<=90||_>=48&&_<=57||_===45||_===46||_===95||_===126||C&&_===47||y&&_===91||y&&_===93||y&&_===58)T!==-1&&(E+=encodeURIComponent(k.substring(T,$)),T=-1),E!==void 0&&(E+=k.charAt($));else{E===void 0&&(E=k.substr(0,$));const O=b[_];O!==void 0?(T!==-1&&(E+=encodeURIComponent(k.substring(T,$)),T=-1),E+=O):T===-1&&(T=$)}}return T!==-1&&(E+=encodeURIComponent(k.substring(T))),E!==void 0?E:k}i(S,"m");function w(k){let C;for(let y=0;y1&&k.scheme==="file"?`//${k.authority}${k.path}`:k.path.charCodeAt(0)===47&&(k.path.charCodeAt(1)>=65&&k.path.charCodeAt(1)<=90||k.path.charCodeAt(1)>=97&&k.path.charCodeAt(1)<=122)&&k.path.charCodeAt(2)===58?C?k.path.substr(1):k.path[1].toLowerCase()+k.path.substr(2):k.path,a&&(y=y.replace(/\//g,"\\")),y}i(I,"v");function R(k,C){const y=C?w:S;let E="",{scheme:T,authority:$,path:_,query:O,fragment:x}=k;if(T&&(E+=T,E+=":"),($||T==="file")&&(E+=f,E+=f),$){let D=$.indexOf("@");if(D!==-1){const G=$.substr(0,D);$=$.substr(D+1),D=G.lastIndexOf(":"),D===-1?E+=y(G,!1,!1):(E+=y(G.substr(0,D),!1,!1),E+=":",E+=y(G.substr(D+1),!1,!0)),E+="@"}$=$.toLowerCase(),D=$.lastIndexOf(":"),D===-1?E+=y($,!1,!0):(E+=y($.substr(0,D),!1,!0),E+=$.substr(D))}if(_){if(_.length>=3&&_.charCodeAt(0)===47&&_.charCodeAt(2)===58){const D=_.charCodeAt(1);D>=65&&D<=90&&(_=`/${String.fromCharCode(D+32)}:${_.substr(3)}`)}else if(_.length>=2&&_.charCodeAt(1)===58){const D=_.charCodeAt(0);D>=65&&D<=90&&(_=`${String.fromCharCode(D+32)}:${_.substr(2)}`)}E+=y(_,!0,!1)}return O&&(E+="?",E+=y(O,!1,!1)),x&&(E+="#",E+=C?x:S(x,!1,!1)),E}i(R,"b");function P(k){try{return decodeURIComponent(k)}catch{return k.length>3?k.substr(0,3)+P(k.substr(3)):k}}i(P,"C");const z=/(%[0-9A-Za-z][0-9A-Za-z])+/g;function X(k){return k.match(z)?k.replace(z,(C=>P(C))):k}i(X,"w");var Z=r(975);const ce=Z.posix||Z,se="/";var Se;(function(k){k.joinPath=function(C,...y){return C.with({path:ce.join(C.path,...y)})},k.resolvePath=function(C,...y){let E=C.path,T=!1;E[0]!==se&&(E=se+E,T=!0);let $=ce.resolve(E,...y);return T&&$[0]===se&&!C.authority&&($=$.substring(1)),C.with({path:$})},k.dirname=function(C){if(C.path.length===0||C.path===se)return C;let y=ce.dirname(C.path);return y.length===1&&y.charCodeAt(0)===46&&(y=""),C.with({path:y})},k.basename=function(C){return ce.basename(C.path)},k.extname=function(C){return ce.extname(C.path)}})(Se||(Se={})),JS=n})();var{URI:vt,Utils:Li}=JS,rt;(function(e){e.basename=Li.basename,e.dirname=Li.dirname,e.extname=Li.extname,e.joinPath=Li.joinPath,e.resolvePath=Li.resolvePath;const t=typeof process=="object"&&process?.platform==="win32";function r(o,l){return o?.toString()===l?.toString()}i(r,"equals"),e.equals=r;function n(o,l){const u=typeof o=="string"?vt.parse(o).path:o.path,c=typeof l=="string"?vt.parse(l).path:l.path,f=u.split("/").filter(b=>b.length>0),d=c.split("/").filter(b=>b.length>0);if(t){const b=/^[A-Z]:$/;if(f[0]&&b.test(f[0])&&(f[0]=f[0].toLowerCase()),d[0]&&b.test(d[0])&&(d[0]=d[0].toLowerCase()),f[0]!==d[0])return c.substring(1)}let m=0;for(;m({name:n.name,uri:rt.joinPath(vt.parse(t),n.name).toString(),element:n.element})):[]}all(){return this.collectValues(this.root)}findAll(e){const t=this.getNode(rt.normalize(e),!1);return t?this.collectValues(t):[]}getNode(e,t){const r=e.split("/");e.charAt(e.length-1)==="/"&&r.pop();let n=this.root;for(const a of r){let s=n.children.get(a);if(!s)if(t)s={name:a,children:new Map,parent:n},n.children.set(a,s);else return;n=s}return n}collectValues(e){const t=[];e.element&&t.push(e.element);for(const r of e.children.values())t.push(...this.collectValues(r));return t}},J;(function(e){e[e.Changed=0]="Changed",e[e.Parsed=1]="Parsed",e[e.IndexedContent=2]="IndexedContent",e[e.ComputedScopes=3]="ComputedScopes",e[e.Linked=4]="Linked",e[e.IndexedReferences=5]="IndexedReferences",e[e.Validated=6]="Validated"})(J||(J={}));var ZS=class{static{i(this,"DefaultLangiumDocumentFactory")}constructor(e){this.serviceRegistry=e.ServiceRegistry,this.textDocuments=e.workspace.TextDocuments,this.fileSystemProvider=e.workspace.FileSystemProvider}async fromUri(e,t=pe.CancellationToken.None){const r=await this.fileSystemProvider.readFile(e);return this.createAsync(e,r,t)}fromTextDocument(e,t,r){return t=t??vt.parse(e.uri),pe.CancellationToken.is(r)?this.createAsync(t,e,r):this.create(t,e,r)}fromString(e,t,r){return pe.CancellationToken.is(r)?this.createAsync(t,e,r):this.create(t,e,r)}fromModel(e,t){return this.create(t,{$model:e})}create(e,t,r){if(typeof t=="string"){const n=this.parse(e,t,r);return this.createLangiumDocument(n,e,void 0,t)}else if("$model"in t){const n={value:t.$model,parserErrors:[],lexerErrors:[]};return this.createLangiumDocument(n,e)}else{const n=this.parse(e,t.getText(),r);return this.createLangiumDocument(n,e,t)}}async createAsync(e,t,r){if(typeof t=="string"){const n=await this.parseAsync(e,t,r);return this.createLangiumDocument(n,e,void 0,t)}else{const n=await this.parseAsync(e,t.getText(),r);return this.createLangiumDocument(n,e,t)}}createLangiumDocument(e,t,r,n){let a;if(r)a={parseResult:e,uri:t,state:J.Parsed,references:[],textDocument:r};else{const s=this.createTextDocumentGetter(t,n);a={parseResult:e,uri:t,state:J.Parsed,references:[],get textDocument(){return s()}}}return e.value.$document=a,a}async update(e,t){const r=e.parseResult.value.$cstNode?.root.fullText,n=this.textDocuments?.get(e.uri.toString()),a=n?n.getText():await this.fileSystemProvider.readFile(e.uri);if(n)Object.defineProperty(e,"textDocument",{value:n});else{const s=this.createTextDocumentGetter(e.uri,a);Object.defineProperty(e,"textDocument",{get:s})}return r!==a&&(e.parseResult=await this.parseAsync(e.uri,a,t),e.parseResult.value.$document=e),e.state=J.Parsed,e}parse(e,t,r){return this.serviceRegistry.getServices(e).parser.LangiumParser.parse(t,r)}parseAsync(e,t,r){return this.serviceRegistry.getServices(e).parser.AsyncParser.parse(t,r)}createTextDocumentGetter(e,t){const r=this.serviceRegistry;let n;return()=>n??(n=Sl.create(e.toString(),r.getServices(e).LanguageMetaData.languageId,0,t??""))}},QS=class{static{i(this,"DefaultLangiumDocuments")}constructor(e){this.documentTrie=new Um,this.services=e,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory,this.documentBuilder=()=>e.workspace.DocumentBuilder}get all(){return ue(this.documentTrie.all())}addDocument(e){const t=e.uri.toString();if(this.documentTrie.has(t))throw new Error(`A document with the URI '${t}' is already present.`);this.documentTrie.insert(t,e)}getDocument(e){const t=e.toString();return this.documentTrie.find(t)}getDocuments(e){const t=e.toString();return this.documentTrie.findAll(t)}async getOrCreateDocument(e,t){let r=this.getDocument(e);return r||(r=await this.langiumDocumentFactory.fromUri(e,t),this.addDocument(r),r)}createDocument(e,t,r){if(r)return this.langiumDocumentFactory.fromString(t,e,r).then(n=>(this.addDocument(n),n));{const n=this.langiumDocumentFactory.fromString(t,e);return this.addDocument(n),n}}hasDocument(e){return this.documentTrie.has(e.toString())}invalidateDocument(e){const t=e.toString(),r=this.documentTrie.find(t);return r&&this.documentBuilder().resetToState(r,J.Changed),r}deleteDocument(e){const t=e.toString(),r=this.documentTrie.find(t);return r&&(r.state=J.Changed,this.documentTrie.delete(t)),r}deleteDocuments(e){const t=e.toString(),r=this.documentTrie.findAll(t);for(const n of r)n.state=J.Changed;return this.documentTrie.delete(t),r}},ln=Symbol("RefResolving"),ew=class{static{i(this,"DefaultLinker")}constructor(e){this.reflection=e.shared.AstReflection,this.langiumDocuments=()=>e.shared.workspace.LangiumDocuments,this.scopeProvider=e.references.ScopeProvider,this.astNodeLocator=e.workspace.AstNodeLocator,this.profiler=e.shared.profilers.LangiumProfiler,this.languageId=e.LanguageMetaData.languageId}async link(e,t=pe.CancellationToken.None){if(this.profiler?.isActive("linking")){const r=this.profiler.createTask("linking",this.languageId);r.start();try{for(const n of Mt(e.parseResult.value))await ze(t),Wa(n).forEach(a=>{const s=`${n.$type}:${a.property}`;r.startSubTask(s);try{this.doLink(a,e)}finally{r.stopSubTask(s)}})}finally{r.stop()}}else for(const r of Mt(e.parseResult.value))await ze(t),Wa(r).forEach(n=>this.doLink(n,e))}doLink(e,t){const r=e.reference;if("_ref"in r&&r._ref===void 0){r._ref=ln;try{const n=this.getCandidate(e);if(dn(n))r._ref=n;else{r._nodeDescription=n;const a=this.loadAstNode(n);r._ref=a??this.createLinkingError(e,n)}}catch(n){console.error(`An error occurred while resolving reference to '${r.$refText}':`,n);const a=n.message??String(n);r._ref={info:e,message:`An error occurred while resolving reference to '${r.$refText}': ${a}`}}t.references.push(r)}else if("_items"in r&&r._items===void 0){r._items=ln;try{const n=this.getCandidates(e),a=[];if(dn(n))r._linkingError=n;else for(const s of n){const o=this.loadAstNode(s);o&&a.push({ref:o,$nodeDescription:s})}r._items=a}catch(n){r._linkingError={info:e,message:`An error occurred while resolving reference to '${r.$refText}': ${n}`},r._items=[]}t.references.push(r)}}unlink(e){for(const t of e.references)"_ref"in t?(t._ref=void 0,delete t._nodeDescription):"_items"in t&&(t._items=void 0,delete t._linkingError);e.references=[]}getCandidate(e){return this.scopeProvider.getScope(e).getElement(e.reference.$refText)??this.createLinkingError(e)}getCandidates(e){const r=this.scopeProvider.getScope(e).getElements(e.reference.$refText).distinct(n=>`${n.documentUri}#${n.path}`).toArray();return r.length>0?r:this.createLinkingError(e)}buildReference(e,t,r,n){const a=this,s={$refNode:r,$refText:n,_ref:void 0,get ref(){if(Oe(this._ref))return this._ref;if(Sd(this._nodeDescription)){const o=a.loadAstNode(this._nodeDescription);this._ref=o??a.createLinkingError({reference:s,container:e,property:t},this._nodeDescription)}else if(this._ref===void 0){this._ref=ln;const o=Ga(e).$document,l=a.getLinkedNode({reference:s,container:e,property:t});if(l.error&&o&&o.state0))return this._linkingError=a.createLinkingError({reference:s,container:e,property:t})}};return s}throwCyclicReferenceError(e,t,r){throw new Error(`Cyclic reference resolution detected: ${this.astNodeLocator.getAstNodePath(e)}/${t} (symbol '${r}')`)}getLinkedNode(e){try{const t=this.getCandidate(e);if(dn(t))return{error:t};const r=this.loadAstNode(t);return r?{node:r,descr:t}:{descr:t,error:this.createLinkingError(e,t)}}catch(t){console.error(`An error occurred while resolving reference to '${e.reference.$refText}':`,t);const r=t.message??String(t);return{error:{info:e,message:`An error occurred while resolving reference to '${e.reference.$refText}': ${r}`}}}}loadAstNode(e){if(e.node)return e.node;const t=this.langiumDocuments().getDocument(e.documentUri);if(t)return this.astNodeLocator.getAstNode(t.parseResult.value,e.path)}createLinkingError(e,t){const r=Ga(e.container).$document;r&&r.stateGn(t)&&t.isMulti)}findDeclarations(e){if(e){const t=vp(e),r=e.astNode;if(t&&r){const n=r[t.feature];if(tt(n)||tr(n))return qo(n);if(Array.isArray(n)){for(const a of n)if((tt(a)||tr(a))&&a.$refNode&&a.$refNode.offset<=e.offset&&a.$refNode.end>=e.end)return qo(a)}}if(r){const n=this.nameProvider.getNameNode(r);if(n&&(n===e||Jd(e,n)))return this.getSelfNodes(r)}}return[]}getSelfNodes(e){if(this.hasMultiReference){const t=this.index.findAllReferences(e,this.nodeLocator.getAstNodePath(e)),r=this.getNodeFromReferenceDescription(t.head());if(r){for(const n of Wa(r))if(tr(n.reference)&&n.reference.items.some(a=>a.ref===e))return n.reference.items.map(a=>a.ref)}return[e]}else return[e]}getNodeFromReferenceDescription(e){if(!e)return;const t=this.documents.getDocument(e.sourceUri);if(t)return this.nodeLocator.getAstNode(t.parseResult.value,e.sourcePath)}findDeclarationNodes(e){const t=this.findDeclarations(e),r=[];for(const n of t){const a=this.nameProvider.getNameNode(n)??n.$cstNode;a&&r.push(a)}return r}findReferences(e,t){const r=[];t.includeDeclaration&&r.push(...this.getSelfReferences(e));let n=this.index.findAllReferences(e,this.nodeLocator.getAstNodePath(e));return t.documentUri&&(n=n.filter(a=>rt.equals(a.sourceUri,t.documentUri))),r.push(...n),ue(r)}getSelfReferences(e){const t=this.getSelfNodes(e),r=[];for(const n of t){const a=this.nameProvider.getNameNode(n);if(a){const s=xt(n),o=this.nodeLocator.getAstNodePath(n);r.push({sourceUri:s.uri,sourcePath:o,targetUri:s.uri,targetPath:o,segment:Ha(a),local:!0})}}return r}},wr=class{static{i(this,"MultiMap")}constructor(e){if(this.map=new Map,e)for(const[t,r]of e)this.add(t,r)}get size(){return vs.sum(ue(this.map.values()).map(e=>e.length))}clear(){this.map.clear()}delete(e,t){if(t===void 0)return this.map.delete(e);{const r=this.map.get(e);if(r){const n=r.indexOf(t);if(n>=0)return r.length===1?this.map.delete(e):r.splice(n,1),!0}return!1}}get(e){return this.map.get(e)??[]}getStream(e){const t=this.map.get(e);return t?ue(t):Ba}has(e,t){if(t===void 0)return this.map.has(e);{const r=this.map.get(e);return r?r.indexOf(t)>=0:!1}}add(e,t){return this.map.has(e)?this.map.get(e).push(t):this.map.set(e,[t]),this}addAll(e,t){return this.map.has(e)?this.map.get(e).push(...t):this.map.set(e,Array.from(t)),this}forEach(e){this.map.forEach((t,r)=>t.forEach(n=>e(n,r,this)))}[Symbol.iterator](){return this.entries().iterator()}entries(){return ue(this.map.entries()).flatMap(([e,t])=>t.map(r=>[e,r]))}keys(){return ue(this.map.keys())}values(){return ue(this.map.values()).flat()}entriesGroupedByKey(){return ue(this.map.entries())}},Il=class{static{i(this,"BiMap")}get size(){return this.map.size}constructor(e){if(this.map=new Map,this.inverse=new Map,e)for(const[t,r]of e)this.set(t,r)}clear(){this.map.clear(),this.inverse.clear()}set(e,t){return this.map.set(e,t),this.inverse.set(t,e),this}get(e){return this.map.get(e)}getKey(e){return this.inverse.get(e)}delete(e){const t=this.map.get(e);return t!==void 0?(this.map.delete(e),this.inverse.delete(t),!0):!1}},nw=class{static{i(this,"DefaultScopeComputation")}constructor(e){this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider}async collectExportedSymbols(e,t=pe.CancellationToken.None){return this.collectExportedSymbolsForNode(e.parseResult.value,e,void 0,t)}async collectExportedSymbolsForNode(e,t,r=Ms,n=pe.CancellationToken.None){const a=[];this.addExportedSymbol(e,a,t);for(const s of r(e))await ze(n),this.addExportedSymbol(s,a,t);return a}addExportedSymbol(e,t,r){const n=this.nameProvider.getName(e);n&&t.push(this.descriptions.createDescription(e,n,r))}async collectLocalSymbols(e,t=pe.CancellationToken.None){const r=e.parseResult.value,n=new wr;for(const a of Ir(r))await ze(t),this.addLocalSymbol(a,e,n);return n}addLocalSymbol(e,t,r){const n=e.$container;if(n){const a=this.nameProvider.getName(e);a&&r.add(n,this.descriptions.createDescription(e,a,t))}}},Zf=class{static{i(this,"StreamScope")}constructor(e,t,r){this.elements=e,this.outerScope=t,this.caseInsensitive=r?.caseInsensitive??!1,this.concatOuterScope=r?.concatOuterScope??!0}getAllElements(){return this.outerScope?this.elements.concat(this.outerScope.getAllElements()):this.elements}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.caseInsensitive?this.elements.find(n=>n.name.toLowerCase()===t):this.elements.find(n=>n.name===e);if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}getElements(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.caseInsensitive?this.elements.filter(n=>n.name.toLowerCase()===t):this.elements.filter(n=>n.name===e);return(this.concatOuterScope||r.isEmpty())&&this.outerScope?r.concat(this.outerScope.getElements(e)):r}},RF=class{static{i(this,"MapScope")}constructor(e,t,r){this.elements=new Map,this.caseInsensitive=r?.caseInsensitive??!1,this.concatOuterScope=r?.concatOuterScope??!0;for(const n of e){const a=this.caseInsensitive?n.name.toLowerCase():n.name;this.elements.set(a,n)}this.outerScope=t}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t);if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}getElements(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t),n=r?[r]:[];return(this.concatOuterScope||n.length>0)&&this.outerScope?ue(n).concat(this.outerScope.getElements(e)):ue(n)}getAllElements(){let e=ue(this.elements.values());return this.outerScope&&(e=e.concat(this.outerScope.getAllElements())),e}},aw=class{static{i(this,"MultiMapScope")}constructor(e,t,r){this.elements=new wr,this.caseInsensitive=r?.caseInsensitive??!1,this.concatOuterScope=r?.concatOuterScope??!0;for(const n of e){const a=this.caseInsensitive?n.name.toLowerCase():n.name;this.elements.add(a,n)}this.outerScope=t}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t)[0];if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}getElements(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t);return(this.concatOuterScope||r.length===0)&&this.outerScope?ue(r).concat(this.outerScope.getElements(e)):ue(r)}getAllElements(){let e=ue(this.elements.values());return this.outerScope&&(e=e.concat(this.outerScope.getAllElements())),e}},AF={getElement(){},getElements(){return Ba},getAllElements(){return Ba}},Mu=class{static{i(this,"DisposableCache")}constructor(){this.toDispose=[],this.isDisposed=!1}onDispose(e){this.toDispose.push(e)}dispose(){this.throwIfDisposed(),this.clear(),this.isDisposed=!0,this.toDispose.forEach(e=>e.dispose())}throwIfDisposed(){if(this.isDisposed)throw new Error("This cache has already been disposed")}},Wm=class extends Mu{static{i(this,"SimpleCache")}constructor(){super(...arguments),this.cache=new Map}has(e){return this.throwIfDisposed(),this.cache.has(e)}set(e,t){this.throwIfDisposed(),this.cache.set(e,t)}get(e,t){if(this.throwIfDisposed(),this.cache.has(e))return this.cache.get(e);if(t){const r=t();return this.cache.set(e,r),r}else return}delete(e){return this.throwIfDisposed(),this.cache.delete(e)}clear(){this.throwIfDisposed(),this.cache.clear()}},Gu=class extends Mu{static{i(this,"ContextCache")}constructor(e){super(),this.cache=new Map,this.converter=e??(t=>t)}has(e,t){return this.throwIfDisposed(),this.cacheForContext(e).has(t)}set(e,t,r){this.throwIfDisposed(),this.cacheForContext(e).set(t,r)}get(e,t,r){this.throwIfDisposed();const n=this.cacheForContext(e);if(n.has(t))return n.get(t);if(r){const a=r();return n.set(t,a),a}else return}delete(e,t){return this.throwIfDisposed(),this.cacheForContext(e).delete(t)}clear(e){if(this.throwIfDisposed(),e){const t=this.converter(e);this.cache.delete(t)}else this.cache.clear()}cacheForContext(e){const t=this.converter(e);let r=this.cache.get(t);return r||(r=new Map,this.cache.set(t,r)),r}},iw=class extends Gu{static{i(this,"DocumentCache")}constructor(e,t){super(r=>r.toString()),t?(this.toDispose.push(e.workspace.DocumentBuilder.onDocumentPhase(t,r=>{this.clear(r.uri.toString())})),this.toDispose.push(e.workspace.DocumentBuilder.onUpdate((r,n)=>{for(const a of n)this.clear(a)}))):this.toDispose.push(e.workspace.DocumentBuilder.onUpdate((r,n)=>{const a=r.concat(n);for(const s of a)this.clear(s)}))}},qm=class extends Wm{static{i(this,"WorkspaceCache")}constructor(e,t){super(),t?(this.toDispose.push(e.workspace.DocumentBuilder.onBuildPhase(t,()=>{this.clear()})),this.toDispose.push(e.workspace.DocumentBuilder.onUpdate((r,n)=>{n.length>0&&this.clear()}))):this.toDispose.push(e.workspace.DocumentBuilder.onUpdate(()=>{this.clear()}))}},sw=class{static{i(this,"DefaultScopeProvider")}constructor(e){this.reflection=e.shared.AstReflection,this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider,this.indexManager=e.shared.workspace.IndexManager,this.globalScopeCache=new qm(e.shared)}getScope(e){const t=[],r=this.reflection.getReferenceType(e),n=xt(e.container).localSymbols;if(n){let s=e.container;do n.has(s)&&t.push(n.getStream(s).filter(o=>this.reflection.isSubtype(o.type,r))),s=s.$container;while(s)}let a=this.getGlobalScope(r,e);for(let s=t.length-1;s>=0;s--)a=this.createScope(t[s],a);return a}createScope(e,t,r){return new Zf(ue(e),t,r)}createScopeForNodes(e,t,r){const n=ue(e).map(a=>{const s=this.nameProvider.getName(a);if(s)return this.descriptions.createDescription(a,s)}).nonNullable();return new Zf(n,t,r)}getGlobalScope(e,t){return this.globalScopeCache.get(e,()=>new aw(this.indexManager.allElements(e)))}};function Vm(e){return typeof e.$comment=="string"}i(Vm,"isAstNodeWithComment");function Qf(e){return typeof e=="object"&&!!e&&("$ref"in e||"$error"in e)}i(Qf,"isIntermediateReference");var ow=class{static{i(this,"DefaultJsonSerializer")}constructor(e){this.ignoreProperties=new Set(["$container","$containerProperty","$containerIndex","$document","$cstNode"]),this.langiumDocuments=e.shared.workspace.LangiumDocuments,this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider,this.commentProvider=e.documentation.CommentProvider}serialize(e,t){const r=t??{},n=t?.replacer,a=i((o,l)=>this.replacer(o,l,r),"defaultReplacer"),s=n?(o,l)=>n(o,l,a):a;try{return this.currentDocument=xt(e),JSON.stringify(e,s,t?.space)}finally{this.currentDocument=void 0}}deserialize(e,t){const r=t??{},n=JSON.parse(e);return this.linkNode(n,n,r),n}replacer(e,t,{refText:r,sourceText:n,textRegions:a,comments:s,uriConverter:o}){if(!this.ignoreProperties.has(e))if(tt(t)){const l=t.ref,u=r?t.$refText:void 0;if(l){const c=xt(l);let f="";this.currentDocument&&this.currentDocument!==c&&(o?f=o(c.uri,l):f=c.uri.toString());const d=this.astNodeLocator.getAstNodePath(l);return{$ref:`${f}#${d}`,$refText:u}}else return{$error:t.error?.message??"Could not resolve reference",$refText:u}}else if(tr(t)){const l=r?t.$refText:void 0,u=[];for(const c of t.items){const f=c.ref,d=xt(c.ref);let m="";this.currentDocument&&this.currentDocument!==d&&(o?m=o(d.uri,f):m=d.uri.toString());const g=this.astNodeLocator.getAstNodePath(f);u.push(`${m}#${g}`)}return{$refs:u,$refText:l}}else if(Oe(t)){let l;if(a&&(l=this.addAstNodeRegionWithAssignmentsTo({...t}),(!e||t.$document)&&l?.$textRegion&&(l.$textRegion.documentURI=this.currentDocument?.uri.toString())),n&&!e&&(l??(l={...t}),l.$sourceText=t.$cstNode?.text),s){l??(l={...t});const u=this.commentProvider.getComment(t);u&&(l.$comment=u.replace(/\r/g,""))}return l??t}else return t}addAstNodeRegionWithAssignmentsTo(e){const t=i(r=>({offset:r.offset,end:r.end,length:r.length,range:r.range}),"createDocumentSegment");if(e.$cstNode){const r=e.$textRegion=t(e.$cstNode),n=r.assignments={};return Object.keys(e).filter(a=>!a.startsWith("$")).forEach(a=>{const s=yp(e.$cstNode,a).map(t);s.length!==0&&(n[a]=s)}),e}}linkNode(e,t,r,n,a,s){for(const[l,u]of Object.entries(e))if(Array.isArray(u))for(let c=0;c{await this.handleException(()=>e.call(t,r,n,a),"An error occurred during validation",n,r)}}async handleException(e,t,r,n){try{await e()}catch(a){if(ea(a))throw a;console.error(`${t}:`,a),a instanceof Error&&a.stack&&console.error(a.stack);const s=a instanceof Error?a.message:String(a);r("error",`${t}: ${s}`,{node:n})}}addEntry(e,t){if(e==="AstNode"){this.entries.add("AstNode",t);return}for(const r of this.reflection.getAllSubTypes(e))this.entries.add(r,t)}getChecks(e,t){let r=ue(this.entries.get(e)).concat(this.entries.get("AstNode"));return t&&(r=r.filter(n=>t.includes(n.category))),r.map(n=>n.check)}registerBeforeDocument(e,t=this){this.entriesBefore.push(this.wrapPreparationException(e,"An error occurred during set-up of the validation",t))}registerAfterDocument(e,t=this){this.entriesAfter.push(this.wrapPreparationException(e,"An error occurred during tear-down of the validation",t))}wrapPreparationException(e,t,r){return async(n,a,s,o)=>{await this.handleException(()=>e.call(r,n,a,s,o),t,a,n)}}get checksBefore(){return this.entriesBefore}get checksAfter(){return this.entriesAfter}getAllValidationCategories(e){return this.knownCategories}},cw=Object.freeze({validateNode:!0,validateChildren:!0}),fw=class{static{i(this,"DefaultDocumentValidator")}constructor(e){this.validationRegistry=e.validation.ValidationRegistry,this.metadata=e.LanguageMetaData,this.profiler=e.shared.profilers.LangiumProfiler,this.languageId=e.LanguageMetaData.languageId}async validateDocument(e,t={},r=pe.CancellationToken.None){const n=e.parseResult,a=[];if(await ze(r),(!t.categories||t.categories.includes("built-in"))&&(this.processLexingErrors(n,a,t),t.stopAfterLexingErrors&&a.some(s=>s.data?.code===bt.LexingError)||(this.processParsingErrors(n,a,t),t.stopAfterParsingErrors&&a.some(s=>s.data?.code===bt.ParsingError))||(this.processLinkingErrors(e,a,t),t.stopAfterLinkingErrors&&a.some(s=>s.data?.code===bt.LinkingError))))return a;try{a.push(...await this.validateAst(n.value,t,r))}catch(s){if(ea(s))throw s;console.error("An error occurred during validation:",s)}return await ze(r),a}processLexingErrors(e,t,r){const n=[...e.lexerErrors,...e.lexerReport?.diagnostics??[]];for(const a of n){const s=a.severity??"error",o={severity:ys(s),range:{start:{line:a.line-1,character:a.column-1},end:{line:a.line-1,character:a.column+a.length-1}},message:a.message,data:Ym(s),source:this.getSource()};t.push(o)}}processParsingErrors(e,t,r){for(const n of e.parserErrors){let a;if(isNaN(n.token.startOffset)){if("previousToken"in n){const s=n.previousToken;if(isNaN(s.startOffset)){const o={line:0,character:0};a={start:o,end:o}}else{const o={line:s.endLine-1,character:s.endColumn};a={start:o,end:o}}}}else a=Ts(n.token);if(a){const s={severity:ys("error"),range:a,message:n.message,data:_n(bt.ParsingError),source:this.getSource()};t.push(s)}}}processLinkingErrors(e,t,r){for(const n of e.references){const a=n.error;if(a){const s={node:a.info.container,range:n.$refNode?.range,property:a.info.property,index:a.info.index,data:{code:bt.LinkingError,containerType:a.info.container.$type,property:a.info.property,refText:a.info.reference.$refText}};t.push(this.toDiagnostic("error",a.message,s))}}}async validateAst(e,t,r=pe.CancellationToken.None){const n=[],a=i((s,o,l)=>{n.push(this.toDiagnostic(s,o,l))},"acceptor");return await this.validateAstBefore(e,t,a,r),await this.validateAstNodes(e,t,a,r),await this.validateAstAfter(e,t,a,r),n}async validateAstBefore(e,t,r,n=pe.CancellationToken.None){const a=this.validationRegistry.checksBefore;for(const s of a)await ze(n),await s(e,r,t.categories??[],n)}async validateAstNodes(e,t,r,n=pe.CancellationToken.None){if(this.profiler?.isActive("validating")){const a=this.profiler.createTask("validating",this.languageId);a.start();try{const s=Mt(e).iterator();for(const o of s){a.startSubTask(o.$type);const l=this.validateSingleNodeOptions(o,t);if(l.validateNode)try{const u=this.validationRegistry.getChecks(o.$type,t.categories);for(const c of u)await c(o,r,n)}finally{a.stopSubTask(o.$type)}l.validateChildren||s.prune()}}finally{a.stop()}}else{const a=Mt(e).iterator();for(const s of a){await ze(n);const o=this.validateSingleNodeOptions(s,t);if(o.validateNode){const l=this.validationRegistry.getChecks(s.$type,t.categories);for(const u of l)await u(s,r,n)}o.validateChildren||a.prune()}}}validateSingleNodeOptions(e,t){return cw}async validateAstAfter(e,t,r,n=pe.CancellationToken.None){const a=this.validationRegistry.checksAfter;for(const s of a)await ze(n),await s(e,r,t.categories??[],n)}toDiagnostic(e,t,r){return{message:t,range:Hm(r),severity:ys(e),code:r.code,codeDescription:r.codeDescription,tags:r.tags,relatedInformation:r.relatedInformation,data:r.data,source:this.getSource()}}getSource(){return this.metadata.languageId}};function Hm(e){if(e.range)return e.range;let t;return typeof e.property=="string"?t=Hl(e.node.$cstNode,e.property,e.index):typeof e.keyword=="string"&&(t=gp(e.node.$cstNode,e.keyword,e.index)),t??(t=e.node.$cstNode),t?t.range:{start:{line:0,character:0},end:{line:0,character:0}}}i(Hm,"getDiagnosticRange");function ys(e){switch(e){case"error":return 1;case"warning":return 2;case"info":return 3;case"hint":return 4;default:throw new Error("Invalid diagnostic severity: "+e)}}i(ys,"toDiagnosticSeverity");function Ym(e){switch(e){case"error":return _n(bt.LexingError);case"warning":return _n(bt.LexingWarning);case"info":return _n(bt.LexingInfo);case"hint":return _n(bt.LexingHint);default:throw new Error("Invalid diagnostic severity: "+e)}}i(Ym,"toDiagnosticData");var bt;(function(e){e.LexingError="lexing-error",e.LexingWarning="lexing-warning",e.LexingInfo="lexing-info",e.LexingHint="lexing-hint",e.ParsingError="parsing-error",e.LinkingError="linking-error"})(bt||(bt={}));var dw=class{static{i(this,"DefaultAstNodeDescriptionProvider")}constructor(e){this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider}createDescription(e,t,r){const n=r??xt(e);t??(t=this.nameProvider.getName(e));const a=this.astNodeLocator.getAstNodePath(e);if(!t)throw new Error(`Node at path ${a} has no name.`);let s;const o=i(()=>s??(s=Ha(this.nameProvider.getNameNode(e)??e.$cstNode)),"nameSegmentGetter");return{node:e,name:t,get nameSegment(){return o()},selectionSegment:Ha(e.$cstNode),type:e.$type,documentUri:n.uri,path:a}}},pw=class{static{i(this,"DefaultReferenceDescriptionProvider")}constructor(e){this.nodeLocator=e.workspace.AstNodeLocator}async createDescriptions(e,t=pe.CancellationToken.None){const r=[],n=e.parseResult.value;for(const a of Mt(n))await ze(t),Wa(a).forEach(s=>{s.reference.error||r.push(...this.createInfoDescriptions(s))});return r}createInfoDescriptions(e){const t=e.reference;if(t.error||!t.$refNode)return[];let r=[];tt(t)&&t.$nodeDescription?r=[t.$nodeDescription]:tr(t)&&(r=t.items.map(l=>l.$nodeDescription).filter(l=>l!==void 0));const n=xt(e.container).uri,a=this.nodeLocator.getAstNodePath(e.container),s=[],o=Ha(t.$refNode);for(const l of r)s.push({sourceUri:n,sourcePath:a,targetUri:l.documentUri,targetPath:l.path,segment:o,local:rt.equals(l.documentUri,n)});return s}},mw=class{static{i(this,"DefaultAstNodeLocator")}constructor(){this.segmentSeparator="/",this.indexSeparator="@"}getAstNodePath(e){if(e.$container){const t=this.getAstNodePath(e.$container),r=this.getPathSegment(e);return t+this.segmentSeparator+r}return""}getPathSegment({$containerProperty:e,$containerIndex:t}){if(!e)throw new Error("Missing '$containerProperty' in AST node.");return t!==void 0?e+this.indexSeparator+t:e}getAstNode(e,t){return t.split(this.segmentSeparator).reduce((n,a)=>{if(!n||a.length===0)return n;const s=a.indexOf(this.indexSeparator);if(s>0){const o=a.substring(0,s),l=parseInt(a.substring(s+1));return n[o]?.[l]}return n[a]},e)}},Fu={};Ol(Fu,Ed(Qa()));var hw=class{static{i(this,"DefaultConfigurationProvider")}constructor(e){this._ready=new Sr,this.onConfigurationSectionUpdateEmitter=new Fu.Emitter,this.settings={},this.workspaceConfig=!1,this.serviceRegistry=e.ServiceRegistry}get ready(){return this._ready.promise}initialize(e){this.workspaceConfig=e.capabilities.workspace?.configuration??!1}async initialized(e){if(this.workspaceConfig){if(e.register){const t=this.serviceRegistry.all;e.register({section:t.map(r=>this.toSectionName(r.LanguageMetaData.languageId))})}if(e.fetchConfiguration){const t=this.serviceRegistry.all.map(n=>({section:this.toSectionName(n.LanguageMetaData.languageId)})),r=await e.fetchConfiguration(t);t.forEach((n,a)=>{this.updateSectionConfiguration(n.section,r[a])})}}this._ready.resolve()}updateConfiguration(e){typeof e.settings!="object"||e.settings===null||Object.entries(e.settings).forEach(([t,r])=>{this.updateSectionConfiguration(t,r),this.onConfigurationSectionUpdateEmitter.fire({section:t,configuration:r})})}updateSectionConfiguration(e,t){this.settings[e]=t}async getConfiguration(e,t){await this.ready;const r=this.toSectionName(e);if(this.settings[r])return this.settings[r][t]}toSectionName(e){return`${e}`}get onConfigurationSectionUpdate(){return this.onConfigurationSectionUpdateEmitter.event}},lo=Ed(rN()),In;(function(e){function t(r){return{dispose:i(async()=>await r(),"dispose")}}i(t,"create"),e.create=t})(In||(In={}));var yw=class{static{i(this,"DefaultDocumentBuilder")}constructor(e){this.updateBuildOptions={validation:{categories:["built-in","fast"]}},this.updateListeners=[],this.buildPhaseListeners=new wr,this.documentPhaseListeners=new wr,this.buildState=new Map,this.documentBuildWaiters=new Map,this.currentState=J.Changed,this.langiumDocuments=e.workspace.LangiumDocuments,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory,this.textDocuments=e.workspace.TextDocuments,this.indexManager=e.workspace.IndexManager,this.fileSystemProvider=e.workspace.FileSystemProvider,this.workspaceManager=()=>e.workspace.WorkspaceManager,this.serviceRegistry=e.ServiceRegistry}async build(e,t={},r=pe.CancellationToken.None){for(const n of e){const a=n.uri.toString();if(n.state===J.Validated){if(typeof t.validation=="boolean"&&t.validation)this.resetToState(n,J.IndexedReferences);else if(typeof t.validation=="object"){const s=this.findMissingValidationCategories(n,t);s.length>0&&(this.buildState.set(a,{completed:!1,options:{validation:{categories:s}},result:this.buildState.get(a)?.result}),n.state=J.IndexedReferences)}}else this.buildState.delete(a)}this.currentState=J.Changed,await this.emitUpdate(e.map(n=>n.uri),[]),await this.buildDocuments(e,t,r)}async update(e,t,r=pe.CancellationToken.None){this.currentState=J.Changed;const n=[];for(const l of t){const u=this.langiumDocuments.deleteDocuments(l);for(const c of u)n.push(c.uri),this.cleanUpDeleted(c)}const a=(await Promise.all(e.map(l=>this.findChangedUris(l)))).flat();for(const l of a){let u=this.langiumDocuments.getDocument(l);u===void 0&&(u=this.langiumDocumentFactory.fromModel({$type:"INVALID"},l),u.state=J.Changed,this.langiumDocuments.addDocument(u)),this.resetToState(u,J.Changed)}const s=ue(a).concat(n).map(l=>l.toString()).toSet();this.langiumDocuments.all.filter(l=>!s.has(l.uri.toString())&&this.shouldRelink(l,s)).forEach(l=>this.resetToState(l,J.ComputedScopes)),await this.emitUpdate(a,n),await ze(r);const o=this.sortDocuments(this.langiumDocuments.all.filter(l=>l.state=1}findMissingValidationCategories(e,t){const r=this.buildState.get(e.uri.toString()),n=this.serviceRegistry.getServices(e.uri).validation.ValidationRegistry.getAllValidationCategories(e),a=r?.result?.validationChecks?new Set(r?.result?.validationChecks):r?.completed?n:new Set,s=t===void 0||t.validation===!0?n:typeof t.validation=="object"?t.validation.categories??n:[];return ue(s).filter(o=>!a.has(o)).toArray()}async findChangedUris(e){if(this.langiumDocuments.getDocument(e)??this.textDocuments?.get(e))return[e];try{const r=await this.fileSystemProvider.stat(e);if(r.isDirectory)return await this.workspaceManager().searchFolder(e);if(this.workspaceManager().shouldIncludeEntry(r))return[e]}catch{}return[]}async emitUpdate(e,t){await Promise.all(this.updateListeners.map(r=>r(e,t)))}sortDocuments(e){let t=0,r=e.length-1;for(;t=0&&!this.hasTextDocument(e[r]);)r--;tr.error!==void 0)?!0:this.indexManager.isAffected(e,t)}onUpdate(e){return this.updateListeners.push(e),In.create(()=>{const t=this.updateListeners.indexOf(e);t>=0&&this.updateListeners.splice(t,1)})}resetToState(e,t){switch(t){case J.Changed:case J.Parsed:this.indexManager.removeContent(e.uri);case J.IndexedContent:e.localSymbols=void 0;case J.ComputedScopes:this.serviceRegistry.getServices(e.uri).references.Linker.unlink(e);case J.Linked:this.indexManager.removeReferences(e.uri);case J.IndexedReferences:e.diagnostics=void 0,this.buildState.delete(e.uri.toString());case J.Validated:}e.state>t&&(e.state=t)}cleanUpDeleted(e){this.buildState.delete(e.uri.toString()),this.indexManager.remove(e.uri),e.state=J.Changed}async buildDocuments(e,t,r){this.prepareBuild(e,t),await this.runCancelable(e,J.Parsed,r,s=>this.langiumDocumentFactory.update(s,r)),await this.runCancelable(e,J.IndexedContent,r,s=>this.indexManager.updateContent(s,r)),await this.runCancelable(e,J.ComputedScopes,r,async s=>{const o=this.serviceRegistry.getServices(s.uri).references.ScopeComputation;s.localSymbols=await o.collectLocalSymbols(s,r)});const n=e.filter(s=>this.shouldLink(s));await this.runCancelable(n,J.Linked,r,s=>this.serviceRegistry.getServices(s.uri).references.Linker.link(s,r)),await this.runCancelable(n,J.IndexedReferences,r,s=>this.indexManager.updateReferences(s,r));const a=e.filter(s=>this.shouldValidate(s)?!0:(this.markAsCompleted(s),!1));await this.runCancelable(a,J.Validated,r,async s=>{await this.validate(s,r),this.markAsCompleted(s)})}markAsCompleted(e){const t=this.buildState.get(e.uri.toString());t&&(t.completed=!0)}prepareBuild(e,t){for(const r of e){const n=r.uri.toString(),a=this.buildState.get(n);(!a||a.completed)&&this.buildState.set(n,{completed:!1,options:t,result:a?.result})}}async runCancelable(e,t,r,n){for(const s of e)s.states.state===t);await this.notifyBuildPhase(a,t,r),this.currentState=t}onBuildPhase(e,t){return this.buildPhaseListeners.add(e,t),In.create(()=>{this.buildPhaseListeners.delete(e,t)})}onDocumentPhase(e,t){return this.documentPhaseListeners.add(e,t),In.create(()=>{this.documentPhaseListeners.delete(e,t)})}waitUntil(e,t,r){let n;return t&&"path"in t?n=t:r=t,r??(r=pe.CancellationToken.None),n?this.awaitDocumentState(e,n,r):this.awaitBuilderState(e,r)}awaitDocumentState(e,t,r){const n=this.langiumDocuments.getDocument(t);if(n){if(n.state>=e)return Promise.resolve(t);if(r.isCancellationRequested)return Promise.reject(er);if(this.currentState>=e&&e>n.state)return Promise.reject(new lo.ResponseError(lo.LSPErrorCodes.RequestFailed,`Document state of ${t.toString()} is ${J[n.state]}, requiring ${J[e]}, but workspace state is already ${J[this.currentState]}. Returning undefined.`))}else return Promise.reject(new lo.ResponseError(lo.LSPErrorCodes.ServerCancelled,`No document found for URI: ${t.toString()}`));return new Promise((a,s)=>{const o=this.onDocumentPhase(e,u=>{rt.equals(u.uri,t)&&(o.dispose(),l.dispose(),a(u.uri))}),l=r.onCancellationRequested(()=>{o.dispose(),l.dispose(),s(er)})})}awaitBuilderState(e,t){return this.currentState>=e?Promise.resolve():t.isCancellationRequested?Promise.reject(er):new Promise((r,n)=>{const a=this.onBuildPhase(e,()=>{a.dispose(),s.dispose(),r()}),s=t.onCancellationRequested(()=>{a.dispose(),s.dispose(),n(er)})})}async notifyDocumentPhase(e,t,r){const a=this.documentPhaseListeners.get(t).slice();for(const s of a)try{await ze(r),await s(e,r)}catch(o){if(!ea(o))throw o}}async notifyBuildPhase(e,t,r){if(e.length===0)return;const a=this.buildPhaseListeners.get(t).slice();for(const s of a)await ze(r),await s(e,r)}shouldLink(e){return this.getBuildOptions(e).eagerLinking??!0}shouldValidate(e){return!!this.getBuildOptions(e).validation}async validate(e,t){const r=this.serviceRegistry.getServices(e.uri).validation.DocumentValidator,n=this.getBuildOptions(e),a=typeof n.validation=="object"?{...n.validation}:{};a.categories=this.findMissingValidationCategories(e,n);const s=await r.validateDocument(e,a,t);e.diagnostics?e.diagnostics.push(...s):e.diagnostics=s;const o=this.buildState.get(e.uri.toString());o&&(o.result??(o.result={}),o.result.validationChecks?o.result.validationChecks=ue(o.result.validationChecks).concat(a.categories).distinct().toArray():o.result.validationChecks=[...a.categories])}getBuildOptions(e){return this.buildState.get(e.uri.toString())?.options??{}}},gw=class{static{i(this,"DefaultIndexManager")}constructor(e){this.symbolIndex=new Map,this.symbolByTypeIndex=new Gu,this.referenceIndex=new Map,this.documents=e.workspace.LangiumDocuments,this.serviceRegistry=e.ServiceRegistry,this.astReflection=e.AstReflection}findAllReferences(e,t){const r=xt(e).uri,n=[];return this.referenceIndex.forEach(a=>{a.forEach(s=>{rt.equals(s.targetUri,r)&&s.targetPath===t&&n.push(s)})}),ue(n)}allElements(e,t){let r=ue(this.symbolIndex.keys());return t&&(r=r.filter(n=>!t||t.has(n))),r.map(n=>this.getFileDescriptions(n,e)).flat()}getFileDescriptions(e,t){return t?this.symbolByTypeIndex.get(e,t,()=>(this.symbolIndex.get(e)??[]).filter(a=>this.astReflection.isSubtype(a.type,t))):this.symbolIndex.get(e)??[]}remove(e){this.removeContent(e),this.removeReferences(e)}removeContent(e){const t=e.toString();this.symbolIndex.delete(t),this.symbolByTypeIndex.clear(t)}removeReferences(e){const t=e.toString();this.referenceIndex.delete(t)}async updateContent(e,t=pe.CancellationToken.None){const n=await this.serviceRegistry.getServices(e.uri).references.ScopeComputation.collectExportedSymbols(e,t),a=e.uri.toString();this.symbolIndex.set(a,n),this.symbolByTypeIndex.clear(a)}async updateReferences(e,t=pe.CancellationToken.None){const n=await this.serviceRegistry.getServices(e.uri).workspace.ReferenceDescriptionProvider.createDescriptions(e,t);this.referenceIndex.set(e.uri.toString(),n)}isAffected(e,t){const r=this.referenceIndex.get(e.uri.toString());return r?r.some(n=>!n.local&&t.has(n.targetUri.toString())):!1}},vw=class{static{i(this,"DefaultWorkspaceManager")}constructor(e){this.initialBuildOptions={},this._ready=new Sr,this.serviceRegistry=e.ServiceRegistry,this.langiumDocuments=e.workspace.LangiumDocuments,this.documentBuilder=e.workspace.DocumentBuilder,this.fileSystemProvider=e.workspace.FileSystemProvider,this.mutex=e.workspace.WorkspaceLock}get ready(){return this._ready.promise}get workspaceFolders(){return this.folders}initialize(e){this.folders=e.workspaceFolders??void 0}initialized(e){return this.mutex.write(t=>this.initializeWorkspace(this.folders??[],t))}async initializeWorkspace(e,t=pe.CancellationToken.None){const r=await this.performStartup(e);await ze(t),await this.documentBuilder.build(r,this.initialBuildOptions,t)}async performStartup(e){const t=[],r=i(s=>{t.push(s),this.langiumDocuments.hasDocument(s.uri)||this.langiumDocuments.addDocument(s)},"collector");await this.loadAdditionalDocuments(e,r);const n=[];await Promise.all(e.map(s=>this.getRootFolder(s)).map(async s=>this.traverseFolder(s,n)));const a=ue(n).distinct(s=>s.toString()).filter(s=>!this.langiumDocuments.hasDocument(s));return await this.loadWorkspaceDocuments(a,r),this._ready.resolve(),t}async loadWorkspaceDocuments(e,t){await Promise.all(e.map(async r=>{const n=await this.langiumDocuments.getOrCreateDocument(r);t(n)}))}loadAdditionalDocuments(e,t){return Promise.resolve()}getRootFolder(e){return vt.parse(e.uri)}async traverseFolder(e,t){try{const r=await this.fileSystemProvider.readDirectory(e);await Promise.all(r.map(async n=>{this.shouldIncludeEntry(n)&&(n.isDirectory?await this.traverseFolder(n.uri,t):n.isFile&&t.push(n.uri))}))}catch(r){console.error("Failure to read directory content of "+e.toString(!0),r)}}async searchFolder(e){const t=[];return await this.traverseFolder(e,t),t}shouldIncludeEntry(e){const t=rt.basename(e.uri);return t.startsWith(".")?!1:e.isDirectory?t!=="node_modules"&&t!=="out":e.isFile?this.serviceRegistry.hasServices(e.uri):!1}},Tw=class{static{i(this,"DefaultLexerErrorMessageProvider")}buildUnexpectedCharactersMessage(e,t,r,n,a){return kf.buildUnexpectedCharactersMessage(e,t,r,n,a)}buildUnableToPopLexerModeMessage(e){return kf.buildUnableToPopLexerModeMessage(e)}},Xm={mode:"full"},Jm=class{static{i(this,"DefaultLexer")}constructor(e){this.errorMessageProvider=e.parser.LexerErrorMessageProvider,this.tokenBuilder=e.parser.TokenBuilder;const t=this.tokenBuilder.buildTokens(e.Grammar,{caseInsensitive:e.LanguageMetaData.caseInsensitive});this.tokenTypes=this.toTokenTypeDictionary(t);const r=Pl(t)?Object.values(t):t,n=e.LanguageMetaData.mode==="production";this.chevrotainLexer=new nt(r,{positionTracking:"full",skipValidations:n,errorMessageProvider:this.errorMessageProvider})}get definition(){return this.tokenTypes}tokenize(e,t=Xm){const r=this.chevrotainLexer.tokenize(e);return{tokens:r.tokens,errors:r.errors,hidden:r.groups.hidden??[],report:this.tokenBuilder.flushLexingReport?.(e)}}toTokenTypeDictionary(e){if(Pl(e))return e;const t=ju(e)?Object.values(e.modes).flat():e,r={};return t.forEach(n=>r[n.name]=n),r}};function zu(e){return Array.isArray(e)&&(e.length===0||"name"in e[0])}i(zu,"isTokenTypeArray");function ju(e){return e&&"modes"in e&&"defaultMode"in e}i(ju,"isIMultiModeLexerDefinition");function Pl(e){return!zu(e)&&!ju(e)}i(Pl,"isTokenTypeDictionary");Ds();function Zm(e,t,r){let n,a;typeof e=="string"?(a=t,n=r):(a=e.range.start,n=t),a||(a=ie.create(0,0));const s=eh(e),o=Bu(n),l=$w({lines:s,position:a,options:o});return Ew({index:0,tokens:l,position:a})}i(Zm,"parseJSDoc");function Qm(e,t){const r=Bu(t),n=eh(e);if(n.length===0)return!1;const a=n[0],s=n[n.length-1],o=r.start,l=r.end;return!!o?.exec(a)&&!!l?.exec(s)}i(Qm,"isJSDoc");function eh(e){let t="";return typeof e=="string"?t=e:t=e.text,t.split(Av)}i(eh,"getLines");var Ny=/\s*(@([\p{L}][\p{L}\p{N}]*)?)/uy,EF=/\{(@[\p{L}][\p{L}\p{N}]*)(\s*)([^\r\n}]+)?\}/gu;function $w(e){const t=[];let r=e.position.line,n=e.position.character;for(let a=0;a=l.length){if(t.length>0){const f=ie.create(r,n);t.push({type:"break",content:"",range:Q.create(f,f)})}}else{Ny.lastIndex=u;const f=Ny.exec(l);if(f){const d=f[0],m=f[1],g=ie.create(r,n+u),v=ie.create(r,n+u+d.length);t.push({type:"tag",content:m,range:Q.create(g,v)}),u+=d.length,u=kl(l,u)}if(u0&&t[t.length-1].type==="break"?t.slice(0,-1):t}i($w,"tokenize");function Rw(e,t,r,n){const a=[];if(e.length===0){const s=ie.create(r,n),o=ie.create(r,n+t.length);a.push({type:"text",content:t,range:Q.create(s,o)})}else{let s=0;for(const l of e){const u=l.index,c=t.substring(s,u);c.length>0&&a.push({type:"text",content:t.substring(s,u),range:Q.create(ie.create(r,s+n),ie.create(r,u+n))});let f=c.length+1;const d=l[1];if(a.push({type:"inline-tag",content:d,range:Q.create(ie.create(r,s+f+n),ie.create(r,s+f+d.length+n))}),f+=d.length,l.length===4){f+=l[2].length;const m=l[3];a.push({type:"text",content:m,range:Q.create(ie.create(r,s+f+n),ie.create(r,s+f+m.length+n))})}else a.push({type:"text",content:"",range:Q.create(ie.create(r,s+f+n),ie.create(r,s+f+n))});s=u+l[0].length}const o=t.substring(s);o.length>0&&a.push({type:"text",content:o,range:Q.create(ie.create(r,s+n),ie.create(r,s+n+o.length))})}return a}i(Rw,"buildInlineTokens");var CF=/\S/,bF=/\s*$/;function kl(e,t){const r=e.substring(t).match(CF);return r?t+r.index:e.length}i(kl,"skipWhitespace");function Aw(e){const t=e.match(bF);if(t&&typeof t.index=="number")return t.index}i(Aw,"lastCharacter");function Ew(e){const t=ie.create(e.position.line,e.position.character);if(e.tokens.length===0)return new Py([],Q.create(t,t));const r=[];for(;e.indext.name===e)}getTags(e){return this.getAllTags().filter(t=>t.name===e)}getAllTags(){return this.elements.filter(e=>"name"in e)}toString(){let e="";for(const t of this.elements)if(e.length===0)e=t.toString();else{const r=t.toString();e+=td(e)+r}return e.trim()}toMarkdown(e){let t="";for(const r of this.elements)if(t.length===0)t=r.toMarkdown(e);else{const n=r.toMarkdown(e);t+=td(t)+n}return t.trim()}},Zu=class{static{i(this,"JSDocTagImpl")}constructor(e,t,r,n){this.name=e,this.content=t,this.inline=r,this.range=n}toString(){let e=`@${this.name}`;const t=this.content.toString();return this.content.inlines.length===1?e=`${e} ${t}`:this.content.inlines.length>1&&(e=`${e} +${t}`),this.inline?`{${e}}`:e}toMarkdown(e){return e?.renderTag?.(this)??this.toMarkdownDefault(e)}toMarkdownDefault(e){const t=this.content.toMarkdown(e);if(this.inline){const a=Sw(this.name,t,e??{});if(typeof a=="string")return a}let r="";e?.tag==="italic"||e?.tag===void 0?r="*":e?.tag==="bold"?r="**":e?.tag==="bold-italic"&&(r="***");let n=`${r}@${this.name}${r}`;return this.content.inlines.length===1?n=`${n} — ${t}`:this.content.inlines.length>1&&(n=`${n} +${t}`),this.inline?`{${n}}`:n}};function Sw(e,t,r){if(e==="linkplain"||e==="linkcode"||e==="link"){const n=t.indexOf(" ");let a=t;if(n>0){const o=kl(t,n);a=t.substring(o),t=t.substring(0,n)}return(e==="linkcode"||e==="link"&&r.link==="code")&&(a=`\`${a}\``),r.renderLink?.(t,a)??ww(t,a)}}i(Sw,"renderInlineTag");function ww(e,t){try{return vt.parse(e,!0),`[${t}](${e})`}catch{return e}}i(ww,"renderLinkDefault");var ed=class{static{i(this,"JSDocTextImpl")}constructor(e,t){this.inlines=e,this.range=t}toString(){let e="";for(let t=0;tr.range.start.line&&(e+=` +`)}return e}toMarkdown(e){let t="";for(let r=0;rn.range.start.line&&(t+=` +`)}return t}},Iw=class{static{i(this,"JSDocLineImpl")}constructor(e,t){this.text=e,this.range=t}toString(){return this.text}toMarkdown(){return this.text}};function td(e){return e.endsWith(` +`)?` +`:` + +`}i(td,"fillNewlines");var Nw=class{static{i(this,"JSDocDocumentationProvider")}constructor(e){this.indexManager=e.shared.workspace.IndexManager,this.commentProvider=e.documentation.CommentProvider}getDocumentation(e){const t=this.commentProvider.getComment(e);if(t&&Qm(t))return Zm(t).toMarkdown({renderLink:i((n,a)=>this.documentationLinkRenderer(e,n,a),"renderLink"),renderTag:i(n=>this.documentationTagRenderer(e,n),"renderTag")})}documentationLinkRenderer(e,t,r){const n=this.findNameInLocalSymbols(e,t)??this.findNameInGlobalScope(e,t);if(n&&n.nameSegment){const a=n.nameSegment.range.start.line+1,s=n.nameSegment.range.start.character+1,o=n.documentUri.with({fragment:`L${a},${s}`});return`[${r}](${o.toString()})`}else return}documentationTagRenderer(e,t){}findNameInLocalSymbols(e,t){const n=xt(e).localSymbols;if(!n)return;let a=e;do{const o=n.getStream(a).find(l=>l.name===t);if(o)return o;a=a.$container}while(a)}findNameInGlobalScope(e,t){return this.indexManager.allElements().find(n=>n.name===t)}},Pw=class{static{i(this,"DefaultCommentProvider")}constructor(e){this.grammarConfig=()=>e.parser.GrammarConfig}getComment(e){return Vm(e)?e.$comment:tp(e.$cstNode,this.grammarConfig().multilineCommentRules)?.text}},kw=class{static{i(this,"DefaultAsyncParser")}constructor(e){this.syncParser=e.parser.LangiumParser}parse(e,t){return Promise.resolve(this.syncParser.parse(e))}},_F=class{static{i(this,"AbstractThreadedAsyncParser")}constructor(e){this.threadCount=8,this.terminationDelay=200,this.workerPool=[],this.queue=[],this.hydrator=e.serializer.Hydrator}initializeWorkers(){for(;this.workerPool.length{if(this.queue.length>0){const t=this.queue.shift();t&&(e.lock(),t.resolve(e))}}),this.workerPool.push(e)}}async parse(e,t){const r=await this.acquireParserWorker(t),n=new Sr;let a;const s=t.onCancellationRequested(()=>{a=setTimeout(()=>{this.terminateWorker(r)},this.terminationDelay)});return r.parse(e).then(o=>{const l=this.hydrator.hydrate(o);n.resolve(l)}).catch(o=>{n.reject(o)}).finally(()=>{s.dispose(),clearTimeout(a)}),n.promise}terminateWorker(e){e.terminate();const t=this.workerPool.indexOf(e);t>=0&&this.workerPool.splice(t,1)}async acquireParserWorker(e){this.initializeWorkers();for(const r of this.workerPool)if(r.ready)return r.lock(),r;const t=new Sr;return e.onCancellationRequested(()=>{const r=this.queue.indexOf(t);r>=0&&this.queue.splice(r,1),t.reject(er)}),this.queue.push(t),t.promise}},SF=class{static{i(this,"ParserWorker")}get ready(){return this._ready}get onReady(){return this.onReadyEmitter.event}constructor(e,t,r,n){this.onReadyEmitter=new Fu.Emitter,this.deferred=new Sr,this._ready=!0,this._parsing=!1,this.sendMessage=e,this._terminate=n,t(a=>{const s=a;this.deferred.resolve(s),this.unlock()}),r(a=>{this.deferred.reject(a),this.unlock()})}terminate(){this.deferred.reject(er),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 Sr,this.sendMessage(e),this.deferred.promise}},Ow=class{static{i(this,"DefaultWorkspaceLock")}constructor(){this.previousTokenSource=new pe.CancellationTokenSource,this.writeQueue=[],this.readQueue=[],this.done=!0}write(e){this.cancelWrite();const t=xu();return this.previousTokenSource=t,this.enqueue(this.writeQueue,e,t.token)}read(e){return this.enqueue(this.readQueue,e)}enqueue(e,t,r=pe.CancellationToken.None){const n=new Sr,a={action:t,deferred:n,cancellationToken:r};return e.push(a),this.performNextOperation(),n.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:t,deferred:r,cancellationToken:n})=>{try{const a=await Promise.resolve().then(()=>t(n));r.resolve(a)}catch(a){ea(a)?r.resolve(void 0):r.reject(a)}})),this.done=!0,this.performNextOperation()}cancelWrite(){this.previousTokenSource.cancel()}},Lw=class{static{i(this,"DefaultHydrator")}constructor(e){this.grammarElementIdMap=new Il,this.tokenTypeIdMap=new Il,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(t=>({...t,message:t.message})),value:this.dehydrateAstNode(e.value,this.createDehyrationContext(e.value))}}dehydrateLexerReport(e){return e}createDehyrationContext(e){const t=new Map,r=new Map;for(const n of Mt(e))t.set(n,{});if(e.$cstNode)for(const n of Va(e.$cstNode))r.set(n,{});return{astNodes:t,cstNodes:r}}dehydrateAstNode(e,t){const r=t.astNodes.get(e);r.$type=e.$type,r.$containerIndex=e.$containerIndex,r.$containerProperty=e.$containerProperty,e.$cstNode!==void 0&&(r.$cstNode=this.dehydrateCstNode(e.$cstNode,t));for(const[n,a]of Object.entries(e))if(!n.startsWith("$"))if(Array.isArray(a)){const s=[];r[n]=s;for(const o of a)Oe(o)?s.push(this.dehydrateAstNode(o,t)):tt(o)?s.push(this.dehydrateReference(o,t)):s.push(o)}else Oe(a)?r[n]=this.dehydrateAstNode(a,t):tt(a)?r[n]=this.dehydrateReference(a,t):a!==void 0&&(r[n]=a);return r}dehydrateReference(e,t){const r={};return r.$refText=e.$refText,e.$refNode&&(r.$refNode=t.cstNodes.get(e.$refNode)),r}dehydrateCstNode(e,t){const r=t.cstNodes.get(e);return xl(e)?r.fullText=e.fullText:r.grammarSource=this.getGrammarElementId(e.grammarSource),r.hidden=e.hidden,r.astNode=t.astNodes.get(e.astNode),Tr(e)?r.content=e.content.map(n=>this.dehydrateCstNode(n,t)):Dn(e)&&(r.tokenType=e.tokenType.name,r.offset=e.offset,r.length=e.length,r.startLine=e.range.start.line,r.startColumn=e.range.start.character,r.endLine=e.range.end.line,r.endColumn=e.range.end.character),r}hydrate(e){const t=e.value,r=this.createHydrationContext(t);return"$cstNode"in t&&this.hydrateCstNode(t.$cstNode,r),{lexerErrors:e.lexerErrors,lexerReport:e.lexerReport,parserErrors:e.parserErrors,value:this.hydrateAstNode(t,r)}}createHydrationContext(e){const t=new Map,r=new Map;for(const a of Mt(e))t.set(a,{});let n;if(e.$cstNode)for(const a of Va(e.$cstNode)){let s;"fullText"in a?(s=new Pm(a.fullText),n=s):"content"in a?s=new Pu:"tokenType"in a&&(s=this.hydrateCstLeafNode(a)),s&&(r.set(a,s),s.root=n)}return{astNodes:t,cstNodes:r}}hydrateAstNode(e,t){const r=t.astNodes.get(e);r.$type=e.$type,r.$containerIndex=e.$containerIndex,r.$containerProperty=e.$containerProperty,e.$cstNode&&(r.$cstNode=t.cstNodes.get(e.$cstNode));for(const[n,a]of Object.entries(e))if(!n.startsWith("$"))if(Array.isArray(a)){const s=[];r[n]=s;for(const o of a)Oe(o)?s.push(this.setParent(this.hydrateAstNode(o,t),r)):tt(o)?s.push(this.hydrateReference(o,r,n,t)):s.push(o)}else Oe(a)?r[n]=this.setParent(this.hydrateAstNode(a,t),r):tt(a)?r[n]=this.hydrateReference(a,r,n,t):a!==void 0&&(r[n]=a);return r}setParent(e,t){return e.$container=t,e}hydrateReference(e,t,r,n){return this.linker.buildReference(t,r,n.cstNodes.get(e.$refNode),e.$refText)}hydrateCstNode(e,t,r=0){const n=t.cstNodes.get(e);if(typeof e.grammarSource=="number"&&(n.grammarSource=this.getGrammarElement(e.grammarSource)),n.astNode=t.astNodes.get(e.astNode),Tr(n))for(const a of e.content){const s=this.hydrateCstNode(a,t,r++);n.content.push(s)}return n}hydrateCstLeafNode(e){const t=this.getTokenType(e.tokenType),r=e.offset,n=e.length,a=e.startLine,s=e.startColumn,o=e.endLine,l=e.endColumn,u=e.hidden;return new Cl(r,n,{start:{line:a,character:s},end:{line:o,character:l}},t,u)}getTokenType(e){return this.lexer.definition[e]}getGrammarElementId(e){if(e)return this.grammarElementIdMap.size===0&&this.createGrammarElementIdMap(),this.grammarElementIdMap.get(e)}getGrammarElement(e){return this.grammarElementIdMap.size===0&&this.createGrammarElementIdMap(),this.grammarElementIdMap.getKey(e)}createGrammarElementIdMap(){let e=0;for(const t of Mt(this.grammar))Ml(t)&&this.grammarElementIdMap.set(t,e++)}};function je(e){return{documentation:{CommentProvider:i(t=>new Pw(t),"CommentProvider"),DocumentationProvider:i(t=>new Nw(t),"DocumentationProvider")},parser:{AsyncParser:i(t=>new kw(t),"AsyncParser"),GrammarConfig:i(t=>bp(t),"GrammarConfig"),LangiumParser:i(t=>Mm(t),"LangiumParser"),CompletionParser:i(t=>xm(t),"CompletionParser"),ValueConverter:i(()=>new Fm,"ValueConverter"),TokenBuilder:i(()=>new Lu,"TokenBuilder"),Lexer:i(t=>new Jm(t),"Lexer"),ParserErrorMessageProvider:i(()=>new Om,"ParserErrorMessageProvider"),LexerErrorMessageProvider:i(()=>new Tw,"LexerErrorMessageProvider")},workspace:{AstNodeLocator:i(()=>new mw,"AstNodeLocator"),AstNodeDescriptionProvider:i(t=>new dw(t),"AstNodeDescriptionProvider"),ReferenceDescriptionProvider:i(t=>new pw(t),"ReferenceDescriptionProvider")},references:{Linker:i(t=>new ew(t),"Linker"),NameProvider:i(()=>new tw,"NameProvider"),ScopeProvider:i(t=>new sw(t),"ScopeProvider"),ScopeComputation:i(t=>new nw(t),"ScopeComputation"),References:i(t=>new rw(t),"References")},serializer:{Hydrator:i(t=>new Lw(t),"Hydrator"),JsonSerializer:i(t=>new ow(t),"JsonSerializer")},validation:{DocumentValidator:i(t=>new fw(t),"DocumentValidator"),ValidationRegistry:i(t=>new uw(t),"ValidationRegistry")},shared:i(()=>e.shared,"shared")}}i(je,"createDefaultCoreModule");function Be(e){return{ServiceRegistry:i(t=>new lw(t),"ServiceRegistry"),workspace:{LangiumDocuments:i(t=>new QS(t),"LangiumDocuments"),LangiumDocumentFactory:i(t=>new ZS(t),"LangiumDocumentFactory"),DocumentBuilder:i(t=>new yw(t),"DocumentBuilder"),IndexManager:i(t=>new gw(t),"IndexManager"),WorkspaceManager:i(t=>new vw(t),"WorkspaceManager"),FileSystemProvider:i(t=>e.fileSystemProvider(t),"FileSystemProvider"),WorkspaceLock:i(()=>new Ow,"WorkspaceLock"),ConfigurationProvider:i(t=>new hw(t),"ConfigurationProvider")},profilers:{}}}i(Be,"createDefaultSharedCoreModule");var rd;(function(e){e.merge=(t,r)=>Za(Za({},t),r)})(rd||(rd={}));function ee(e,t,r,n,a,s,o,l,u){const c=[e,t,r,n,a,s,o,l,u].reduce(Za,{});return ih(c)}i(ee,"inject");var Dw=Symbol("isProxy");function ah(e){if(e&&e[Dw])for(const t of Object.values(e))ah(t);return e}i(ah,"eagerLoad");function ih(e,t){const r=new Proxy({},{deleteProperty:i(()=>!1,"deleteProperty"),set:i(()=>{throw new Error("Cannot set property on injected service container")},"set"),get:i((n,a)=>a===Dw?!0:nd(n,a,e,t||r),"get"),getOwnPropertyDescriptor:i((n,a)=>(nd(n,a,e,t||r),Object.getOwnPropertyDescriptor(n,a)),"getOwnPropertyDescriptor"),has:i((n,a)=>a in e,"has"),ownKeys:i(()=>[...Object.getOwnPropertyNames(e)],"ownKeys")});return r}i(ih,"_inject");var ky=Symbol();function nd(e,t,r,n){if(t in e){if(e[t]instanceof Error)throw new Error("Construction failure. Please make sure that your dependencies are constructable. Cause: "+e[t]);if(e[t]===ky)throw new Error('Cycle detected. Please make "'+String(t)+'" lazy. Visit https://langium.org/docs/reference/configuration-services/#resolving-cyclic-dependencies');return e[t]}else if(t in r){const a=r[t];e[t]=ky;try{e[t]=typeof a=="function"?a(n):ih(a,n)}catch(s){throw e[t]=s instanceof Error?s:void 0,s}return e[t]}else return}i(nd,"_resolve");function Za(e,t){if(t){for(const[r,n]of Object.entries(t))if(n!=null)if(typeof n=="object"){const a=e[r];typeof a=="object"&&a!==null?e[r]=Za(a,n):e[r]=Za({},n)}else e[r]=n}return e}i(Za,"_merge");var ad={indentTokenName:"INDENT",dedentTokenName:"DEDENT",whitespaceTokenName:"WS",ignoreIndentationDelimiters:[]},Sn;(function(e){e.REGULAR="indentation-sensitive",e.IGNORE_INDENTATION="ignore-indentation"})(Sn||(Sn={}));var xw=class extends Lu{static{i(this,"IndentationAwareTokenBuilder")}constructor(e=ad){super(),this.indentationStack=[0],this.whitespaceRegExp=/[ \t]+/y,this.options={...ad,...e},this.indentTokenType=za({name:this.options.indentTokenName,pattern:this.indentMatcher.bind(this),line_breaks:!1}),this.dedentTokenType=za({name:this.options.dedentTokenName,pattern:this.dedentMatcher.bind(this),line_breaks:!1})}buildTokens(e,t){const r=super.buildTokens(e,t);if(!zu(r))throw new Error("Invalid tokens built by default builder");const{indentTokenName:n,dedentTokenName:a,whitespaceTokenName:s,ignoreIndentationDelimiters:o}=this.options;let l,u,c;const f=[];for(const d of r){for(const[m,g]of o)d.name===m?d.PUSH_MODE=Sn.IGNORE_INDENTATION:d.name===g&&(d.POP_MODE=!0);d.name===a?l=d:d.name===n?u=d:d.name===s?c=d:f.push(d)}if(!l||!u||!c)throw new Error("Some indentation/whitespace tokens not found!");return o.length>0?{modes:{[Sn.REGULAR]:[l,u,...f,c],[Sn.IGNORE_INDENTATION]:[...f,c]},defaultMode:Sn.REGULAR}:[l,u,c,...f]}flushLexingReport(e){return{...super.flushLexingReport(e),remainingDedents:this.flushRemainingDedents(e)}}isStartOfLine(e,t){return t===0||`\r +`.includes(e[t-1])}matchWhitespace(e,t,r,n){this.whitespaceRegExp.lastIndex=t;const a=this.whitespaceRegExp.exec(e);return{currIndentLevel:a?.[0].length??0,prevIndentLevel:this.indentationStack.at(-1),match:a}}createIndentationTokenInstance(e,t,r,n){const a=this.getLineNumber(t,n);return Zs(e,r,n,n+r.length,a,a,1,r.length)}getLineNumber(e,t){return e.substring(0,t).split(/\r\n|\r|\n/).length}indentMatcher(e,t,r,n){if(!this.isStartOfLine(e,t))return null;const{currIndentLevel:a,prevIndentLevel:s,match:o}=this.matchWhitespace(e,t,r,n);return a<=s?null:(this.indentationStack.push(a),o)}dedentMatcher(e,t,r,n){if(!this.isStartOfLine(e,t))return null;const{currIndentLevel:a,prevIndentLevel:s,match:o}=this.matchWhitespace(e,t,r,n);if(a>=s)return null;const l=this.indentationStack.lastIndexOf(a);if(l===-1)return this.diagnostics.push({severity:"error",message:`Invalid dedent level ${a} at offset: ${t}. Current indentation stack: ${this.indentationStack}`,offset:t,length:o?.[0]?.length??0,line:this.getLineNumber(e,t),column:1}),null;const u=this.indentationStack.length-l-1,c=e.substring(0,t).match(/[\r\n]+$/)?.[0].length??1;for(let f=0;f1;)t.push(this.createIndentationTokenInstance(this.dedentTokenType,e,"",e.length)),this.indentationStack.pop();return this.indentationStack=[0],t}},wF=class extends Jm{static{i(this,"IndentationAwareLexer")}constructor(e){if(super(e),e.parser.TokenBuilder instanceof xw)this.indentationTokenBuilder=e.parser.TokenBuilder;else throw new Error("IndentationAwareLexer requires an accompanying IndentationAwareTokenBuilder")}tokenize(e,t=Xm){const r=super.tokenize(e),n=r.report;t?.mode==="full"&&r.tokens.push(...n.remainingDedents),n.remainingDedents=[];const{indentTokenType:a,dedentTokenType:s}=this.indentationTokenBuilder,o=a.tokenTypeIdx,l=s.tokenTypeIdx,u=[],c=r.tokens.length-1;for(let f=0;f=0&&u.push(r.tokens[c]),r.tokens=u,r}},sh={};Wr(sh,{AstUtils:()=>Id,BiMap:()=>Il,Cancellation:()=>pe,ContextCache:()=>Gu,CstUtils:()=>_d,DONE_RESULT:()=>et,Deferred:()=>Sr,Disposable:()=>In,DisposableCache:()=>Mu,DocumentCache:()=>iw,EMPTY_STREAM:()=>Ba,ErrorWithLocation:()=>Kl,GrammarUtils:()=>ip,MultiMap:()=>wr,OperationCancelled:()=>er,Reduction:()=>vs,RegExpUtils:()=>op,SimpleCache:()=>Wm,StreamImpl:()=>Qt,TreeStreamImpl:()=>Ua,URI:()=>vt,UriTrie:()=>Um,UriUtils:()=>rt,WorkspaceCache:()=>qm,assertCondition:()=>sp,assertUnreachable:()=>qr,delayNextTick:()=>Du,interruptAndCheck:()=>ze,isOperationCancelled:()=>ea,loadGrammarFromJson:()=>Ue,setInterruptionPeriod:()=>zm,startCancelableOperation:()=>xu,stream:()=>ue});Ol(sh,Fu);var Mw=class{static{i(this,"EmptyFileSystemProvider")}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[]}},Xe={fileSystemProvider:i(()=>new Mw,"fileSystemProvider")},IF={Grammar:i(()=>{},"Grammar"),LanguageMetaData:i(()=>({caseInsensitive:!1,fileExtensions:[".langium"],languageId:"langium"}),"LanguageMetaData")},NF={AstReflection:i(()=>new Xd,"AstReflection")};function Gw(){const e=ee(Be(Xe),NF),t=ee(je({shared:e}),IF);return e.ServiceRegistry.register(t),t}i(Gw,"createMinimalGrammarServices");function Ue(e){const t=Gw(),r=t.serializer.JsonSerializer.deserialize(e);return t.shared.workspace.LangiumDocumentFactory.fromModel(r,vt.parse(`memory:/${r.name??"grammar"}.langium`)),r}i(Ue,"loadGrammarFromJson");Ol(Vg,sh);var PF=class{static{i(this,"DefaultLangiumProfiler")}constructor(e){this.activeCategories=new Set,this.allCategories=new Set(["validating","parsing","linking"]),this.activeCategories=e??new Set(this.allCategories),this.records=new wr}isActive(e){return this.activeCategories.has(e)}start(...e){e?e.forEach(t=>this.activeCategories.add(t)):this.activeCategories=new Set(this.allCategories)}stop(...e){e?e.forEach(t=>this.activeCategories.delete(t)):this.activeCategories.clear()}createTask(e,t){if(!this.isActive(e))throw new Error(`Category "${e}" is not active.`);return console.log(`Creating profiling task for '${e}.${t}'.`),new Fw(r=>this.records.add(e,this.dumpRecord(e,r)),t)}dumpRecord(e,t){console.info(`Task ${e}.${t.identifier} executed in ${t.duration.toFixed(2)}ms and ended at ${t.date.toISOString()}`);const r=[];for(const s of t.entries.keys()){const o=t.entries.get(s),l=o.reduce((u,c)=>u+c);r.push({name:`${t.identifier}.${s}`,count:o.length,duration:l})}const n=t.duration-r.map(s=>s.duration).reduce((s,o)=>s+o,0);r.push({name:t.identifier,count:1,duration:n}),r.sort((s,o)=>o.duration-s.duration);function a(s){return Math.round(100*s)/100}return i(a,"Round"),console.table(r.map(s=>({Element:s.name,Count:s.count,"Self %":a(100*s.duration/t.duration),"Time (ms)":a(s.duration)}))),t}getRecords(...e){return e.length===0?this.records.values():this.records.entries().filter(t=>e.some(r=>r===t[0])).flatMap(t=>t[1])}},Fw=class{static{i(this,"ProfilingTask")}constructor(e,t){this.stack=[],this.entries=new wr,this.addRecord=e,this.identifier=t}start(){if(this.startTime!==void 0)throw new Error(`Task "${this.identifier}" is already started.`);this.startTime=performance.now()}stop(){if(this.startTime===void 0)throw new Error(`Task "${this.identifier}" was not started.`);if(this.stack.length!==0)throw new Error(`Task "${this.identifier}" cannot be stopped before sub-task(s): ${this.stack.map(t=>t.id).join(", ")}.`);const e={identifier:this.identifier,date:new Date,duration:performance.now()-this.startTime,entries:this.entries};this.addRecord(e),this.startTime=void 0,this.entries.clear()}startSubTask(e){this.stack.push({id:e,start:performance.now(),content:0})}stopSubTask(e){const t=this.stack.pop();if(!t)throw new Error(`Task "${this.identifier}.${e}" was not started.`);if(t.id!==e)throw new Error(`Sub-Task "${t.id}" is not already stopped.`);const r=performance.now()-t.start;this.stack.at(-1)!==void 0&&(this.stack[this.stack.length-1].content+=r);const n=r-t.content;this.entries.add(e,n)}},id;(e=>{e.Terminals={ARROW_DIRECTION:/L|R|T|B/,ARROW_GROUP:/\{group\}/,ARROW_INTO:/<|>/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,ID:/[\w]([-\w]*\w)?/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,ARCH_ICON:/\([\w-:]+\)/,ARCH_TITLE:/\[(?:"([^"\\]|\\.)*"|'([^'\\]|\\.)*'|[\w ]+)\]/}})(id||(id={}));var sd;(e=>{e.Terminals={DOMAIN_NAME:/complex|complicated|clear|chaotic|confusion/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(sd||(sd={}));var od;(e=>{e.Terminals={EM_ID:/[_a-zA-Z][\w_]*/,EM_FID:/\d{1,3}/,EM_DATA_INLINE:/\{(.*)\}|"(.*)"|'(.*)'/,EM_DATA_BLOCK:/\{[\t ]*\r?\n(?:[\S\s]*?\r?\n)?\}(?:\r?\n|(?!\S))/,EM_ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,EM_ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,EM_TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,EM_WS:/\s+/,EM_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,EM_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,EM_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,EM_ML_COMMENT:/\/\*[\s\S]*?\*\//,EM_SL_COMMENT:/\/\/[^\n\r]*/}})(od||(od={}));var ld;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,INT:/0|[1-9][0-9]*(?!\.)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,REFERENCE:/\w([-\./\w]*[-\w])?/}})(ld||(ld={}));var ud;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(ud||(ud={}));var cd;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,INT:/0|[1-9][0-9]*(?!\.)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(cd||(cd={}));var fd;(e=>{e.Terminals={NUMBER_PIE:/(?:-?[0-9]+\.[0-9]+(?!\.))|(?:-?(0|[1-9][0-9]*)(?!\.))/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(fd||(fd={}));var dd;(e=>{e.Terminals={GRATICULE:/circle|polygon/,BOOLEAN:/true|false/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,NUMBER:/(?:[0-9]+\.[0-9]+(?!\.))|(?:0|[1-9][0-9]*(?!\.))/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,ID:/[\w]([-\w]*\w)?/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(dd||(dd={}));var pd;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ABNF_RULENAME:/[A-Za-z][A-Za-z0-9-]*/,ABNF_STRING:/"[^"]*"/,ABNF_NUMVAL:/%[xXdDbB][0-9A-Fa-f]+(?:-[0-9A-Fa-f]+|\.[0-9A-Fa-f]+)*/,ABNF_REPEAT:/[0-9]*\*[0-9]*/,ABNF_EXACT_REPEAT:/[0-9]+/,ABNF_WHITESPACE:/[\t \r\n]+/,ABNF_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,ABNF_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,ABNF_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,ABNF_COMMENT:/;[^\n\r]*/}})(pd||(pd={}));var md;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,EBNF_ID:/[A-Z_a-z][\w-]*/,EBNF_STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,EBNF_SPECIAL_SEQUENCE:/\?(?=[^?;]*[^?\s;][^?;]*\?)[^?;]*\?/,EBNF_WHITESPACE:/[\t \r\n]+/,EBNF_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,EBNF_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,EBNF_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,EBNF_BLOCK_COMMENT:/\/\*[\s\S]*?\*\//,EBNF_ISO_COMMENT:/\(\*[\s\S]*?\*\)/}})(md||(md={}));var hd;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,RR_ID:/[A-Z_a-z][\w-]*/,RR_STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,RR_WHITESPACE:/[\t \r\n]+/,RR_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,RR_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,RR_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,RR_BLOCK_COMMENT:/\/\*[\s\S]*?\*\//}})(hd||(hd={}));var yd;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,PEG_ID:/[A-Z_a-z][\w-]*/,PEG_STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,PEG_WHITESPACE:/[\t \r\n]+/,PEG_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,PEG_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,PEG_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,PEG_LINE_COMMENT:/#[^\n\r]*/}})(yd||(yd={}));var gd;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,TREEMAP_KEYWORD:/treemap-beta|treemap/,CLASS_DEF:/classDef\s+([a-zA-Z_][a-zA-Z0-9_]+)(?:\s+([^;\r\n]*))?(?:;)?/,STYLE_SEPARATOR:/:::/,SEPARATOR:/:/,COMMA:/,/,INDENTATION:/[ \t]{1,}/,WS:/[ \t]+/,ML_COMMENT:/\%\%[^\n]*/,NL:/\r?\n/,ID2:/[a-zA-Z_][a-zA-Z0-9_]*/,NUMBER2:/[0-9_\.\,]+/,STRING2:/"[^"]*"|'[^']*'/}})(gd||(gd={}));var vd;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,CLASS_ANNOTATION:/[ \t]+:::[ \t]*[A-Za-z_][\w-]*/,ICON_ANNOTATION:/[ \t]+icon\([\w-]*(?::[\w-]+)?\)/,DESC_ANNOTATION:/[ \t]+##[^\n\r]*/,INDENTATION:/[ \t]{1,}/,QUOTED_NAME:/"[^"]*"|'[^']*'/,WS:/[ \t]+/,ML_COMMENT:/\%\%[^\n]*/,NL:/\r?\n/,BARE_NAME:/(?!:::|icon\(|##)[^ \t\n\r"'](?:(?![ \t]+:::[ \t]*[A-Za-z_]|[ \t]+icon\(|[ \t]+##)[^\n\r])*/}})(vd||(vd={}));var Td;(e=>{e.Terminals={WARDLEY_NUMBER:/[0-9]+\.[0-9]+/,ARROW:/->/,LINK_PORT:/\+<>|\+>|\+|-\.->|>|\+'[^']*'<>|\+'[^']*'<|\+'[^']*'>/,LINK_LABEL:/;[^\n\r]+/,STRATEGY:/build|buy|outsource|market/,KW_WARDLEY:/wardley-beta/,KW_SIZE:/size/,KW_EVOLUTION:/evolution/,KW_ANCHOR:/anchor/,KW_COMPONENT:/component/,KW_LABEL:/label/,KW_INERTIA:/inertia/,KW_EVOLVE:/evolve/,KW_PIPELINE:/pipeline/,KW_NOTE:/note/,KW_ANNOTATIONS:/annotations/,KW_ANNOTATION:/annotation/,KW_ACCELERATOR:/accelerator/,KW_DEACCELERATOR:/deaccelerator/,NAME_WITH_SPACES:/(?!title\s|accTitle|accDescr)[A-Za-z](?:[A-Za-z0-9_()&]|-(?!>))*(?:[ \t]+[A-Za-z(](?:[A-Za-z0-9_()&]|-(?!>))*)*/,WS:/[ \t]+/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,INT:/0|[1-9][0-9]*(?!\.)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,ID:/[\w]([-\w]*\w)?/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(Td||(Td={}));({...id.Terminals,...sd.Terminals,...od.Terminals,...ld.Terminals,...ud.Terminals,...cd.Terminals,...fd.Terminals,...dd.Terminals,...pd.Terminals,...md.Terminals,...hd.Terminals,...yd.Terminals,...vd.Terminals,...gd.Terminals,...Td.Terminals});var Oy={$type:"AbnfAlternation",alternatives:"alternatives"},Ly={$type:"AbnfConcatenation",elements:"elements"},Qu={$type:"AbnfElement",primary:"primary",repeat:"repeat"},Dy={$type:"AbnfGroup",element:"element"},xy={$type:"AbnfNumVal",value:"value"},My={$type:"AbnfOptionalGroup",element:"element"},ua={$type:"AbnfPrimary"},ec={$type:"AbnfRule",definition:"definition",name:"name"},Gy={$type:"AbnfRuleName",name:"name"},Fy={$type:"AbnfStringLiteral",value:"value"},uo={$type:"Accelerator",name:"name",x:"x",y:"y"},tc={$type:"Alignment",direction:"direction",members:"members"},co={$type:"Anchor",evolution:"evolution",name:"name",visibility:"visibility"},Di={$type:"Annotation",number:"number",text:"text",x:"x",y:"y"},rc={$type:"Annotations",x:"x",y:"y"},Yt={$type:"Architecture",accDescr:"accDescr",accTitle:"accTitle",alignments:"alignments",edges:"edges",groups:"groups",junctions:"junctions",services:"services",title:"title"};function kF(e){return Ne.isInstance(e,Yt.$type)}i(kF,"isArchitecture");var fo={$type:"Axis",label:"label",name:"name"},Uo={$type:"Branch",name:"name",order:"order"};function OF(e){return Ne.isInstance(e,Uo.$type)}i(OF,"isBranch");var zy={$type:"Checkout",branch:"branch"},po={$type:"CherryPicking",id:"id",parent:"parent",tags:"tags"},nc={$type:"ClassDefStatement",className:"className",styleText:"styleText"},Ra={$type:"Commit",id:"id",message:"message",tags:"tags",type:"type"};function LF(e){return Ne.isInstance(e,Ra.$type)}i(LF,"isCommit");var mo={$type:"Common",accDescr:"accDescr",accTitle:"accTitle",title:"title"},Jr={$type:"Component",decorator:"decorator",evolution:"evolution",inertia:"inertia",label:"label",name:"name",visibility:"visibility"},ho={$type:"Curve",entries:"entries",label:"label",name:"name"},un={$type:"Cynefin",accDescr:"accDescr",accTitle:"accTitle",domains:"domains",title:"title",transitions:"transitions"};function DF(e){return Ne.isInstance(e,un.$type)}i(DF,"isCynefin");var yo={$type:"Deaccelerator",name:"name",x:"x",y:"y"},jy={$type:"Decorator",strategy:"strategy"},ca={$type:"Direction",accDescr:"accDescr",accTitle:"accTitle",dir:"dir",statements:"statements",title:"title"},Ko={$type:"DomainBlock",domain:"domain",items:"items"};function xF(e){return Ne.isInstance(e,Ko.$type)}i(xF,"isDomainBlock");var $d={$type:"DomainItem",label:"label"};function MF(e){return Ne.isInstance(e,$d.$type)}i(MF,"isDomainItem");var By={$type:"EbnfChoice",alternatives:"alternatives"},Uy={$type:"EbnfExceptionPostfix",except:"except"},Ky={$type:"EbnfGroup",element:"element"},Wy={$type:"EbnfNonTerminal",name:"name"},qy={$type:"EbnfOneOrMorePostfix",operator:"operator"},Vy={$type:"EbnfOptional",element:"element"},Hy={$type:"EbnfOptionalPostfix",operator:"operator"},xi={$type:"EbnfPostfix"},Zr={$type:"EbnfPrimary"},Yy={$type:"EbnfRepetition",element:"element"},ac={$type:"EbnfRule",definition:"definition",name:"name"},Xy={$type:"EbnfSequence",elements:"elements"},Jy={$type:"EbnfSpecial",text:"text"},ic={$type:"EbnfTerm",base:"base",postfixes:"postfixes"},Zy={$type:"EbnfTerminal",value:"value"},Qy={$type:"EbnfZeroOrMorePostfix",operator:"operator"},Vt={$type:"Edge",lhsDir:"lhsDir",lhsGroup:"lhsGroup",lhsId:"lhsId",lhsInto:"lhsInto",rhsDir:"rhsDir",rhsGroup:"rhsGroup",rhsId:"rhsId",rhsInto:"rhsInto",title:"title"},fa={$type:"EmDataEntity",dataBlockValue:"dataBlockValue",dataType:"dataType",name:"name"},Qr={$type:"EmFrame"},Mi={$type:"EmGwt",givenStatements:"givenStatements",sourceFrame:"sourceFrame",thenStatements:"thenStatements",whenStatements:"whenStatements"},eg={$type:"EmGwtStatement",entityIdentifier:"entityIdentifier"},sc={$type:"EmModelEntity",name:"name"};function GF(e){return e==="rmo"||e==="readmodel"||e==="ui"||e==="cmd"||e==="command"||e==="evt"||e==="event"||e==="pcr"||e==="processor"}i(GF,"isEmModelEntityType");var go={$type:"EmNoteEntity",dataBlockValue:"dataBlockValue",dataType:"dataType",sourceFrame:"sourceFrame"},hr={$type:"EmResetFrame",dataInlineValue:"dataInlineValue",dataReference:"dataReference",dataType:"dataType",entityIdentifier:"entityIdentifier",modelEntityType:"modelEntityType",name:"name",sourceFrames:"sourceFrames"};function FF(e){return Ne.isInstance(e,hr.$type)}i(FF,"isEmResetFrame");var Lr={$type:"EmTimeFrame",dataInlineValue:"dataInlineValue",dataReference:"dataReference",dataType:"dataType",entityIdentifier:"entityIdentifier",modelEntityType:"modelEntityType",name:"name",sourceFrames:"sourceFrames"},oc={$type:"Entry",axis:"axis",value:"value"},fr={$type:"EventModel",accDescr:"accDescr",accTitle:"accTitle",dataEntities:"dataEntities",frames:"frames",gwtEntities:"gwtEntities",modelEntities:"modelEntities",noteEntities:"noteEntities",title:"title"},tg={$type:"Evolution",stages:"stages"},vo={$type:"EvolutionStage",boundary:"boundary",name:"name",secondName:"secondName"},lc={$type:"Evolve",component:"component",target:"target"},cn={$type:"GitGraph",accDescr:"accDescr",accTitle:"accTitle",statements:"statements",title:"title"};function zF(e){return Ne.isInstance(e,cn.$type)}i(zF,"isGitGraph");var Gi={$type:"Group",icon:"icon",id:"id",in:"in",title:"title"},es={$type:"Info",accDescr:"accDescr",accTitle:"accTitle",title:"title"};function jF(e){return Ne.isInstance(e,es.$type)}i(jF,"isInfo");var Fi={$type:"Item",classSelector:"classSelector",name:"name"},uc={$type:"Junction",id:"id",in:"in"},zi={$type:"Label",negX:"negX",negY:"negY",offsetX:"offsetX",offsetY:"offsetY"},To={$type:"Leaf",classSelector:"classSelector",name:"name",value:"value"},en={$type:"Link",arrow:"arrow",from:"from",fromPort:"fromPort",linkLabel:"linkLabel",to:"to",toPort:"toPort"},Aa={$type:"Merge",branch:"branch",id:"id",tags:"tags",type:"type"};function BF(e){return Ne.isInstance(e,Aa.$type)}i(BF,"isMerge");var $o={$type:"Note",evolution:"evolution",text:"text",visibility:"visibility"},cc={$type:"Option",name:"name",value:"value"},Ea={$type:"Packet",accDescr:"accDescr",accTitle:"accTitle",blocks:"blocks",title:"title"};function UF(e){return Ne.isInstance(e,Ea.$type)}i(UF,"isPacket");var Ca={$type:"PacketBlock",bits:"bits",end:"end",label:"label",start:"start"};function KF(e){return Ne.isInstance(e,Ca.$type)}i(KF,"isPacketBlock");var rg={$type:"PegAny",dot:"dot"},ng={$type:"PegGroup",element:"element"},ag={$type:"PegIdentifier",name:"name"},ig={$type:"PegLiteral",value:"value"},sg={$type:"PegOrderedChoice",alternatives:"alternatives"},fc={$type:"PegPrefix",operator:"operator",suffix:"suffix"},ji={$type:"PegPrimary"},dc={$type:"PegRule",definition:"definition",name:"name"},og={$type:"PegSequence",elements:"elements"},pc={$type:"PegSuffix",operator:"operator",primary:"primary"},fn={$type:"Pie",accDescr:"accDescr",accTitle:"accTitle",sections:"sections",showData:"showData",title:"title"};function WF(e){return Ne.isInstance(e,fn.$type)}i(WF,"isPie");var Wo={$type:"PieSection",label:"label",value:"value"};function qF(e){return Ne.isInstance(e,Wo.$type)}i(qF,"isPieSection");var mc={$type:"Pipeline",components:"components",parent:"parent"},Ro={$type:"PipelineComponent",evolution:"evolution",label:"label",name:"name"},tn={$type:"Radar",accDescr:"accDescr",accTitle:"accTitle",axes:"axes",curves:"curves",options:"options",title:"title"},ba={$type:"Railroad",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function VF(e){return Ne.isInstance(e,ba.$type)}i(VF,"isRailroad");var _a={$type:"RailroadAbnf",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function HF(e){return Ne.isInstance(e,_a.$type)}i(HF,"isRailroadAbnf");var lg={$type:"RailroadChoiceExpr",alternatives:"alternatives"},Sa={$type:"RailroadEbnf",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function YF(e){return Ne.isInstance(e,Sa.$type)}i(YF,"isRailroadEbnf");var dr={$type:"RailroadExpression"},ug={$type:"RailroadNonTerminalExpr",name:"name"},cg={$type:"RailroadOneOrMoreExpr",element:"element"},fg={$type:"RailroadOptionalExpr",element:"element"},wa={$type:"RailroadPeg",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function XF(e){return Ne.isInstance(e,wa.$type)}i(XF,"isRailroadPeg");var hc={$type:"RailroadRule",definition:"definition",name:"name"},dg={$type:"RailroadSequenceExpr",elements:"elements"},pg={$type:"RailroadSpecialExpr",text:"text"},mg={$type:"RailroadTerminalExpr",value:"value"},hg={$type:"RailroadZeroOrMoreExpr",element:"element"},yc={$type:"Section",classSelector:"classSelector",name:"name"},da={$type:"Service",icon:"icon",iconText:"iconText",id:"id",in:"in",title:"title"},gc={$type:"Size",height:"height",width:"width"},pa={$type:"Statement"},ts={$type:"Transition",from:"from",label:"label",to:"to"};function JF(e){return Ne.isInstance(e,ts.$type)}i(JF,"isTransition");var Ia={$type:"Treemap",accDescr:"accDescr",accTitle:"accTitle",title:"title",TreemapRows:"TreemapRows"};function ZF(e){return Ne.isInstance(e,Ia.$type)}i(ZF,"isTreemap");var vc={$type:"TreemapRow",indent:"indent",item:"item"},ma={$type:"TreeNode",classAnnotation:"classAnnotation",descAnnotation:"descAnnotation",iconAnnotation:"iconAnnotation",indent:"indent",name:"name"},Bi={$type:"TreeView",accDescr:"accDescr",accTitle:"accTitle",nodes:"nodes",title:"title"},We={$type:"Wardley",accDescr:"accDescr",accelerators:"accelerators",accTitle:"accTitle",anchors:"anchors",annotation:"annotation",annotations:"annotations",components:"components",deaccelerators:"deaccelerators",evolution:"evolution",evolves:"evolves",links:"links",notes:"notes",pipelines:"pipelines",size:"size",title:"title"};function QF(e){return Ne.isInstance(e,We.$type)}i(QF,"isWardley");var zw=class extends wd{constructor(){super(...arguments),this.types={AbnfAlternation:{name:Oy.$type,properties:{alternatives:{name:Oy.alternatives,defaultValue:[]}},superTypes:[]},AbnfConcatenation:{name:Ly.$type,properties:{elements:{name:Ly.elements,defaultValue:[]}},superTypes:[]},AbnfElement:{name:Qu.$type,properties:{primary:{name:Qu.primary},repeat:{name:Qu.repeat}},superTypes:[]},AbnfGroup:{name:Dy.$type,properties:{element:{name:Dy.element}},superTypes:[ua.$type]},AbnfNumVal:{name:xy.$type,properties:{value:{name:xy.value}},superTypes:[ua.$type]},AbnfOptionalGroup:{name:My.$type,properties:{element:{name:My.element}},superTypes:[ua.$type]},AbnfPrimary:{name:ua.$type,properties:{},superTypes:[]},AbnfRule:{name:ec.$type,properties:{definition:{name:ec.definition},name:{name:ec.name}},superTypes:[]},AbnfRuleName:{name:Gy.$type,properties:{name:{name:Gy.name}},superTypes:[ua.$type]},AbnfStringLiteral:{name:Fy.$type,properties:{value:{name:Fy.value}},superTypes:[ua.$type]},Accelerator:{name:uo.$type,properties:{name:{name:uo.name},x:{name:uo.x},y:{name:uo.y}},superTypes:[]},Alignment:{name:tc.$type,properties:{direction:{name:tc.direction},members:{name:tc.members,defaultValue:[]}},superTypes:[]},Anchor:{name:co.$type,properties:{evolution:{name:co.evolution},name:{name:co.name},visibility:{name:co.visibility}},superTypes:[]},Annotation:{name:Di.$type,properties:{number:{name:Di.number},text:{name:Di.text},x:{name:Di.x},y:{name:Di.y}},superTypes:[]},Annotations:{name:rc.$type,properties:{x:{name:rc.x},y:{name:rc.y}},superTypes:[]},Architecture:{name:Yt.$type,properties:{accDescr:{name:Yt.accDescr},accTitle:{name:Yt.accTitle},alignments:{name:Yt.alignments,defaultValue:[]},edges:{name:Yt.edges,defaultValue:[]},groups:{name:Yt.groups,defaultValue:[]},junctions:{name:Yt.junctions,defaultValue:[]},services:{name:Yt.services,defaultValue:[]},title:{name:Yt.title}},superTypes:[]},Axis:{name:fo.$type,properties:{label:{name:fo.label},name:{name:fo.name}},superTypes:[]},Branch:{name:Uo.$type,properties:{name:{name:Uo.name},order:{name:Uo.order}},superTypes:[pa.$type]},Checkout:{name:zy.$type,properties:{branch:{name:zy.branch}},superTypes:[pa.$type]},CherryPicking:{name:po.$type,properties:{id:{name:po.id},parent:{name:po.parent},tags:{name:po.tags,defaultValue:[]}},superTypes:[pa.$type]},ClassDefStatement:{name:nc.$type,properties:{className:{name:nc.className},styleText:{name:nc.styleText}},superTypes:[]},Commit:{name:Ra.$type,properties:{id:{name:Ra.id},message:{name:Ra.message},tags:{name:Ra.tags,defaultValue:[]},type:{name:Ra.type}},superTypes:[pa.$type]},Common:{name:mo.$type,properties:{accDescr:{name:mo.accDescr},accTitle:{name:mo.accTitle},title:{name:mo.title}},superTypes:[]},Component:{name:Jr.$type,properties:{decorator:{name:Jr.decorator},evolution:{name:Jr.evolution},inertia:{name:Jr.inertia,defaultValue:!1},label:{name:Jr.label},name:{name:Jr.name},visibility:{name:Jr.visibility}},superTypes:[]},Curve:{name:ho.$type,properties:{entries:{name:ho.entries,defaultValue:[]},label:{name:ho.label},name:{name:ho.name}},superTypes:[]},Cynefin:{name:un.$type,properties:{accDescr:{name:un.accDescr},accTitle:{name:un.accTitle},domains:{name:un.domains,defaultValue:[]},title:{name:un.title},transitions:{name:un.transitions,defaultValue:[]}},superTypes:[]},Deaccelerator:{name:yo.$type,properties:{name:{name:yo.name},x:{name:yo.x},y:{name:yo.y}},superTypes:[]},Decorator:{name:jy.$type,properties:{strategy:{name:jy.strategy}},superTypes:[]},Direction:{name:ca.$type,properties:{accDescr:{name:ca.accDescr},accTitle:{name:ca.accTitle},dir:{name:ca.dir},statements:{name:ca.statements,defaultValue:[]},title:{name:ca.title}},superTypes:[cn.$type]},DomainBlock:{name:Ko.$type,properties:{domain:{name:Ko.domain},items:{name:Ko.items,defaultValue:[]}},superTypes:[]},DomainItem:{name:$d.$type,properties:{label:{name:$d.label}},superTypes:[]},EbnfChoice:{name:By.$type,properties:{alternatives:{name:By.alternatives,defaultValue:[]}},superTypes:[]},EbnfExceptionPostfix:{name:Uy.$type,properties:{except:{name:Uy.except}},superTypes:[xi.$type]},EbnfGroup:{name:Ky.$type,properties:{element:{name:Ky.element}},superTypes:[Zr.$type]},EbnfNonTerminal:{name:Wy.$type,properties:{name:{name:Wy.name}},superTypes:[Zr.$type]},EbnfOneOrMorePostfix:{name:qy.$type,properties:{operator:{name:qy.operator}},superTypes:[xi.$type]},EbnfOptional:{name:Vy.$type,properties:{element:{name:Vy.element}},superTypes:[Zr.$type]},EbnfOptionalPostfix:{name:Hy.$type,properties:{operator:{name:Hy.operator}},superTypes:[xi.$type]},EbnfPostfix:{name:xi.$type,properties:{},superTypes:[]},EbnfPrimary:{name:Zr.$type,properties:{},superTypes:[]},EbnfRepetition:{name:Yy.$type,properties:{element:{name:Yy.element}},superTypes:[Zr.$type]},EbnfRule:{name:ac.$type,properties:{definition:{name:ac.definition},name:{name:ac.name}},superTypes:[]},EbnfSequence:{name:Xy.$type,properties:{elements:{name:Xy.elements,defaultValue:[]}},superTypes:[]},EbnfSpecial:{name:Jy.$type,properties:{text:{name:Jy.text}},superTypes:[Zr.$type]},EbnfTerm:{name:ic.$type,properties:{base:{name:ic.base},postfixes:{name:ic.postfixes,defaultValue:[]}},superTypes:[]},EbnfTerminal:{name:Zy.$type,properties:{value:{name:Zy.value}},superTypes:[Zr.$type]},EbnfZeroOrMorePostfix:{name:Qy.$type,properties:{operator:{name:Qy.operator}},superTypes:[xi.$type]},Edge:{name:Vt.$type,properties:{lhsDir:{name:Vt.lhsDir},lhsGroup:{name:Vt.lhsGroup,defaultValue:!1},lhsId:{name:Vt.lhsId},lhsInto:{name:Vt.lhsInto,defaultValue:!1},rhsDir:{name:Vt.rhsDir},rhsGroup:{name:Vt.rhsGroup,defaultValue:!1},rhsId:{name:Vt.rhsId},rhsInto:{name:Vt.rhsInto,defaultValue:!1},title:{name:Vt.title}},superTypes:[]},EmDataEntity:{name:fa.$type,properties:{dataBlockValue:{name:fa.dataBlockValue},dataType:{name:fa.dataType},name:{name:fa.name}},superTypes:[]},EmFrame:{name:Qr.$type,properties:{},superTypes:[]},EmGwt:{name:Mi.$type,properties:{givenStatements:{name:Mi.givenStatements,defaultValue:[]},sourceFrame:{name:Mi.sourceFrame,referenceType:Qr.$type},thenStatements:{name:Mi.thenStatements,defaultValue:[]},whenStatements:{name:Mi.whenStatements,defaultValue:[]}},superTypes:[]},EmGwtStatement:{name:eg.$type,properties:{entityIdentifier:{name:eg.entityIdentifier,referenceType:sc.$type}},superTypes:[]},EmModelEntity:{name:sc.$type,properties:{name:{name:sc.name}},superTypes:[]},EmNoteEntity:{name:go.$type,properties:{dataBlockValue:{name:go.dataBlockValue},dataType:{name:go.dataType},sourceFrame:{name:go.sourceFrame,referenceType:Qr.$type}},superTypes:[]},EmResetFrame:{name:hr.$type,properties:{dataInlineValue:{name:hr.dataInlineValue},dataReference:{name:hr.dataReference,referenceType:fa.$type},dataType:{name:hr.dataType},entityIdentifier:{name:hr.entityIdentifier},modelEntityType:{name:hr.modelEntityType},name:{name:hr.name},sourceFrames:{name:hr.sourceFrames,defaultValue:[],referenceType:Qr.$type}},superTypes:[Qr.$type]},EmTimeFrame:{name:Lr.$type,properties:{dataInlineValue:{name:Lr.dataInlineValue},dataReference:{name:Lr.dataReference,referenceType:fa.$type},dataType:{name:Lr.dataType},entityIdentifier:{name:Lr.entityIdentifier},modelEntityType:{name:Lr.modelEntityType},name:{name:Lr.name},sourceFrames:{name:Lr.sourceFrames,defaultValue:[],referenceType:Qr.$type}},superTypes:[Qr.$type]},Entry:{name:oc.$type,properties:{axis:{name:oc.axis,referenceType:fo.$type},value:{name:oc.value}},superTypes:[]},EventModel:{name:fr.$type,properties:{accDescr:{name:fr.accDescr},accTitle:{name:fr.accTitle},dataEntities:{name:fr.dataEntities,defaultValue:[]},frames:{name:fr.frames,defaultValue:[]},gwtEntities:{name:fr.gwtEntities,defaultValue:[]},modelEntities:{name:fr.modelEntities,defaultValue:[]},noteEntities:{name:fr.noteEntities,defaultValue:[]},title:{name:fr.title}},superTypes:[]},Evolution:{name:tg.$type,properties:{stages:{name:tg.stages,defaultValue:[]}},superTypes:[]},EvolutionStage:{name:vo.$type,properties:{boundary:{name:vo.boundary},name:{name:vo.name},secondName:{name:vo.secondName}},superTypes:[]},Evolve:{name:lc.$type,properties:{component:{name:lc.component},target:{name:lc.target}},superTypes:[]},GitGraph:{name:cn.$type,properties:{accDescr:{name:cn.accDescr},accTitle:{name:cn.accTitle},statements:{name:cn.statements,defaultValue:[]},title:{name:cn.title}},superTypes:[]},Group:{name:Gi.$type,properties:{icon:{name:Gi.icon},id:{name:Gi.id},in:{name:Gi.in},title:{name:Gi.title}},superTypes:[]},Info:{name:es.$type,properties:{accDescr:{name:es.accDescr},accTitle:{name:es.accTitle},title:{name:es.title}},superTypes:[]},Item:{name:Fi.$type,properties:{classSelector:{name:Fi.classSelector},name:{name:Fi.name}},superTypes:[]},Junction:{name:uc.$type,properties:{id:{name:uc.id},in:{name:uc.in}},superTypes:[]},Label:{name:zi.$type,properties:{negX:{name:zi.negX,defaultValue:!1},negY:{name:zi.negY,defaultValue:!1},offsetX:{name:zi.offsetX},offsetY:{name:zi.offsetY}},superTypes:[]},Leaf:{name:To.$type,properties:{classSelector:{name:To.classSelector},name:{name:To.name},value:{name:To.value}},superTypes:[Fi.$type]},Link:{name:en.$type,properties:{arrow:{name:en.arrow},from:{name:en.from},fromPort:{name:en.fromPort},linkLabel:{name:en.linkLabel},to:{name:en.to},toPort:{name:en.toPort}},superTypes:[]},Merge:{name:Aa.$type,properties:{branch:{name:Aa.branch},id:{name:Aa.id},tags:{name:Aa.tags,defaultValue:[]},type:{name:Aa.type}},superTypes:[pa.$type]},Note:{name:$o.$type,properties:{evolution:{name:$o.evolution},text:{name:$o.text},visibility:{name:$o.visibility}},superTypes:[]},Option:{name:cc.$type,properties:{name:{name:cc.name},value:{name:cc.value,defaultValue:!1}},superTypes:[]},Packet:{name:Ea.$type,properties:{accDescr:{name:Ea.accDescr},accTitle:{name:Ea.accTitle},blocks:{name:Ea.blocks,defaultValue:[]},title:{name:Ea.title}},superTypes:[]},PacketBlock:{name:Ca.$type,properties:{bits:{name:Ca.bits},end:{name:Ca.end},label:{name:Ca.label},start:{name:Ca.start}},superTypes:[]},PegAny:{name:rg.$type,properties:{dot:{name:rg.dot}},superTypes:[ji.$type]},PegGroup:{name:ng.$type,properties:{element:{name:ng.element}},superTypes:[ji.$type]},PegIdentifier:{name:ag.$type,properties:{name:{name:ag.name}},superTypes:[ji.$type]},PegLiteral:{name:ig.$type,properties:{value:{name:ig.value}},superTypes:[ji.$type]},PegOrderedChoice:{name:sg.$type,properties:{alternatives:{name:sg.alternatives,defaultValue:[]}},superTypes:[]},PegPrefix:{name:fc.$type,properties:{operator:{name:fc.operator},suffix:{name:fc.suffix}},superTypes:[]},PegPrimary:{name:ji.$type,properties:{},superTypes:[]},PegRule:{name:dc.$type,properties:{definition:{name:dc.definition},name:{name:dc.name}},superTypes:[]},PegSequence:{name:og.$type,properties:{elements:{name:og.elements,defaultValue:[]}},superTypes:[]},PegSuffix:{name:pc.$type,properties:{operator:{name:pc.operator},primary:{name:pc.primary}},superTypes:[]},Pie:{name:fn.$type,properties:{accDescr:{name:fn.accDescr},accTitle:{name:fn.accTitle},sections:{name:fn.sections,defaultValue:[]},showData:{name:fn.showData,defaultValue:!1},title:{name:fn.title}},superTypes:[]},PieSection:{name:Wo.$type,properties:{label:{name:Wo.label},value:{name:Wo.value}},superTypes:[]},Pipeline:{name:mc.$type,properties:{components:{name:mc.components,defaultValue:[]},parent:{name:mc.parent}},superTypes:[]},PipelineComponent:{name:Ro.$type,properties:{evolution:{name:Ro.evolution},label:{name:Ro.label},name:{name:Ro.name}},superTypes:[]},Radar:{name:tn.$type,properties:{accDescr:{name:tn.accDescr},accTitle:{name:tn.accTitle},axes:{name:tn.axes,defaultValue:[]},curves:{name:tn.curves,defaultValue:[]},options:{name:tn.options,defaultValue:[]},title:{name:tn.title}},superTypes:[]},Railroad:{name:ba.$type,properties:{accDescr:{name:ba.accDescr},accTitle:{name:ba.accTitle},rules:{name:ba.rules,defaultValue:[]},title:{name:ba.title}},superTypes:[]},RailroadAbnf:{name:_a.$type,properties:{accDescr:{name:_a.accDescr},accTitle:{name:_a.accTitle},rules:{name:_a.rules,defaultValue:[]},title:{name:_a.title}},superTypes:[]},RailroadChoiceExpr:{name:lg.$type,properties:{alternatives:{name:lg.alternatives,defaultValue:[]}},superTypes:[dr.$type]},RailroadEbnf:{name:Sa.$type,properties:{accDescr:{name:Sa.accDescr},accTitle:{name:Sa.accTitle},rules:{name:Sa.rules,defaultValue:[]},title:{name:Sa.title}},superTypes:[]},RailroadExpression:{name:dr.$type,properties:{},superTypes:[]},RailroadNonTerminalExpr:{name:ug.$type,properties:{name:{name:ug.name}},superTypes:[dr.$type]},RailroadOneOrMoreExpr:{name:cg.$type,properties:{element:{name:cg.element}},superTypes:[dr.$type]},RailroadOptionalExpr:{name:fg.$type,properties:{element:{name:fg.element}},superTypes:[dr.$type]},RailroadPeg:{name:wa.$type,properties:{accDescr:{name:wa.accDescr},accTitle:{name:wa.accTitle},rules:{name:wa.rules,defaultValue:[]},title:{name:wa.title}},superTypes:[]},RailroadRule:{name:hc.$type,properties:{definition:{name:hc.definition},name:{name:hc.name}},superTypes:[]},RailroadSequenceExpr:{name:dg.$type,properties:{elements:{name:dg.elements,defaultValue:[]}},superTypes:[dr.$type]},RailroadSpecialExpr:{name:pg.$type,properties:{text:{name:pg.text}},superTypes:[dr.$type]},RailroadTerminalExpr:{name:mg.$type,properties:{value:{name:mg.value}},superTypes:[dr.$type]},RailroadZeroOrMoreExpr:{name:hg.$type,properties:{element:{name:hg.element}},superTypes:[dr.$type]},Section:{name:yc.$type,properties:{classSelector:{name:yc.classSelector},name:{name:yc.name}},superTypes:[Fi.$type]},Service:{name:da.$type,properties:{icon:{name:da.icon},iconText:{name:da.iconText},id:{name:da.id},in:{name:da.in},title:{name:da.title}},superTypes:[]},Size:{name:gc.$type,properties:{height:{name:gc.height},width:{name:gc.width}},superTypes:[]},Statement:{name:pa.$type,properties:{},superTypes:[]},Transition:{name:ts.$type,properties:{from:{name:ts.from},label:{name:ts.label},to:{name:ts.to}},superTypes:[]},TreeNode:{name:ma.$type,properties:{classAnnotation:{name:ma.classAnnotation},descAnnotation:{name:ma.descAnnotation},iconAnnotation:{name:ma.iconAnnotation},indent:{name:ma.indent},name:{name:ma.name}},superTypes:[]},TreeView:{name:Bi.$type,properties:{accDescr:{name:Bi.accDescr},accTitle:{name:Bi.accTitle},nodes:{name:Bi.nodes,defaultValue:[]},title:{name:Bi.title}},superTypes:[]},Treemap:{name:Ia.$type,properties:{accDescr:{name:Ia.accDescr},accTitle:{name:Ia.accTitle},title:{name:Ia.title},TreemapRows:{name:Ia.TreemapRows,defaultValue:[]}},superTypes:[]},TreemapRow:{name:vc.$type,properties:{indent:{name:vc.indent},item:{name:vc.item}},superTypes:[]},Wardley:{name:We.$type,properties:{accDescr:{name:We.accDescr},accelerators:{name:We.accelerators,defaultValue:[]},accTitle:{name:We.accTitle},anchors:{name:We.anchors,defaultValue:[]},annotation:{name:We.annotation,defaultValue:[]},annotations:{name:We.annotations,defaultValue:[]},components:{name:We.components,defaultValue:[]},deaccelerators:{name:We.deaccelerators,defaultValue:[]},evolution:{name:We.evolution},evolves:{name:We.evolves,defaultValue:[]},links:{name:We.links,defaultValue:[]},notes:{name:We.notes,defaultValue:[]},pipelines:{name:We.pipelines,defaultValue:[]},size:{name:We.size},title:{name:We.title}},superTypes:[]}}}static{i(this,"MermaidAstReflection")}},Ne=new zw,yg,ez=i(()=>yg??(yg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"ArchitectureGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Architecture","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"architecture-beta"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"groups","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"services","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"junctions","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"edges","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"alignments","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"LeftPort","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"lhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"RightPort","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"rhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Keyword","value":":"}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Arrow","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]},{"$type":"Assignment","feature":"lhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"--"},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]}},{"$type":"Keyword","value":"-"}]}]},{"$type":"Assignment","feature":"rhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"Group","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"group"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Service","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"service"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"iconText","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]}}],"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Junction","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"junction"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Edge","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"lhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"lhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"rhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"rhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Alignment","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"align"},{"$type":"Assignment","feature":"direction","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"row"},{"$type":"Keyword","value":"column"}]}},{"$type":"Assignment","feature":"members","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"members","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]},"cardinality":"+"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"ARROW_DIRECTION","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"L"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"R"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"T"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"B"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_GROUP","definition":{"$type":"RegexToken","regex":"/\\\\{group\\\\}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_INTO","definition":{"$type":"RegexToken","regex":"/<|>/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@19"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@20"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","name":"ARCH_ICON","definition":{"$type":"RegexToken","regex":"/\\\\([\\\\w-:]+\\\\)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_TITLE","definition":{"$type":"RegexToken","regex":"/\\\\[(?:\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'|[\\\\w ]+)\\\\]/","parenthesized":false},"fragment":false,"hidden":false}],"interfaces":[],"types":[]}`)),"ArchitectureGrammarGrammar"),gg,tz=i(()=>gg??(gg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"CynefinGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Cynefin","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"cynefin-beta"},{"$type":"Keyword","value":"cynefin-beta:"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"Assignment","feature":"domains","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"transitions","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"DomainBlock","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"domain","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Assignment","feature":"items","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"DomainItem","definition":{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Transition","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"from","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":"-->"},{"$type":"Assignment","feature":"to","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"DOMAIN_NAME","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"complex"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"complicated"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"clear"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"chaotic"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"confusion"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@11"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@12"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"CynefinGrammarGrammar"),vg,rz=i(()=>vg??(vg=Ue('{"$type":"Grammar","isDeclared":true,"name":"EventModeling","interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"rules":[{"$type":"ParserRule","entry":true,"name":"EventModel","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"eventmodeling"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]}},{"$type":"Assignment","feature":"modelEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"frames","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"dataEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"noteEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"gwtEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmModelEntityType","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"rmo"},{"$type":"Keyword","value":"readmodel"},{"$type":"Keyword","value":"ui"},{"$type":"Keyword","value":"cmd"},{"$type":"Keyword","value":"command"},{"$type":"Keyword","value":"evt"},{"$type":"Keyword","value":"event"},{"$type":"Keyword","value":"pcr"},{"$type":"Keyword","value":"processor"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmDataType","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"json"},{"$type":"Keyword","value":"jsobj"},{"$type":"Keyword","value":"figma"},{"$type":"Keyword","value":"salt"},{"$type":"Keyword","value":"uri"},{"$type":"Keyword","value":"md"},{"$type":"Keyword","value":"html"},{"$type":"Keyword","value":"text"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"EmDataInline","definition":{"$type":"Group","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"`"},{"$type":"Assignment","feature":"dataType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Keyword","value":"`"}],"cardinality":"?"},{"$type":"Assignment","feature":"dataInlineValue","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"EmDataBlock","definition":{"$type":"Group","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"`"},{"$type":"Assignment","feature":"dataType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Keyword","value":"`"}],"cardinality":"?"},{"$type":"Assignment","feature":"dataBlockValue","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"QualifiedName","dataType":"string","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"Group","elements":[{"$type":"Keyword","value":"."},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmTimeFrame","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"tf"},{"$type":"Keyword","value":"timeframe"}]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Assignment","feature":"modelEntityType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"entityIdentifier","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"->>"},{"$type":"Assignment","feature":"sourceFrames","operator":"+=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}}],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"[["},{"$type":"Assignment","feature":"dataReference","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@10"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":"]]"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmResetFrame","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"rf"},{"$type":"Keyword","value":"resetframe"}]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Assignment","feature":"modelEntityType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"entityIdentifier","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"->>"},{"$type":"Assignment","feature":"sourceFrames","operator":"+=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}}],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"[["},{"$type":"Assignment","feature":"dataReference","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@10"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":"]]"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmFrame","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmModelEntity","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"entity"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmDataEntity","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"data"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmNoteEntity","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"note"},{"$type":"Assignment","feature":"sourceFrame","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmGwt","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"gwt"},{"$type":"Assignment","feature":"sourceFrame","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":"given"},{"$type":"Assignment","feature":"givenStatements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"+"},{"$type":"Group","elements":[{"$type":"Keyword","value":"when"},{"$type":"Assignment","feature":"whenStatements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"+"}],"cardinality":"?"},{"$type":"Keyword","value":"then"},{"$type":"Assignment","feature":"thenStatements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"+"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmGwtStatement","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},{"$type":"Assignment","feature":"entityIdentifier","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@9"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EM_EID","dataType":"string","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EM_FI","dataType":"string","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"EM_ID","definition":{"$type":"RegexToken","regex":"/[_a-zA-Z][\\\\w_]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_FID","definition":{"$type":"RegexToken","regex":"/\\\\d{1,3}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_DATA_INLINE","definition":{"$type":"RegexToken","regex":"/\\\\{(.*)\\\\}|\\"(.*)\\"|\'(.*)\'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_DATA_BLOCK","definition":{"$type":"RegexToken","regex":"/\\\\{[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?\\\\}(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"EM_WS","definition":{"$type":"RegexToken","regex":"/\\\\s+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_ML_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_SL_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\/[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"imports":[],"types":[]}')),"EventModelingGrammar"),Tg,nz=i(()=>Tg??(Tg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"GitGraphGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"GitGraph","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Keyword","value":":"}]},{"$type":"Keyword","value":"gitGraph:"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]},{"$type":"Keyword","value":":"}]}]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]},{"$type":"Assignment","feature":"statements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Direction","definition":{"$type":"Assignment","feature":"dir","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"LR"},{"$type":"Keyword","value":"TB"},{"$type":"Keyword","value":"BT"}]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Commit","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"commit"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"msg:","cardinality":"?"},{"$type":"Assignment","feature":"message","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Branch","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"branch"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"order:"},{"$type":"Assignment","feature":"order","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Merge","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"merge"},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]}},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Checkout","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"checkout"},{"$type":"Keyword","value":"switch"}]},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"CherryPicking","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"cherry-pick"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"parent:"},{"$type":"Assignment","feature":"parent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@14"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@15"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","name":"REFERENCE","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\\\w([-\\\\./\\\\w]*[-\\\\w])?/","parenthesized":false},"fragment":false,"hidden":false}],"interfaces":[],"types":[]}`)),"GitGraphGrammarGrammar"),$g,az=i(()=>$g??($g=Ue(`{"$type":"Grammar","isDeclared":true,"name":"InfoGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Info","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"info"},{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"showInfo"},{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"*"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"?"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@7"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@8"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"InfoGrammarGrammar"),Rg,iz=i(()=>Rg??(Rg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"PacketGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Packet","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"packet"},{"$type":"Keyword","value":"packet-beta"}]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]},{"$type":"Assignment","feature":"blocks","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PacketBlock","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Assignment","feature":"start","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"end","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}],"cardinality":"?"}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"+"},{"$type":"Assignment","feature":"bits","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]}]},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@8"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@9"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"PacketGrammarGrammar"),Ag,sz=i(()=>Ag??(Ag=Ue(`{"$type":"Grammar","isDeclared":true,"name":"PieGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Pie","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"pie"},{"$type":"Assignment","feature":"showData","operator":"?=","terminal":{"$type":"Keyword","value":"showData"},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"Assignment","feature":"sections","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PieSection","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"FLOAT_PIE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/-?[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT_PIE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/-?(0|[1-9][0-9]*)(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER_PIE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@2"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@3"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@11"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@12"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"PieGrammarGrammar"),Eg,oz=i(()=>Eg??(Eg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RadarGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Radar","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"radar-beta"},{"$type":"Keyword","value":"radar-beta:"},{"$type":"Group","elements":[{"$type":"Keyword","value":"radar-beta"},{"$type":"Keyword","value":":"}]}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]},{"$type":"Group","elements":[{"$type":"Keyword","value":"axis"},{"$type":"Assignment","feature":"axes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"axes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"curve"},{"$type":"Assignment","feature":"curves","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"curves","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}}],"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"options","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"options","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}],"cardinality":"*"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Label","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"Axis","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Curve","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"?"},{"$type":"Keyword","value":"{"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Keyword","value":"}"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Entries","definition":{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"}]}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"DetailedEntry","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"axis","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@2"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":":","cardinality":"?"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"NumberEntry","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Option","definition":{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"showLegend"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"ticks"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"max"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"min"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"graticule"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}}]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"GRATICULE","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"circle"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"polygon"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@15"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@16"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[{"$type":"Interface","name":"Entry","attributes":[{"$type":"TypeAttribute","name":"axis","isOptional":true,"type":{"$type":"ReferenceType","referenceType":{"$type":"SimpleType","typeRef":{"$ref":"#/rules@2"}},"isMulti":false}},{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"number"},"isOptional":false}],"superTypes":[]}],"types":[]}`)),"RadarGrammarGrammar"),Cg,lz=i(()=>Cg??(Cg=Ue('{"$type":"Grammar","isDeclared":true,"name":"RailroadAbnfGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_RULENAME","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Za-z][A-Za-z0-9-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_NUMVAL","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/%[xXdDbB][0-9A-Fa-f]+(?:-[0-9A-Fa-f]+|\\\\.[0-9A-Fa-f]+)*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_REPEAT","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[0-9]*\\\\*[0-9]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_EXACT_REPEAT","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[0-9]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_COMMENT","definition":{"$type":"RegexToken","regex":"/;[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"RailroadAbnf","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-abnf-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Keyword","value":"="},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfAlternation","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"/"},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfConcatenation","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},"cardinality":"+"},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfElement","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"repeat","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"repeat","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}],"cardinality":"?"},{"$type":"Assignment","feature":"primary","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfPrimary","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfStringLiteral","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfNumVal","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfRuleName","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfGroup","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfOptionalGroup","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"RailroadAbnf","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfAlternation","attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@3"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfConcatenation","attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@4"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfElement","attributes":[{"$type":"TypeAttribute","name":"repeat","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"primary","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfPrimary","attributes":[],"superTypes":[]},{"$type":"Interface","name":"AbnfStringLiteral","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"AbnfNumVal","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"AbnfRuleName","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"AbnfGroup","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"AbnfOptionalGroup","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]}],"imports":[],"types":[]}')),"RailroadAbnfGrammarGrammar"),bg,uz=i(()=>bg??(bg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RailroadEbnfGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EBNF_ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Z_a-z][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EBNF_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EBNF_SPECIAL_SEQUENCE","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\\\?(?=[^?;]*[^?\\\\s;][^?;]*\\\\?)[^?;]*\\\\?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_BLOCK_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_ISO_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\(\\\\*[\\\\s\\\\S]*?\\\\*\\\\)/","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"RailroadEbnf","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-ebnf-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"="},{"$type":"Keyword","value":"::="}]},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfChoice","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"|"},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfSequence","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":",","cardinality":"?"},{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfTerm","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"base","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"Assignment","feature":"postfixes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfPrimary","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfTerminal","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfNonTerminal","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfSpecial","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfGroup","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfOptional","returnType":{"$ref":"#/interfaces@11"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfRepetition","returnType":{"$ref":"#/interfaces@12"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"{"},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":"}"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfPostfix","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@25"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@26"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@27"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@28"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfOptionalPostfix","returnType":{"$ref":"#/interfaces@13"},"definition":{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"?"}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfZeroOrMorePostfix","returnType":{"$ref":"#/interfaces@14"},"definition":{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"*"}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfOneOrMorePostfix","returnType":{"$ref":"#/interfaces@15"},"definition":{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"+"}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfExceptionPostfix","returnType":{"$ref":"#/interfaces@16"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"except","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"RailroadEbnf","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfChoice","attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@3"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfSequence","attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@4"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfTerm","attributes":[{"$type":"TypeAttribute","name":"base","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false},{"$type":"TypeAttribute","name":"postfixes","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@6"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfPrimary","attributes":[],"superTypes":[]},{"$type":"Interface","name":"EbnfPostfix","attributes":[],"superTypes":[]},{"$type":"Interface","name":"EbnfTerminal","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfNonTerminal","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfSpecial","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"text","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfGroup","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"EbnfOptional","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"EbnfRepetition","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"EbnfOptionalPostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"operator","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfZeroOrMorePostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"operator","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfOneOrMorePostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"operator","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfExceptionPostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"except","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false}]}],"imports":[],"types":[]}`)),"RailroadEbnfGrammarGrammar"),_g,cz=i(()=>_g??(_g=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RailroadGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"RR_ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Z_a-z][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"RR_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"RR_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_BLOCK_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"Railroad","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Keyword","value":"="},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadExpression","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadSequenceExpr","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"sequence"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"*"},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadChoiceExpr","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"choice"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"*"},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadOptionalExpr","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"optional"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadOneOrMoreExpr","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"oneOrMore"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadZeroOrMoreExpr","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"zeroOrMore"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadTerminalExpr","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"terminal"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadNonTerminalExpr","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"nonterminal"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadSpecialExpr","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"special"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"Railroad","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"RailroadRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"RailroadExpression","attributes":[],"superTypes":[]},{"$type":"Interface","name":"RailroadSequenceExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}}},"isOptional":false}]},{"$type":"Interface","name":"RailroadChoiceExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}}},"isOptional":false}]},{"$type":"Interface","name":"RailroadOptionalExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"RailroadOneOrMoreExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"RailroadZeroOrMoreExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"RailroadTerminalExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"RailroadNonTerminalExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"RailroadSpecialExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"text","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]}],"imports":[],"types":[]}`)),"RailroadGrammarGrammar"),Sg,fz=i(()=>Sg??(Sg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RailroadPegGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"PEG_ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Z_a-z][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"PEG_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/#[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"RailroadPeg","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-peg-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Keyword","value":"<-"},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegOrderedChoice","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"/"},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegSequence","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"+"},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegPrefix","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"&"}},{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"!"}}],"cardinality":"?"},{"$type":"Assignment","feature":"suffix","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegSuffix","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"primary","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"?"}},{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"*"}},{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"+"}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegPrimary","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegLiteral","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegIdentifier","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegGroup","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegAny","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Assignment","feature":"dot","operator":"=","terminal":{"$type":"Keyword","value":"."}},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"RailroadPeg","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegOrderedChoice","attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@3"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegSequence","attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@4"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegPrefix","attributes":[{"$type":"TypeAttribute","name":"operator","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"suffix","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegSuffix","attributes":[{"$type":"TypeAttribute","name":"primary","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@6"}},"isOptional":false},{"$type":"TypeAttribute","name":"operator","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]},{"$type":"Interface","name":"PegPrimary","attributes":[],"superTypes":[]},{"$type":"Interface","name":"PegLiteral","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"PegIdentifier","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"PegGroup","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"PegAny","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"dot","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]}],"imports":[],"types":[]}`)),"RailroadPegGrammarGrammar"),wg,dz=i(()=>wg??(wg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"TreemapGrammar","rules":[{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","entry":true,"name":"Treemap","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]},{"$type":"Assignment","feature":"TreemapRows","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"TREEMAP_KEYWORD","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"treemap-beta"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"treemap"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"CLASS_DEF","definition":{"$type":"RegexToken","regex":"/classDef\\\\s+([a-zA-Z_][a-zA-Z0-9_]+)(?:\\\\s+([^;\\\\r\\\\n]*))?(?:;)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STYLE_SEPARATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":":::"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"SEPARATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":":"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"COMMA","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":","},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INDENTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]{1,}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WS","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ML_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\%\\\\%[^\\\\n]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"NL","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false},{"$type":"ParserRule","name":"TreemapRow","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"indent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"item","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"ClassDef","dataType":"string","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Item","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Section","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},{"$type":"Assignment","feature":"classSelector","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Leaf","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[],"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[],"cardinality":"?"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},{"$type":"Assignment","feature":"classSelector","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"ID2","definition":{"$type":"RegexToken","regex":"/[a-zA-Z_][a-zA-Z0-9_]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER2","definition":{"$type":"RegexToken","regex":"/[0-9_\\\\.\\\\,]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"MyNumber","dataType":"number","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"STRING2","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|'[^']*'/","parenthesized":false},"fragment":false,"hidden":false}],"interfaces":[{"$type":"Interface","name":"Item","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"classSelector","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]},{"$type":"Interface","name":"Section","superTypes":[{"$ref":"#/interfaces@0"}],"attributes":[]},{"$type":"Interface","name":"Leaf","superTypes":[{"$ref":"#/interfaces@0"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"number"},"isOptional":false}]},{"$type":"Interface","name":"ClassDefStatement","attributes":[{"$type":"TypeAttribute","name":"className","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"styleText","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"Treemap","attributes":[{"$type":"TypeAttribute","name":"TreemapRows","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/rules@15"}}},"isOptional":false},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"imports":[],"types":[],"$comment":"/**\\n * Treemap grammar for Langium\\n * Converted from mindmap grammar\\n *\\n * The ML_COMMENT and NL hidden terminals handle whitespace, comments, and newlines\\n * before the treemap keyword, allowing for empty lines and comments before the\\n * treemap declaration.\\n */"}`)),"TreemapGrammarGrammar"),Ig,pz=i(()=>Ig??(Ig=Ue(`{"$type":"Grammar","isDeclared":true,"name":"TreeViewGrammar","rules":[{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","entry":true,"name":"TreeView","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"treeView-beta"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[],"cardinality":"?"},{"$type":"Assignment","feature":"nodes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"CLASS_ANNOTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+:::[ \\\\t]*[A-Za-z_][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ICON_ANNOTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+icon\\\\([\\\\w-]*(?::[\\\\w-]+)?\\\\)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"DESC_ANNOTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+##[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INDENTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]{1,}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"QUOTED_NAME","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|'[^']*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WS","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ML_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\%\\\\%[^\\\\n]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"NL","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","name":"BARE_NAME","definition":{"$type":"RegexToken","regex":"/(?!:::|icon\\\\(|##)[^ \\\\t\\\\n\\\\r\\"'](?:(?![ \\\\t]+:::[ \\\\t]*[A-Za-z_]|[ \\\\t]+icon\\\\(|[ \\\\t]+##)[^\\\\n\\\\r])*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TreeNode","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"indent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}}]},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"classAnnotation","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"iconAnnotation","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"descAnnotation","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"TreeView","attributes":[{"$type":"TypeAttribute","name":"nodes","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/rules@14"}}},"isOptional":false},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"imports":[],"types":[],"$comment":"/**\\n * TreeView grammar for Langium\\n *\\n * Supports both quoted labels (\\"my file\\") and bare labels (index.js).\\n * Annotations (:::class, icon(), ## description) are parsed directly into\\n * AST fields by the grammar. Value conversion for stripping quotes, extracting\\n * class names, icon names, and description text happens in valueConverter.ts.\\n *\\n * The ML_COMMENT and NL hidden terminals handle whitespace, comments, and newlines\\n * before the treeView keyword, allowing for empty lines and comments before the\\n * treeView declaration.\\n */"}`)),"TreeViewGrammarGrammar"),Ng,mz=i(()=>Ng??(Ng=Ue(`{"$type":"Grammar","isDeclared":true,"name":"WardleyGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Wardley","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@25"},"arguments":[]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@42"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"size","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Assignment","feature":"anchors","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"components","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"links","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"evolves","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"pipelines","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"notes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Assignment","feature":"annotations","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Assignment","feature":"annotation","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Assignment","feature":"accelerators","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"Assignment","feature":"deaccelerators","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"Size","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@26"},"arguments":[]},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"width","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"height","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Evolution","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@27"},"arguments":[]},{"$type":"Assignment","feature":"stages","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]},{"$type":"Assignment","feature":"stages","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}}],"cardinality":"+"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EvolutionStage","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"@"},{"$type":"Assignment","feature":"boundary","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}}],"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"/"},{"$type":"Assignment","feature":"secondName","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Anchor","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@28"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"visibility","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Component","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"visibility","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"decorator","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"inertia","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@31"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"inertia","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@31"},"arguments":[]}},{"$type":"Keyword","value":")"}]}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Label","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"negX","operator":"?=","terminal":{"$type":"Keyword","value":"-"},"cardinality":"?"},{"$type":"Assignment","feature":"offsetX","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"negY","operator":"?=","terminal":{"$type":"Keyword","value":"-"},"cardinality":"?"},{"$type":"Assignment","feature":"offsetY","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Decorator","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"strategy","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Link","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"from","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Assignment","feature":"fromPort","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"arrow","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]},"cardinality":"?"},{"$type":"Assignment","feature":"to","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Assignment","feature":"toPort","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"linkLabel","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Evolve","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@32"},"arguments":[]},{"$type":"Assignment","feature":"component","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Assignment","feature":"target","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Pipeline","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@33"},"arguments":[]},{"$type":"Assignment","feature":"parent","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"{"},{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[],"cardinality":"+"},{"$type":"Assignment","feature":"components","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"+"},{"$type":"Keyword","value":"}"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PipelineComponent","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Note","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@34"},"arguments":[]},{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"visibility","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Annotations","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@35"},"arguments":[]},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Annotation","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@36"},"arguments":[]},{"$type":"Assignment","feature":"number","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"CoordinateValue","dataType":"number","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Accelerator","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@37"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Deaccelerator","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@38"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"WARDLEY_NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"->"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"LINK_PORT","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"+<>"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"+>"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"+<"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"LINK_ARROW","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"-->"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"-.->"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":">"},"parenthesized":false}],"parenthesized":false},{"$type":"RegexToken","regex":"/\\\\+'[^']*'<>/","parenthesized":false}],"parenthesized":false},{"$type":"RegexToken","regex":"/\\\\+'[^']*'/","parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"LINK_LABEL","definition":{"$type":"RegexToken","regex":"/;[^\\\\n\\\\r]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRATEGY","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"build"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"buy"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"outsource"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"market"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_WARDLEY","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"wardley-beta"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_SIZE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"size"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_EVOLUTION","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"evolution"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ANCHOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"anchor"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_COMPONENT","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"component"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_LABEL","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"label"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_INERTIA","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"inertia"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_EVOLVE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"evolve"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_PIPELINE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"pipeline"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_NOTE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"note"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ANNOTATIONS","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"annotations"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ANNOTATION","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"annotation"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ACCELERATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"accelerator"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_DEACCELERATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"deaccelerator"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NAME_WITH_SPACES","definition":{"$type":"RegexToken","regex":"/(?!title\\\\s|accTitle|accDescr)[A-Za-z](?:[A-Za-z0-9_()&]|-(?!>))*(?:[ \\\\t]+[A-Za-z(](?:[A-Za-z0-9_()&]|-(?!>))*)*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WS","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+/","parenthesized":false},"fragment":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@44"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@45"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@46"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@47"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@48"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"WardleyGrammarGrammar"),hz={languageId:"architecture",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},yz={languageId:"cynefin",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},gz={languageId:"eventmodeling",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},vz={languageId:"gitGraph",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Tz={languageId:"info",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},$z={languageId:"packet",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Rz={languageId:"pie",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Az={languageId:"radar",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Ez={languageId:"railroadAbnf",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Cz={languageId:"railroadEbnf",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},bz={languageId:"railroad",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},_z={languageId:"railroadPeg",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Sz={languageId:"treemap",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},wz={languageId:"treeView",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Iz={languageId:"wardley",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},ut={AstReflection:i(()=>new zw,"AstReflection")},Nz={Grammar:i(()=>ez(),"Grammar"),LanguageMetaData:i(()=>hz,"LanguageMetaData"),parser:{}},Pz={Grammar:i(()=>tz(),"Grammar"),LanguageMetaData:i(()=>yz,"LanguageMetaData"),parser:{}},kz={Grammar:i(()=>rz(),"Grammar"),LanguageMetaData:i(()=>gz,"LanguageMetaData"),parser:{}},Oz={Grammar:i(()=>nz(),"Grammar"),LanguageMetaData:i(()=>vz,"LanguageMetaData"),parser:{}},Lz={Grammar:i(()=>az(),"Grammar"),LanguageMetaData:i(()=>Tz,"LanguageMetaData"),parser:{}},Dz={Grammar:i(()=>iz(),"Grammar"),LanguageMetaData:i(()=>$z,"LanguageMetaData"),parser:{}},xz={Grammar:i(()=>sz(),"Grammar"),LanguageMetaData:i(()=>Rz,"LanguageMetaData"),parser:{}},Mz={Grammar:i(()=>oz(),"Grammar"),LanguageMetaData:i(()=>Az,"LanguageMetaData"),parser:{}},Gz={Grammar:i(()=>lz(),"Grammar"),LanguageMetaData:i(()=>Ez,"LanguageMetaData"),parser:{}},Fz={Grammar:i(()=>uz(),"Grammar"),LanguageMetaData:i(()=>Cz,"LanguageMetaData"),parser:{}},zz={Grammar:i(()=>cz(),"Grammar"),LanguageMetaData:i(()=>bz,"LanguageMetaData"),parser:{}},jz={Grammar:i(()=>fz(),"Grammar"),LanguageMetaData:i(()=>_z,"LanguageMetaData"),parser:{}},Bz={Grammar:i(()=>dz(),"Grammar"),LanguageMetaData:i(()=>Sz,"LanguageMetaData"),parser:{}},Uz={Grammar:i(()=>pz(),"Grammar"),LanguageMetaData:i(()=>wz,"LanguageMetaData"),parser:{}},Kz={Grammar:i(()=>mz(),"Grammar"),LanguageMetaData:i(()=>Iz,"LanguageMetaData"),parser:{}},Wz=/accDescr(?:[\t ]*:([^\n\r]*)|\s*{([^}]*)})/,qz=/accTitle[\t ]*:([^\n\r]*)/,Vz=/title([\t ][^\n\r]*|)/,Hz={ACC_DESCR:Wz,ACC_TITLE:qz,TITLE:Vz},lr=class extends Fm{static{i(this,"AbstractMermaidValueConverter")}runConverter(e,t,r){let n=this.runCommonConverter(e,t,r);return n===void 0&&(n=this.runCustomConverter(e,t,r)),n===void 0?super.runConverter(e,t,r):n}runCommonConverter(e,t,r){const n=Hz[e.name];if(n===void 0)return;const a=n.exec(t);if(a!==null){if(a[1]!==void 0)return a[1].trim().replace(/[\t ]{2,}/gm," ");if(a[2]!==void 0)return a[2].replace(/^\s*/gm,"").replace(/\s+$/gm,"").replace(/[\t ]{2,}/gm," ").replace(/[\n\r]{2,}/gm,` +`)}}},ui=class extends lr{static{i(this,"CommonValueConverter")}runCustomConverter(e,t,r){}},ct=class extends Lu{static{i(this,"AbstractMermaidTokenBuilder")}constructor(e){super(),this.keywords=new Set(e)}buildKeywordTokens(e,t,r){const n=super.buildKeywordTokens(e,t,r);return n.forEach(a=>{this.keywords.has(a.name)&&a.PATTERN!==void 0&&(a.PATTERN=new RegExp(a.PATTERN.toString()+"(?:(?=%%)|(?!\\S))"))}),n}};(class extends ct{static{i(this,"CommonTokenBuilder")}});/*! Bundled license information: + +lodash-es/lodash.js: + (** + * @license + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" -o ./` + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + *) +*/var Yz=class extends ct{static{i(this,"RadarTokenBuilder")}constructor(){super(["radar-beta"])}},jw={parser:{TokenBuilder:i(()=>new Yz,"TokenBuilder"),ValueConverter:i(()=>new ui,"ValueConverter")}};function Bw(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Mz,jw);return t.ServiceRegistry.register(r),{shared:t,Radar:r}}i(Bw,"createRadarServices");var Xz=class extends ct{static{i(this,"RailroadTokenBuilder")}constructor(){super(["railroad-beta"])}},Pg=i(e=>{const t=e.slice(1,-1);let r="";for(let n=0;nnew Xz,"TokenBuilder"),ValueConverter:i(()=>new Jz,"ValueConverter")}};function Kw(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),zz,Uw);return t.ServiceRegistry.register(r),{shared:t,Railroad:r}}i(Kw,"createRailroadServices");var Zz=class extends ct{static{i(this,"RailroadEbnfTokenBuilder")}constructor(){super(["railroad-ebnf-beta"])}},kg=i(e=>{const t=e.slice(1,-1);let r="";for(let n=0;nnew Zz,"TokenBuilder"),ValueConverter:i(()=>new Qz,"ValueConverter")}};function qw(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Fz,Ww);return t.ServiceRegistry.register(r),{shared:t,RailroadEbnf:r}}i(qw,"createRailroadEbnfServices");var ej=class extends ct{static{i(this,"RailroadAbnfTokenBuilder")}constructor(){super(["railroad-abnf-beta"])}},tj=class extends lr{static{i(this,"RailroadAbnfValueConverter")}runConverter(e,t,r){const n=super.runConverter(e,t,r);if(e.name==="TITLE"&&typeof n=="string"){const a=n.trim();if(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))return a.slice(1,-1)}return n}runCustomConverter(e,t,r){if(e.name==="ABNF_STRING")return t.slice(1,-1)}},Vw={parser:{TokenBuilder:i(()=>new ej,"TokenBuilder"),ValueConverter:i(()=>new tj,"ValueConverter")}};function Hw(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Gz,Vw);return t.ServiceRegistry.register(r),{shared:t,RailroadAbnf:r}}i(Hw,"createRailroadAbnfServices");var rj=class extends ct{static{i(this,"RailroadPegTokenBuilder")}constructor(){super(["railroad-peg-beta"])}},Og=i(e=>{const t=e.slice(1,-1);let r="";for(let n=0;nnew rj,"TokenBuilder"),ValueConverter:i(()=>new nj,"ValueConverter")}};function Xw(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),jz,Yw);return t.ServiceRegistry.register(r),{shared:t,RailroadPeg:r}}i(Xw,"createRailroadPegServices");var aj=class extends ct{static{i(this,"TreemapTokenBuilder")}constructor(){super(["treemap"])}},ij=/classDef\s+([A-Z_a-z]\w+)(?:\s+([^\n\r;]*))?;?/,sj=class extends lr{static{i(this,"TreemapValueConverter")}runCustomConverter(e,t,r){if(e.name==="NUMBER2")return parseFloat(t.replace(/,/g,""));if(e.name==="SEPARATOR")return t.substring(1,t.length-1);if(e.name==="STRING2")return t.substring(1,t.length-1);if(e.name==="INDENTATION")return t.length;if(e.name==="ClassDef"){if(typeof t!="string")return t;const n=ij.exec(t);if(n)return{$type:"ClassDefStatement",className:n[1],styleText:n[2]||void 0}}}};function Jw(e){const t=e.validation.TreemapValidator,r=e.validation.ValidationRegistry;if(r){const n={Treemap:t.checkSingleRoot.bind(t)};r.register(n,t)}}i(Jw,"registerValidationChecks");var oj=class{static{i(this,"TreemapValidator")}checkSingleRoot(e,t){let r;for(const n of e.TreemapRows)n.item&&(r===void 0&&n.indent===void 0?r=0:n.indent===void 0?t("error","Multiple root nodes are not allowed in a treemap.",{node:n,property:"item"}):r!==void 0&&r>=parseInt(n.indent,10)&&t("error","Multiple root nodes are not allowed in a treemap.",{node:n,property:"item"}))}},Zw={parser:{TokenBuilder:i(()=>new aj,"TokenBuilder"),ValueConverter:i(()=>new sj,"ValueConverter")},validation:{TreemapValidator:i(()=>new oj,"TreemapValidator")}};function Qw(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Bz,Zw);return t.ServiceRegistry.register(r),Jw(r),{shared:t,Treemap:r}}i(Qw,"createTreemapServices");var lj=class extends lr{static{i(this,"WardleyValueConverter")}runCustomConverter(e,t,r){switch(e.name.toUpperCase()){case"LINK_LABEL":return t.substring(1).trim();default:return}}},eI={parser:{ValueConverter:i(()=>new lj,"ValueConverter")}};function tI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Kz,eI);return t.ServiceRegistry.register(r),{shared:t,Wardley:r}}i(tI,"createWardleyServices");var uj=class extends ct{static{i(this,"CynefinTokenBuilder")}constructor(){super(["cynefin-beta"])}},rI={parser:{TokenBuilder:i(()=>new uj,"TokenBuilder"),ValueConverter:i(()=>new ui,"ValueConverter")}};function nI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Pz,rI);return t.ServiceRegistry.register(r),{shared:t,Cynefin:r}}i(nI,"createCynefinServices");var cj=class extends ct{static{i(this,"GitGraphTokenBuilder")}constructor(){super(["gitGraph"])}},aI={parser:{TokenBuilder:i(()=>new cj,"TokenBuilder"),ValueConverter:i(()=>new ui,"ValueConverter")}};function iI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Oz,aI);return t.ServiceRegistry.register(r),{shared:t,GitGraph:r}}i(iI,"createGitGraphServices");var fj=class extends ct{static{i(this,"InfoTokenBuilder")}constructor(){super(["info","showInfo"])}},sI={parser:{TokenBuilder:i(()=>new fj,"TokenBuilder"),ValueConverter:i(()=>new ui,"ValueConverter")}};function oI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Lz,sI);return t.ServiceRegistry.register(r),{shared:t,Info:r}}i(oI,"createInfoServices");var dj=class extends ct{static{i(this,"PacketTokenBuilder")}constructor(){super(["packet"])}},lI={parser:{TokenBuilder:i(()=>new dj,"TokenBuilder"),ValueConverter:i(()=>new ui,"ValueConverter")}};function uI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Dz,lI);return t.ServiceRegistry.register(r),{shared:t,Packet:r}}i(uI,"createPacketServices");var pj=class extends ct{static{i(this,"PieTokenBuilder")}constructor(){super(["pie","showData"])}},mj=class extends lr{static{i(this,"PieValueConverter")}runCustomConverter(e,t,r){if(e.name==="PIE_SECTION_LABEL")return t.replace(/"/g,"").trim()}},cI={parser:{TokenBuilder:i(()=>new pj,"TokenBuilder"),ValueConverter:i(()=>new mj,"ValueConverter")}};function fI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),xz,cI);return t.ServiceRegistry.register(r),{shared:t,Pie:r}}i(fI,"createPieServices");var hj=class extends lr{static{i(this,"TreeViewValueConverter")}runCustomConverter(e,t,r){if(e.name==="INDENTATION")return t?.length||0;if(e.name==="QUOTED_NAME")return t.substring(1,t.length-1);if(e.name==="BARE_NAME")return t.replace(/[\t ]+$/,"");if(e.name==="CLASS_ANNOTATION")return t.trim().substring(3).trim();if(e.name==="ICON_ANNOTATION"){const n=t.trim();return n.substring(5,n.length-1)}if(e.name==="DESC_ANNOTATION")return t.trim().substring(2).trim()}},yj=class extends ct{static{i(this,"TreeViewTokenBuilder")}constructor(){super(["treeView-beta"])}},dI={parser:{TokenBuilder:i(()=>new yj,"TokenBuilder"),ValueConverter:i(()=>new hj,"ValueConverter")}};function pI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Uz,dI);return t.ServiceRegistry.register(r),{shared:t,TreeView:r}}i(pI,"createTreeViewServices");var gj=class extends ct{static{i(this,"ArchitectureTokenBuilder")}constructor(){super(["architecture"])}},vj=class extends lr{static{i(this,"ArchitectureValueConverter")}runCustomConverter(e,t,r){if(e.name==="ARCH_ICON")return t.replace(/[()]/g,"").trim();if(e.name==="ARCH_TEXT_ICON")return t.replace(/["()]/g,"");if(e.name==="ARCH_TITLE"){let n=t.replace(/^\[|]$/g,"").trim();return(n.startsWith('"')&&n.endsWith('"')||n.startsWith("'")&&n.endsWith("'"))&&(n=n.slice(1,-1),n=n.replace(/\\"/g,'"').replace(/\\'/g,"'")),n.trim()}}},mI={parser:{TokenBuilder:i(()=>new gj,"TokenBuilder"),ValueConverter:i(()=>new vj,"ValueConverter")}};function hI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),Nz,mI);return t.ServiceRegistry.register(r),{shared:t,Architecture:r}}i(hI,"createArchitectureServices");var Tj=class extends ct{static{i(this,"EventModelingTokenBuilder")}constructor(){super(["eventmodeling"])}},Lg=new Set(["cmd","command"]),Dg=new Set(["evt","event"]),Tc=new Set(["rmo","readmodel"]),xg=new Set(["pcr","processor"]),Mg=new Set(["ui"]);function yI(e){const t=e.validation.EventModelingValidator,r=e.validation.ValidationRegistry;if(r){const n={EmTimeFrame:t.checkSourceFrameTypes.bind(t),EmResetFrame:t.checkSourceFrameTypes.bind(t)};r.register(n,t)}}i(yI,"registerValidationChecks");var $j=class{static{i(this,"EventModelingValidator")}checkSourceFrameTypes(e,t){e.sourceFrames.length!==0&&(Lg.has(e.modelEntityType)?this.validateSources(e,new Set([...Mg,...xg]),"command","ui or processor",t):Dg.has(e.modelEntityType)?this.validateSources(e,Lg,"event","command",t):Tc.has(e.modelEntityType)?this.validateSources(e,Dg,"read model","event",t):xg.has(e.modelEntityType)?this.validateSources(e,Tc,"processor","read model",t):Mg.has(e.modelEntityType)&&this.validateSources(e,Tc,"ui","read model",t))}validateSources(e,t,r,n,a){for(const s of e.sourceFrames){const o=s.ref;o!==void 0&&!t.has(o.modelEntityType)&&a("error",`A ${r} can only receive input from a ${n}, not from '${o.modelEntityType}'.`,{node:e,property:"sourceFrames"})}}},gI={parser:{TokenBuilder:i(()=>new Tj,"TokenBuilder"),ValueConverter:i(()=>new ui,"ValueConverter")},validation:{EventModelingValidator:i(()=>new $j,"EventModelingValidator")}};function vI(e=Xe){const t=ee(Be(e),ut),r=ee(je({shared:t}),kz,gI);return t.ServiceRegistry.register(r),yI(r),{shared:t,EventModel:r}}i(vI,"createEventModelingServices");var qe={},Rj={info:i(async()=>{const{createInfoServices:e}=await Promise.resolve().then(function(){return Cj}),t=e().Info.parser.LangiumParser;qe.info=t},"info"),packet:i(async()=>{const{createPacketServices:e}=await Promise.resolve().then(function(){return bj}),t=e().Packet.parser.LangiumParser;qe.packet=t},"packet"),pie:i(async()=>{const{createPieServices:e}=await Promise.resolve().then(function(){return _j}),t=e().Pie.parser.LangiumParser;qe.pie=t},"pie"),treeView:i(async()=>{const{createTreeViewServices:e}=await Promise.resolve().then(function(){return Sj}),t=e().TreeView.parser.LangiumParser;qe.treeView=t},"treeView"),architecture:i(async()=>{const{createArchitectureServices:e}=await Promise.resolve().then(function(){return wj}),t=e().Architecture.parser.LangiumParser;qe.architecture=t},"architecture"),gitGraph:i(async()=>{const{createGitGraphServices:e}=await Promise.resolve().then(function(){return Ij}),t=e().GitGraph.parser.LangiumParser;qe.gitGraph=t},"gitGraph"),eventmodeling:i(async()=>{const{createEventModelingServices:e}=await Promise.resolve().then(function(){return Nj}),t=e().EventModel.parser.LangiumParser;qe.eventmodeling=t},"eventmodeling"),radar:i(async()=>{const{createRadarServices:e}=await Promise.resolve().then(function(){return Pj}),t=e().Radar.parser.LangiumParser;qe.radar=t},"radar"),railroad:i(async()=>{const{createRailroadServices:e}=await Promise.resolve().then(function(){return kj}),t=e().Railroad.parser.LangiumParser;qe.railroad=t},"railroad"),railroadEbnf:i(async()=>{const{createRailroadEbnfServices:e}=await Promise.resolve().then(function(){return Oj}),t=e().RailroadEbnf.parser.LangiumParser;qe.railroadEbnf=t},"railroadEbnf"),railroadAbnf:i(async()=>{const{createRailroadAbnfServices:e}=await Promise.resolve().then(function(){return Lj}),t=e().RailroadAbnf.parser.LangiumParser;qe.railroadAbnf=t},"railroadAbnf"),railroadPeg:i(async()=>{const{createRailroadPegServices:e}=await Promise.resolve().then(function(){return Dj}),t=e().RailroadPeg.parser.LangiumParser;qe.railroadPeg=t},"railroadPeg"),treemap:i(async()=>{const{createTreemapServices:e}=await Promise.resolve().then(function(){return xj}),t=e().Treemap.parser.LangiumParser;qe.treemap=t},"treemap"),wardley:i(async()=>{const{createWardleyServices:e}=await Promise.resolve().then(function(){return Mj}),t=e().Wardley.parser.LangiumParser;qe.wardley=t},"wardley"),cynefin:i(async()=>{const{createCynefinServices:e}=await Promise.resolve().then(function(){return Gj}),t=e().Cynefin.parser.LangiumParser;qe.cynefin=t},"cynefin")};async function Aj(e,t){const r=Rj[e];if(!r)throw new Error(`Unknown diagram type: ${e}`);qe[e]||await r();const a=qe[e].parse(t);if(a.lexerErrors.length>0||a.parserErrors.length>0)throw new Ej(a);return a.value}i(Aj,"parse");var Ej=class extends Error{constructor(e){const t=e.lexerErrors.map(n=>{const a=n.line!==void 0&&!isNaN(n.line)?n.line:"?",s=n.column!==void 0&&!isNaN(n.column)?n.column:"?";return`Lexer error on line ${a}, column ${s}: ${n.message}`}).join(` +`),r=e.parserErrors.map(n=>{const a=n.token.startLine!==void 0&&!isNaN(n.token.startLine)?n.token.startLine:"?",s=n.token.startColumn!==void 0&&!isNaN(n.token.startColumn)?n.token.startColumn:"?";return`Parse error on line ${a}, column ${s}: ${n.message}`}).join(` +`);super(`Parsing failed: ${t} ${r}`),this.result=e}static{i(this,"MermaidParseError")}},Cj=Object.freeze({__proto__:null,InfoModule:sI,createInfoServices:oI}),bj=Object.freeze({__proto__:null,PacketModule:lI,createPacketServices:uI}),_j=Object.freeze({__proto__:null,PieModule:cI,createPieServices:fI}),Sj=Object.freeze({__proto__:null,TreeViewModule:dI,createTreeViewServices:pI}),wj=Object.freeze({__proto__:null,ArchitectureModule:mI,createArchitectureServices:hI}),Ij=Object.freeze({__proto__:null,GitGraphModule:aI,createGitGraphServices:iI}),Nj=Object.freeze({__proto__:null,EventModelingModule:gI,createEventModelingServices:vI}),Pj=Object.freeze({__proto__:null,RadarModule:jw,createRadarServices:Bw}),kj=Object.freeze({__proto__:null,RailroadModule:Uw,createRailroadServices:Kw}),Oj=Object.freeze({__proto__:null,RailroadEbnfModule:Ww,createRailroadEbnfServices:qw}),Lj=Object.freeze({__proto__:null,RailroadAbnfModule:Vw,createRailroadAbnfServices:Hw}),Dj=Object.freeze({__proto__:null,RailroadPegModule:Yw,createRailroadPegServices:Xw}),xj=Object.freeze({__proto__:null,TreemapModule:Zw,createTreemapServices:Qw}),Mj=Object.freeze({__proto__:null,WardleyModule:eI,createWardleyServices:tI}),Gj=Object.freeze({__proto__:null,CynefinModule:rI,createCynefinServices:nI});export{Ej as M,qw as a,Hw as b,Kw as c,Xw as d,FF as i,Aj as p}; diff --git a/apps/kimi-code/dist-web/assets/cynefin-VYW2F7L2-DZANU5FS.js b/apps/kimi-code/dist-web/assets/cynefin-VYW2F7L2-DZANU5FS.js new file mode 100644 index 0000000000000000000000000000000000000000..a8695217b86d809431a134203c7bfe7a207a161b --- /dev/null +++ b/apps/kimi-code/dist-web/assets/cynefin-VYW2F7L2-DZANU5FS.js @@ -0,0 +1,178 @@ +import{bR as et}from"./index-Baap3_X9.js";var RI=Object.create,Ds=Object.defineProperty,AI=Object.getOwnPropertyDescriptor,Ad=Object.getOwnPropertyNames,EI=Object.getPrototypeOf,CI=Object.prototype.hasOwnProperty,i=(e,t)=>Ds(e,"name",{value:t,configurable:!0}),bI=(e,t)=>function(){return e&&(t=(0,e[Ad(e)[0]])(e=0)),t},H=(e,t)=>function(){return t||(0,e[Ad(e)[0]])((t={exports:{}}).exports,t),t.exports},Vr=(e,t)=>{for(var r in t)Ds(e,r,{get:t[r],enumerable:!0})},Ed=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Ad(t))!CI.call(e,a)&&a!==r&&Ds(e,a,{get:()=>t[a],enumerable:!(n=AI(t,a))||n.enumerable});return e},Ll=(e,t,r)=>(Ed(e,t,"default"),r),Cd=(e,t,r)=>(r=e!=null?RI(EI(e)):{},Ed(Ds(r,"default",{value:e,enumerable:!0}),e)),bd=e=>Ed(Ds({},"__esModule",{value:!0}),e),Dl={};Vr(Dl,{AnnotatedTextEdit:()=>mr,ChangeAnnotation:()=>an,ChangeAnnotationIdentifier:()=>Ke,CodeAction:()=>ef,CodeActionContext:()=>Qc,CodeActionKind:()=>Zc,CodeActionTriggerKind:()=>Xi,CodeDescription:()=>Nc,CodeLens:()=>tf,Color:()=>Co,ColorInformation:()=>Cc,ColorPresentation:()=>bc,Command:()=>nn,CompletionItem:()=>zc,CompletionItemKind:()=>Lc,CompletionItemLabelDetails:()=>Fc,CompletionItemTag:()=>xc,CompletionList:()=>jc,CreateFile:()=>ya,DeleteFile:()=>va,Diagnostic:()=>Vi,DiagnosticRelatedInformation:()=>bo,DiagnosticSeverity:()=>wc,DiagnosticTag:()=>Ic,DocumentHighlight:()=>Vc,DocumentHighlightKind:()=>Wc,DocumentLink:()=>nf,DocumentSymbol:()=>Jc,DocumentUri:()=>Rc,EOL:()=>zg,FoldingRange:()=>Sc,FoldingRangeKind:()=>_c,FormattingOptions:()=>rf,Hover:()=>Bc,InlayHint:()=>pf,InlayHintKind:()=>wo,InlayHintLabelPart:()=>Io,InlineCompletionContext:()=>Tf,InlineCompletionItem:()=>hf,InlineCompletionList:()=>yf,InlineCompletionTriggerKind:()=>gf,InlineValueContext:()=>df,InlineValueEvaluatableExpression:()=>ff,InlineValueText:()=>uf,InlineValueVariableLookup:()=>cf,InsertReplaceEdit:()=>Mc,InsertTextFormat:()=>Dc,InsertTextMode:()=>Gc,Location:()=>Wi,LocationLink:()=>Ec,MarkedString:()=>Yi,MarkupContent:()=>Ta,MarkupKind:()=>So,OptionalVersionedTextDocumentIdentifier:()=>Hi,ParameterInformation:()=>Uc,Position:()=>ie,Range:()=>Q,RenameFile:()=>ga,SelectedCompletionInfo:()=>vf,SelectionRange:()=>af,SemanticTokenModifiers:()=>of,SemanticTokenTypes:()=>sf,SemanticTokens:()=>lf,SignatureInformation:()=>Kc,StringValue:()=>mf,SymbolInformation:()=>Yc,SymbolKind:()=>qc,SymbolTag:()=>Hc,TextDocument:()=>Rf,TextDocumentEdit:()=>qi,TextDocumentIdentifier:()=>Pc,TextDocumentItem:()=>Oc,TextEdit:()=>Yt,URI:()=>Eo,VersionedTextDocumentIdentifier:()=>kc,WorkspaceChange:()=>Fg,WorkspaceEdit:()=>_o,WorkspaceFolder:()=>$f,WorkspaceSymbol:()=>Xc,integer:()=>Ac,uinteger:()=>Ki});var Rc,Eo,Ac,Ki,ie,Q,Wi,Ec,Co,Cc,bc,_c,Sc,bo,wc,Ic,Nc,Vi,nn,Yt,an,Ke,mr,qi,ya,ga,va,_o,ki,Ku,Fg,Pc,kc,Hi,Oc,So,Ta,Lc,Dc,xc,Mc,Gc,Fc,zc,jc,Yi,Bc,Uc,Kc,Wc,Vc,qc,Hc,Yc,Xc,Jc,Zc,Xi,Qc,ef,tf,rf,nf,af,sf,of,lf,uf,cf,ff,df,wo,Io,pf,mf,hf,yf,gf,vf,Tf,$f,zg,Rf,lh,A,xs=bI({"../../node_modules/.pnpm/vscode-languageserver-types@3.17.5/node_modules/vscode-languageserver-types/lib/esm/main.js"(){(function(e){function t(r){return typeof r=="string"}i(t,"is"),e.is=t})(Rc||(Rc={})),(function(e){function t(r){return typeof r=="string"}i(t,"is"),e.is=t})(Eo||(Eo={})),(function(e){e.MIN_VALUE=-2147483648,e.MAX_VALUE=2147483647;function t(r){return typeof r=="number"&&e.MIN_VALUE<=r&&r<=e.MAX_VALUE}i(t,"is"),e.is=t})(Ac||(Ac={})),(function(e){e.MIN_VALUE=0,e.MAX_VALUE=2147483647;function t(r){return typeof r=="number"&&e.MIN_VALUE<=r&&r<=e.MAX_VALUE}i(t,"is"),e.is=t})(Ki||(Ki={})),(function(e){function t(n,a){return n===Number.MAX_VALUE&&(n=Ki.MAX_VALUE),a===Number.MAX_VALUE&&(a=Ki.MAX_VALUE),{line:n,character:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&A.uinteger(a.line)&&A.uinteger(a.character)}i(r,"is"),e.is=r})(ie||(ie={})),(function(e){function t(n,a,s,o){if(A.uinteger(n)&&A.uinteger(a)&&A.uinteger(s)&&A.uinteger(o))return{start:ie.create(n,a),end:ie.create(s,o)};if(ie.is(n)&&ie.is(a))return{start:n,end:a};throw new Error(`Range#create called with invalid arguments[${n}, ${a}, ${s}, ${o}]`)}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&ie.is(a.start)&&ie.is(a.end)}i(r,"is"),e.is=r})(Q||(Q={})),(function(e){function t(n,a){return{uri:n,range:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&Q.is(a.range)&&(A.string(a.uri)||A.undefined(a.uri))}i(r,"is"),e.is=r})(Wi||(Wi={})),(function(e){function t(n,a,s,o){return{targetUri:n,targetRange:a,targetSelectionRange:s,originSelectionRange:o}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&Q.is(a.targetRange)&&A.string(a.targetUri)&&Q.is(a.targetSelectionRange)&&(Q.is(a.originSelectionRange)||A.undefined(a.originSelectionRange))}i(r,"is"),e.is=r})(Ec||(Ec={})),(function(e){function t(n,a,s,o){return{red:n,green:a,blue:s,alpha:o}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.numberRange(a.red,0,1)&&A.numberRange(a.green,0,1)&&A.numberRange(a.blue,0,1)&&A.numberRange(a.alpha,0,1)}i(r,"is"),e.is=r})(Co||(Co={})),(function(e){function t(n,a){return{range:n,color:a}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&Q.is(a.range)&&Co.is(a.color)}i(r,"is"),e.is=r})(Cc||(Cc={})),(function(e){function t(n,a,s){return{label:n,textEdit:a,additionalTextEdits:s}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.string(a.label)&&(A.undefined(a.textEdit)||Yt.is(a))&&(A.undefined(a.additionalTextEdits)||A.typedArray(a.additionalTextEdits,Yt.is))}i(r,"is"),e.is=r})(bc||(bc={})),(function(e){e.Comment="comment",e.Imports="imports",e.Region="region"})(_c||(_c={})),(function(e){function t(n,a,s,o,l,u){const c={startLine:n,endLine:a};return A.defined(s)&&(c.startCharacter=s),A.defined(o)&&(c.endCharacter=o),A.defined(l)&&(c.kind=l),A.defined(u)&&(c.collapsedText=u),c}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.uinteger(a.startLine)&&A.uinteger(a.startLine)&&(A.undefined(a.startCharacter)||A.uinteger(a.startCharacter))&&(A.undefined(a.endCharacter)||A.uinteger(a.endCharacter))&&(A.undefined(a.kind)||A.string(a.kind))}i(r,"is"),e.is=r})(Sc||(Sc={})),(function(e){function t(n,a){return{location:n,message:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Wi.is(a.location)&&A.string(a.message)}i(r,"is"),e.is=r})(bo||(bo={})),(function(e){e.Error=1,e.Warning=2,e.Information=3,e.Hint=4})(wc||(wc={})),(function(e){e.Unnecessary=1,e.Deprecated=2})(Ic||(Ic={})),(function(e){function t(r){const n=r;return A.objectLiteral(n)&&A.string(n.href)}i(t,"is"),e.is=t})(Nc||(Nc={})),(function(e){function t(n,a,s,o,l,u){let c={range:n,message:a};return A.defined(s)&&(c.severity=s),A.defined(o)&&(c.code=o),A.defined(l)&&(c.source=l),A.defined(u)&&(c.relatedInformation=u),c}i(t,"create"),e.create=t;function r(n){var a;let s=n;return A.defined(s)&&Q.is(s.range)&&A.string(s.message)&&(A.number(s.severity)||A.undefined(s.severity))&&(A.integer(s.code)||A.string(s.code)||A.undefined(s.code))&&(A.undefined(s.codeDescription)||A.string((a=s.codeDescription)===null||a===void 0?void 0:a.href))&&(A.string(s.source)||A.undefined(s.source))&&(A.undefined(s.relatedInformation)||A.typedArray(s.relatedInformation,bo.is))}i(r,"is"),e.is=r})(Vi||(Vi={})),(function(e){function t(n,a,...s){let o={title:n,command:a};return A.defined(s)&&s.length>0&&(o.arguments=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.title)&&A.string(a.command)}i(r,"is"),e.is=r})(nn||(nn={})),(function(e){function t(s,o){return{range:s,newText:o}}i(t,"replace"),e.replace=t;function r(s,o){return{range:{start:s,end:s},newText:o}}i(r,"insert"),e.insert=r;function n(s){return{range:s,newText:""}}i(n,"del"),e.del=n;function a(s){const o=s;return A.objectLiteral(o)&&A.string(o.newText)&&Q.is(o.range)}i(a,"is"),e.is=a})(Yt||(Yt={})),(function(e){function t(n,a,s){const o={label:n};return a!==void 0&&(o.needsConfirmation=a),s!==void 0&&(o.description=s),o}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&A.string(a.label)&&(A.boolean(a.needsConfirmation)||a.needsConfirmation===void 0)&&(A.string(a.description)||a.description===void 0)}i(r,"is"),e.is=r})(an||(an={})),(function(e){function t(r){const n=r;return A.string(n)}i(t,"is"),e.is=t})(Ke||(Ke={})),(function(e){function t(s,o,l){return{range:s,newText:o,annotationId:l}}i(t,"replace"),e.replace=t;function r(s,o,l){return{range:{start:s,end:s},newText:o,annotationId:l}}i(r,"insert"),e.insert=r;function n(s,o){return{range:s,newText:"",annotationId:o}}i(n,"del"),e.del=n;function a(s){const o=s;return Yt.is(o)&&(an.is(o.annotationId)||Ke.is(o.annotationId))}i(a,"is"),e.is=a})(mr||(mr={})),(function(e){function t(n,a){return{textDocument:n,edits:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Hi.is(a.textDocument)&&Array.isArray(a.edits)}i(r,"is"),e.is=r})(qi||(qi={})),(function(e){function t(n,a,s){let o={kind:"create",uri:n};return a!==void 0&&(a.overwrite!==void 0||a.ignoreIfExists!==void 0)&&(o.options=a),s!==void 0&&(o.annotationId=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return a&&a.kind==="create"&&A.string(a.uri)&&(a.options===void 0||(a.options.overwrite===void 0||A.boolean(a.options.overwrite))&&(a.options.ignoreIfExists===void 0||A.boolean(a.options.ignoreIfExists)))&&(a.annotationId===void 0||Ke.is(a.annotationId))}i(r,"is"),e.is=r})(ya||(ya={})),(function(e){function t(n,a,s,o){let l={kind:"rename",oldUri:n,newUri:a};return s!==void 0&&(s.overwrite!==void 0||s.ignoreIfExists!==void 0)&&(l.options=s),o!==void 0&&(l.annotationId=o),l}i(t,"create"),e.create=t;function r(n){let a=n;return a&&a.kind==="rename"&&A.string(a.oldUri)&&A.string(a.newUri)&&(a.options===void 0||(a.options.overwrite===void 0||A.boolean(a.options.overwrite))&&(a.options.ignoreIfExists===void 0||A.boolean(a.options.ignoreIfExists)))&&(a.annotationId===void 0||Ke.is(a.annotationId))}i(r,"is"),e.is=r})(ga||(ga={})),(function(e){function t(n,a,s){let o={kind:"delete",uri:n};return a!==void 0&&(a.recursive!==void 0||a.ignoreIfNotExists!==void 0)&&(o.options=a),s!==void 0&&(o.annotationId=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return a&&a.kind==="delete"&&A.string(a.uri)&&(a.options===void 0||(a.options.recursive===void 0||A.boolean(a.options.recursive))&&(a.options.ignoreIfNotExists===void 0||A.boolean(a.options.ignoreIfNotExists)))&&(a.annotationId===void 0||Ke.is(a.annotationId))}i(r,"is"),e.is=r})(va||(va={})),(function(e){function t(r){let n=r;return n&&(n.changes!==void 0||n.documentChanges!==void 0)&&(n.documentChanges===void 0||n.documentChanges.every(a=>A.string(a.kind)?ya.is(a)||ga.is(a)||va.is(a):qi.is(a)))}i(t,"is"),e.is=t})(_o||(_o={})),ki=class{static{i(this,"TextEditChangeImpl")}constructor(e,t){this.edits=e,this.changeAnnotations=t}insert(e,t,r){let n,a;if(r===void 0?n=Yt.insert(e,t):Ke.is(r)?(a=r,n=mr.insert(e,t,r)):(this.assertChangeAnnotations(this.changeAnnotations),a=this.changeAnnotations.manage(r),n=mr.insert(e,t,a)),this.edits.push(n),a!==void 0)return a}replace(e,t,r){let n,a;if(r===void 0?n=Yt.replace(e,t):Ke.is(r)?(a=r,n=mr.replace(e,t,r)):(this.assertChangeAnnotations(this.changeAnnotations),a=this.changeAnnotations.manage(r),n=mr.replace(e,t,a)),this.edits.push(n),a!==void 0)return a}delete(e,t){let r,n;if(t===void 0?r=Yt.del(e):Ke.is(t)?(n=t,r=mr.del(e,t)):(this.assertChangeAnnotations(this.changeAnnotations),n=this.changeAnnotations.manage(t),r=mr.del(e,n)),this.edits.push(r),n!==void 0)return n}add(e){this.edits.push(e)}all(){return this.edits}clear(){this.edits.splice(0,this.edits.length)}assertChangeAnnotations(e){if(e===void 0)throw new Error("Text edit change is not configured to manage change annotations.")}},Ku=class{static{i(this,"ChangeAnnotations")}constructor(e){this._annotations=e===void 0?Object.create(null):e,this._counter=0,this._size=0}all(){return this._annotations}get size(){return this._size}manage(e,t){let r;if(Ke.is(e)?r=e:(r=this.nextId(),t=e),this._annotations[r]!==void 0)throw new Error(`Id ${r} is already in use.`);if(t===void 0)throw new Error(`No annotation provided for id ${r}`);return this._annotations[r]=t,this._size++,r}nextId(){return this._counter++,this._counter.toString()}},Fg=class{static{i(this,"WorkspaceChange")}constructor(e){this._textEditChanges=Object.create(null),e!==void 0?(this._workspaceEdit=e,e.documentChanges?(this._changeAnnotations=new Ku(e.changeAnnotations),e.changeAnnotations=this._changeAnnotations.all(),e.documentChanges.forEach(t=>{if(qi.is(t)){const r=new ki(t.edits,this._changeAnnotations);this._textEditChanges[t.textDocument.uri]=r}})):e.changes&&Object.keys(e.changes).forEach(t=>{const r=new ki(e.changes[t]);this._textEditChanges[t]=r})):this._workspaceEdit={}}get edit(){return this.initDocumentChanges(),this._changeAnnotations!==void 0&&(this._changeAnnotations.size===0?this._workspaceEdit.changeAnnotations=void 0:this._workspaceEdit.changeAnnotations=this._changeAnnotations.all()),this._workspaceEdit}getTextEditChange(e){if(Hi.is(e)){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");const t={uri:e.uri,version:e.version};let r=this._textEditChanges[t.uri];if(!r){const n=[],a={textDocument:t,edits:n};this._workspaceEdit.documentChanges.push(a),r=new ki(n,this._changeAnnotations),this._textEditChanges[t.uri]=r}return r}else{if(this.initChanges(),this._workspaceEdit.changes===void 0)throw new Error("Workspace edit is not configured for normal text edit changes.");let t=this._textEditChanges[e];if(!t){let r=[];this._workspaceEdit.changes[e]=r,t=new ki(r),this._textEditChanges[e]=t}return t}}initDocumentChanges(){this._workspaceEdit.documentChanges===void 0&&this._workspaceEdit.changes===void 0&&(this._changeAnnotations=new Ku,this._workspaceEdit.documentChanges=[],this._workspaceEdit.changeAnnotations=this._changeAnnotations.all())}initChanges(){this._workspaceEdit.documentChanges===void 0&&this._workspaceEdit.changes===void 0&&(this._workspaceEdit.changes=Object.create(null))}createFile(e,t,r){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");let n;an.is(t)||Ke.is(t)?n=t:r=t;let a,s;if(n===void 0?a=ya.create(e,r):(s=Ke.is(n)?n:this._changeAnnotations.manage(n),a=ya.create(e,r,s)),this._workspaceEdit.documentChanges.push(a),s!==void 0)return s}renameFile(e,t,r,n){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");let a;an.is(r)||Ke.is(r)?a=r:n=r;let s,o;if(a===void 0?s=ga.create(e,t,n):(o=Ke.is(a)?a:this._changeAnnotations.manage(a),s=ga.create(e,t,n,o)),this._workspaceEdit.documentChanges.push(s),o!==void 0)return o}deleteFile(e,t,r){if(this.initDocumentChanges(),this._workspaceEdit.documentChanges===void 0)throw new Error("Workspace edit is not configured for document changes.");let n;an.is(t)||Ke.is(t)?n=t:r=t;let a,s;if(n===void 0?a=va.create(e,r):(s=Ke.is(n)?n:this._changeAnnotations.manage(n),a=va.create(e,r,s)),this._workspaceEdit.documentChanges.push(a),s!==void 0)return s}},(function(e){function t(n){return{uri:n}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)}i(r,"is"),e.is=r})(Pc||(Pc={})),(function(e){function t(n,a){return{uri:n,version:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)&&A.integer(a.version)}i(r,"is"),e.is=r})(kc||(kc={})),(function(e){function t(n,a){return{uri:n,version:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)&&(a.version===null||A.integer(a.version))}i(r,"is"),e.is=r})(Hi||(Hi={})),(function(e){function t(n,a,s,o){return{uri:n,languageId:a,version:s,text:o}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.string(a.uri)&&A.string(a.languageId)&&A.integer(a.version)&&A.string(a.text)}i(r,"is"),e.is=r})(Oc||(Oc={})),(function(e){e.PlainText="plaintext",e.Markdown="markdown";function t(r){const n=r;return n===e.PlainText||n===e.Markdown}i(t,"is"),e.is=t})(So||(So={})),(function(e){function t(r){const n=r;return A.objectLiteral(r)&&So.is(n.kind)&&A.string(n.value)}i(t,"is"),e.is=t})(Ta||(Ta={})),(function(e){e.Text=1,e.Method=2,e.Function=3,e.Constructor=4,e.Field=5,e.Variable=6,e.Class=7,e.Interface=8,e.Module=9,e.Property=10,e.Unit=11,e.Value=12,e.Enum=13,e.Keyword=14,e.Snippet=15,e.Color=16,e.File=17,e.Reference=18,e.Folder=19,e.EnumMember=20,e.Constant=21,e.Struct=22,e.Event=23,e.Operator=24,e.TypeParameter=25})(Lc||(Lc={})),(function(e){e.PlainText=1,e.Snippet=2})(Dc||(Dc={})),(function(e){e.Deprecated=1})(xc||(xc={})),(function(e){function t(n,a,s){return{newText:n,insert:a,replace:s}}i(t,"create"),e.create=t;function r(n){const a=n;return a&&A.string(a.newText)&&Q.is(a.insert)&&Q.is(a.replace)}i(r,"is"),e.is=r})(Mc||(Mc={})),(function(e){e.asIs=1,e.adjustIndentation=2})(Gc||(Gc={})),(function(e){function t(r){const n=r;return n&&(A.string(n.detail)||n.detail===void 0)&&(A.string(n.description)||n.description===void 0)}i(t,"is"),e.is=t})(Fc||(Fc={})),(function(e){function t(r){return{label:r}}i(t,"create"),e.create=t})(zc||(zc={})),(function(e){function t(r,n){return{items:r||[],isIncomplete:!!n}}i(t,"create"),e.create=t})(jc||(jc={})),(function(e){function t(n){return n.replace(/[\\`*_{}[\]()#+\-.!]/g,"\\$&")}i(t,"fromPlainText"),e.fromPlainText=t;function r(n){const a=n;return A.string(a)||A.objectLiteral(a)&&A.string(a.language)&&A.string(a.value)}i(r,"is"),e.is=r})(Yi||(Yi={})),(function(e){function t(r){let n=r;return!!n&&A.objectLiteral(n)&&(Ta.is(n.contents)||Yi.is(n.contents)||A.typedArray(n.contents,Yi.is))&&(r.range===void 0||Q.is(r.range))}i(t,"is"),e.is=t})(Bc||(Bc={})),(function(e){function t(r,n){return n?{label:r,documentation:n}:{label:r}}i(t,"create"),e.create=t})(Uc||(Uc={})),(function(e){function t(r,n,...a){let s={label:r};return A.defined(n)&&(s.documentation=n),A.defined(a)?s.parameters=a:s.parameters=[],s}i(t,"create"),e.create=t})(Kc||(Kc={})),(function(e){e.Text=1,e.Read=2,e.Write=3})(Wc||(Wc={})),(function(e){function t(r,n){let a={range:r};return A.number(n)&&(a.kind=n),a}i(t,"create"),e.create=t})(Vc||(Vc={})),(function(e){e.File=1,e.Module=2,e.Namespace=3,e.Package=4,e.Class=5,e.Method=6,e.Property=7,e.Field=8,e.Constructor=9,e.Enum=10,e.Interface=11,e.Function=12,e.Variable=13,e.Constant=14,e.String=15,e.Number=16,e.Boolean=17,e.Array=18,e.Object=19,e.Key=20,e.Null=21,e.EnumMember=22,e.Struct=23,e.Event=24,e.Operator=25,e.TypeParameter=26})(qc||(qc={})),(function(e){e.Deprecated=1})(Hc||(Hc={})),(function(e){function t(r,n,a,s,o){let l={name:r,kind:n,location:{uri:s,range:a}};return o&&(l.containerName=o),l}i(t,"create"),e.create=t})(Yc||(Yc={})),(function(e){function t(r,n,a,s){return s!==void 0?{name:r,kind:n,location:{uri:a,range:s}}:{name:r,kind:n,location:{uri:a}}}i(t,"create"),e.create=t})(Xc||(Xc={})),(function(e){function t(n,a,s,o,l,u){let c={name:n,detail:a,kind:s,range:o,selectionRange:l};return u!==void 0&&(c.children=u),c}i(t,"create"),e.create=t;function r(n){let a=n;return a&&A.string(a.name)&&A.number(a.kind)&&Q.is(a.range)&&Q.is(a.selectionRange)&&(a.detail===void 0||A.string(a.detail))&&(a.deprecated===void 0||A.boolean(a.deprecated))&&(a.children===void 0||Array.isArray(a.children))&&(a.tags===void 0||Array.isArray(a.tags))}i(r,"is"),e.is=r})(Jc||(Jc={})),(function(e){e.Empty="",e.QuickFix="quickfix",e.Refactor="refactor",e.RefactorExtract="refactor.extract",e.RefactorInline="refactor.inline",e.RefactorRewrite="refactor.rewrite",e.Source="source",e.SourceOrganizeImports="source.organizeImports",e.SourceFixAll="source.fixAll"})(Zc||(Zc={})),(function(e){e.Invoked=1,e.Automatic=2})(Xi||(Xi={})),(function(e){function t(n,a,s){let o={diagnostics:n};return a!=null&&(o.only=a),s!=null&&(o.triggerKind=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.typedArray(a.diagnostics,Vi.is)&&(a.only===void 0||A.typedArray(a.only,A.string))&&(a.triggerKind===void 0||a.triggerKind===Xi.Invoked||a.triggerKind===Xi.Automatic)}i(r,"is"),e.is=r})(Qc||(Qc={})),(function(e){function t(n,a,s){let o={title:n},l=!0;return typeof a=="string"?(l=!1,o.kind=a):nn.is(a)?o.command=a:o.edit=a,l&&s!==void 0&&(o.kind=s),o}i(t,"create"),e.create=t;function r(n){let a=n;return a&&A.string(a.title)&&(a.diagnostics===void 0||A.typedArray(a.diagnostics,Vi.is))&&(a.kind===void 0||A.string(a.kind))&&(a.edit!==void 0||a.command!==void 0)&&(a.command===void 0||nn.is(a.command))&&(a.isPreferred===void 0||A.boolean(a.isPreferred))&&(a.edit===void 0||_o.is(a.edit))}i(r,"is"),e.is=r})(ef||(ef={})),(function(e){function t(n,a){let s={range:n};return A.defined(a)&&(s.data=a),s}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Q.is(a.range)&&(A.undefined(a.command)||nn.is(a.command))}i(r,"is"),e.is=r})(tf||(tf={})),(function(e){function t(n,a){return{tabSize:n,insertSpaces:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&A.uinteger(a.tabSize)&&A.boolean(a.insertSpaces)}i(r,"is"),e.is=r})(rf||(rf={})),(function(e){function t(n,a,s){return{range:n,target:a,data:s}}i(t,"create"),e.create=t;function r(n){let a=n;return A.defined(a)&&Q.is(a.range)&&(A.undefined(a.target)||A.string(a.target))}i(r,"is"),e.is=r})(nf||(nf={})),(function(e){function t(n,a){return{range:n,parent:a}}i(t,"create"),e.create=t;function r(n){let a=n;return A.objectLiteral(a)&&Q.is(a.range)&&(a.parent===void 0||e.is(a.parent))}i(r,"is"),e.is=r})(af||(af={})),(function(e){e.namespace="namespace",e.type="type",e.class="class",e.enum="enum",e.interface="interface",e.struct="struct",e.typeParameter="typeParameter",e.parameter="parameter",e.variable="variable",e.property="property",e.enumMember="enumMember",e.event="event",e.function="function",e.method="method",e.macro="macro",e.keyword="keyword",e.modifier="modifier",e.comment="comment",e.string="string",e.number="number",e.regexp="regexp",e.operator="operator",e.decorator="decorator"})(sf||(sf={})),(function(e){e.declaration="declaration",e.definition="definition",e.readonly="readonly",e.static="static",e.deprecated="deprecated",e.abstract="abstract",e.async="async",e.modification="modification",e.documentation="documentation",e.defaultLibrary="defaultLibrary"})(of||(of={})),(function(e){function t(r){const n=r;return A.objectLiteral(n)&&(n.resultId===void 0||typeof n.resultId=="string")&&Array.isArray(n.data)&&(n.data.length===0||typeof n.data[0]=="number")}i(t,"is"),e.is=t})(lf||(lf={})),(function(e){function t(n,a){return{range:n,text:a}}i(t,"create"),e.create=t;function r(n){const a=n;return a!=null&&Q.is(a.range)&&A.string(a.text)}i(r,"is"),e.is=r})(uf||(uf={})),(function(e){function t(n,a,s){return{range:n,variableName:a,caseSensitiveLookup:s}}i(t,"create"),e.create=t;function r(n){const a=n;return a!=null&&Q.is(a.range)&&A.boolean(a.caseSensitiveLookup)&&(A.string(a.variableName)||a.variableName===void 0)}i(r,"is"),e.is=r})(cf||(cf={})),(function(e){function t(n,a){return{range:n,expression:a}}i(t,"create"),e.create=t;function r(n){const a=n;return a!=null&&Q.is(a.range)&&(A.string(a.expression)||a.expression===void 0)}i(r,"is"),e.is=r})(ff||(ff={})),(function(e){function t(n,a){return{frameId:n,stoppedLocation:a}}i(t,"create"),e.create=t;function r(n){const a=n;return A.defined(a)&&Q.is(n.stoppedLocation)}i(r,"is"),e.is=r})(df||(df={})),(function(e){e.Type=1,e.Parameter=2;function t(r){return r===1||r===2}i(t,"is"),e.is=t})(wo||(wo={})),(function(e){function t(n){return{value:n}}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&(a.tooltip===void 0||A.string(a.tooltip)||Ta.is(a.tooltip))&&(a.location===void 0||Wi.is(a.location))&&(a.command===void 0||nn.is(a.command))}i(r,"is"),e.is=r})(Io||(Io={})),(function(e){function t(n,a,s){const o={position:n,label:a};return s!==void 0&&(o.kind=s),o}i(t,"create"),e.create=t;function r(n){const a=n;return A.objectLiteral(a)&&ie.is(a.position)&&(A.string(a.label)||A.typedArray(a.label,Io.is))&&(a.kind===void 0||wo.is(a.kind))&&a.textEdits===void 0||A.typedArray(a.textEdits,Yt.is)&&(a.tooltip===void 0||A.string(a.tooltip)||Ta.is(a.tooltip))&&(a.paddingLeft===void 0||A.boolean(a.paddingLeft))&&(a.paddingRight===void 0||A.boolean(a.paddingRight))}i(r,"is"),e.is=r})(pf||(pf={})),(function(e){function t(r){return{kind:"snippet",value:r}}i(t,"createSnippet"),e.createSnippet=t})(mf||(mf={})),(function(e){function t(r,n,a,s){return{insertText:r,filterText:n,range:a,command:s}}i(t,"create"),e.create=t})(hf||(hf={})),(function(e){function t(r){return{items:r}}i(t,"create"),e.create=t})(yf||(yf={})),(function(e){e.Invoked=0,e.Automatic=1})(gf||(gf={})),(function(e){function t(r,n){return{range:r,text:n}}i(t,"create"),e.create=t})(vf||(vf={})),(function(e){function t(r,n){return{triggerKind:r,selectedCompletionInfo:n}}i(t,"create"),e.create=t})(Tf||(Tf={})),(function(e){function t(r){const n=r;return A.objectLiteral(n)&&Eo.is(n.uri)&&A.string(n.name)}i(t,"is"),e.is=t})($f||($f={})),zg=[` +`,`\r +`,"\r"],(function(e){function t(s,o,l,u){return new lh(s,o,l,u)}i(t,"create"),e.create=t;function r(s){let o=s;return!!(A.defined(o)&&A.string(o.uri)&&(A.undefined(o.languageId)||A.string(o.languageId))&&A.uinteger(o.lineCount)&&A.func(o.getText)&&A.func(o.positionAt)&&A.func(o.offsetAt))}i(r,"is"),e.is=r;function n(s,o){let l=s.getText(),u=a(o,(f,d)=>{let m=f.range.start.line-d.range.start.line;return m===0?f.range.start.character-d.range.start.character:m}),c=l.length;for(let f=u.length-1;f>=0;f--){let d=u[f],m=s.offsetAt(d.range.start),g=s.offsetAt(d.range.end);if(g<=c)l=l.substring(0,m)+d.newText+l.substring(g,l.length);else throw new Error("Overlapping edit");c=m}return l}i(n,"applyEdits"),e.applyEdits=n;function a(s,o){if(s.length<=1)return s;const l=s.length/2|0,u=s.slice(0,l),c=s.slice(l);a(u,o),a(c,o);let f=0,d=0,m=0;for(;f0&&e.push(t.length),this._lineOffsets=e}return this._lineOffsets}positionAt(e){e=Math.max(Math.min(e,this._content.length),0);let t=this.getLineOffsets(),r=0,n=t.length;if(n===0)return ie.create(0,e);for(;re?n=s:r=s+1}let a=r-1;return ie.create(a,e-t[a])}offsetAt(e){let t=this.getLineOffsets();if(e.line>=t.length)return this._content.length;if(e.line<0)return 0;let r=t[e.line],n=e.line+1"u"}i(n,"undefined"),e.undefined=n;function a(g){return g===!0||g===!1}i(a,"boolean"),e.boolean=a;function s(g){return t.call(g)==="[object String]"}i(s,"string"),e.string=s;function o(g){return t.call(g)==="[object Number]"}i(o,"number"),e.number=o;function l(g,v,b){return t.call(g)==="[object Number]"&&v<=g&&g<=b}i(l,"numberRange"),e.numberRange=l;function u(g){return t.call(g)==="[object Number]"&&-2147483648<=g&&g<=2147483647}i(u,"integer"),e.integer=u;function c(g){return t.call(g)==="[object Number]"&&0<=g&&g<=2147483647}i(c,"uinteger"),e.uinteger=c;function f(g){return t.call(g)==="[object Function]"}i(f,"func"),e.func=f;function d(g){return g!==null&&typeof g=="object"}i(d,"objectLiteral"),e.objectLiteral=d;function m(g,v){return Array.isArray(g)&&g.every(v)}i(m,"typedArray"),e.typedArray=m})(A||(A={}))}}),Dn=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/ral.js"(e){Object.defineProperty(e,"__esModule",{value:!0});var t;function r(){if(t===void 0)throw new Error("No runtime abstraction layer installed");return t}i(r,"RAL"),(function(n){function a(s){if(s===void 0)throw new Error("No runtime abstraction layer provided");t=s}i(a,"install"),n.install=a})(r||(r={})),e.default=r}}),Ms=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/is.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.stringArray=e.array=e.func=e.error=e.number=e.string=e.boolean=void 0;function t(u){return u===!0||u===!1}i(t,"boolean"),e.boolean=t;function r(u){return typeof u=="string"||u instanceof String}i(r,"string"),e.string=r;function n(u){return typeof u=="number"||u instanceof Number}i(n,"number"),e.number=n;function a(u){return u instanceof Error}i(a,"error"),e.error=a;function s(u){return typeof u=="function"}i(s,"func"),e.func=s;function o(u){return Array.isArray(u)}i(o,"array"),e.array=o;function l(u){return o(u)&&u.every(c=>r(c))}i(l,"stringArray"),e.stringArray=l}}),ei=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/events.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Emitter=e.Event=void 0;var t=Dn(),r;(function(s){const o={dispose(){}};s.None=function(){return o}})(r||(e.Event=r={}));var n=class{static{i(this,"CallbackList")}add(s,o=null,l){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(s),this._contexts.push(o),Array.isArray(l)&&l.push({dispose:i(()=>this.remove(s,o),"dispose")})}remove(s,o=null){if(!this._callbacks)return;let l=!1;for(let u=0,c=this._callbacks.length;u{this._callbacks||(this._callbacks=new n),this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(o,l);const c={dispose:i(()=>{this._callbacks&&(this._callbacks.remove(o,l),c.dispose=jg._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))},"dispose")};return Array.isArray(u)&&u.push(c),c}),this._event}fire(o){this._callbacks&&this._callbacks.invoke.call(this._callbacks,o)}dispose(){this._callbacks&&(this._callbacks.dispose(),this._callbacks=void 0)}};e.Emitter=a,a._noop=function(){}}}),xl=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/cancellation.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.CancellationTokenSource=e.CancellationToken=void 0;var t=Dn(),r=Ms(),n=ei(),a;(function(u){u.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:n.Event.None}),u.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:n.Event.None});function c(f){const d=f;return d&&(d===u.None||d===u.Cancelled||r.boolean(d.isCancellationRequested)&&!!d.onCancellationRequested)}i(c,"is"),u.is=c})(a||(e.CancellationToken=a={}));var s=Object.freeze(function(u,c){const f=(0,t.default)().timer.setTimeout(u.bind(c),0);return{dispose(){f.dispose()}}}),o=class{static{i(this,"MutableToken")}constructor(){this._isCancelled=!1}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?s:(this._emitter||(this._emitter=new n.Emitter),this._emitter.event)}dispose(){this._emitter&&(this._emitter.dispose(),this._emitter=void 0)}},l=class{static{i(this,"CancellationTokenSource")}get token(){return this._token||(this._token=new o),this._token}cancel(){this._token?this._token.cancel():this._token=a.Cancelled}dispose(){this._token?this._token instanceof o&&this._token.dispose():this._token=a.None}};e.CancellationTokenSource=l}}),Bg=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messages.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Message=e.NotificationType9=e.NotificationType8=e.NotificationType7=e.NotificationType6=e.NotificationType5=e.NotificationType4=e.NotificationType3=e.NotificationType2=e.NotificationType1=e.NotificationType0=e.NotificationType=e.RequestType9=e.RequestType8=e.RequestType7=e.RequestType6=e.RequestType5=e.RequestType4=e.RequestType3=e.RequestType2=e.RequestType1=e.RequestType=e.RequestType0=e.AbstractMessageSignature=e.ParameterStructures=e.ResponseError=e.ErrorCodes=void 0;var t=Ms(),r;(function(y){y.ParseError=-32700,y.InvalidRequest=-32600,y.MethodNotFound=-32601,y.InvalidParams=-32602,y.InternalError=-32603,y.jsonrpcReservedErrorRangeStart=-32099,y.serverErrorStart=-32099,y.MessageWriteError=-32099,y.MessageReadError=-32098,y.PendingResponseRejected=-32097,y.ConnectionInactive=-32096,y.ServerNotInitialized=-32002,y.UnknownErrorCode=-32001,y.jsonrpcReservedErrorRangeEnd=-32e3,y.serverErrorEnd=-32e3})(r||(e.ErrorCodes=r={}));var n=class Ug extends Error{static{i(this,"ResponseError")}constructor(E,T,$){super(T),this.code=t.number(E)?E:r.UnknownErrorCode,this.data=$,Object.setPrototypeOf(this,Ug.prototype)}toJson(){const E={code:this.code,message:this.message};return this.data!==void 0&&(E.data=this.data),E}};e.ResponseError=n;var a=class No{static{i(this,"ParameterStructures")}constructor(E){this.kind=E}static is(E){return E===No.auto||E===No.byName||E===No.byPosition}toString(){return this.kind}};e.ParameterStructures=a,a.auto=new a("auto"),a.byPosition=new a("byPosition"),a.byName=new a("byName");var s=class{static{i(this,"AbstractMessageSignature")}constructor(y,E){this.method=y,this.numberOfParams=E}get parameterStructures(){return a.auto}};e.AbstractMessageSignature=s;var o=class extends s{static{i(this,"RequestType0")}constructor(y){super(y,0)}};e.RequestType0=o;var l=class extends s{static{i(this,"RequestType")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.RequestType=l;var u=class extends s{static{i(this,"RequestType1")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.RequestType1=u;var c=class extends s{static{i(this,"RequestType2")}constructor(y){super(y,2)}};e.RequestType2=c;var f=class extends s{static{i(this,"RequestType3")}constructor(y){super(y,3)}};e.RequestType3=f;var d=class extends s{static{i(this,"RequestType4")}constructor(y){super(y,4)}};e.RequestType4=d;var m=class extends s{static{i(this,"RequestType5")}constructor(y){super(y,5)}};e.RequestType5=m;var g=class extends s{static{i(this,"RequestType6")}constructor(y){super(y,6)}};e.RequestType6=g;var v=class extends s{static{i(this,"RequestType7")}constructor(y){super(y,7)}};e.RequestType7=v;var b=class extends s{static{i(this,"RequestType8")}constructor(y){super(y,8)}};e.RequestType8=b;var S=class extends s{static{i(this,"RequestType9")}constructor(y){super(y,9)}};e.RequestType9=S;var w=class extends s{static{i(this,"NotificationType")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.NotificationType=w;var I=class extends s{static{i(this,"NotificationType0")}constructor(y){super(y,0)}};e.NotificationType0=I;var R=class extends s{static{i(this,"NotificationType1")}constructor(y,E=a.auto){super(y,1),this._parameterStructures=E}get parameterStructures(){return this._parameterStructures}};e.NotificationType1=R;var P=class extends s{static{i(this,"NotificationType2")}constructor(y){super(y,2)}};e.NotificationType2=P;var z=class extends s{static{i(this,"NotificationType3")}constructor(y){super(y,3)}};e.NotificationType3=z;var X=class extends s{static{i(this,"NotificationType4")}constructor(y){super(y,4)}};e.NotificationType4=X;var Z=class extends s{static{i(this,"NotificationType5")}constructor(y){super(y,5)}};e.NotificationType5=Z;var ce=class extends s{static{i(this,"NotificationType6")}constructor(y){super(y,6)}};e.NotificationType6=ce;var se=class extends s{static{i(this,"NotificationType7")}constructor(y){super(y,7)}};e.NotificationType7=se;var Se=class extends s{static{i(this,"NotificationType8")}constructor(y){super(y,8)}};e.NotificationType8=Se;var k=class extends s{static{i(this,"NotificationType9")}constructor(y){super(y,9)}};e.NotificationType9=k;var C;(function(y){function E(_){const O=_;return O&&t.string(O.method)&&(t.string(O.id)||t.number(O.id))}i(E,"isRequest"),y.isRequest=E;function T(_){const O=_;return O&&t.string(O.method)&&_.id===void 0}i(T,"isNotification"),y.isNotification=T;function $(_){const O=_;return O&&(O.result!==void 0||!!O.error)&&(t.string(O.id)||t.number(O.id)||O.id===null)}i($,"isResponse"),y.isResponse=$})(C||(e.Message=C={}))}}),Kg=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/linkedMap.js"(e){var t;Object.defineProperty(e,"__esModule",{value:!0}),e.LRUCache=e.LinkedMap=e.Touch=void 0;var r;(function(s){s.None=0,s.First=1,s.AsOld=s.First,s.Last=2,s.AsNew=s.Last})(r||(e.Touch=r={}));var n=class{static{i(this,"LinkedMap")}constructor(){this[t]="LinkedMap",this._map=new Map,this._head=void 0,this._tail=void 0,this._size=0,this._state=0}clear(){this._map.clear(),this._head=void 0,this._tail=void 0,this._size=0,this._state++}isEmpty(){return!this._head&&!this._tail}get size(){return this._size}get first(){return this._head?.value}get last(){return this._tail?.value}has(s){return this._map.has(s)}get(s,o=r.None){const l=this._map.get(s);if(l)return o!==r.None&&this.touch(l,o),l.value}set(s,o,l=r.None){let u=this._map.get(s);if(u)u.value=o,l!==r.None&&this.touch(u,l);else{switch(u={key:s,value:o,next:void 0,previous:void 0},l){case r.None:this.addItemLast(u);break;case r.First:this.addItemFirst(u);break;case r.Last:this.addItemLast(u);break;default:this.addItemLast(u);break}this._map.set(s,u),this._size++}return this}delete(s){return!!this.remove(s)}remove(s){const o=this._map.get(s);if(o)return this._map.delete(s),this.removeItem(o),this._size--,o.value}shift(){if(!this._head&&!this._tail)return;if(!this._head||!this._tail)throw new Error("Invalid list");const s=this._head;return this._map.delete(s.key),this.removeItem(s),this._size--,s.value}forEach(s,o){const l=this._state;let u=this._head;for(;u;){if(o?s.bind(o)(u.value,u.key,this):s(u.value,u.key,this),this._state!==l)throw new Error("LinkedMap got modified during iteration.");u=u.next}}keys(){const s=this._state;let o=this._head;const l={[Symbol.iterator]:()=>l,next:i(()=>{if(this._state!==s)throw new Error("LinkedMap got modified during iteration.");if(o){const u={value:o.key,done:!1};return o=o.next,u}else return{value:void 0,done:!0}},"next")};return l}values(){const s=this._state;let o=this._head;const l={[Symbol.iterator]:()=>l,next:i(()=>{if(this._state!==s)throw new Error("LinkedMap got modified during iteration.");if(o){const u={value:o.value,done:!1};return o=o.next,u}else return{value:void 0,done:!0}},"next")};return l}entries(){const s=this._state;let o=this._head;const l={[Symbol.iterator]:()=>l,next:i(()=>{if(this._state!==s)throw new Error("LinkedMap got modified during iteration.");if(o){const u={value:[o.key,o.value],done:!1};return o=o.next,u}else return{value:void 0,done:!0}},"next")};return l}[(t=Symbol.toStringTag,Symbol.iterator)](){return this.entries()}trimOld(s){if(s>=this.size)return;if(s===0){this.clear();return}let o=this._head,l=this.size;for(;o&&l>s;)this._map.delete(o.key),o=o.next,l--;this._head=o,this._size=l,o&&(o.previous=void 0),this._state++}addItemFirst(s){if(!this._head&&!this._tail)this._tail=s;else if(this._head)s.next=this._head,this._head.previous=s;else throw new Error("Invalid list");this._head=s,this._state++}addItemLast(s){if(!this._head&&!this._tail)this._head=s;else if(this._tail)s.previous=this._tail,this._tail.next=s;else throw new Error("Invalid list");this._tail=s,this._state++}removeItem(s){if(s===this._head&&s===this._tail)this._head=void 0,this._tail=void 0;else if(s===this._head){if(!s.next)throw new Error("Invalid list");s.next.previous=void 0,this._head=s.next}else if(s===this._tail){if(!s.previous)throw new Error("Invalid list");s.previous.next=void 0,this._tail=s.previous}else{const o=s.next,l=s.previous;if(!o||!l)throw new Error("Invalid list");o.previous=l,l.next=o}s.next=void 0,s.previous=void 0,this._state++}touch(s,o){if(!this._head||!this._tail)throw new Error("Invalid list");if(!(o!==r.First&&o!==r.Last)){if(o===r.First){if(s===this._head)return;const l=s.next,u=s.previous;s===this._tail?(u.next=void 0,this._tail=u):(l.previous=u,u.next=l),s.previous=void 0,s.next=this._head,this._head.previous=s,this._head=s,this._state++}else if(o===r.Last){if(s===this._tail)return;const l=s.next,u=s.previous;s===this._head?(l.previous=void 0,this._head=l):(l.previous=u,u.next=l),s.next=void 0,s.previous=this._tail,this._tail.next=s,this._tail=s,this._state++}}}toJSON(){const s=[];return this.forEach((o,l)=>{s.push([l,o])}),s}fromJSON(s){this.clear();for(const[o,l]of s)this.set(o,l)}};e.LinkedMap=n;var a=class extends n{static{i(this,"LRUCache")}constructor(s,o=1){super(),this._limit=s,this._ratio=Math.min(Math.max(0,o),1)}get limit(){return this._limit}set limit(s){this._limit=s,this.checkTrim()}get ratio(){return this._ratio}set ratio(s){this._ratio=Math.min(Math.max(0,s),1),this.checkTrim()}get(s,o=r.AsNew){return super.get(s,o)}peek(s){return super.get(s,r.None)}set(s,o){return super.set(s,o,r.Last),this.checkTrim(),this}checkTrim(){this.size>this._limit&&this.trimOld(Math.round(this._limit*this._ratio))}};e.LRUCache=a}}),_I=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/disposable.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Disposable=void 0;var t;(function(r){function n(a){return{dispose:a}}i(n,"create"),r.create=n})(t||(e.Disposable=t={}))}}),SI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/sharedArrayCancellation.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.SharedArrayReceiverStrategy=e.SharedArraySenderStrategy=void 0;var t=xl(),r;(function(l){l.Continue=0,l.Cancelled=1})(r||(r={}));var n=class{static{i(this,"SharedArraySenderStrategy")}constructor(){this.buffers=new Map}enableCancellation(l){if(l.id===null)return;const u=new SharedArrayBuffer(4),c=new Int32Array(u,0,1);c[0]=r.Continue,this.buffers.set(l.id,u),l.$cancellationData=u}async sendCancellation(l,u){const c=this.buffers.get(u);if(c===void 0)return;const f=new Int32Array(c,0,1);Atomics.store(f,0,r.Cancelled)}cleanup(l){this.buffers.delete(l)}dispose(){this.buffers.clear()}};e.SharedArraySenderStrategy=n;var a=class{static{i(this,"SharedArrayBufferCancellationToken")}constructor(l){this.data=new Int32Array(l,0,1)}get isCancellationRequested(){return Atomics.load(this.data,0)===r.Cancelled}get onCancellationRequested(){throw new Error("Cancellation over SharedArrayBuffer doesn't support cancellation events")}},s=class{static{i(this,"SharedArrayBufferCancellationTokenSource")}constructor(l){this.token=new a(l)}cancel(){}dispose(){}},o=class{static{i(this,"SharedArrayReceiverStrategy")}constructor(){this.kind="request"}createCancellationTokenSource(l){const u=l.$cancellationData;return u===void 0?new t.CancellationTokenSource:new s(u)}};e.SharedArrayReceiverStrategy=o}}),Wg=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/semaphore.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.Semaphore=void 0;var t=Dn(),r=class{static{i(this,"Semaphore")}constructor(n=1){if(n<=0)throw new Error("Capacity must be greater than 0");this._capacity=n,this._active=0,this._waiting=[]}lock(n){return new Promise((a,s)=>{this._waiting.push({thunk:n,resolve:a,reject:s}),this.runNext()})}get active(){return this._active}runNext(){this._waiting.length===0||this._active===this._capacity||(0,t.default)().timer.setImmediate(()=>this.doRunNext())}doRunNext(){if(this._waiting.length===0||this._active===this._capacity)return;const n=this._waiting.shift();if(this._active++,this._active>this._capacity)throw new Error("To many thunks active");try{const a=n.thunk();a instanceof Promise?a.then(s=>{this._active--,n.resolve(s),this.runNext()},s=>{this._active--,n.reject(s),this.runNext()}):(this._active--,n.resolve(a),this.runNext())}catch(a){this._active--,n.reject(a),this.runNext()}}};e.Semaphore=r}}),wI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messageReader.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ReadableStreamMessageReader=e.AbstractMessageReader=e.MessageReader=void 0;var t=Dn(),r=Ms(),n=ei(),a=Wg(),s;(function(c){function f(d){let m=d;return m&&r.func(m.listen)&&r.func(m.dispose)&&r.func(m.onError)&&r.func(m.onClose)&&r.func(m.onPartialMessage)}i(f,"is"),c.is=f})(s||(e.MessageReader=s={}));var o=class{static{i(this,"AbstractMessageReader")}constructor(){this.errorEmitter=new n.Emitter,this.closeEmitter=new n.Emitter,this.partialMessageEmitter=new n.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(c){this.errorEmitter.fire(this.asError(c))}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}get onPartialMessage(){return this.partialMessageEmitter.event}firePartialMessage(c){this.partialMessageEmitter.fire(c)}asError(c){return c instanceof Error?c:new Error(`Reader received error. Reason: ${r.string(c.message)?c.message:"unknown"}`)}};e.AbstractMessageReader=o;var l;(function(c){function f(d){let m,g;const v=new Map;let b;const S=new Map;if(d===void 0||typeof d=="string")m=d??"utf-8";else{if(m=d.charset??"utf-8",d.contentDecoder!==void 0&&(g=d.contentDecoder,v.set(g.name,g)),d.contentDecoders!==void 0)for(const w of d.contentDecoders)v.set(w.name,w);if(d.contentTypeDecoder!==void 0&&(b=d.contentTypeDecoder,S.set(b.name,b)),d.contentTypeDecoders!==void 0)for(const w of d.contentTypeDecoders)S.set(w.name,w)}return b===void 0&&(b=(0,t.default)().applicationJson.decoder,S.set(b.name,b)),{charset:m,contentDecoder:g,contentDecoders:v,contentTypeDecoder:b,contentTypeDecoders:S}}i(f,"fromOptions"),c.fromOptions=f})(l||(l={}));var u=class extends o{static{i(this,"ReadableStreamMessageReader")}constructor(c,f){super(),this.readable=c,this.options=l.fromOptions(f),this.buffer=(0,t.default)().messageBuffer.create(this.options.charset),this._partialMessageTimeout=1e4,this.nextMessageLength=-1,this.messageToken=0,this.readSemaphore=new a.Semaphore(1)}set partialMessageTimeout(c){this._partialMessageTimeout=c}get partialMessageTimeout(){return this._partialMessageTimeout}listen(c){this.nextMessageLength=-1,this.messageToken=0,this.partialMessageTimer=void 0,this.callback=c;const f=this.readable.onData(d=>{this.onData(d)});return this.readable.onError(d=>this.fireError(d)),this.readable.onClose(()=>this.fireClose()),f}onData(c){try{for(this.buffer.append(c);;){if(this.nextMessageLength===-1){const d=this.buffer.tryReadHeaders(!0);if(!d)return;const m=d.get("content-length");if(!m){this.fireError(new Error(`Header must provide a Content-Length property. +${JSON.stringify(Object.fromEntries(d))}`));return}const g=parseInt(m);if(isNaN(g)){this.fireError(new Error(`Content-Length value must be a number. Got ${m}`));return}this.nextMessageLength=g}const f=this.buffer.tryReadBody(this.nextMessageLength);if(f===void 0){this.setPartialMessageTimer();return}this.clearPartialMessageTimer(),this.nextMessageLength=-1,this.readSemaphore.lock(async()=>{const d=this.options.contentDecoder!==void 0?await this.options.contentDecoder.decode(f):f,m=await this.options.contentTypeDecoder.decode(d,this.options);this.callback(m)}).catch(d=>{this.fireError(d)})}}catch(f){this.fireError(f)}}clearPartialMessageTimer(){this.partialMessageTimer&&(this.partialMessageTimer.dispose(),this.partialMessageTimer=void 0)}setPartialMessageTimer(){this.clearPartialMessageTimer(),!(this._partialMessageTimeout<=0)&&(this.partialMessageTimer=(0,t.default)().timer.setTimeout((c,f)=>{this.partialMessageTimer=void 0,c===this.messageToken&&(this.firePartialMessage({messageToken:c,waitingTime:f}),this.setPartialMessageTimer())},this._partialMessageTimeout,this.messageToken,this._partialMessageTimeout))}};e.ReadableStreamMessageReader=u}}),II=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messageWriter.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.WriteableStreamMessageWriter=e.AbstractMessageWriter=e.MessageWriter=void 0;var t=Dn(),r=Ms(),n=Wg(),a=ei(),s="Content-Length: ",o=`\r +`,l;(function(d){function m(g){let v=g;return v&&r.func(v.dispose)&&r.func(v.onClose)&&r.func(v.onError)&&r.func(v.write)}i(m,"is"),d.is=m})(l||(e.MessageWriter=l={}));var u=class{static{i(this,"AbstractMessageWriter")}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(d,m,g){this.errorEmitter.fire([this.asError(d),m,g])}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}asError(d){return d instanceof Error?d:new Error(`Writer received error. Reason: ${r.string(d.message)?d.message:"unknown"}`)}};e.AbstractMessageWriter=u;var c;(function(d){function m(g){return g===void 0||typeof g=="string"?{charset:g??"utf-8",contentTypeEncoder:(0,t.default)().applicationJson.encoder}:{charset:g.charset??"utf-8",contentEncoder:g.contentEncoder,contentTypeEncoder:g.contentTypeEncoder??(0,t.default)().applicationJson.encoder}}i(m,"fromOptions"),d.fromOptions=m})(c||(c={}));var f=class extends u{static{i(this,"WriteableStreamMessageWriter")}constructor(d,m){super(),this.writable=d,this.options=c.fromOptions(m),this.errorCount=0,this.writeSemaphore=new n.Semaphore(1),this.writable.onError(g=>this.fireError(g)),this.writable.onClose(()=>this.fireClose())}async write(d){return this.writeSemaphore.lock(async()=>this.options.contentTypeEncoder.encode(d,this.options).then(g=>this.options.contentEncoder!==void 0?this.options.contentEncoder.encode(g):g).then(g=>{const v=[];return v.push(s,g.byteLength.toString(),o),v.push(o),this.doWrite(d,v,g)},g=>{throw this.fireError(g),g}))}async doWrite(d,m,g){try{return await this.writable.write(m.join(""),"ascii"),this.writable.write(g)}catch(v){return this.handleError(v,d),Promise.reject(v)}}handleError(d,m){this.errorCount++,this.fireError(d,m,this.errorCount)}end(){this.writable.end()}};e.WriteableStreamMessageWriter=f}}),NI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/messageBuffer.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.AbstractMessageBuffer=void 0;var t=13,r=10,n=`\r +`,a=class{static{i(this,"AbstractMessageBuffer")}constructor(s="utf-8"){this._encoding=s,this._chunks=[],this._totalLength=0}get encoding(){return this._encoding}append(s){const o=typeof s=="string"?this.fromString(s,this._encoding):s;this._chunks.push(o),this._totalLength+=o.byteLength}tryReadHeaders(s=!1){if(this._chunks.length===0)return;let o=0,l=0,u=0,c=0;e:for(;lthis._totalLength)throw new Error("Cannot read so many bytes!");if(this._chunks[0].byteLength===s){const c=this._chunks[0];return this._chunks.shift(),this._totalLength-=s,this.asNative(c)}if(this._chunks[0].byteLength>s){const c=this._chunks[0],f=this.asNative(c,s);return this._chunks[0]=c.slice(s),this._totalLength-=s,f}const o=this.allocNative(s);let l=0,u=0;for(;s>0;){const c=this._chunks[u];if(c.byteLength>s){const f=c.slice(0,s);o.set(f,l),l+=s,this._chunks[u]=c.slice(s),this._totalLength-=s,s-=s}else o.set(c,l),l+=c.byteLength,this._chunks.shift(),this._totalLength-=c.byteLength,s-=c.byteLength}return o}};e.AbstractMessageBuffer=a}}),PI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/connection.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.createMessageConnection=e.ConnectionOptions=e.MessageStrategy=e.CancellationStrategy=e.CancellationSenderStrategy=e.CancellationReceiverStrategy=e.RequestCancellationReceiverStrategy=e.IdCancellationReceiverStrategy=e.ConnectionStrategy=e.ConnectionError=e.ConnectionErrors=e.LogTraceNotification=e.SetTraceNotification=e.TraceFormat=e.TraceValues=e.Trace=e.NullLogger=e.ProgressType=e.ProgressToken=void 0;var t=Dn(),r=Ms(),n=Bg(),a=Kg(),s=ei(),o=xl(),l;(function(y){y.type=new n.NotificationType("$/cancelRequest")})(l||(l={}));var u;(function(y){function E(T){return typeof T=="string"||typeof T=="number"}i(E,"is"),y.is=E})(u||(e.ProgressToken=u={}));var c;(function(y){y.type=new n.NotificationType("$/progress")})(c||(c={}));var f=class{static{i(this,"ProgressType")}constructor(){}};e.ProgressType=f;var d;(function(y){function E(T){return r.func(T)}i(E,"is"),y.is=E})(d||(d={})),e.NullLogger=Object.freeze({error:i(()=>{},"error"),warn:i(()=>{},"warn"),info:i(()=>{},"info"),log:i(()=>{},"log")});var m;(function(y){y[y.Off=0]="Off",y[y.Messages=1]="Messages",y[y.Compact=2]="Compact",y[y.Verbose=3]="Verbose"})(m||(e.Trace=m={}));var g;(function(y){y.Off="off",y.Messages="messages",y.Compact="compact",y.Verbose="verbose"})(g||(e.TraceValues=g={})),(function(y){function E($){if(!r.string($))return y.Off;switch($=$.toLowerCase(),$){case"off":return y.Off;case"messages":return y.Messages;case"compact":return y.Compact;case"verbose":return y.Verbose;default:return y.Off}}i(E,"fromString"),y.fromString=E;function T($){switch($){case y.Off:return"off";case y.Messages:return"messages";case y.Compact:return"compact";case y.Verbose:return"verbose";default:return"off"}}i(T,"toString"),y.toString=T})(m||(e.Trace=m={}));var v;(function(y){y.Text="text",y.JSON="json"})(v||(e.TraceFormat=v={})),(function(y){function E(T){return r.string(T)?(T=T.toLowerCase(),T==="json"?y.JSON:y.Text):y.Text}i(E,"fromString"),y.fromString=E})(v||(e.TraceFormat=v={}));var b;(function(y){y.type=new n.NotificationType("$/setTrace")})(b||(e.SetTraceNotification=b={}));var S;(function(y){y.type=new n.NotificationType("$/logTrace")})(S||(e.LogTraceNotification=S={}));var w;(function(y){y[y.Closed=1]="Closed",y[y.Disposed=2]="Disposed",y[y.AlreadyListening=3]="AlreadyListening"})(w||(e.ConnectionErrors=w={}));var I=class Vg extends Error{static{i(this,"ConnectionError")}constructor(E,T){super(T),this.code=E,Object.setPrototypeOf(this,Vg.prototype)}};e.ConnectionError=I;var R;(function(y){function E(T){const $=T;return $&&r.func($.cancelUndispatched)}i(E,"is"),y.is=E})(R||(e.ConnectionStrategy=R={}));var P;(function(y){function E(T){const $=T;return $&&($.kind===void 0||$.kind==="id")&&r.func($.createCancellationTokenSource)&&($.dispose===void 0||r.func($.dispose))}i(E,"is"),y.is=E})(P||(e.IdCancellationReceiverStrategy=P={}));var z;(function(y){function E(T){const $=T;return $&&$.kind==="request"&&r.func($.createCancellationTokenSource)&&($.dispose===void 0||r.func($.dispose))}i(E,"is"),y.is=E})(z||(e.RequestCancellationReceiverStrategy=z={}));var X;(function(y){y.Message=Object.freeze({createCancellationTokenSource(T){return new o.CancellationTokenSource}});function E(T){return P.is(T)||z.is(T)}i(E,"is"),y.is=E})(X||(e.CancellationReceiverStrategy=X={}));var Z;(function(y){y.Message=Object.freeze({sendCancellation(T,$){return T.sendNotification(l.type,{id:$})},cleanup(T){}});function E(T){const $=T;return $&&r.func($.sendCancellation)&&r.func($.cleanup)}i(E,"is"),y.is=E})(Z||(e.CancellationSenderStrategy=Z={}));var ce;(function(y){y.Message=Object.freeze({receiver:X.Message,sender:Z.Message});function E(T){const $=T;return $&&X.is($.receiver)&&Z.is($.sender)}i(E,"is"),y.is=E})(ce||(e.CancellationStrategy=ce={}));var se;(function(y){function E(T){const $=T;return $&&r.func($.handleMessage)}i(E,"is"),y.is=E})(se||(e.MessageStrategy=se={}));var Se;(function(y){function E(T){const $=T;return $&&(ce.is($.cancellationStrategy)||R.is($.connectionStrategy)||se.is($.messageStrategy))}i(E,"is"),y.is=E})(Se||(e.ConnectionOptions=Se={}));var k;(function(y){y[y.New=1]="New",y[y.Listening=2]="Listening",y[y.Closed=3]="Closed",y[y.Disposed=4]="Disposed"})(k||(k={}));function C(y,E,T,$){const _=T!==void 0?T:e.NullLogger;let O=0,x=0,D=0;const G="2.0";let W;const Y=new Map;let V;const Pe=new Map,oe=new Map;let Le,De=new a.LinkedMap,ke=new Map,Ze=new Set,Je=new Map,ne=m.Off,Kt=v.Text,Ee,kt=k.New;const ra=new s.Emitter,fi=new s.Emitter,di=new s.Emitter,pi=new s.Emitter,mi=new s.Emitter,Ot=$&&$.cancellationStrategy?$.cancellationStrategy:ce.Message;function na(h){if(h===null)throw new Error("Can't send requests with id null since the response can't be correlated.");return"req-"+h.toString()}i(na,"createRequestQueueKey");function hi(h){return h===null?"res-unknown-"+(++D).toString():"res-"+h.toString()}i(hi,"createResponseQueueKey");function yi(){return"not-"+(++x).toString()}i(yi,"createNotificationQueueKey");function gi(h,N){n.Message.isRequest(N)?h.set(na(N.id),N):n.Message.isResponse(N)?h.set(hi(N.id),N):h.set(yi(),N)}i(gi,"addMessageToQueue");function vi(h){}i(vi,"cancelUndispatched");function aa(){return kt===k.Listening}i(aa,"isListening");function ia(){return kt===k.Closed}i(ia,"isClosed");function Wt(){return kt===k.Disposed}i(Wt,"isDisposed");function sa(){(kt===k.New||kt===k.Listening)&&(kt=k.Closed,fi.fire(void 0))}i(sa,"closeHandler");function Ti(h){ra.fire([h,void 0,void 0])}i(Ti,"readErrorHandler");function $i(h){ra.fire(h)}i($i,"writeErrorHandler"),y.onClose(sa),y.onError(Ti),E.onClose(sa),E.onError($i);function oa(){Le||De.size===0||(Le=(0,t.default)().timer.setImmediate(()=>{Le=void 0,Ri()}))}i(oa,"triggerMessageQueue");function la(h){n.Message.isRequest(h)?Ai(h):n.Message.isNotification(h)?Ci(h):n.Message.isResponse(h)?Ei(h):bi(h)}i(la,"handleMessage");function Ri(){if(De.size===0)return;const h=De.shift();try{const N=$?.messageStrategy;se.is(N)?N.handleMessage(h,la):la(h)}finally{oa()}}i(Ri,"processMessageQueue");const no=i(h=>{try{if(n.Message.isNotification(h)&&h.method===l.type.method){const N=h.params.id,L=na(N),M=De.get(L);if(n.Message.isRequest(M)){const fe=$?.connectionStrategy,Ce=fe&&fe.cancelUndispatched?fe.cancelUndispatched(M,vi):void 0;if(Ce&&(Ce.error!==void 0||Ce.result!==void 0)){De.delete(L),Je.delete(N),Ce.id=M.id,Lr(Ce,h.method,Date.now()),E.write(Ce).catch(()=>_.error("Sending response for canceled message failed."));return}}const he=Je.get(N);if(he!==void 0){he.cancel(),Jr(h);return}else Ze.add(N)}gi(De,h)}finally{oa()}},"callback");function Ai(h){if(Wt())return;function N(te,$e,le){const xe={jsonrpc:G,id:h.id};te instanceof n.ResponseError?xe.error=te.toJson():xe.result=te===void 0?null:te,Lr(xe,$e,le),E.write(xe).catch(()=>_.error("Sending response failed."))}i(N,"reply");function L(te,$e,le){const xe={jsonrpc:G,id:h.id,error:te.toJson()};Lr(xe,$e,le),E.write(xe).catch(()=>_.error("Sending response failed."))}i(L,"replyError");function M(te,$e,le){te===void 0&&(te=null);const xe={jsonrpc:G,id:h.id,result:te};Lr(xe,$e,le),E.write(xe).catch(()=>_.error("Sending response failed."))}i(M,"replySuccess"),wi(h);const he=Y.get(h.method);let fe,Ce;he&&(fe=he.type,Ce=he.handler);const we=Date.now();if(Ce||W){const te=h.id??String(Date.now()),$e=P.is(Ot.receiver)?Ot.receiver.createCancellationTokenSource(te):Ot.receiver.createCancellationTokenSource(h);h.id!==null&&Ze.has(h.id)&&$e.cancel(),h.id!==null&&Je.set(te,$e);try{let le;if(Ce)if(h.params===void 0){if(fe!==void 0&&fe.numberOfParams!==0){L(new n.ResponseError(n.ErrorCodes.InvalidParams,`Request ${h.method} defines ${fe.numberOfParams} params but received none.`),h.method,we);return}le=Ce($e.token)}else if(Array.isArray(h.params)){if(fe!==void 0&&fe.parameterStructures===n.ParameterStructures.byName){L(new n.ResponseError(n.ErrorCodes.InvalidParams,`Request ${h.method} defines parameters by name but received parameters by position`),h.method,we);return}le=Ce(...h.params,$e.token)}else{if(fe!==void 0&&fe.parameterStructures===n.ParameterStructures.byPosition){L(new n.ResponseError(n.ErrorCodes.InvalidParams,`Request ${h.method} defines parameters by position but received parameters by name`),h.method,we);return}le=Ce(h.params,$e.token)}else W&&(le=W(h.method,h.params,$e.token));const xe=le;le?xe.then?xe.then(Qe=>{Je.delete(te),N(Qe,h.method,we)},Qe=>{Je.delete(te),Qe instanceof n.ResponseError?L(Qe,h.method,we):Qe&&r.string(Qe.message)?L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed with message: ${Qe.message}`),h.method,we):L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed unexpectedly without providing any details.`),h.method,we)}):(Je.delete(te),N(le,h.method,we)):(Je.delete(te),M(le,h.method,we))}catch(le){Je.delete(te),le instanceof n.ResponseError?N(le,h.method,we):le&&r.string(le.message)?L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed with message: ${le.message}`),h.method,we):L(new n.ResponseError(n.ErrorCodes.InternalError,`Request ${h.method} failed unexpectedly without providing any details.`),h.method,we)}}else L(new n.ResponseError(n.ErrorCodes.MethodNotFound,`Unhandled method ${h.method}`),h.method,we)}i(Ai,"handleRequest");function Ei(h){if(!Wt())if(h.id===null)h.error?_.error(`Received response message without id: Error is: +${JSON.stringify(h.error,void 0,4)}`):_.error("Received response message without id. No further error information provided.");else{const N=h.id,L=ke.get(N);if(Ii(h,L),L!==void 0){ke.delete(N);try{if(h.error){const M=h.error;L.reject(new n.ResponseError(M.code,M.message,M.data))}else if(h.result!==void 0)L.resolve(h.result);else throw new Error("Should never happen.")}catch(M){M.message?_.error(`Response handler '${L.method}' failed with message: ${M.message}`):_.error(`Response handler '${L.method}' failed unexpectedly.`)}}}}i(Ei,"handleResponse");function Ci(h){if(Wt())return;let N,L;if(h.method===l.type.method){const M=h.params.id;Ze.delete(M),Jr(h);return}else{const M=Pe.get(h.method);M&&(L=M.handler,N=M.type)}if(L||V)try{if(Jr(h),L)if(h.params===void 0)N!==void 0&&N.numberOfParams!==0&&N.parameterStructures!==n.ParameterStructures.byName&&_.error(`Notification ${h.method} defines ${N.numberOfParams} params but received none.`),L();else if(Array.isArray(h.params)){const M=h.params;h.method===c.type.method&&M.length===2&&u.is(M[0])?L({token:M[0],value:M[1]}):(N!==void 0&&(N.parameterStructures===n.ParameterStructures.byName&&_.error(`Notification ${h.method} defines parameters by name but received parameters by position`),N.numberOfParams!==h.params.length&&_.error(`Notification ${h.method} defines ${N.numberOfParams} params but received ${M.length} arguments`)),L(...M))}else N!==void 0&&N.parameterStructures===n.ParameterStructures.byPosition&&_.error(`Notification ${h.method} defines parameters by position but received parameters by name`),L(h.params);else V&&V(h.method,h.params)}catch(M){M.message?_.error(`Notification handler '${h.method}' failed with message: ${M.message}`):_.error(`Notification handler '${h.method}' failed unexpectedly.`)}else di.fire(h)}i(Ci,"handleNotification");function bi(h){if(!h){_.error("Received empty message.");return}_.error(`Received message which is neither a response nor a notification message: +${JSON.stringify(h,null,4)}`);const N=h;if(r.string(N.id)||r.number(N.id)){const L=N.id,M=ke.get(L);M&&M.reject(new Error("The received response has neither a result nor an error property."))}}i(bi,"handleInvalidMessage");function bt(h){if(h!=null)switch(ne){case m.Verbose:return JSON.stringify(h,null,4);case m.Compact:return JSON.stringify(h);default:return}}i(bt,"stringifyTrace");function _i(h){if(!(ne===m.Off||!Ee))if(Kt===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&h.params&&(N=`Params: ${bt(h.params)} + +`),Ee.log(`Sending request '${h.method} - (${h.id})'.`,N)}else Vt("send-request",h)}i(_i,"traceSendingRequest");function Si(h){if(!(ne===m.Off||!Ee))if(Kt===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&(h.params?N=`Params: ${bt(h.params)} + +`:N=`No parameters provided. + +`),Ee.log(`Sending notification '${h.method}'.`,N)}else Vt("send-notification",h)}i(Si,"traceSendingNotification");function Lr(h,N,L){if(!(ne===m.Off||!Ee))if(Kt===v.Text){let M;(ne===m.Verbose||ne===m.Compact)&&(h.error&&h.error.data?M=`Error data: ${bt(h.error.data)} + +`:h.result?M=`Result: ${bt(h.result)} + +`:h.error===void 0&&(M=`No result returned. + +`)),Ee.log(`Sending response '${N} - (${h.id})'. Processing request took ${Date.now()-L}ms`,M)}else Vt("send-response",h)}i(Lr,"traceSendingResponse");function wi(h){if(!(ne===m.Off||!Ee))if(Kt===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&h.params&&(N=`Params: ${bt(h.params)} + +`),Ee.log(`Received request '${h.method} - (${h.id})'.`,N)}else Vt("receive-request",h)}i(wi,"traceReceivedRequest");function Jr(h){if(!(ne===m.Off||!Ee||h.method===S.type.method))if(Kt===v.Text){let N;(ne===m.Verbose||ne===m.Compact)&&(h.params?N=`Params: ${bt(h.params)} + +`:N=`No parameters provided. + +`),Ee.log(`Received notification '${h.method}'.`,N)}else Vt("receive-notification",h)}i(Jr,"traceReceivedNotification");function Ii(h,N){if(!(ne===m.Off||!Ee))if(Kt===v.Text){let L;if((ne===m.Verbose||ne===m.Compact)&&(h.error&&h.error.data?L=`Error data: ${bt(h.error.data)} + +`:h.result?L=`Result: ${bt(h.result)} + +`:h.error===void 0&&(L=`No result returned. + +`)),N){const M=h.error?` Request failed: ${h.error.message} (${h.error.code}).`:"";Ee.log(`Received response '${N.method} - (${h.id})' in ${Date.now()-N.timerStart}ms.${M}`,L)}else Ee.log(`Received response ${h.id} without active response promise.`,L)}else Vt("receive-response",h)}i(Ii,"traceReceivedResponse");function Vt(h,N){if(!Ee||ne===m.Off)return;const L={isLSPMessage:!0,type:h,message:N,timestamp:Date.now()};Ee.log(L)}i(Vt,"logLSPMessage");function cr(){if(ia())throw new I(w.Closed,"Connection is closed.");if(Wt())throw new I(w.Disposed,"Connection is disposed.")}i(cr,"throwIfClosedOrDisposed");function Ni(){if(aa())throw new I(w.AlreadyListening,"Connection is already listening")}i(Ni,"throwIfListening");function Pi(){if(!aa())throw new Error("Call listen() first.")}i(Pi,"throwIfNotListening");function fr(h){return h===void 0?null:h}i(fr,"undefinedToNull");function ua(h){if(h!==null)return h}i(ua,"nullToUndefined");function p(h){return h!=null&&!Array.isArray(h)&&typeof h=="object"}i(p,"isNamedParam");function ae(h,N){switch(h){case n.ParameterStructures.auto:return p(N)?ua(N):[fr(N)];case n.ParameterStructures.byName:if(!p(N))throw new Error("Received parameters by name but param is not an object literal.");return ua(N);case n.ParameterStructures.byPosition:return[fr(N)];default:throw new Error(`Unknown parameter structure ${h.toString()}`)}}i(ae,"computeSingleParam");function Te(h,N){let L;const M=h.numberOfParams;switch(M){case 0:L=void 0;break;case 1:L=ae(h.parameterStructures,N[0]);break;default:L=[];for(let he=0;he{cr();let L,M;if(r.string(h)){L=h;const fe=N[0];let Ce=0,we=n.ParameterStructures.auto;n.ParameterStructures.is(fe)&&(Ce=1,we=fe);let te=N.length;const $e=te-Ce;switch($e){case 0:M=void 0;break;case 1:M=ae(we,N[Ce]);break;default:if(we===n.ParameterStructures.byName)throw new Error(`Received ${$e} parameters for 'by Name' notification parameter structure.`);M=N.slice(Ce,te).map(le=>fr(le));break}}else{const fe=N;L=h.method,M=Te(h,fe)}const he={jsonrpc:G,method:L,params:M};return Si(he),E.write(he).catch(fe=>{throw _.error("Sending notification failed."),fe})},"sendNotification"),onNotification:i((h,N)=>{cr();let L;return r.func(h)?V=h:N&&(r.string(h)?(L=h,Pe.set(h,{type:void 0,handler:N})):(L=h.method,Pe.set(h.method,{type:h,handler:N}))),{dispose:i(()=>{L!==void 0?Pe.delete(L):V=void 0},"dispose")}},"onNotification"),onProgress:i((h,N,L)=>{if(oe.has(N))throw new Error(`Progress handler for token ${N} already registered`);return oe.set(N,L),{dispose:i(()=>{oe.delete(N)},"dispose")}},"onProgress"),sendProgress:i((h,N,L)=>q.sendNotification(c.type,{token:N,value:L}),"sendProgress"),onUnhandledProgress:pi.event,sendRequest:i((h,...N)=>{cr(),Pi();let L,M,he;if(r.string(h)){L=h;const te=N[0],$e=N[N.length-1];let le=0,xe=n.ParameterStructures.auto;n.ParameterStructures.is(te)&&(le=1,xe=te);let Qe=N.length;o.CancellationToken.is($e)&&(Qe=Qe-1,he=$e);const qt=Qe-le;switch(qt){case 0:M=void 0;break;case 1:M=ae(xe,N[le]);break;default:if(xe===n.ParameterStructures.byName)throw new Error(`Received ${qt} parameters for 'by Name' request parameter structure.`);M=N.slice(le,Qe).map($I=>fr($I));break}}else{const te=N;L=h.method,M=Te(h,te);const $e=h.numberOfParams;he=o.CancellationToken.is(te[$e])?te[$e]:void 0}const fe=O++;let Ce;he&&(Ce=he.onCancellationRequested(()=>{const te=Ot.sender.sendCancellation(q,fe);return te===void 0?(_.log(`Received no promise from cancellation strategy when cancelling id ${fe}`),Promise.resolve()):te.catch(()=>{_.log(`Sending cancellation messages for id ${fe} failed`)})}));const we={jsonrpc:G,id:fe,method:L,params:M};return _i(we),typeof Ot.sender.enableCancellation=="function"&&Ot.sender.enableCancellation(we),new Promise(async(te,$e)=>{const le=i(qt=>{te(qt),Ot.sender.cleanup(fe),Ce?.dispose()},"resolveWithCleanup"),xe=i(qt=>{$e(qt),Ot.sender.cleanup(fe),Ce?.dispose()},"rejectWithCleanup"),Qe={method:L,timerStart:Date.now(),resolve:le,reject:xe};try{await E.write(we),ke.set(fe,Qe)}catch(qt){throw _.error("Sending request failed."),Qe.reject(new n.ResponseError(n.ErrorCodes.MessageWriteError,qt.message?qt.message:"Unknown reason")),qt}})},"sendRequest"),onRequest:i((h,N)=>{cr();let L=null;return d.is(h)?(L=void 0,W=h):r.string(h)?(L=null,N!==void 0&&(L=h,Y.set(h,{handler:N,type:void 0}))):N!==void 0&&(L=h.method,Y.set(h.method,{type:h,handler:N})),{dispose:i(()=>{L!==null&&(L!==void 0?Y.delete(L):W=void 0)},"dispose")}},"onRequest"),hasPendingResponse:i(()=>ke.size>0,"hasPendingResponse"),trace:i(async(h,N,L)=>{let M=!1,he=v.Text;L!==void 0&&(r.boolean(L)?M=L:(M=L.sendNotification||!1,he=L.traceFormat||v.Text)),ne=h,Kt=he,ne===m.Off?Ee=void 0:Ee=N,M&&!ia()&&!Wt()&&await q.sendNotification(b.type,{value:m.toString(h)})},"trace"),onError:ra.event,onClose:fi.event,onUnhandledNotification:di.event,onDispose:mi.event,end:i(()=>{E.end()},"end"),dispose:i(()=>{if(Wt())return;kt=k.Disposed,mi.fire(void 0);const h=new n.ResponseError(n.ErrorCodes.PendingResponseRejected,"Pending response rejected since connection got disposed");for(const N of ke.values())N.reject(h);ke=new Map,Je=new Map,Ze=new Set,De=new a.LinkedMap,r.func(E.dispose)&&E.dispose(),r.func(y.dispose)&&y.dispose()},"dispose"),listen:i(()=>{cr(),Ni(),kt=k.Listening,y.listen(no)},"listen"),inspect:i(()=>{(0,t.default)().console.log("inspect")},"inspect")};return q.onNotification(S.type,h=>{if(ne===m.Off||!Ee)return;const N=ne===m.Verbose||ne===m.Compact;Ee.log(h.message,N?h.verbose:void 0)}),q.onNotification(c.type,h=>{const N=oe.get(h.token);N?N(h.value):pi.fire(h)}),q}i(C,"createMessageConnection"),e.createMessageConnection=C}}),Af=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/common/api.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ProgressType=e.ProgressToken=e.createMessageConnection=e.NullLogger=e.ConnectionOptions=e.ConnectionStrategy=e.AbstractMessageBuffer=e.WriteableStreamMessageWriter=e.AbstractMessageWriter=e.MessageWriter=e.ReadableStreamMessageReader=e.AbstractMessageReader=e.MessageReader=e.SharedArrayReceiverStrategy=e.SharedArraySenderStrategy=e.CancellationToken=e.CancellationTokenSource=e.Emitter=e.Event=e.Disposable=e.LRUCache=e.Touch=e.LinkedMap=e.ParameterStructures=e.NotificationType9=e.NotificationType8=e.NotificationType7=e.NotificationType6=e.NotificationType5=e.NotificationType4=e.NotificationType3=e.NotificationType2=e.NotificationType1=e.NotificationType0=e.NotificationType=e.ErrorCodes=e.ResponseError=e.RequestType9=e.RequestType8=e.RequestType7=e.RequestType6=e.RequestType5=e.RequestType4=e.RequestType3=e.RequestType2=e.RequestType1=e.RequestType0=e.RequestType=e.Message=e.RAL=void 0,e.MessageStrategy=e.CancellationStrategy=e.CancellationSenderStrategy=e.CancellationReceiverStrategy=e.ConnectionError=e.ConnectionErrors=e.LogTraceNotification=e.SetTraceNotification=e.TraceFormat=e.TraceValues=e.Trace=void 0;var t=Bg();Object.defineProperty(e,"Message",{enumerable:!0,get:i(function(){return t.Message},"get")}),Object.defineProperty(e,"RequestType",{enumerable:!0,get:i(function(){return t.RequestType},"get")}),Object.defineProperty(e,"RequestType0",{enumerable:!0,get:i(function(){return t.RequestType0},"get")}),Object.defineProperty(e,"RequestType1",{enumerable:!0,get:i(function(){return t.RequestType1},"get")}),Object.defineProperty(e,"RequestType2",{enumerable:!0,get:i(function(){return t.RequestType2},"get")}),Object.defineProperty(e,"RequestType3",{enumerable:!0,get:i(function(){return t.RequestType3},"get")}),Object.defineProperty(e,"RequestType4",{enumerable:!0,get:i(function(){return t.RequestType4},"get")}),Object.defineProperty(e,"RequestType5",{enumerable:!0,get:i(function(){return t.RequestType5},"get")}),Object.defineProperty(e,"RequestType6",{enumerable:!0,get:i(function(){return t.RequestType6},"get")}),Object.defineProperty(e,"RequestType7",{enumerable:!0,get:i(function(){return t.RequestType7},"get")}),Object.defineProperty(e,"RequestType8",{enumerable:!0,get:i(function(){return t.RequestType8},"get")}),Object.defineProperty(e,"RequestType9",{enumerable:!0,get:i(function(){return t.RequestType9},"get")}),Object.defineProperty(e,"ResponseError",{enumerable:!0,get:i(function(){return t.ResponseError},"get")}),Object.defineProperty(e,"ErrorCodes",{enumerable:!0,get:i(function(){return t.ErrorCodes},"get")}),Object.defineProperty(e,"NotificationType",{enumerable:!0,get:i(function(){return t.NotificationType},"get")}),Object.defineProperty(e,"NotificationType0",{enumerable:!0,get:i(function(){return t.NotificationType0},"get")}),Object.defineProperty(e,"NotificationType1",{enumerable:!0,get:i(function(){return t.NotificationType1},"get")}),Object.defineProperty(e,"NotificationType2",{enumerable:!0,get:i(function(){return t.NotificationType2},"get")}),Object.defineProperty(e,"NotificationType3",{enumerable:!0,get:i(function(){return t.NotificationType3},"get")}),Object.defineProperty(e,"NotificationType4",{enumerable:!0,get:i(function(){return t.NotificationType4},"get")}),Object.defineProperty(e,"NotificationType5",{enumerable:!0,get:i(function(){return t.NotificationType5},"get")}),Object.defineProperty(e,"NotificationType6",{enumerable:!0,get:i(function(){return t.NotificationType6},"get")}),Object.defineProperty(e,"NotificationType7",{enumerable:!0,get:i(function(){return t.NotificationType7},"get")}),Object.defineProperty(e,"NotificationType8",{enumerable:!0,get:i(function(){return t.NotificationType8},"get")}),Object.defineProperty(e,"NotificationType9",{enumerable:!0,get:i(function(){return t.NotificationType9},"get")}),Object.defineProperty(e,"ParameterStructures",{enumerable:!0,get:i(function(){return t.ParameterStructures},"get")});var r=Kg();Object.defineProperty(e,"LinkedMap",{enumerable:!0,get:i(function(){return r.LinkedMap},"get")}),Object.defineProperty(e,"LRUCache",{enumerable:!0,get:i(function(){return r.LRUCache},"get")}),Object.defineProperty(e,"Touch",{enumerable:!0,get:i(function(){return r.Touch},"get")});var n=_I();Object.defineProperty(e,"Disposable",{enumerable:!0,get:i(function(){return n.Disposable},"get")});var a=ei();Object.defineProperty(e,"Event",{enumerable:!0,get:i(function(){return a.Event},"get")}),Object.defineProperty(e,"Emitter",{enumerable:!0,get:i(function(){return a.Emitter},"get")});var s=xl();Object.defineProperty(e,"CancellationTokenSource",{enumerable:!0,get:i(function(){return s.CancellationTokenSource},"get")}),Object.defineProperty(e,"CancellationToken",{enumerable:!0,get:i(function(){return s.CancellationToken},"get")});var o=SI();Object.defineProperty(e,"SharedArraySenderStrategy",{enumerable:!0,get:i(function(){return o.SharedArraySenderStrategy},"get")}),Object.defineProperty(e,"SharedArrayReceiverStrategy",{enumerable:!0,get:i(function(){return o.SharedArrayReceiverStrategy},"get")});var l=wI();Object.defineProperty(e,"MessageReader",{enumerable:!0,get:i(function(){return l.MessageReader},"get")}),Object.defineProperty(e,"AbstractMessageReader",{enumerable:!0,get:i(function(){return l.AbstractMessageReader},"get")}),Object.defineProperty(e,"ReadableStreamMessageReader",{enumerable:!0,get:i(function(){return l.ReadableStreamMessageReader},"get")});var u=II();Object.defineProperty(e,"MessageWriter",{enumerable:!0,get:i(function(){return u.MessageWriter},"get")}),Object.defineProperty(e,"AbstractMessageWriter",{enumerable:!0,get:i(function(){return u.AbstractMessageWriter},"get")}),Object.defineProperty(e,"WriteableStreamMessageWriter",{enumerable:!0,get:i(function(){return u.WriteableStreamMessageWriter},"get")});var c=NI();Object.defineProperty(e,"AbstractMessageBuffer",{enumerable:!0,get:i(function(){return c.AbstractMessageBuffer},"get")});var f=PI();Object.defineProperty(e,"ConnectionStrategy",{enumerable:!0,get:i(function(){return f.ConnectionStrategy},"get")}),Object.defineProperty(e,"ConnectionOptions",{enumerable:!0,get:i(function(){return f.ConnectionOptions},"get")}),Object.defineProperty(e,"NullLogger",{enumerable:!0,get:i(function(){return f.NullLogger},"get")}),Object.defineProperty(e,"createMessageConnection",{enumerable:!0,get:i(function(){return f.createMessageConnection},"get")}),Object.defineProperty(e,"ProgressToken",{enumerable:!0,get:i(function(){return f.ProgressToken},"get")}),Object.defineProperty(e,"ProgressType",{enumerable:!0,get:i(function(){return f.ProgressType},"get")}),Object.defineProperty(e,"Trace",{enumerable:!0,get:i(function(){return f.Trace},"get")}),Object.defineProperty(e,"TraceValues",{enumerable:!0,get:i(function(){return f.TraceValues},"get")}),Object.defineProperty(e,"TraceFormat",{enumerable:!0,get:i(function(){return f.TraceFormat},"get")}),Object.defineProperty(e,"SetTraceNotification",{enumerable:!0,get:i(function(){return f.SetTraceNotification},"get")}),Object.defineProperty(e,"LogTraceNotification",{enumerable:!0,get:i(function(){return f.LogTraceNotification},"get")}),Object.defineProperty(e,"ConnectionErrors",{enumerable:!0,get:i(function(){return f.ConnectionErrors},"get")}),Object.defineProperty(e,"ConnectionError",{enumerable:!0,get:i(function(){return f.ConnectionError},"get")}),Object.defineProperty(e,"CancellationReceiverStrategy",{enumerable:!0,get:i(function(){return f.CancellationReceiverStrategy},"get")}),Object.defineProperty(e,"CancellationSenderStrategy",{enumerable:!0,get:i(function(){return f.CancellationSenderStrategy},"get")}),Object.defineProperty(e,"CancellationStrategy",{enumerable:!0,get:i(function(){return f.CancellationStrategy},"get")}),Object.defineProperty(e,"MessageStrategy",{enumerable:!0,get:i(function(){return f.MessageStrategy},"get")});var d=Dn();e.RAL=d.default}}),kI=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/browser/ril.js"(e){Object.defineProperty(e,"__esModule",{value:!0});var t=Af(),r=class qg extends t.AbstractMessageBuffer{static{i(this,"MessageBuffer")}constructor(c="utf-8"){super(c),this.asciiDecoder=new TextDecoder("ascii")}emptyBuffer(){return qg.emptyBuffer}fromString(c,f){return new TextEncoder().encode(c)}toString(c,f){return f==="ascii"?this.asciiDecoder.decode(c):new TextDecoder(f).decode(c)}asNative(c,f){return f===void 0?c:c.slice(0,f)}allocNative(c){return new Uint8Array(c)}};r.emptyBuffer=new Uint8Array(0);var n=class{static{i(this,"ReadableStreamWrapper")}constructor(u){this.socket=u,this._onData=new t.Emitter,this._messageListener=c=>{c.data.arrayBuffer().then(d=>{this._onData.fire(new Uint8Array(d))},()=>{(0,t.RAL)().console.error("Converting blob to array buffer failed.")})},this.socket.addEventListener("message",this._messageListener)}onClose(u){return this.socket.addEventListener("close",u),t.Disposable.create(()=>this.socket.removeEventListener("close",u))}onError(u){return this.socket.addEventListener("error",u),t.Disposable.create(()=>this.socket.removeEventListener("error",u))}onEnd(u){return this.socket.addEventListener("end",u),t.Disposable.create(()=>this.socket.removeEventListener("end",u))}onData(u){return this._onData.event(u)}},a=class{static{i(this,"WritableStreamWrapper")}constructor(u){this.socket=u}onClose(u){return this.socket.addEventListener("close",u),t.Disposable.create(()=>this.socket.removeEventListener("close",u))}onError(u){return this.socket.addEventListener("error",u),t.Disposable.create(()=>this.socket.removeEventListener("error",u))}onEnd(u){return this.socket.addEventListener("end",u),t.Disposable.create(()=>this.socket.removeEventListener("end",u))}write(u,c){if(typeof u=="string"){if(c!==void 0&&c!=="utf-8")throw new Error(`In a Browser environments only utf-8 text encoding is supported. But got encoding: ${c}`);this.socket.send(u)}else this.socket.send(u);return Promise.resolve()}end(){this.socket.close()}},s=new TextEncoder,o=Object.freeze({messageBuffer:Object.freeze({create:i(u=>new r(u),"create")}),applicationJson:Object.freeze({encoder:Object.freeze({name:"application/json",encode:i((u,c)=>{if(c.charset!=="utf-8")throw new Error(`In a Browser environments only utf-8 text encoding is supported. But got encoding: ${c.charset}`);return Promise.resolve(s.encode(JSON.stringify(u,void 0,0)))},"encode")}),decoder:Object.freeze({name:"application/json",decode:i((u,c)=>{if(!(u instanceof Uint8Array))throw new Error("In a Browser environments only Uint8Arrays are supported.");return Promise.resolve(JSON.parse(new TextDecoder(c.charset).decode(u)))},"decode")})}),stream:Object.freeze({asReadableStream:i(u=>new n(u),"asReadableStream"),asWritableStream:i(u=>new a(u),"asWritableStream")}),console,timer:Object.freeze({setTimeout(u,c,...f){const d=setTimeout(u,c,...f);return{dispose:i(()=>clearTimeout(d),"dispose")}},setImmediate(u,...c){const f=setTimeout(u,0,...c);return{dispose:i(()=>clearTimeout(f),"dispose")}},setInterval(u,c,...f){const d=setInterval(u,c,...f);return{dispose:i(()=>clearInterval(d),"dispose")}}})});function l(){return o}i(l,"RIL"),(function(u){function c(){t.RAL.install(o)}i(c,"install"),u.install=c})(l||(l={})),e.default=l}}),ti=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/lib/browser/main.js"(e){var t=e&&e.__createBinding||(Object.create?(function(u,c,f,d){d===void 0&&(d=f);var m=Object.getOwnPropertyDescriptor(c,f);(!m||("get"in m?!c.__esModule:m.writable||m.configurable))&&(m={enumerable:!0,get:i(function(){return c[f]},"get")}),Object.defineProperty(u,d,m)}):(function(u,c,f,d){d===void 0&&(d=f),u[d]=c[f]})),r=e&&e.__exportStar||function(u,c){for(var f in u)f!=="default"&&!Object.prototype.hasOwnProperty.call(c,f)&&t(c,u,f)};Object.defineProperty(e,"__esModule",{value:!0}),e.createMessageConnection=e.BrowserMessageWriter=e.BrowserMessageReader=void 0;var n=kI();n.default.install();var a=Af();r(Af(),e);var s=class extends a.AbstractMessageReader{static{i(this,"BrowserMessageReader")}constructor(u){super(),this._onData=new a.Emitter,this._messageListener=c=>{this._onData.fire(c.data)},u.addEventListener("error",c=>this.fireError(c)),u.onmessage=this._messageListener}listen(u){return this._onData.event(u)}};e.BrowserMessageReader=s;var o=class extends a.AbstractMessageWriter{static{i(this,"BrowserMessageWriter")}constructor(u){super(),this.port=u,this.errorCount=0,u.addEventListener("error",c=>this.fireError(c))}write(u){try{return this.port.postMessage(u),Promise.resolve()}catch(c){return this.handleError(c,u),Promise.reject(c)}}handleError(u,c){this.errorCount++,this.fireError(u,c,this.errorCount)}end(){}};e.BrowserMessageWriter=o;function l(u,c,f,d){return f===void 0&&(f=a.NullLogger),a.ConnectionStrategy.is(d)&&(d={connectionStrategy:d}),(0,a.createMessageConnection)(u,c,f,d)}i(l,"createMessageConnection"),e.createMessageConnection=l}}),uh=H({"../../node_modules/.pnpm/vscode-jsonrpc@8.2.0/node_modules/vscode-jsonrpc/browser.js"(e,t){t.exports=ti()}}),Ae=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/messages.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ProtocolNotificationType=e.ProtocolNotificationType0=e.ProtocolRequestType=e.ProtocolRequestType0=e.RegistrationType=e.MessageDirection=void 0;var t=ti(),r;(function(u){u.clientToServer="clientToServer",u.serverToClient="serverToClient",u.both="both"})(r||(e.MessageDirection=r={}));var n=class{static{i(this,"RegistrationType")}constructor(u){this.method=u}};e.RegistrationType=n;var a=class extends t.RequestType0{static{i(this,"ProtocolRequestType0")}constructor(u){super(u)}};e.ProtocolRequestType0=a;var s=class extends t.RequestType{static{i(this,"ProtocolRequestType")}constructor(u){super(u,t.ParameterStructures.byName)}};e.ProtocolRequestType=s;var o=class extends t.NotificationType0{static{i(this,"ProtocolNotificationType0")}constructor(u){super(u)}};e.ProtocolNotificationType0=o;var l=class extends t.NotificationType{static{i(this,"ProtocolNotificationType")}constructor(u){super(u,t.ParameterStructures.byName)}};e.ProtocolNotificationType=l}}),_d=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/utils/is.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.objectLiteral=e.typedArray=e.stringArray=e.array=e.func=e.error=e.number=e.string=e.boolean=void 0;function t(f){return f===!0||f===!1}i(t,"boolean"),e.boolean=t;function r(f){return typeof f=="string"||f instanceof String}i(r,"string"),e.string=r;function n(f){return typeof f=="number"||f instanceof Number}i(n,"number"),e.number=n;function a(f){return f instanceof Error}i(a,"error"),e.error=a;function s(f){return typeof f=="function"}i(s,"func"),e.func=s;function o(f){return Array.isArray(f)}i(o,"array"),e.array=o;function l(f){return o(f)&&f.every(d=>r(d))}i(l,"stringArray"),e.stringArray=l;function u(f,d){return Array.isArray(f)&&f.every(d)}i(u,"typedArray"),e.typedArray=u;function c(f){return f!==null&&typeof f=="object"}i(c,"objectLiteral"),e.objectLiteral=c}}),OI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.implementation.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ImplementationRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/implementation",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.ImplementationRequest=r={}))}}),LI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeDefinition.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.TypeDefinitionRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/typeDefinition",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.TypeDefinitionRequest=r={}))}}),DI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.workspaceFolder.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DidChangeWorkspaceFoldersNotification=e.WorkspaceFoldersRequest=void 0;var t=Ae(),r;(function(a){a.method="workspace/workspaceFolders",a.messageDirection=t.MessageDirection.serverToClient,a.type=new t.ProtocolRequestType0(a.method)})(r||(e.WorkspaceFoldersRequest=r={}));var n;(function(a){a.method="workspace/didChangeWorkspaceFolders",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolNotificationType(a.method)})(n||(e.DidChangeWorkspaceFoldersNotification=n={}))}}),xI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.configuration.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ConfigurationRequest=void 0;var t=Ae(),r;(function(n){n.method="workspace/configuration",n.messageDirection=t.MessageDirection.serverToClient,n.type=new t.ProtocolRequestType(n.method)})(r||(e.ConfigurationRequest=r={}))}}),MI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.colorProvider.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ColorPresentationRequest=e.DocumentColorRequest=void 0;var t=Ae(),r;(function(a){a.method="textDocument/documentColor",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(r||(e.DocumentColorRequest=r={}));var n;(function(a){a.method="textDocument/colorPresentation",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(n||(e.ColorPresentationRequest=n={}))}}),GI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.foldingRange.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.FoldingRangeRefreshRequest=e.FoldingRangeRequest=void 0;var t=Ae(),r;(function(a){a.method="textDocument/foldingRange",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(r||(e.FoldingRangeRequest=r={}));var n;(function(a){a.method="workspace/foldingRange/refresh",a.messageDirection=t.MessageDirection.serverToClient,a.type=new t.ProtocolRequestType0(a.method)})(n||(e.FoldingRangeRefreshRequest=n={}))}}),FI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.declaration.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DeclarationRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/declaration",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.DeclarationRequest=r={}))}}),zI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.selectionRange.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.SelectionRangeRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/selectionRange",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.SelectionRangeRequest=r={}))}}),jI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.progress.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.WorkDoneProgressCancelNotification=e.WorkDoneProgressCreateRequest=e.WorkDoneProgress=void 0;var t=ti(),r=Ae(),n;(function(o){o.type=new t.ProgressType;function l(u){return u===o.type}i(l,"is"),o.is=l})(n||(e.WorkDoneProgress=n={}));var a;(function(o){o.method="window/workDoneProgress/create",o.messageDirection=r.MessageDirection.serverToClient,o.type=new r.ProtocolRequestType(o.method)})(a||(e.WorkDoneProgressCreateRequest=a={}));var s;(function(o){o.method="window/workDoneProgress/cancel",o.messageDirection=r.MessageDirection.clientToServer,o.type=new r.ProtocolNotificationType(o.method)})(s||(e.WorkDoneProgressCancelNotification=s={}))}}),BI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.callHierarchy.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.CallHierarchyOutgoingCallsRequest=e.CallHierarchyIncomingCallsRequest=e.CallHierarchyPrepareRequest=void 0;var t=Ae(),r;(function(s){s.method="textDocument/prepareCallHierarchy",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(r||(e.CallHierarchyPrepareRequest=r={}));var n;(function(s){s.method="callHierarchy/incomingCalls",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(n||(e.CallHierarchyIncomingCallsRequest=n={}));var a;(function(s){s.method="callHierarchy/outgoingCalls",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(a||(e.CallHierarchyOutgoingCallsRequest=a={}))}}),UI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.semanticTokens.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.SemanticTokensRefreshRequest=e.SemanticTokensRangeRequest=e.SemanticTokensDeltaRequest=e.SemanticTokensRequest=e.SemanticTokensRegistrationType=e.TokenFormat=void 0;var t=Ae(),r;(function(u){u.Relative="relative"})(r||(e.TokenFormat=r={}));var n;(function(u){u.method="textDocument/semanticTokens",u.type=new t.RegistrationType(u.method)})(n||(e.SemanticTokensRegistrationType=n={}));var a;(function(u){u.method="textDocument/semanticTokens/full",u.messageDirection=t.MessageDirection.clientToServer,u.type=new t.ProtocolRequestType(u.method),u.registrationMethod=n.method})(a||(e.SemanticTokensRequest=a={}));var s;(function(u){u.method="textDocument/semanticTokens/full/delta",u.messageDirection=t.MessageDirection.clientToServer,u.type=new t.ProtocolRequestType(u.method),u.registrationMethod=n.method})(s||(e.SemanticTokensDeltaRequest=s={}));var o;(function(u){u.method="textDocument/semanticTokens/range",u.messageDirection=t.MessageDirection.clientToServer,u.type=new t.ProtocolRequestType(u.method),u.registrationMethod=n.method})(o||(e.SemanticTokensRangeRequest=o={}));var l;(function(u){u.method="workspace/semanticTokens/refresh",u.messageDirection=t.MessageDirection.serverToClient,u.type=new t.ProtocolRequestType0(u.method)})(l||(e.SemanticTokensRefreshRequest=l={}))}}),KI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.showDocument.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.ShowDocumentRequest=void 0;var t=Ae(),r;(function(n){n.method="window/showDocument",n.messageDirection=t.MessageDirection.serverToClient,n.type=new t.ProtocolRequestType(n.method)})(r||(e.ShowDocumentRequest=r={}))}}),WI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.linkedEditingRange.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.LinkedEditingRangeRequest=void 0;var t=Ae(),r;(function(n){n.method="textDocument/linkedEditingRange",n.messageDirection=t.MessageDirection.clientToServer,n.type=new t.ProtocolRequestType(n.method)})(r||(e.LinkedEditingRangeRequest=r={}))}}),VI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.fileOperations.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.WillDeleteFilesRequest=e.DidDeleteFilesNotification=e.DidRenameFilesNotification=e.WillRenameFilesRequest=e.DidCreateFilesNotification=e.WillCreateFilesRequest=e.FileOperationPatternKind=void 0;var t=Ae(),r;(function(c){c.file="file",c.folder="folder"})(r||(e.FileOperationPatternKind=r={}));var n;(function(c){c.method="workspace/willCreateFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolRequestType(c.method)})(n||(e.WillCreateFilesRequest=n={}));var a;(function(c){c.method="workspace/didCreateFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolNotificationType(c.method)})(a||(e.DidCreateFilesNotification=a={}));var s;(function(c){c.method="workspace/willRenameFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolRequestType(c.method)})(s||(e.WillRenameFilesRequest=s={}));var o;(function(c){c.method="workspace/didRenameFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolNotificationType(c.method)})(o||(e.DidRenameFilesNotification=o={}));var l;(function(c){c.method="workspace/didDeleteFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolNotificationType(c.method)})(l||(e.DidDeleteFilesNotification=l={}));var u;(function(c){c.method="workspace/willDeleteFiles",c.messageDirection=t.MessageDirection.clientToServer,c.type=new t.ProtocolRequestType(c.method)})(u||(e.WillDeleteFilesRequest=u={}))}}),qI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.moniker.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.MonikerRequest=e.MonikerKind=e.UniquenessLevel=void 0;var t=Ae(),r;(function(s){s.document="document",s.project="project",s.group="group",s.scheme="scheme",s.global="global"})(r||(e.UniquenessLevel=r={}));var n;(function(s){s.$import="import",s.$export="export",s.local="local"})(n||(e.MonikerKind=n={}));var a;(function(s){s.method="textDocument/moniker",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(a||(e.MonikerRequest=a={}))}}),HI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.typeHierarchy.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.TypeHierarchySubtypesRequest=e.TypeHierarchySupertypesRequest=e.TypeHierarchyPrepareRequest=void 0;var t=Ae(),r;(function(s){s.method="textDocument/prepareTypeHierarchy",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(r||(e.TypeHierarchyPrepareRequest=r={}));var n;(function(s){s.method="typeHierarchy/supertypes",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(n||(e.TypeHierarchySupertypesRequest=n={}));var a;(function(s){s.method="typeHierarchy/subtypes",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(a||(e.TypeHierarchySubtypesRequest=a={}))}}),YI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlineValue.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.InlineValueRefreshRequest=e.InlineValueRequest=void 0;var t=Ae(),r;(function(a){a.method="textDocument/inlineValue",a.messageDirection=t.MessageDirection.clientToServer,a.type=new t.ProtocolRequestType(a.method)})(r||(e.InlineValueRequest=r={}));var n;(function(a){a.method="workspace/inlineValue/refresh",a.messageDirection=t.MessageDirection.serverToClient,a.type=new t.ProtocolRequestType0(a.method)})(n||(e.InlineValueRefreshRequest=n={}))}}),XI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.inlayHint.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.InlayHintRefreshRequest=e.InlayHintResolveRequest=e.InlayHintRequest=void 0;var t=Ae(),r;(function(s){s.method="textDocument/inlayHint",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(r||(e.InlayHintRequest=r={}));var n;(function(s){s.method="inlayHint/resolve",s.messageDirection=t.MessageDirection.clientToServer,s.type=new t.ProtocolRequestType(s.method)})(n||(e.InlayHintResolveRequest=n={}));var a;(function(s){s.method="workspace/inlayHint/refresh",s.messageDirection=t.MessageDirection.serverToClient,s.type=new t.ProtocolRequestType0(s.method)})(a||(e.InlayHintRefreshRequest=a={}))}}),JI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.diagnostic.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DiagnosticRefreshRequest=e.WorkspaceDiagnosticRequest=e.DocumentDiagnosticRequest=e.DocumentDiagnosticReportKind=e.DiagnosticServerCancellationData=void 0;var t=ti(),r=_d(),n=Ae(),a;(function(c){function f(d){const m=d;return m&&r.boolean(m.retriggerRequest)}i(f,"is"),c.is=f})(a||(e.DiagnosticServerCancellationData=a={}));var s;(function(c){c.Full="full",c.Unchanged="unchanged"})(s||(e.DocumentDiagnosticReportKind=s={}));var o;(function(c){c.method="textDocument/diagnostic",c.messageDirection=n.MessageDirection.clientToServer,c.type=new n.ProtocolRequestType(c.method),c.partialResult=new t.ProgressType})(o||(e.DocumentDiagnosticRequest=o={}));var l;(function(c){c.method="workspace/diagnostic",c.messageDirection=n.MessageDirection.clientToServer,c.type=new n.ProtocolRequestType(c.method),c.partialResult=new t.ProgressType})(l||(e.WorkspaceDiagnosticRequest=l={}));var u;(function(c){c.method="workspace/diagnostic/refresh",c.messageDirection=n.MessageDirection.serverToClient,c.type=new n.ProtocolRequestType0(c.method)})(u||(e.DiagnosticRefreshRequest=u={}))}}),ZI=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/protocol.notebook.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.DidCloseNotebookDocumentNotification=e.DidSaveNotebookDocumentNotification=e.DidChangeNotebookDocumentNotification=e.NotebookCellArrayChange=e.DidOpenNotebookDocumentNotification=e.NotebookDocumentSyncRegistrationType=e.NotebookDocument=e.NotebookCell=e.ExecutionSummary=e.NotebookCellKind=void 0;var t=(xs(),bd(Dl)),r=_d(),n=Ae(),a;(function(v){v.Markup=1,v.Code=2;function b(S){return S===1||S===2}i(b,"is"),v.is=b})(a||(e.NotebookCellKind=a={}));var s;(function(v){function b(I,R){const P={executionOrder:I};return(R===!0||R===!1)&&(P.success=R),P}i(b,"create"),v.create=b;function S(I){const R=I;return r.objectLiteral(R)&&t.uinteger.is(R.executionOrder)&&(R.success===void 0||r.boolean(R.success))}i(S,"is"),v.is=S;function w(I,R){return I===R?!0:I==null||R===null||R===void 0?!1:I.executionOrder===R.executionOrder&&I.success===R.success}i(w,"equals"),v.equals=w})(s||(e.ExecutionSummary=s={}));var o;(function(v){function b(R,P){return{kind:R,document:P}}i(b,"create"),v.create=b;function S(R){const P=R;return r.objectLiteral(P)&&a.is(P.kind)&&t.DocumentUri.is(P.document)&&(P.metadata===void 0||r.objectLiteral(P.metadata))}i(S,"is"),v.is=S;function w(R,P){const z=new Set;return R.document!==P.document&&z.add("document"),R.kind!==P.kind&&z.add("kind"),R.executionSummary!==P.executionSummary&&z.add("executionSummary"),(R.metadata!==void 0||P.metadata!==void 0)&&!I(R.metadata,P.metadata)&&z.add("metadata"),(R.executionSummary!==void 0||P.executionSummary!==void 0)&&!s.equals(R.executionSummary,P.executionSummary)&&z.add("executionSummary"),z}i(w,"diff"),v.diff=w;function I(R,P){if(R===P)return!0;if(R==null||P===null||P===void 0||typeof R!=typeof P||typeof R!="object")return!1;const z=Array.isArray(R),X=Array.isArray(P);if(z!==X)return!1;if(z&&X){if(R.length!==P.length)return!1;for(let Z=0;Z0}i(ae,"hasId"),p.hasId=ae})(O||(e.StaticRegistrationOptions=O={}));var x;(function(p){function ae(Te){const q=Te;return q&&(q.documentSelector===null||C.is(q.documentSelector))}i(ae,"is"),p.is=ae})(x||(e.TextDocumentRegistrationOptions=x={}));var D;(function(p){function ae(q){const h=q;return n.objectLiteral(h)&&(h.workDoneProgress===void 0||n.boolean(h.workDoneProgress))}i(ae,"is"),p.is=ae;function Te(q){const h=q;return h&&n.boolean(h.workDoneProgress)}i(Te,"hasWorkDoneProgress"),p.hasWorkDoneProgress=Te})(D||(e.WorkDoneProgressOptions=D={}));var G;(function(p){p.method="initialize",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(G||(e.InitializeRequest=G={}));var W;(function(p){p.unknownProtocolVersion=1})(W||(e.InitializeErrorCodes=W={}));var Y;(function(p){p.method="initialized",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(Y||(e.InitializedNotification=Y={}));var V;(function(p){p.method="shutdown",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType0(p.method)})(V||(e.ShutdownRequest=V={}));var Pe;(function(p){p.method="exit",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType0(p.method)})(Pe||(e.ExitNotification=Pe={}));var oe;(function(p){p.method="workspace/didChangeConfiguration",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(oe||(e.DidChangeConfigurationNotification=oe={}));var Le;(function(p){p.Error=1,p.Warning=2,p.Info=3,p.Log=4,p.Debug=5})(Le||(e.MessageType=Le={}));var De;(function(p){p.method="window/showMessage",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(De||(e.ShowMessageNotification=De={}));var ke;(function(p){p.method="window/showMessageRequest",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolRequestType(p.method)})(ke||(e.ShowMessageRequest=ke={}));var Ze;(function(p){p.method="window/logMessage",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(Ze||(e.LogMessageNotification=Ze={}));var Je;(function(p){p.method="telemetry/event",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(Je||(e.TelemetryEventNotification=Je={}));var ne;(function(p){p.None=0,p.Full=1,p.Incremental=2})(ne||(e.TextDocumentSyncKind=ne={}));var Kt;(function(p){p.method="textDocument/didOpen",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(Kt||(e.DidOpenTextDocumentNotification=Kt={}));var Ee;(function(p){function ae(q){let h=q;return h!=null&&typeof h.text=="string"&&h.range!==void 0&&(h.rangeLength===void 0||typeof h.rangeLength=="number")}i(ae,"isIncremental"),p.isIncremental=ae;function Te(q){let h=q;return h!=null&&typeof h.text=="string"&&h.range===void 0&&h.rangeLength===void 0}i(Te,"isFull"),p.isFull=Te})(Ee||(e.TextDocumentContentChangeEvent=Ee={}));var kt;(function(p){p.method="textDocument/didChange",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(kt||(e.DidChangeTextDocumentNotification=kt={}));var ra;(function(p){p.method="textDocument/didClose",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(ra||(e.DidCloseTextDocumentNotification=ra={}));var fi;(function(p){p.method="textDocument/didSave",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(fi||(e.DidSaveTextDocumentNotification=fi={}));var di;(function(p){p.Manual=1,p.AfterDelay=2,p.FocusOut=3})(di||(e.TextDocumentSaveReason=di={}));var pi;(function(p){p.method="textDocument/willSave",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(pi||(e.WillSaveTextDocumentNotification=pi={}));var mi;(function(p){p.method="textDocument/willSaveWaitUntil",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(mi||(e.WillSaveTextDocumentWaitUntilRequest=mi={}));var Ot;(function(p){p.method="workspace/didChangeWatchedFiles",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolNotificationType(p.method)})(Ot||(e.DidChangeWatchedFilesNotification=Ot={}));var na;(function(p){p.Created=1,p.Changed=2,p.Deleted=3})(na||(e.FileChangeType=na={}));var hi;(function(p){function ae(Te){const q=Te;return n.objectLiteral(q)&&(r.URI.is(q.baseUri)||r.WorkspaceFolder.is(q.baseUri))&&n.string(q.pattern)}i(ae,"is"),p.is=ae})(hi||(e.RelativePattern=hi={}));var yi;(function(p){p.Create=1,p.Change=2,p.Delete=4})(yi||(e.WatchKind=yi={}));var gi;(function(p){p.method="textDocument/publishDiagnostics",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolNotificationType(p.method)})(gi||(e.PublishDiagnosticsNotification=gi={}));var vi;(function(p){p.Invoked=1,p.TriggerCharacter=2,p.TriggerForIncompleteCompletions=3})(vi||(e.CompletionTriggerKind=vi={}));var aa;(function(p){p.method="textDocument/completion",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(aa||(e.CompletionRequest=aa={}));var ia;(function(p){p.method="completionItem/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(ia||(e.CompletionResolveRequest=ia={}));var Wt;(function(p){p.method="textDocument/hover",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Wt||(e.HoverRequest=Wt={}));var sa;(function(p){p.Invoked=1,p.TriggerCharacter=2,p.ContentChange=3})(sa||(e.SignatureHelpTriggerKind=sa={}));var Ti;(function(p){p.method="textDocument/signatureHelp",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ti||(e.SignatureHelpRequest=Ti={}));var $i;(function(p){p.method="textDocument/definition",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})($i||(e.DefinitionRequest=$i={}));var oa;(function(p){p.method="textDocument/references",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(oa||(e.ReferencesRequest=oa={}));var la;(function(p){p.method="textDocument/documentHighlight",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(la||(e.DocumentHighlightRequest=la={}));var Ri;(function(p){p.method="textDocument/documentSymbol",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ri||(e.DocumentSymbolRequest=Ri={}));var no;(function(p){p.method="textDocument/codeAction",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(no||(e.CodeActionRequest=no={}));var Ai;(function(p){p.method="codeAction/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ai||(e.CodeActionResolveRequest=Ai={}));var Ei;(function(p){p.method="workspace/symbol",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ei||(e.WorkspaceSymbolRequest=Ei={}));var Ci;(function(p){p.method="workspaceSymbol/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ci||(e.WorkspaceSymbolResolveRequest=Ci={}));var bi;(function(p){p.method="textDocument/codeLens",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(bi||(e.CodeLensRequest=bi={}));var bt;(function(p){p.method="codeLens/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(bt||(e.CodeLensResolveRequest=bt={}));var _i;(function(p){p.method="workspace/codeLens/refresh",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolRequestType0(p.method)})(_i||(e.CodeLensRefreshRequest=_i={}));var Si;(function(p){p.method="textDocument/documentLink",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Si||(e.DocumentLinkRequest=Si={}));var Lr;(function(p){p.method="documentLink/resolve",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Lr||(e.DocumentLinkResolveRequest=Lr={}));var wi;(function(p){p.method="textDocument/formatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(wi||(e.DocumentFormattingRequest=wi={}));var Jr;(function(p){p.method="textDocument/rangeFormatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Jr||(e.DocumentRangeFormattingRequest=Jr={}));var Ii;(function(p){p.method="textDocument/rangesFormatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ii||(e.DocumentRangesFormattingRequest=Ii={}));var Vt;(function(p){p.method="textDocument/onTypeFormatting",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Vt||(e.DocumentOnTypeFormattingRequest=Vt={}));var cr;(function(p){p.Identifier=1})(cr||(e.PrepareSupportDefaultBehavior=cr={}));var Ni;(function(p){p.method="textDocument/rename",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Ni||(e.RenameRequest=Ni={}));var Pi;(function(p){p.method="textDocument/prepareRename",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(Pi||(e.PrepareRenameRequest=Pi={}));var fr;(function(p){p.method="workspace/executeCommand",p.messageDirection=t.MessageDirection.clientToServer,p.type=new t.ProtocolRequestType(p.method)})(fr||(e.ExecuteCommandRequest=fr={}));var ua;(function(p){p.method="workspace/applyEdit",p.messageDirection=t.MessageDirection.serverToClient,p.type=new t.ProtocolRequestType("workspace/applyEdit")})(ua||(e.ApplyWorkspaceEditRequest=ua={}))}}),tN=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/connection.js"(e){Object.defineProperty(e,"__esModule",{value:!0}),e.createProtocolConnection=void 0;var t=ti();function r(n,a,s,o){return t.ConnectionStrategy.is(o)&&(o={connectionStrategy:o}),(0,t.createMessageConnection)(n,a,s,o)}i(r,"createProtocolConnection"),e.createProtocolConnection=r}}),rN=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/common/api.js"(e){var t=e&&e.__createBinding||(Object.create?(function(s,o,l,u){u===void 0&&(u=l);var c=Object.getOwnPropertyDescriptor(o,l);(!c||("get"in c?!o.__esModule:c.writable||c.configurable))&&(c={enumerable:!0,get:i(function(){return o[l]},"get")}),Object.defineProperty(s,u,c)}):(function(s,o,l,u){u===void 0&&(u=l),s[u]=o[l]})),r=e&&e.__exportStar||function(s,o){for(var l in s)l!=="default"&&!Object.prototype.hasOwnProperty.call(o,l)&&t(o,s,l)};Object.defineProperty(e,"__esModule",{value:!0}),e.LSPErrorCodes=e.createProtocolConnection=void 0,r(ti(),e),r((xs(),bd(Dl)),e),r(Ae(),e),r(eN(),e);var n=tN();Object.defineProperty(e,"createProtocolConnection",{enumerable:!0,get:i(function(){return n.createProtocolConnection},"get")});var a;(function(s){s.lspReservedErrorRangeStart=-32899,s.RequestFailed=-32803,s.ServerCancelled=-32802,s.ContentModified=-32801,s.RequestCancelled=-32800,s.lspReservedErrorRangeEnd=-32800})(a||(e.LSPErrorCodes=a={}))}}),nN=H({"../../node_modules/.pnpm/vscode-languageserver-protocol@3.17.5/node_modules/vscode-languageserver-protocol/lib/browser/main.js"(e){var t=e&&e.__createBinding||(Object.create?(function(s,o,l,u){u===void 0&&(u=l);var c=Object.getOwnPropertyDescriptor(o,l);(!c||("get"in c?!o.__esModule:c.writable||c.configurable))&&(c={enumerable:!0,get:i(function(){return o[l]},"get")}),Object.defineProperty(s,u,c)}):(function(s,o,l,u){u===void 0&&(u=l),s[u]=o[l]})),r=e&&e.__exportStar||function(s,o){for(var l in s)l!=="default"&&!Object.prototype.hasOwnProperty.call(o,l)&&t(o,s,l)};Object.defineProperty(e,"__esModule",{value:!0}),e.createProtocolConnection=void 0;var n=uh();r(uh(),e),r(rN(),e);function a(s,o,l,u){return(0,n.createMessageConnection)(s,o,l,u)}i(a,"createProtocolConnection"),e.createProtocolConnection=a}}),Hg={};Vr(Hg,{AbstractAstReflection:()=>Id,AbstractCstNode:()=>Pm,AbstractLangiumParser:()=>Om,AbstractParserErrorMessageProvider:()=>MS,AbstractThreadedAsyncParser:()=>SF,AstUtils:()=>Nd,BiMap:()=>Nl,Cancellation:()=>pe,CompositeCstNodeImpl:()=>ku,ContextCache:()=>Fu,CstNodeBuilder:()=>OS,CstUtils:()=>Sd,DEFAULT_TOKENIZE_OPTIONS:()=>Jm,DONE_RESULT:()=>tt,DatatypeSymbol:()=>_l,DefaultAstNodeDescriptionProvider:()=>pw,DefaultAstNodeLocator:()=>hw,DefaultAsyncParser:()=>Ow,DefaultCommentProvider:()=>kw,DefaultConfigurationProvider:()=>yw,DefaultDocumentBuilder:()=>gw,DefaultDocumentValidator:()=>dw,DefaultHydrator:()=>Dw,DefaultIndexManager:()=>vw,DefaultJsonSerializer:()=>lw,DefaultLangiumDocumentFactory:()=>QS,DefaultLangiumDocuments:()=>ew,DefaultLangiumProfiler:()=>kF,DefaultLexer:()=>Zm,DefaultLexerErrorMessageProvider:()=>$w,DefaultLinker:()=>tw,DefaultNameProvider:()=>rw,DefaultReferenceDescriptionProvider:()=>mw,DefaultReferences:()=>nw,DefaultScopeComputation:()=>aw,DefaultScopeProvider:()=>ow,DefaultServiceRegistry:()=>uw,DefaultTokenBuilder:()=>Du,DefaultValueConverter:()=>zm,DefaultWorkspaceLock:()=>Lw,DefaultWorkspaceManager:()=>Tw,Deferred:()=>wr,Disposable:()=>Nn,DisposableCache:()=>Gu,DocumentCache:()=>sw,DocumentState:()=>J,DocumentValidator:()=>_t,EMPTY_SCOPE:()=>EF,EMPTY_STREAM:()=>Ua,EmptyFileSystem:()=>Xe,EmptyFileSystemProvider:()=>Gw,ErrorWithLocation:()=>Wl,GrammarAST:()=>Jg,GrammarUtils:()=>sp,IndentationAwareLexer:()=>IF,IndentationAwareTokenBuilder:()=>Mw,JSDocDocumentationProvider:()=>Pw,LangiumCompletionParser:()=>GS,LangiumParser:()=>xS,LangiumParserErrorMessageProvider:()=>Lm,LeafCstNodeImpl:()=>bl,LexingMode:()=>wn,MapScope:()=>AF,Module:()=>nd,MultiMap:()=>Ir,MultiMapScope:()=>iw,OperationCancelled:()=>tr,ParserWorker:()=>wF,ProfilingTask:()=>zw,Reduction:()=>Ts,RefResolving:()=>un,RegExpUtils:()=>lp,RootCstNodeImpl:()=>km,SimpleCache:()=>Vm,StreamImpl:()=>er,StreamScope:()=>Qf,TextDocument:()=>wl,TreeStreamImpl:()=>Ka,URI:()=>Tt,UriTrie:()=>Km,UriUtils:()=>nt,VALIDATE_EACH_NODE:()=>fw,ValidationCategory:()=>Pl,ValidationRegistry:()=>cw,ValueConverter:()=>Zt,WorkspaceCache:()=>qm,assertCondition:()=>op,assertUnreachable:()=>qr,createCompletionParser:()=>Mm,createDefaultCoreModule:()=>je,createDefaultSharedCoreModule:()=>Be,createGrammarConfig:()=>_p,createLangiumParser:()=>Gm,createParser:()=>Ou,delayNextTick:()=>xu,diagnosticData:()=>Sn,eagerLoad:()=>ih,getDiagnosticRange:()=>Ym,indentationBuilderDefaultOptions:()=>id,inject:()=>ee,interruptAndCheck:()=>ze,isAstNode:()=>Oe,isAstNodeDescription:()=>wd,isAstNodeWithComment:()=>Hm,isCompositeCstNode:()=>$r,isIMultiModeLexerDefinition:()=>Bu,isJSDoc:()=>eh,isLeafCstNode:()=>xn,isLinkingError:()=>pn,isMultiReference:()=>rr,isNamed:()=>Wm,isOperationCancelled:()=>ta,isReference:()=>rt,isRootCstNode:()=>Ml,isTokenTypeArray:()=>ju,isTokenTypeDictionary:()=>kl,loadGrammarFromJson:()=>Ue,parseJSDoc:()=>Qm,prepareLangiumParser:()=>Fm,setInterruptionPeriod:()=>jm,startCancelableOperation:()=>Mu,stream:()=>ue,toDiagnosticData:()=>Xm,toDiagnosticSeverity:()=>gs});var Sd={};Vr(Sd,{DefaultNameRegexp:()=>tp,RangeComparison:()=>Qt,compareRange:()=>Qd,findCommentNode:()=>rp,findDeclarationNodeAtOffset:()=>yv,findLeafNodeAtOffset:()=>Kl,findLeafNodeBeforeOffset:()=>np,flattenCst:()=>hv,getDatatypeNode:()=>mv,getInteriorNodes:()=>Tv,getNextNode:()=>gv,getPreviousNode:()=>ip,getStartlineNode:()=>vv,inRange:()=>ep,isChildNode:()=>Zd,isCommentNode:()=>ul,streamCst:()=>Ha,toDocumentSegment:()=>Ya,tokenToRange:()=>$s});function Oe(e){return typeof e=="object"&&e!==null&&typeof e.$type=="string"}i(Oe,"isAstNode");function rt(e){return typeof e=="object"&&e!==null&&typeof e.$refText=="string"&&"ref"in e}i(rt,"isReference");function rr(e){return typeof e=="object"&&e!==null&&typeof e.$refText=="string"&&"items"in e}i(rr,"isMultiReference");function wd(e){return typeof e=="object"&&e!==null&&typeof e.name=="string"&&typeof e.type=="string"&&typeof e.path=="string"}i(wd,"isAstNodeDescription");function pn(e){return typeof e=="object"&&e!==null&&typeof e.info=="object"&&typeof e.message=="string"}i(pn,"isLinkingError");var Id=class{static{i(this,"AbstractAstReflection")}constructor(){this.subtypes={},this.allSubtypes={}}getAllTypes(){return Object.keys(this.types)}getReferenceType(e){const t=this.types[e.container.$type];if(!t)throw new Error(`Type ${e.container.$type||"undefined"} not found.`);const r=t.properties[e.property]?.referenceType;if(!r)throw new Error(`Property ${e.property||"undefined"} of type ${e.container.$type} is not a reference.`);return r}getTypeMetaData(e){const t=this.types[e];return t||{name:e,properties:{},superTypes:[]}}isInstance(e,t){return Oe(e)&&this.isSubtype(e.$type,t)}isSubtype(e,t){if(e===t)return!0;let r=this.subtypes[e];r||(r=this.subtypes[e]={});const n=r[t];if(n!==void 0)return n;{const a=this.types[e],s=a?a.superTypes.some(o=>this.isSubtype(o,t)):!1;return r[t]=s,s}}getAllSubTypes(e){const t=this.allSubtypes[e];if(t)return t;{const r=this.getAllTypes(),n=[];for(const a of r)this.isSubtype(a,e)&&n.push(a);return this.allSubtypes[e]=n,n}}};function $r(e){return typeof e=="object"&&e!==null&&Array.isArray(e.content)}i($r,"isCompositeCstNode");function xn(e){return typeof e=="object"&&e!==null&&typeof e.tokenType=="object"}i(xn,"isLeafCstNode");function Ml(e){return $r(e)&&typeof e.fullText=="string"}i(Ml,"isRootCstNode");var er=class hr{static{i(this,"StreamImpl")}constructor(t,r){this.startFn=t,this.nextFn=r}iterator(){const t={state:this.startFn(),next:i(()=>this.nextFn(t.state),"next"),[Symbol.iterator]:()=>t};return t}[Symbol.iterator](){return this.iterator()}isEmpty(){return!!this.iterator().next().done}count(){const t=this.iterator();let r=0,n=t.next();for(;!n.done;)r++,n=t.next();return r}toArray(){const t=[],r=this.iterator();let n;do n=r.next(),n.value!==void 0&&t.push(n.value);while(!n.done);return t}toSet(){return new Set(this)}toMap(t,r){const n=this.map(a=>[t?t(a):a,r?r(a):a]);return new Map(n)}toString(){return this.join()}concat(t){return new hr(()=>({first:this.startFn(),firstDone:!1,iterator:t[Symbol.iterator]()}),r=>{let n;if(!r.firstDone){do if(n=this.nextFn(r.first),!n.done)return n;while(!n.done);r.firstDone=!0}do if(n=r.iterator.next(),!n.done)return n;while(!n.done);return tt})}join(t=","){const r=this.iterator();let n="",a,s=!1;do a=r.next(),a.done||(s&&(n+=t),n+=Yg(a.value)),s=!0;while(!a.done);return n}indexOf(t,r=0){const n=this.iterator();let a=0,s=n.next();for(;!s.done;){if(a>=r&&s.value===t)return a;s=n.next(),a++}return-1}every(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(!t(n.value))return!1;n=r.next()}return!0}some(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(t(n.value))return!0;n=r.next()}return!1}forEach(t){const r=this.iterator();let n=0,a=r.next();for(;!a.done;)t(a.value,n),a=r.next(),n++}map(t){return new hr(this.startFn,r=>{const{done:n,value:a}=this.nextFn(r);return n?tt:{done:!1,value:t(a)}})}filter(t){return new hr(this.startFn,r=>{let n;do if(n=this.nextFn(r),!n.done&&t(n.value))return n;while(!n.done);return tt})}nonNullable(){return this.filter(t=>t!=null)}reduce(t,r){const n=this.iterator();let a=r,s=n.next();for(;!s.done;)a===void 0?a=s.value:a=t(a,s.value),s=n.next();return a}reduceRight(t,r){return this.recursiveReduce(this.iterator(),t,r)}recursiveReduce(t,r,n){const a=t.next();if(a.done)return n;const s=this.recursiveReduce(t,r,n);return s===void 0?a.value:r(s,a.value)}find(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(t(n.value))return n.value;n=r.next()}}findIndex(t){const r=this.iterator();let n=0,a=r.next();for(;!a.done;){if(t(a.value))return n;a=r.next(),n++}return-1}includes(t){const r=this.iterator();let n=r.next();for(;!n.done;){if(n.value===t)return!0;n=r.next()}return!1}flatMap(t){return new hr(()=>({this:this.startFn()}),r=>{do{if(r.iterator){const s=r.iterator.next();if(s.done)r.iterator=void 0;else return s}const{done:n,value:a}=this.nextFn(r.this);if(!n){const s=t(a);if(vs(s))r.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}}while(r.iterator);return tt})}flat(t){if(t===void 0&&(t=1),t<=0)return this;const r=t>1?this.flat(t-1):this;return new hr(()=>({this:r.startFn()}),n=>{do{if(n.iterator){const o=n.iterator.next();if(o.done)n.iterator=void 0;else return o}const{done:a,value:s}=r.nextFn(n.this);if(!a)if(vs(s))n.iterator=s[Symbol.iterator]();else return{done:!1,value:s}}while(n.iterator);return tt})}head(){const r=this.iterator().next();if(!r.done)return r.value}tail(t=1){return new hr(()=>{const r=this.startFn();for(let n=0;n({size:0,state:this.startFn()}),r=>(r.size++,r.size>t?tt:this.nextFn(r.state)))}distinct(t){return new hr(()=>({set:new Set,internalState:this.startFn()}),r=>{let n;do if(n=this.nextFn(r.internalState),!n.done){const a=t?t(n.value):n.value;if(!r.set.has(a))return r.set.add(a),n}while(!n.done);return tt})}exclude(t,r){const n=new Set;for(const a of t){const s=r?r(a):a;n.add(s)}return this.filter(a=>{const s=r?r(a):a;return!n.has(s)})}};function Yg(e){return typeof e=="string"?e:typeof e>"u"?"undefined":typeof e.toString=="function"?e.toString():Object.prototype.toString.call(e)}i(Yg,"toString");function vs(e){return!!e&&typeof e[Symbol.iterator]=="function"}i(vs,"isIterable");var Ua=new er(()=>{},()=>tt),tt=Object.freeze({done:!0,value:void 0});function ue(...e){if(e.length===1){const t=e[0];if(t instanceof er)return t;if(vs(t))return new er(()=>t[Symbol.iterator](),r=>r.next());if(typeof t.length=="number")return new er(()=>({index:0}),r=>r.index1?new er(()=>({collIndex:0,arrIndex:0}),t=>{do{if(t.iterator){const r=t.iterator.next();if(!r.done)return r;t.iterator=void 0}if(t.array){if(t.arrIndex({iterators:r?.includeRoot?[[e][Symbol.iterator]()]:[t(e)[Symbol.iterator]()],pruned:!1}),n=>{for(n.pruned&&(n.iterators.pop(),n.pruned=!1);n.iterators.length>0;){const s=n.iterators[n.iterators.length-1].next();if(s.done)n.iterators.pop();else return n.iterators.push(t(s.value)[Symbol.iterator]()),s}return tt})}iterator(){const e={state:this.startFn(),next:i(()=>this.nextFn(e.state),"next"),prune:i(()=>{e.state.pruned=!0},"prune"),[Symbol.iterator]:()=>e};return e}},Ts;(function(e){function t(s){return s.reduce((o,l)=>o+l,0)}i(t,"sum"),e.sum=t;function r(s){return s.reduce((o,l)=>o*l,0)}i(r,"product"),e.product=r;function n(s){return s.reduce((o,l)=>Math.min(o,l))}i(n,"min"),e.min=n;function a(s){return s.reduce((o,l)=>Math.max(o,l))}i(a,"max"),e.max=a})(Ts||(Ts={}));var Nd={};Vr(Nd,{assignMandatoryProperties:()=>Pd,copyAstNode:()=>Yo,findRootNode:()=>Fa,getContainerOfType:()=>Mn,getDocument:()=>Mt,getReferenceNodes:()=>qo,hasContainerOfType:()=>Xg,linkContentToContainer:()=>Wa,streamAllContents:()=>Nr,streamAst:()=>Gt,streamContents:()=>Gs,streamReferences:()=>Va});function Wa(e,t={}){for(const[r,n]of Object.entries(e))r.startsWith("$")||(Array.isArray(n)?n.forEach((a,s)=>{Oe(a)&&(a.$container=e,a.$containerProperty=r,a.$containerIndex=s,t.deep&&Wa(a,t))}):Oe(n)&&(n.$container=e,n.$containerProperty=r,t.deep&&Wa(n,t)))}i(Wa,"linkContentToContainer");function Mn(e,t){let r=e;for(;r;){if(t(r))return r;r=r.$container}}i(Mn,"getContainerOfType");function Xg(e,t){let r=e;for(;r;){if(t(r))return!0;r=r.$container}return!1}i(Xg,"hasContainerOfType");function Mt(e){const r=Fa(e).$document;if(!r)throw new Error("AST node has no document.");return r}i(Mt,"getDocument");function Fa(e){for(;e.$container;)e=e.$container;return e}i(Fa,"findRootNode");function qo(e){return rt(e)?e.ref?[e.ref]:[]:rr(e)?e.items.map(t=>t.ref):[]}i(qo,"getReferenceNodes");function Gs(e,t){if(!e)throw new Error("Node must be an AstNode.");const r=t?.range;return new er(()=>({keys:Object.keys(e),keyIndex:0,arrayIndex:0}),n=>{for(;n.keyIndexGs(r,t))}i(Nr,"streamAllContents");function Gt(e,t){if(e){if(t?.range&&!Ho(e,t.range))return new Ka(e,()=>[])}else throw new Error("Root node must be an AstNode.");return new Ka(e,r=>Gs(r,t),{includeRoot:!0})}i(Gt,"streamAst");function Ho(e,t){if(!t)return!0;const r=e.$cstNode?.range;return r?ep(r,t):!1}i(Ho,"isAstNodeInRange");function Va(e){return new er(()=>({keys:Object.keys(e),keyIndex:0,arrayIndex:0}),t=>{for(;t.keyIndexdt,AbstractParserRule:()=>ns,AbstractRule:()=>Pa,AbstractType:()=>vt,Action:()=>xr,Alternatives:()=>as,ArrayLiteral:()=>Xo,ArrayType:()=>Jo,Assignment:()=>Mr,BooleanLiteral:()=>Zo,CharacterRange:()=>Gr,Condition:()=>Fr,Conjunction:()=>is,CrossReference:()=>zr,Disjunction:()=>ss,EndOfFile:()=>Qo,Grammar:()=>gr,GrammarImport:()=>el,Group:()=>mn,InferredType:()=>tl,InfixRule:()=>Jt,InfixRuleOperatorList:()=>os,InfixRuleOperators:()=>rl,Interface:()=>ka,Keyword:()=>Oa,LangiumGrammarAstReflection:()=>Jd,LangiumGrammarTerminals:()=>aN,NamedArgument:()=>La,NegatedToken:()=>hn,Negation:()=>nl,NumberLiteral:()=>al,Parameter:()=>Da,ParameterReference:()=>il,ParserRule:()=>Lt,ReferenceType:()=>ls,RegexToken:()=>yn,ReturnType:()=>sl,RuleCall:()=>gn,SimpleType:()=>xa,StringLiteral:()=>ol,TerminalAlternatives:()=>vn,TerminalElement:()=>pt,TerminalGroup:()=>Tn,TerminalRule:()=>vr,TerminalRuleCall:()=>$n,Type:()=>us,TypeAttribute:()=>Rn,TypeDefinition:()=>An,UnionType:()=>ll,UnorderedGroup:()=>cs,UntilToken:()=>En,ValueLiteral:()=>Cn,Wildcard:()=>Ma,isAbstractElement:()=>Gl,isAbstractParserRule:()=>Gn,isAbstractRule:()=>Zg,isAbstractType:()=>Qg,isAction:()=>jr,isAlternatives:()=>Fl,isArrayLiteral:()=>ev,isArrayType:()=>Od,isAssignment:()=>Rr,isBooleanLiteral:()=>Ld,isCharacterRange:()=>Dd,isCondition:()=>tv,isConjunction:()=>xd,isCrossReference:()=>Fn,isDisjunction:()=>Md,isEndOfFile:()=>Gd,isGrammar:()=>rv,isGrammarImport:()=>nv,isGroup:()=>zn,isInferredType:()=>Fs,isInfixRule:()=>qa,isInfixRuleOperatorList:()=>av,isInfixRuleOperators:()=>iv,isInterface:()=>Fd,isKeyword:()=>Ar,isNamedArgument:()=>sv,isNegatedToken:()=>zd,isNegation:()=>jd,isNumberLiteral:()=>ov,isParameter:()=>lv,isParameterReference:()=>Bd,isParserRule:()=>it,isReferenceType:()=>Ud,isRegexToken:()=>Kd,isReturnType:()=>Wd,isRuleCall:()=>Er,isSimpleType:()=>zl,isStringLiteral:()=>uv,isTerminalAlternatives:()=>Vd,isTerminalElement:()=>cv,isTerminalGroup:()=>qd,isTerminalRule:()=>Nt,isTerminalRuleCall:()=>jl,isType:()=>Bl,isTypeAttribute:()=>fv,isTypeDefinition:()=>dv,isUnionType:()=>Hd,isUnorderedGroup:()=>Ul,isUntilToken:()=>Yd,isValueLiteral:()=>pv,isWildcard:()=>Xd,reflection:()=>j});var aN={ID:/\^?[_a-zA-Z][\w_]*/,STRING:/"(\\.|[^"\\])*"|'(\\.|[^'\\])*'/,NUMBER:/NaN|-?((\d*\.\d+|\d+)([Ee][+-]?\d+)?|Infinity)/,RegexLiteral:/\/(?![*+?])(?:[^\r\n\[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*\])+\/[a-z]*/,WS:/\s+/,ML_COMMENT:/\/\*[\s\S]*?\*\//,SL_COMMENT:/\/\/[^\n\r]*/},dt={$type:"AbstractElement",cardinality:"cardinality"};function Gl(e){return j.isInstance(e,dt.$type)}i(Gl,"isAbstractElement");var ns={$type:"AbstractParserRule"};function Gn(e){return j.isInstance(e,ns.$type)}i(Gn,"isAbstractParserRule");var Pa={$type:"AbstractRule"};function Zg(e){return j.isInstance(e,Pa.$type)}i(Zg,"isAbstractRule");var vt={$type:"AbstractType"};function Qg(e){return j.isInstance(e,vt.$type)}i(Qg,"isAbstractType");var xr={$type:"Action",cardinality:"cardinality",feature:"feature",inferredType:"inferredType",operator:"operator",type:"type"};function jr(e){return j.isInstance(e,xr.$type)}i(jr,"isAction");var as={$type:"Alternatives",cardinality:"cardinality",elements:"elements"};function Fl(e){return j.isInstance(e,as.$type)}i(Fl,"isAlternatives");var Xo={$type:"ArrayLiteral",elements:"elements"};function ev(e){return j.isInstance(e,Xo.$type)}i(ev,"isArrayLiteral");var Jo={$type:"ArrayType",elementType:"elementType"};function Od(e){return j.isInstance(e,Jo.$type)}i(Od,"isArrayType");var Mr={$type:"Assignment",cardinality:"cardinality",feature:"feature",operator:"operator",predicate:"predicate",terminal:"terminal"};function Rr(e){return j.isInstance(e,Mr.$type)}i(Rr,"isAssignment");var Zo={$type:"BooleanLiteral",true:"true"};function Ld(e){return j.isInstance(e,Zo.$type)}i(Ld,"isBooleanLiteral");var Gr={$type:"CharacterRange",cardinality:"cardinality",left:"left",lookahead:"lookahead",parenthesized:"parenthesized",right:"right"};function Dd(e){return j.isInstance(e,Gr.$type)}i(Dd,"isCharacterRange");var Fr={$type:"Condition"};function tv(e){return j.isInstance(e,Fr.$type)}i(tv,"isCondition");var is={$type:"Conjunction",left:"left",right:"right"};function xd(e){return j.isInstance(e,is.$type)}i(xd,"isConjunction");var zr={$type:"CrossReference",cardinality:"cardinality",deprecatedSyntax:"deprecatedSyntax",isMulti:"isMulti",terminal:"terminal",type:"type"};function Fn(e){return j.isInstance(e,zr.$type)}i(Fn,"isCrossReference");var ss={$type:"Disjunction",left:"left",right:"right"};function Md(e){return j.isInstance(e,ss.$type)}i(Md,"isDisjunction");var Qo={$type:"EndOfFile",cardinality:"cardinality"};function Gd(e){return j.isInstance(e,Qo.$type)}i(Gd,"isEndOfFile");var gr={$type:"Grammar",imports:"imports",interfaces:"interfaces",isDeclared:"isDeclared",name:"name",rules:"rules",types:"types"};function rv(e){return j.isInstance(e,gr.$type)}i(rv,"isGrammar");var el={$type:"GrammarImport",path:"path"};function nv(e){return j.isInstance(e,el.$type)}i(nv,"isGrammarImport");var mn={$type:"Group",cardinality:"cardinality",elements:"elements",guardCondition:"guardCondition",predicate:"predicate"};function zn(e){return j.isInstance(e,mn.$type)}i(zn,"isGroup");var tl={$type:"InferredType",name:"name"};function Fs(e){return j.isInstance(e,tl.$type)}i(Fs,"isInferredType");var Jt={$type:"InfixRule",call:"call",dataType:"dataType",inferredType:"inferredType",name:"name",operators:"operators",parameters:"parameters",returnType:"returnType"};function qa(e){return j.isInstance(e,Jt.$type)}i(qa,"isInfixRule");var os={$type:"InfixRuleOperatorList",associativity:"associativity",operators:"operators"};function av(e){return j.isInstance(e,os.$type)}i(av,"isInfixRuleOperatorList");var rl={$type:"InfixRuleOperators",precedences:"precedences"};function iv(e){return j.isInstance(e,rl.$type)}i(iv,"isInfixRuleOperators");var ka={$type:"Interface",attributes:"attributes",name:"name",superTypes:"superTypes"};function Fd(e){return j.isInstance(e,ka.$type)}i(Fd,"isInterface");var Oa={$type:"Keyword",cardinality:"cardinality",predicate:"predicate",value:"value"};function Ar(e){return j.isInstance(e,Oa.$type)}i(Ar,"isKeyword");var La={$type:"NamedArgument",calledByName:"calledByName",parameter:"parameter",value:"value"};function sv(e){return j.isInstance(e,La.$type)}i(sv,"isNamedArgument");var hn={$type:"NegatedToken",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",terminal:"terminal"};function zd(e){return j.isInstance(e,hn.$type)}i(zd,"isNegatedToken");var nl={$type:"Negation",value:"value"};function jd(e){return j.isInstance(e,nl.$type)}i(jd,"isNegation");var al={$type:"NumberLiteral",value:"value"};function ov(e){return j.isInstance(e,al.$type)}i(ov,"isNumberLiteral");var Da={$type:"Parameter",name:"name"};function lv(e){return j.isInstance(e,Da.$type)}i(lv,"isParameter");var il={$type:"ParameterReference",parameter:"parameter"};function Bd(e){return j.isInstance(e,il.$type)}i(Bd,"isParameterReference");var Lt={$type:"ParserRule",dataType:"dataType",definition:"definition",entry:"entry",fragment:"fragment",inferredType:"inferredType",name:"name",parameters:"parameters",returnType:"returnType"};function it(e){return j.isInstance(e,Lt.$type)}i(it,"isParserRule");var ls={$type:"ReferenceType",isMulti:"isMulti",referenceType:"referenceType"};function Ud(e){return j.isInstance(e,ls.$type)}i(Ud,"isReferenceType");var yn={$type:"RegexToken",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",regex:"regex"};function Kd(e){return j.isInstance(e,yn.$type)}i(Kd,"isRegexToken");var sl={$type:"ReturnType",name:"name"};function Wd(e){return j.isInstance(e,sl.$type)}i(Wd,"isReturnType");var gn={$type:"RuleCall",arguments:"arguments",cardinality:"cardinality",predicate:"predicate",rule:"rule"};function Er(e){return j.isInstance(e,gn.$type)}i(Er,"isRuleCall");var xa={$type:"SimpleType",primitiveType:"primitiveType",stringType:"stringType",typeRef:"typeRef"};function zl(e){return j.isInstance(e,xa.$type)}i(zl,"isSimpleType");var ol={$type:"StringLiteral",value:"value"};function uv(e){return j.isInstance(e,ol.$type)}i(uv,"isStringLiteral");var vn={$type:"TerminalAlternatives",cardinality:"cardinality",elements:"elements",lookahead:"lookahead",parenthesized:"parenthesized"};function Vd(e){return j.isInstance(e,vn.$type)}i(Vd,"isTerminalAlternatives");var pt={$type:"TerminalElement",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized"};function cv(e){return j.isInstance(e,pt.$type)}i(cv,"isTerminalElement");var Tn={$type:"TerminalGroup",cardinality:"cardinality",elements:"elements",lookahead:"lookahead",parenthesized:"parenthesized"};function qd(e){return j.isInstance(e,Tn.$type)}i(qd,"isTerminalGroup");var vr={$type:"TerminalRule",definition:"definition",fragment:"fragment",hidden:"hidden",name:"name",type:"type"};function Nt(e){return j.isInstance(e,vr.$type)}i(Nt,"isTerminalRule");var $n={$type:"TerminalRuleCall",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",rule:"rule"};function jl(e){return j.isInstance(e,$n.$type)}i(jl,"isTerminalRuleCall");var us={$type:"Type",name:"name",type:"type"};function Bl(e){return j.isInstance(e,us.$type)}i(Bl,"isType");var Rn={$type:"TypeAttribute",defaultValue:"defaultValue",isOptional:"isOptional",name:"name",type:"type"};function fv(e){return j.isInstance(e,Rn.$type)}i(fv,"isTypeAttribute");var An={$type:"TypeDefinition"};function dv(e){return j.isInstance(e,An.$type)}i(dv,"isTypeDefinition");var ll={$type:"UnionType",types:"types"};function Hd(e){return j.isInstance(e,ll.$type)}i(Hd,"isUnionType");var cs={$type:"UnorderedGroup",cardinality:"cardinality",elements:"elements"};function Ul(e){return j.isInstance(e,cs.$type)}i(Ul,"isUnorderedGroup");var En={$type:"UntilToken",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized",terminal:"terminal"};function Yd(e){return j.isInstance(e,En.$type)}i(Yd,"isUntilToken");var Cn={$type:"ValueLiteral"};function pv(e){return j.isInstance(e,Cn.$type)}i(pv,"isValueLiteral");var Ma={$type:"Wildcard",cardinality:"cardinality",lookahead:"lookahead",parenthesized:"parenthesized"};function Xd(e){return j.isInstance(e,Ma.$type)}i(Xd,"isWildcard");var Jd=class extends Id{static{i(this,"LangiumGrammarAstReflection")}constructor(){super(...arguments),this.types={AbstractElement:{name:dt.$type,properties:{cardinality:{name:dt.cardinality}},superTypes:[]},AbstractParserRule:{name:ns.$type,properties:{},superTypes:[Pa.$type,vt.$type]},AbstractRule:{name:Pa.$type,properties:{},superTypes:[]},AbstractType:{name:vt.$type,properties:{},superTypes:[]},Action:{name:xr.$type,properties:{cardinality:{name:xr.cardinality},feature:{name:xr.feature},inferredType:{name:xr.inferredType},operator:{name:xr.operator},type:{name:xr.type,referenceType:vt.$type}},superTypes:[dt.$type]},Alternatives:{name:as.$type,properties:{cardinality:{name:as.cardinality},elements:{name:as.elements,defaultValue:[]}},superTypes:[dt.$type]},ArrayLiteral:{name:Xo.$type,properties:{elements:{name:Xo.elements,defaultValue:[]}},superTypes:[Cn.$type]},ArrayType:{name:Jo.$type,properties:{elementType:{name:Jo.elementType}},superTypes:[An.$type]},Assignment:{name:Mr.$type,properties:{cardinality:{name:Mr.cardinality},feature:{name:Mr.feature},operator:{name:Mr.operator},predicate:{name:Mr.predicate},terminal:{name:Mr.terminal}},superTypes:[dt.$type]},BooleanLiteral:{name:Zo.$type,properties:{true:{name:Zo.true,defaultValue:!1}},superTypes:[Fr.$type,Cn.$type]},CharacterRange:{name:Gr.$type,properties:{cardinality:{name:Gr.cardinality},left:{name:Gr.left},lookahead:{name:Gr.lookahead},parenthesized:{name:Gr.parenthesized,defaultValue:!1},right:{name:Gr.right}},superTypes:[pt.$type]},Condition:{name:Fr.$type,properties:{},superTypes:[]},Conjunction:{name:is.$type,properties:{left:{name:is.left},right:{name:is.right}},superTypes:[Fr.$type]},CrossReference:{name:zr.$type,properties:{cardinality:{name:zr.cardinality},deprecatedSyntax:{name:zr.deprecatedSyntax,defaultValue:!1},isMulti:{name:zr.isMulti,defaultValue:!1},terminal:{name:zr.terminal},type:{name:zr.type,referenceType:vt.$type}},superTypes:[dt.$type]},Disjunction:{name:ss.$type,properties:{left:{name:ss.left},right:{name:ss.right}},superTypes:[Fr.$type]},EndOfFile:{name:Qo.$type,properties:{cardinality:{name:Qo.cardinality}},superTypes:[dt.$type]},Grammar:{name:gr.$type,properties:{imports:{name:gr.imports,defaultValue:[]},interfaces:{name:gr.interfaces,defaultValue:[]},isDeclared:{name:gr.isDeclared,defaultValue:!1},name:{name:gr.name},rules:{name:gr.rules,defaultValue:[]},types:{name:gr.types,defaultValue:[]}},superTypes:[]},GrammarImport:{name:el.$type,properties:{path:{name:el.path}},superTypes:[]},Group:{name:mn.$type,properties:{cardinality:{name:mn.cardinality},elements:{name:mn.elements,defaultValue:[]},guardCondition:{name:mn.guardCondition},predicate:{name:mn.predicate}},superTypes:[dt.$type]},InferredType:{name:tl.$type,properties:{name:{name:tl.name}},superTypes:[vt.$type]},InfixRule:{name:Jt.$type,properties:{call:{name:Jt.call},dataType:{name:Jt.dataType},inferredType:{name:Jt.inferredType},name:{name:Jt.name},operators:{name:Jt.operators},parameters:{name:Jt.parameters,defaultValue:[]},returnType:{name:Jt.returnType,referenceType:vt.$type}},superTypes:[ns.$type]},InfixRuleOperatorList:{name:os.$type,properties:{associativity:{name:os.associativity},operators:{name:os.operators,defaultValue:[]}},superTypes:[]},InfixRuleOperators:{name:rl.$type,properties:{precedences:{name:rl.precedences,defaultValue:[]}},superTypes:[]},Interface:{name:ka.$type,properties:{attributes:{name:ka.attributes,defaultValue:[]},name:{name:ka.name},superTypes:{name:ka.superTypes,defaultValue:[],referenceType:vt.$type}},superTypes:[vt.$type]},Keyword:{name:Oa.$type,properties:{cardinality:{name:Oa.cardinality},predicate:{name:Oa.predicate},value:{name:Oa.value}},superTypes:[dt.$type]},NamedArgument:{name:La.$type,properties:{calledByName:{name:La.calledByName,defaultValue:!1},parameter:{name:La.parameter,referenceType:Da.$type},value:{name:La.value}},superTypes:[]},NegatedToken:{name:hn.$type,properties:{cardinality:{name:hn.cardinality},lookahead:{name:hn.lookahead},parenthesized:{name:hn.parenthesized,defaultValue:!1},terminal:{name:hn.terminal}},superTypes:[pt.$type]},Negation:{name:nl.$type,properties:{value:{name:nl.value}},superTypes:[Fr.$type]},NumberLiteral:{name:al.$type,properties:{value:{name:al.value}},superTypes:[Cn.$type]},Parameter:{name:Da.$type,properties:{name:{name:Da.name}},superTypes:[]},ParameterReference:{name:il.$type,properties:{parameter:{name:il.parameter,referenceType:Da.$type}},superTypes:[Fr.$type]},ParserRule:{name:Lt.$type,properties:{dataType:{name:Lt.dataType},definition:{name:Lt.definition},entry:{name:Lt.entry,defaultValue:!1},fragment:{name:Lt.fragment,defaultValue:!1},inferredType:{name:Lt.inferredType},name:{name:Lt.name},parameters:{name:Lt.parameters,defaultValue:[]},returnType:{name:Lt.returnType,referenceType:vt.$type}},superTypes:[ns.$type]},ReferenceType:{name:ls.$type,properties:{isMulti:{name:ls.isMulti,defaultValue:!1},referenceType:{name:ls.referenceType}},superTypes:[An.$type]},RegexToken:{name:yn.$type,properties:{cardinality:{name:yn.cardinality},lookahead:{name:yn.lookahead},parenthesized:{name:yn.parenthesized,defaultValue:!1},regex:{name:yn.regex}},superTypes:[pt.$type]},ReturnType:{name:sl.$type,properties:{name:{name:sl.name}},superTypes:[]},RuleCall:{name:gn.$type,properties:{arguments:{name:gn.arguments,defaultValue:[]},cardinality:{name:gn.cardinality},predicate:{name:gn.predicate},rule:{name:gn.rule,referenceType:Pa.$type}},superTypes:[dt.$type]},SimpleType:{name:xa.$type,properties:{primitiveType:{name:xa.primitiveType},stringType:{name:xa.stringType},typeRef:{name:xa.typeRef,referenceType:vt.$type}},superTypes:[An.$type]},StringLiteral:{name:ol.$type,properties:{value:{name:ol.value}},superTypes:[Cn.$type]},TerminalAlternatives:{name:vn.$type,properties:{cardinality:{name:vn.cardinality},elements:{name:vn.elements,defaultValue:[]},lookahead:{name:vn.lookahead},parenthesized:{name:vn.parenthesized,defaultValue:!1}},superTypes:[pt.$type]},TerminalElement:{name:pt.$type,properties:{cardinality:{name:pt.cardinality},lookahead:{name:pt.lookahead},parenthesized:{name:pt.parenthesized,defaultValue:!1}},superTypes:[dt.$type]},TerminalGroup:{name:Tn.$type,properties:{cardinality:{name:Tn.cardinality},elements:{name:Tn.elements,defaultValue:[]},lookahead:{name:Tn.lookahead},parenthesized:{name:Tn.parenthesized,defaultValue:!1}},superTypes:[pt.$type]},TerminalRule:{name:vr.$type,properties:{definition:{name:vr.definition},fragment:{name:vr.fragment,defaultValue:!1},hidden:{name:vr.hidden,defaultValue:!1},name:{name:vr.name},type:{name:vr.type}},superTypes:[Pa.$type]},TerminalRuleCall:{name:$n.$type,properties:{cardinality:{name:$n.cardinality},lookahead:{name:$n.lookahead},parenthesized:{name:$n.parenthesized,defaultValue:!1},rule:{name:$n.rule,referenceType:vr.$type}},superTypes:[pt.$type]},Type:{name:us.$type,properties:{name:{name:us.name},type:{name:us.type}},superTypes:[vt.$type]},TypeAttribute:{name:Rn.$type,properties:{defaultValue:{name:Rn.defaultValue},isOptional:{name:Rn.isOptional,defaultValue:!1},name:{name:Rn.name},type:{name:Rn.type}},superTypes:[]},TypeDefinition:{name:An.$type,properties:{},superTypes:[]},UnionType:{name:ll.$type,properties:{types:{name:ll.types,defaultValue:[]}},superTypes:[An.$type]},UnorderedGroup:{name:cs.$type,properties:{cardinality:{name:cs.cardinality},elements:{name:cs.elements,defaultValue:[]}},superTypes:[dt.$type]},UntilToken:{name:En.$type,properties:{cardinality:{name:En.cardinality},lookahead:{name:En.lookahead},parenthesized:{name:En.parenthesized,defaultValue:!1},terminal:{name:En.terminal}},superTypes:[pt.$type]},ValueLiteral:{name:Cn.$type,properties:{},superTypes:[]},Wildcard:{name:Ma.$type,properties:{cardinality:{name:Ma.cardinality},lookahead:{name:Ma.lookahead},parenthesized:{name:Ma.parenthesized,defaultValue:!1}},superTypes:[pt.$type]}}}},j=new Jd;function mv(e){let t=e,r=!1;for(;t;){const n=Mn(t.grammarSource,it);if(n&&n.dataType)t=t.container,r=!0;else return r?t:void 0}}i(mv,"getDatatypeNode");function Ha(e){return new Ka(e,t=>$r(t)?t.content:[],{includeRoot:!0})}i(Ha,"streamCst");function hv(e){return Ha(e).filter(xn)}i(hv,"flattenCst");function Zd(e,t){for(;e.container;)if(e=e.container,e===t)return!0;return!1}i(Zd,"isChildNode");function $s(e){return{start:{character:e.startColumn-1,line:e.startLine-1},end:{character:e.endColumn,line:e.endLine-1}}}i($s,"tokenToRange");function Ya(e){if(!e)return;const{offset:t,end:r,range:n}=e;return{range:n,offset:t,end:r,length:r-t}}i(Ya,"toDocumentSegment");var Qt;(function(e){e[e.Before=0]="Before",e[e.After=1]="After",e[e.OverlapFront=2]="OverlapFront",e[e.OverlapBack=3]="OverlapBack",e[e.Inside=4]="Inside",e[e.Outside=5]="Outside"})(Qt||(Qt={}));function Qd(e,t){if(e.end.linet.end.line||e.start.line===t.end.line&&e.start.character>=t.end.character)return Qt.After;const r=e.start.line>t.start.line||e.start.line===t.start.line&&e.start.character>=t.start.character,n=e.end.lineQt.After}i(ep,"inRange");var tp=/^[\w\p{L}]$/u;function yv(e,t,r=tp){if(e){if(t>0){const n=t-e.offset,a=e.text.charAt(n);r.test(a)||t--}return Kl(e,t)}}i(yv,"findDeclarationNodeAtOffset");function rp(e,t){if(e){const r=ip(e,!0);if(r&&ul(r,t))return r;if(Ml(e)){const n=e.content.findIndex(a=>!a.hidden);for(let a=n-1;a>=0;a--){const s=e.content[a];if(ul(s,t))return s}}}}i(rp,"findCommentNode");function ul(e,t){return xn(e)&&t.includes(e.tokenType.name)}i(ul,"isCommentNode");function Kl(e,t){if(xn(e))return e;if($r(e)){const r=ap(e,t,!1);if(r)return Kl(r,t)}}i(Kl,"findLeafNodeAtOffset");function np(e,t){if(xn(e))return e;if($r(e)){const r=ap(e,t,!0);if(r)return np(r,t)}}i(np,"findLeafNodeBeforeOffset");function ap(e,t,r){let n=0,a=e.content.length-1,s;for(;n<=a;){const o=Math.floor((n+a)/2),l=e.content[o];if(l.offset<=t&&l.end>t)return l;l.end<=t?(s=r?l:void 0,n=o+1):a=o-1}return s}i(ap,"binarySearch");function ip(e,t=!0){for(;e.container;){const r=e.container;let n=r.content.indexOf(e);for(;n>0;){n--;const a=r.content[n];if(t||!a.hidden)return a}e=r}}i(ip,"getPreviousNode");function gv(e,t=!0){for(;e.container;){const r=e.container;let n=r.content.indexOf(e);const a=r.content.length-1;for(;nTp,findNameAssignment:()=>Zl,findNodeForKeyword:()=>vp,findNodeForProperty:()=>Yl,findNodesForKeyword:()=>wv,findNodesForKeywordInternal:()=>Jl,findNodesForProperty:()=>gp,getActionAtElement:()=>Rp,getActionType:()=>Ep,getAllReachableRules:()=>Hl,getAllRulesUsedForCrossReferences:()=>Sv,getCrossReferenceTerminal:()=>hp,getEntryRule:()=>dp,getExplicitRuleType:()=>js,getHiddenRules:()=>pp,getRuleType:()=>Cp,getRuleTypeName:()=>Ov,getTypeName:()=>Pn,isArrayCardinality:()=>Nv,isArrayOperator:()=>Pv,isCommentTerminal:()=>yp,isDataType:()=>kv,isDataTypeRule:()=>zs,isOptionalCardinality:()=>Iv,terminalRegex:()=>Bs});var Wl=class extends Error{static{i(this,"ErrorWithLocation")}constructor(e,t){super(e?`${t} at ${e.range.start.line}:${e.range.start.character}`:t)}};function qr(e,t="Error: Got unexpected value."){throw new Error(t)}i(qr,"assertUnreachable");function op(e,t="Error: Condition is violated."){if(!e)throw new Error(t)}i(op,"assertCondition");var lp={};Vr(lp,{NEWLINE_REGEXP:()=>Ev,escapeRegExp:()=>ri,getTerminalParts:()=>bv,isMultilineComment:()=>up,isWhitespace:()=>ql,partialMatches:()=>cp,partialRegExp:()=>fp,whitespaceCharacters:()=>_v});function U(e){return e.charCodeAt(0)}i(U,"cc");function Po(e,t){Array.isArray(e)?e.forEach(function(r){t.push(r)}):t.push(e)}i(Po,"insertToSet");function $a(e,t){if(e[t]===!0)throw"duplicate flag "+t;e[t],e[t]=!0}i($a,"addFlag");function sn(e){if(e===void 0)throw Error("Internal Error - Should never get here!");return!0}i(sn,"ASSERT_EXISTS");function Rv(){throw Error("Internal Error - Should never get here!")}i(Rv,"ASSERT_NEVER_REACH_HERE");function Cf(e){return e.type==="Character"}i(Cf,"isCharacter");var cl=[];for(let e=U("0");e<=U("9");e++)cl.push(e);var fl=[U("_")].concat(cl);for(let e=U("a");e<=U("z");e++)fl.push(e);for(let e=U("A");e<=U("Z");e++)fl.push(e);var ch=[U(" "),U("\f"),U(` +`),U("\r"),U(" "),U("\v"),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U(" "),U("\u2028"),U("\u2029"),U(" "),U(" "),U(" "),U("\uFEFF")],iN=/[0-9a-fA-F]/,ao=/[0-9]/,sN=/[1-9]/,Av=class{static{i(this,"RegExpParser")}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 t=this.disjunction();this.consumeChar("/");const r={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":$a(r,"global");break;case"i":$a(r,"ignoreCase");break;case"m":$a(r,"multiLine");break;case"u":$a(r,"unicode");break;case"y":$a(r,"sticky");break}if(this.idx!==this.input.length)throw Error("Redundant input: "+this.input.substring(this.idx));return{type:"Pattern",flags:r,value:t,loc:this.loc(0)}}disjunction(){const e=[],t=this.idx;for(e.push(this.alternative());this.peekChar()==="|";)this.consumeChar("|"),e.push(this.alternative());return{type:"Disjunction",value:e,loc:this.loc(t)}}alternative(){const e=[],t=this.idx;for(;this.isTerm();)e.push(this.term());return{type:"Alternative",value:e,loc:this.loc(t)}}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 t;switch(this.popChar()){case"=":t="Lookahead";break;case"!":t="NegativeLookahead";break;case"<":{switch(this.popChar()){case"=":t="Lookbehind";break;case"!":t="NegativeLookbehind"}break}}sn(t);const r=this.disjunction();return this.consumeChar(")"),{type:t,value:r,loc:this.loc(e)}}return Rv()}quantifier(e=!1){let t;const r=this.idx;switch(this.popChar()){case"*":t={atLeast:0,atMost:1/0};break;case"+":t={atLeast:1,atMost:1/0};break;case"?":t={atLeast:0,atMost:1};break;case"{":const n=this.integerIncludingZero();switch(this.popChar()){case"}":t={atLeast:n,atMost:n};break;case",":let a;this.isDigit()?(a=this.integerIncludingZero(),t={atLeast:n,atMost:a}):t={atLeast:n,atMost:1/0},this.consumeChar("}");break}if(e===!0&&t===void 0)return;sn(t);break}if(!(e===!0&&t===void 0)&&sn(t))return this.peekChar(0)==="?"?(this.consumeChar("?"),t.greedy=!1):t.greedy=!0,t.type="Quantifier",t.loc=this.loc(r),t}atom(){let e;const t=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()),sn(e))return e.loc=this.loc(t),this.isQuantifier()&&(e.quantifier=this.quantifier()),e}dotAll(){return this.consumeChar("."),{type:"Set",complement:!0,value:[U(` +`),U("\r"),U("\u2028"),U("\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,t=!1;switch(this.popChar()){case"d":e=cl;break;case"D":e=cl,t=!0;break;case"s":e=ch;break;case"S":e=ch,t=!0;break;case"w":e=fl;break;case"W":e=fl,t=!0;break}if(sn(e))return{type:"Set",value:e,complement:t}}controlEscapeAtom(){let e;switch(this.popChar()){case"f":e=U("\f");break;case"n":e=U(` +`);break;case"r":e=U("\r");break;case"t":e=U(" ");break;case"v":e=U("\v");break}if(sn(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:U("\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:U(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:U(e)}}}characterClass(){const e=[];let t=!1;for(this.consumeChar("["),this.peekChar(0)==="^"&&(this.consumeChar("^"),t=!0);this.isClassAtom();){const r=this.classAtom();if(r.type,Cf(r)&&this.isRangeDash()){this.consumeChar("-");const n=this.classAtom();if(n.type,Cf(n)){if(n.value=this.input.length)throw Error("Unexpected end of input");this.idx++}loc(e){return{begin:e,end:this.idx}}},Vl=class{static{i(this,"BaseRegExpVisitor")}visitChildren(e){for(const t in e){const r=e[t];e.hasOwnProperty(t)&&(r.type!==void 0?this.visit(r):Array.isArray(r)&&r.forEach(n=>{this.visit(n)},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){}},Ev=/\r?\n/gm,Cv=new Av,oN=class extends Vl{static{i(this,"TerminalRegExpVisitor")}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 t=String.fromCharCode(e.value);if(!this.multiline&&t===` +`&&(this.multiline=!0),e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const r=ri(t);this.endRegexpStack.push(r),this.isStarting&&(this.startRegexp+=r)}}visitSet(e){if(!this.multiline){const t=this.regex.substring(e.loc.begin,e.loc.end),r=new RegExp(t);this.multiline=!!` +`.match(r)}if(e.quantifier)this.isStarting=!1,this.endRegexpStack=[];else{const t=this.regex.substring(e.loc.begin,e.loc.end);this.endRegexpStack.push(t),this.isStarting&&(this.startRegexp+=t)}}visitChildren(e){e.type==="Group"&&e.quantifier||super.visitChildren(e)}},bn=new oN;function bv(e){try{typeof e!="string"&&(e=e.source),e=`/${e}/`;const t=Cv.pattern(e),r=[];for(const n of t.value.value)bn.reset(e),bn.visit(n),r.push({start:bn.startRegexp,end:bn.endRegex});return r}catch{return[]}}i(bv,"getTerminalParts");function up(e){try{return typeof e=="string"&&(e=new RegExp(e)),e=e.toString(),bn.reset(e),bn.visit(Cv.pattern(e)),bn.multiline}catch{return!1}}i(up,"isMultilineComment");var _v=`\f +\r \v              \u2028\u2029   \uFEFF`.split("");function ql(e){const t=typeof e=="string"?new RegExp(e):e;return _v.some(r=>t.test(r))}i(ql,"isWhitespace");function ri(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}i(ri,"escapeRegExp");function cp(e,t){const r=fp(e),n=t.match(r);return!!n&&n[0].length>0}i(cp,"partialMatches");function fp(e){typeof e=="string"&&(e=new RegExp(e));const t=e,r=e.source;let n=0;function a(){let s="",o;function l(c){s+=r.substr(n,c),n+=c}i(l,"appendRaw");function u(c){s+="(?:"+r.substr(n,c)+"|$)",n+=c}for(i(u,"appendOptional");n",n)-n+1);break;default:u(2);break}break;case"[":o=/\[(?:\\.|.)*?\]/g,o.lastIndex=n,o=o.exec(r)||[],u(o[0].length);break;case"|":case"^":case"$":case"*":case"+":case"?":l(1);break;case"{":o=/\{\d+,?\d*\}/g,o.lastIndex=n,o=o.exec(r),o?l(o[0].length):u(1);break;case"(":if(r[n+1]==="?")switch(r[n+2]){case":":s+="(?:",n+=3,s+=a()+"|$)";break;case"=":s+="(?=",n+=3,s+=a()+")";break;case"!":o=n,n+=3,a(),s+=r.substr(o,n-o);break;case"<":switch(r[n+3]){case"=":case"!":o=n,n+=4,a(),s+=r.substr(o,n-o);break;default:l(r.indexOf(">",n)-n+1),s+=a()+"|$)";break}break}else l(1),s+=a()+"|$)";break;case")":return++n,s;default:u(1);break}return s}return i(a,"process"),new RegExp(a(),e.flags)}i(fp,"partialRegExp");function dp(e){return e.rules.find(t=>it(t)&&t.entry)}i(dp,"getEntryRule");function pp(e){return e.rules.filter(t=>Nt(t)&&t.hidden)}i(pp,"getHiddenRules");function Hl(e,t){const r=new Set,n=dp(e);if(!n)return new Set(e.rules);const a=[n].concat(pp(e));for(const o of a)mp(o,r,t);const s=new Set;for(const o of e.rules)(r.has(o.name)||Nt(o)&&o.hidden)&&s.add(o);return s}i(Hl,"getAllReachableRules");function mp(e,t,r){t.add(e.name),Nr(e).forEach(n=>{if(Er(n)||r&&jl(n)){const a=n.rule.ref;a&&!t.has(a.name)&&mp(a,t,r)}})}i(mp,"ruleDfs");function Sv(e){const t=new Set;return Nr(e).forEach(r=>{Fn(r)&&(it(r.type.ref)&&t.add(r.type.ref),Fs(r.type.ref)&&it(r.type.ref.$container)&&t.add(r.type.ref.$container))}),t}i(Sv,"getAllRulesUsedForCrossReferences");function hp(e){if(e.terminal)return e.terminal;if(e.type.ref)return Zl(e.type.ref)?.terminal}i(hp,"getCrossReferenceTerminal");function yp(e){return e.hidden&&!ql(Bs(e))}i(yp,"isCommentTerminal");function gp(e,t){return!e||!t?[]:Xl(e,t,e.astNode,!0)}i(gp,"findNodesForProperty");function Yl(e,t,r){if(!e||!t)return;const n=Xl(e,t,e.astNode,!0);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}i(Yl,"findNodeForProperty");function Xl(e,t,r,n){if(!n){const a=Mn(e.grammarSource,Rr);if(a&&a.feature===t)return[e]}return $r(e)&&e.astNode===r?e.content.flatMap(a=>Xl(a,t,r,!1)):[]}i(Xl,"findNodesForPropertyInternal");function wv(e,t){return e?Jl(e,t,e?.astNode):[]}i(wv,"findNodesForKeyword");function vp(e,t,r){if(!e)return;const n=Jl(e,t,e?.astNode);if(n.length!==0)return r!==void 0?r=Math.max(0,Math.min(r,n.length-1)):r=0,n[r]}i(vp,"findNodeForKeyword");function Jl(e,t,r){if(e.astNode!==r)return[];if(Ar(e.grammarSource)&&e.grammarSource.value===t)return[e];const n=Ha(e).iterator();let a;const s=[];do if(a=n.next(),!a.done){const o=a.value;o.astNode===r?Ar(o.grammarSource)&&o.grammarSource.value===t&&s.push(o):n.prune()}while(!a.done);return s}i(Jl,"findNodesForKeywordInternal");function Tp(e){const t=e.astNode;for(;t===e.container?.astNode;){const r=Mn(e.grammarSource,Rr);if(r)return r;e=e.container}}i(Tp,"findAssignment");function Zl(e){let t=e;return Fs(t)&&(jr(t.$container)?t=t.$container.$container:Gn(t.$container)?t=t.$container:qr(t.$container)),$p(e,t,new Map)}i(Zl,"findNameAssignment");function $p(e,t,r){function n(a,s){let o;return Mn(a,Rr)||(o=$p(s,s,r)),r.set(e,o),o}if(i(n,"go"),r.has(e))return r.get(e);r.set(e,void 0);for(const a of Nr(t)){if(Rr(a)&&a.feature.toLowerCase()==="name")return r.set(e,a),a;if(Er(a)&&it(a.rule.ref))return n(a,a.rule.ref);if(zl(a)&&a.typeRef?.ref)return n(a,a.typeRef.ref)}}i($p,"findNameAssignmentInternal");function Rp(e){const t=e.$container;if(zn(t)){const r=t.elements,n=r.indexOf(e);for(let a=n-1;a>=0;a--){const s=r[a];if(jr(s))return s;{const o=Nr(r[a]).find(jr);if(o)return o}}}if(Gl(t))return Rp(t)}i(Rp,"getActionAtElement");function Iv(e,t){return e==="?"||e==="*"||zn(t)&&!!t.guardCondition}i(Iv,"isOptionalCardinality");function Nv(e){return e==="*"||e==="+"}i(Nv,"isArrayCardinality");function Pv(e){return e==="+="}i(Pv,"isArrayOperator");function zs(e){return Ap(e,new Set)}i(zs,"isDataTypeRule");function Ap(e,t){if(t.has(e))return!0;t.add(e);for(const r of Nr(e))if(Er(r)){if(!r.rule.ref||it(r.rule.ref)&&!Ap(r.rule.ref,t)||qa(r.rule.ref))return!1}else{if(Rr(r))return!1;if(jr(r))return!1}return!!e.definition}i(Ap,"isDataTypeRuleInternal");function kv(e){return dl(e.type,new Set)}i(kv,"isDataType");function dl(e,t){if(t.has(e))return!0;if(t.add(e),Od(e))return!1;if(Ud(e))return!1;if(Hd(e))return e.types.every(r=>dl(r,t));if(zl(e)){if(e.primitiveType!==void 0)return!0;if(e.stringType!==void 0)return!0;if(e.typeRef!==void 0){const r=e.typeRef.ref;return Bl(r)?dl(r.type,t):!1}else return!1}else return!1}i(dl,"isDataTypeInternal");function js(e){if(!Nt(e)){if(e.inferredType)return e.inferredType.name;if(e.dataType)return e.dataType;if(e.returnType){const t=e.returnType.ref;if(t)return t.name}}}i(js,"getExplicitRuleType");function Pn(e){if(Gn(e))return it(e)&&zs(e)?e.name:js(e)??e.name;if(Fd(e)||Bl(e)||Wd(e))return e.name;if(jr(e)){const t=Ep(e);if(t)return t}else if(Fs(e))return e.name;throw new Error("Cannot get name of Unknown Type")}i(Pn,"getTypeName");function Ep(e){if(e.inferredType)return e.inferredType.name;if(e.type?.ref)return Pn(e.type.ref)}i(Ep,"getActionType");function Ov(e){return Nt(e)?e.type?.name??"string":it(e)&&zs(e)?e.name:js(e)??e.name}i(Ov,"getRuleTypeName");function Cp(e){return Nt(e)?e.type?.name??"string":js(e)??e.name}i(Cp,"getRuleType");function Bs(e){const t={s:!1,i:!1,u:!1},r=jn(e.definition,t),n=Object.entries(t).filter(([,a])=>a).map(([a])=>a).join("");return new RegExp(r,n)}i(Bs,"terminalRegex");var bp=/[\s\S]/.source;function jn(e,t){if(Vd(e))return Lv(e);if(qd(e))return Dv(e);if(Dd(e))return Gv(e);if(jl(e)){const r=e.rule.ref;if(!r)throw new Error("Missing rule reference.");return nr(jn(r.definition),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized})}else{if(zd(e))return Mv(e);if(Yd(e))return xv(e);if(Kd(e)){const r=e.regex.lastIndexOf("/"),n=e.regex.substring(1,r),a=e.regex.substring(r+1);return t&&(t.i=a.includes("i"),t.s=a.includes("s"),t.u=a.includes("u")),nr(n,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}else{if(Xd(e))return nr(bp,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized});throw new Error(`Invalid terminal element: ${e?.$type}, ${e?.$cstNode?.text}`)}}}i(jn,"abstractElementToRegex");function Lv(e){return nr(e.elements.map(t=>jn(t)).join("|"),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}i(Lv,"terminalAlternativesToRegex");function Dv(e){return nr(e.elements.map(t=>jn(t)).join(""),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}i(Dv,"terminalGroupToRegex");function xv(e){return nr(`${bp}*?${jn(e.terminal)}`,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized})}i(xv,"untilTokenToRegex");function Mv(e){return nr(`(?!${jn(e.terminal)})${bp}*?`,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized})}i(Mv,"negateTokenToRegex");function Gv(e){return e.right?nr(`[${ko(e.left)}-${ko(e.right)}]`,{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1}):nr(ko(e.left),{cardinality:e.cardinality,lookahead:e.lookahead,parenthesized:e.parenthesized,wrap:!1})}i(Gv,"characterRangeToRegex");function ko(e){return ri(e.value)}i(ko,"keywordToRegex");function nr(e,t){return(t.parenthesized||t.lookahead||t.wrap!==!1)&&(e=`(${t.lookahead??(t.parenthesized?"":"?:")}${e})`),t.cardinality?`${e}${t.cardinality}`:e}i(nr,"withCardinality");function _p(e){const t=[],r=e.Grammar;for(const n of r.rules)Nt(n)&&yp(n)&&up(Bs(n))&&t.push(n.name);return{multilineCommentRules:t,nameRegexp:tp}}i(_p,"createGrammarConfig");var lN=typeof global=="object"&&global&&global.Object===Object&&global,Fv=lN,uN=typeof self=="object"&&self&&self.Object===Object&&self,cN=Fv||uN||Function("return this")(),ir=cN,fN=ir.Symbol,wt=fN,zv=Object.prototype,dN=zv.hasOwnProperty,pN=zv.toString,Oi=wt?wt.toStringTag:void 0;function jv(e){var t=dN.call(e,Oi),r=e[Oi];try{e[Oi]=void 0;var n=!0}catch{}var a=pN.call(e);return n&&(t?e[Oi]=r:delete e[Oi]),a}i(jv,"getRawTag");var mN=jv,hN=Object.prototype,yN=hN.toString;function Bv(e){return yN.call(e)}i(Bv,"objectToString");var gN=Bv,vN="[object Null]",TN="[object Undefined]",fh=wt?wt.toStringTag:void 0;function Uv(e){return e==null?e===void 0?TN:vN:fh&&fh in Object(e)?mN(e):gN(e)}i(Uv,"baseGetTag");var Hr=Uv;function Kv(e){return e!=null&&typeof e=="object"}i(Kv,"isObjectLike");var jt=Kv,$N="[object Symbol]";function Wv(e){return typeof e=="symbol"||jt(e)&&Hr(e)==$N}i(Wv,"isSymbol");var Ql=Wv;function Vv(e,t){for(var r=-1,n=e==null?0:e.length,a=Array(n);++r0){if(++t>=rP)return arguments[0]}else t=0;return e.apply(void 0,arguments)}}i(uT,"shortOut");var iP=uT;function cT(e){return function(){return e}}i(cT,"constant");var sP=cT,oP=(function(){try{var e=Un(Object,"defineProperty");return e({},"",{}),e}catch{}})(),pl=oP,lP=pl?function(e,t){return pl(e,"toString",{configurable:!0,enumerable:!1,value:sP(t),writable:!0})}:Ws,uP=lP,cP=iP(uP),fP=cP;function fT(e,t){for(var r=-1,n=e==null?0:e.length;++r-1}i(vT,"arrayIncludes");var TT=vT,mP=9007199254740991,hP=/^(?:0|[1-9]\d*)$/;function $T(e,t){var r=typeof e;return t=t??mP,!!t&&(r=="number"||r!="symbol"&&hP.test(e))&&e>-1&&e%1==0&&e-1&&e%1==0&&e<=TP}i(ST,"isLength");var Pp=ST;function wT(e){return e!=null&&Pp(e.length)&&!Pr(e)}i(wT,"isArrayLike");var sr=wT;function IT(e,t,r){if(!It(r))return!1;var n=typeof t;return(n=="number"?sr(r)&&eu(t,r.length):n=="string"&&t in r)?Vs(r[t],e):!1}i(IT,"isIterateeCall");var ru=IT;function NT(e){return Np(function(t,r){var n=-1,a=r.length,s=a>1?r[a-1]:void 0,o=a>2?r[2]:void 0;for(s=e.length>3&&typeof s=="function"?(a--,s):void 0,o&&ru(r[0],r[1],o)&&(s=a<3?void 0:s,a=1),t=Object(t);++n-1}i(s$,"listCacheHas");var Mk=s$;function o$(e,t){var r=this.__data__,n=iu(r,e);return n<0?(++this.size,r.push([e,t])):r[n][1]=t,this}i(o$,"listCacheSet");var Gk=o$;function Wn(e){var t=-1,r=e==null?0:e.length;for(this.clear();++t0&&r(l)?t>1?xp(l,t-1,r,n,a):Dp(a,l):n||(a[a.length]=l)}return a}i(xp,"baseFlatten");var Mp=xp;function E$(e){var t=e==null?0:e.length;return t?Mp(e,1):[]}i(E$,"flatten");var Ft=E$,nO=UT(Object.getPrototypeOf,Object),C$=nO;function b$(e,t,r){var n=-1,a=e.length;t<0&&(t=-t>a?0:a+t),r=r>a?a:r,r<0&&(r+=a),a=t>r?0:r-t>>>0,t>>>=0;for(var s=Array(a);++nl))return!1;var c=s.get(e),f=s.get(t);if(c&&f)return c==t&&f==e;var d=-1,m=!0,g=r&q0?new jp:void 0;for(s.set(e,t),s.set(t,e);++d2?t[2]:void 0;for(a&&ru(t[0],t[1],a)&&(n=1);++r=zL&&(s=Bp,o=!1,t=new jp(t));e:for(;++a-1?a[s?t[o]:o]:void 0}}i(sA,"createFind");var VL=sA,qL=Math.max;function oA(e,t,r){var n=e==null?0:e.length;if(!n)return-1;var a=r==null?0:Ks(r);return a<0&&(a=qL(n+a,0)),mT(e,or(t),a)}i(oA,"findIndex");var HL=oA,YL=VL(HL),Ja=YL;function lA(e){return e&&e.length?e[0]:void 0}i(lA,"head");var Bt=lA;function uA(e,t){var r=-1,n=sr(e)?Array(e.length):[];return Hn(e,function(a,s,o){n[++r]=t(a,s,o)}),n}i(uA,"baseMap");var XL=uA;function cA(e,t){var r=re(e)?Us:XL;return r(e,or(t))}i(cA,"map");var F=cA;function fA(e,t){return Mp(F(e,t),1)}i(fA,"flatMap");var St=fA,JL=Object.prototype,ZL=JL.hasOwnProperty,QL=ML(function(e,t,r){ZL.call(e,r)?e[r].push(t):Ip(e,r,[t])}),eD=QL,tD=Object.prototype,rD=tD.hasOwnProperty;function dA(e,t){return e!=null&&rD.call(e,t)}i(dA,"baseHas");var nD=dA;function pA(e,t){return e!=null&&PR(e,t,nD)}i(pA,"has");var B=pA,aD="[object String]";function mA(e){return typeof e=="string"||!re(e)&&jt(e)&&Hr(e)==aD}i(mA,"isString");var mt=mA;function hA(e,t){return Us(t,function(r){return e[r]})}i(hA,"baseValues");var iD=hA;function yA(e){return e==null?[]:iD(e,$t(e))}i(yA,"values");var Me=yA,sD=Math.max;function gA(e,t,r,n){e=sr(e)?e:Me(e),r=r&&!n?Ks(r):0;var a=e.length;return r<0&&(r=sD(a+r,0)),mt(e)?r<=a&&e.indexOf(t,r)>-1:!!a&&wp(e,t,r)>-1}i(gA,"includes");var ut=gA,oD=Math.max;function vA(e,t,r){var n=e==null?0:e.length;if(!n)return-1;var a=r==null?0:Ks(r);return a<0&&(a=oD(n+a,0)),wp(e,t,a)}i(vA,"indexOf");var Uh=vA,lD="[object Map]",uD="[object Set]",cD=Object.prototype,fD=cD.hasOwnProperty;function TA(e){if(e==null)return!0;if(sr(e)&&(re(e)||typeof e=="string"||typeof e.splice=="function"||Rs(e)||kp(e)||nu(e)))return!e.length;var t=Xa(e);if(t==lD||t==uD)return!e.size;if(Hs(e))return!WT(e).length;for(var r in e)if(fD.call(e,r))return!1;return!0}i(TA,"isEmpty");var me=TA,dD="[object RegExp]";function $A(e){return jt(e)&&Hr(e)==dD}i($A,"baseIsRegExp");var pD=$A,Kh=Br&&Br.isRegExp,mD=Kh?Ys(Kh):pD,Cr=mD;function RA(e){return e===void 0}i(RA,"isUndefined");var br=RA,hD="Expected a function";function AA(e){if(typeof e!="function")throw new TypeError(hD);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}i(AA,"negate");var yD=AA;function EA(e,t,r,n){if(!It(e))return e;t=cu(t,e);for(var a=-1,s=t.length,o=s-1,l=e;l!=null&&++a=CD){var c=t?null:ED(e);if(c)return Up(c);o=!1,a=Bp,u=new jp}else u=t?[]:l;e:for(;++n{t.accept(e)})}},st=class extends lr{static{i(this,"NonTerminal")}constructor(e){super([]),this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}set definition(e){}get definition(){return this.referencedRule!==void 0?this.referencedRule.definition:[]}accept(e){e.visit(this)}},ni=class extends lr{static{i(this,"Rule")}constructor(e){super(e.definition),this.orgText="",Rt(this,Ut(e,t=>t!==void 0))}},ht=class extends lr{static{i(this,"Alternative")}constructor(e){super(e.definition),this.ignoreAmbiguities=!1,Rt(this,Ut(e,t=>t!==void 0))}},He=class extends lr{static{i(this,"Option")}constructor(e){super(e.definition),this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}},Et=class extends lr{static{i(this,"RepetitionMandatory")}constructor(e){super(e.definition),this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}},Ct=class extends lr{static{i(this,"RepetitionMandatoryWithSeparator")}constructor(e){super(e.definition),this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}},be=class extends lr{static{i(this,"Repetition")}constructor(e){super(e.definition),this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}},yt=class extends lr{static{i(this,"RepetitionWithSeparator")}constructor(e){super(e.definition),this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}},gt=class extends lr{static{i(this,"Alternation")}get definition(){return this._definition}set definition(e){this._definition=e}constructor(e){super(e.definition),this.idx=1,this.ignoreAmbiguities=!1,this.hasPredicates=!1,Rt(this,Ut(e,t=>t!==void 0))}},ve=class{static{i(this,"Terminal")}constructor(e){this.idx=1,Rt(this,Ut(e,t=>t!==void 0))}accept(e){e.visit(this)}};function xA(e){return F(e,ms)}i(xA,"serializeGrammar");function ms(e){function t(r){return F(r,ms)}if(i(t,"convertDefinition"),e instanceof st){const r={type:"NonTerminal",name:e.nonTerminalName,idx:e.idx};return mt(e.label)&&(r.label=e.label),r}else{if(e instanceof ht)return{type:"Alternative",definition:t(e.definition)};if(e instanceof He)return{type:"Option",idx:e.idx,definition:t(e.definition)};if(e instanceof Et)return{type:"RepetitionMandatory",idx:e.idx,definition:t(e.definition)};if(e instanceof Ct)return{type:"RepetitionMandatoryWithSeparator",idx:e.idx,separator:ms(new ve({terminalType:e.separator})),definition:t(e.definition)};if(e instanceof yt)return{type:"RepetitionWithSeparator",idx:e.idx,separator:ms(new ve({terminalType:e.separator})),definition:t(e.definition)};if(e instanceof be)return{type:"Repetition",idx:e.idx,definition:t(e.definition)};if(e instanceof gt)return{type:"Alternation",idx:e.idx,definition:t(e.definition)};if(e instanceof ve){const r={type:"Terminal",name:e.terminalType.name,label:LA(e.terminalType),idx:e.idx};mt(e.label)&&(r.terminalLabel=e.label);const n=e.terminalType.PATTERN;return e.terminalType.PATTERN&&(r.pattern=Cr(n)?n.source:n),r}else{if(e instanceof ni)return{type:"Rule",name:e.name,orgText:e.orgText,definition:t(e.definition)};throw Error("non exhaustive match")}}}i(ms,"serializeProduction");var ai=class{static{i(this,"GAstVisitor")}visit(e){const t=e;switch(t.constructor){case st:return this.visitNonTerminal(t);case ht:return this.visitAlternative(t);case He:return this.visitOption(t);case Et:return this.visitRepetitionMandatory(t);case Ct:return this.visitRepetitionMandatoryWithSeparator(t);case yt:return this.visitRepetitionWithSeparator(t);case be:return this.visitRepetition(t);case gt:return this.visitAlternation(t);case ve:return this.visitTerminal(t);case ni:return this.visitRule(t);default:throw Error("non exhaustive match")}}visitNonTerminal(e){}visitAlternative(e){}visitOption(e){}visitRepetition(e){}visitRepetitionMandatory(e){}visitRepetitionMandatoryWithSeparator(e){}visitRepetitionWithSeparator(e){}visitAlternation(e){}visitTerminal(e){}visitRule(e){}};function MA(e){return e instanceof ht||e instanceof He||e instanceof be||e instanceof Et||e instanceof Ct||e instanceof yt||e instanceof ve||e instanceof ni}i(MA,"isSequenceProd");function _s(e,t=[]){return e instanceof He||e instanceof be||e instanceof yt?!0:e instanceof gt?PA(e.definition,n=>_s(n,t)):e instanceof st&&ut(t,e)?!1:e instanceof lr?(e instanceof st&&t.push(e),zt(e.definition,n=>_s(n,t))):!1}i(_s,"isOptionalProd");function GA(e){return e instanceof gt}i(GA,"isBranchingProd");function Dt(e){if(e instanceof st)return"SUBRULE";if(e instanceof He)return"OPTION";if(e instanceof gt)return"OR";if(e instanceof Et)return"AT_LEAST_ONE";if(e instanceof Ct)return"AT_LEAST_ONE_SEP";if(e instanceof yt)return"MANY_SEP";if(e instanceof be)return"MANY";if(e instanceof ve)return"CONSUME";throw Error("non exhaustive match")}i(Dt,"getProductionDslName");var pu=class{static{i(this,"RestWalker")}walk(e,t=[]){K(e.definition,(r,n)=>{const a=qe(e.definition,n+1);if(r instanceof st)this.walkProdRef(r,a,t);else if(r instanceof ve)this.walkTerminal(r,a,t);else if(r instanceof ht)this.walkFlat(r,a,t);else if(r instanceof He)this.walkOption(r,a,t);else if(r instanceof Et)this.walkAtLeastOne(r,a,t);else if(r instanceof Ct)this.walkAtLeastOneSep(r,a,t);else if(r instanceof yt)this.walkManySep(r,a,t);else if(r instanceof be)this.walkMany(r,a,t);else if(r instanceof gt)this.walkOr(r,a,t);else throw Error("non exhaustive match")})}walkTerminal(e,t,r){}walkProdRef(e,t,r){}walkFlat(e,t,r){const n=t.concat(r);this.walk(e,n)}walkOption(e,t,r){const n=t.concat(r);this.walk(e,n)}walkAtLeastOne(e,t,r){const n=[new He({definition:e.definition})].concat(t,r);this.walk(e,n)}walkAtLeastOneSep(e,t,r){const n=If(e,t,r);this.walk(e,n)}walkMany(e,t,r){const n=[new He({definition:e.definition})].concat(t,r);this.walk(e,n)}walkManySep(e,t,r){const n=If(e,t,r);this.walk(e,n)}walkOr(e,t,r){const n=t.concat(r);K(e.definition,a=>{const s=new ht({definition:[a]});this.walk(s,n)})}};function If(e,t,r){return[new He({definition:[new ve({terminalType:e.separator})].concat(e.definition)})].concat(t,r)}i(If,"restForRepetitionWithSeparator");function ii(e){if(e instanceof st)return ii(e.referencedRule);if(e instanceof ve)return jA(e);if(MA(e))return FA(e);if(GA(e))return zA(e);throw Error("non exhaustive match")}i(ii,"first");function FA(e){let t=[];const r=e.definition;let n=0,a=r.length>n,s,o=!0;for(;a&&o;)s=r[n],o=_s(s),t=t.concat(ii(s)),n=n+1,a=r.length>n;return Vp(t)}i(FA,"firstForSequence");function zA(e){const t=F(e.definition,r=>ii(r));return Vp(Ft(t))}i(zA,"firstForBranching");function jA(e){return[e.terminalType]}i(jA,"firstForTerminal");var BA="_~IN~_",_D=class extends pu{static{i(this,"ResyncFollowsWalker")}constructor(e){super(),this.topProd=e,this.follows={}}startWalking(){return this.walk(this.topProd),this.follows}walkTerminal(e,t,r){}walkProdRef(e,t,r){const n=KA(e.referencedRule,e.idx)+this.topProd.name,a=t.concat(r),s=new ht({definition:a}),o=ii(s);this.follows[n]=o}};function UA(e){const t={};return K(e,r=>{const n=new _D(r).startWalking();Rt(t,n)}),t}i(UA,"computeAllProdsFollows");function KA(e,t){return e.name+t+BA}i(KA,"buildBetweenProdsFollowPrefix");var Oo={},SD=new Av;function Zs(e){const t=e.toString();if(Oo.hasOwnProperty(t))return Oo[t];{const r=SD.pattern(t);return Oo[t]=r,r}}i(Zs,"getRegExpAst");function WA(){Oo={}}i(WA,"clearRegExpParserCache");var VA="Complement Sets are not supported for first char optimization",yl=`Unable to use "first char" lexer optimizations: +`;function qA(e,t=!1){try{const r=Zs(e);return gl(r.value,{},r.flags.ignoreCase)}catch(r){if(r.message===VA)t&&qp(`${yl} Unable to optimize: < ${e.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="";t&&(n=` + This will disable the lexer's first char optimizations. + See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#REGEXP_PARSING for details.`),hl(`${yl} + Failed parsing: < ${e.toString()} > + Using the @chevrotain/regexp-to-ast library + Please open an issue at: https://github.com/chevrotain/chevrotain/issues`+n)}}return[]}i(qA,"getOptimizedStartCodesIndices");function gl(e,t,r){switch(e.type){case"Disjunction":for(let a=0;a{if(typeof u=="number")Ji(u,t,r);else{const c=u;if(r===!0)for(let f=c.from;f<=c.to;f++)Ji(f,t,r);else{for(let f=c.from;f<=c.to&&f=Qi){const f=c.from>=Qi?c.from:Qi,d=c.to,m=_r(f),g=_r(d);for(let v=m;v<=g;v++)t[v]=v}}}});break;case"Group":gl(o.value,t,r);break;default:throw Error("Non Exhaustive Match")}const l=o.quantifier!==void 0&&o.quantifier.atLeast===0;if(o.type==="Group"&&vl(o)===!1||o.type!=="Group"&&l===!1)break}break;default:throw Error("non exhaustive match!")}return Me(t)}i(gl,"firstCharOptimizedIndices");function Ji(e,t,r){const n=_r(e);t[n]=n,r===!0&&HA(e,t)}i(Ji,"addOptimizedIdxToResult");function HA(e,t){const r=String.fromCharCode(e),n=r.toUpperCase();if(n!==r){const a=_r(n.charCodeAt(0));t[a]=a}else{const a=r.toLowerCase();if(a!==r){const s=_r(a.charCodeAt(0));t[s]=s}}}i(HA,"handleIgnoreCase");function Nf(e,t){return Ja(e.value,r=>{if(typeof r=="number")return ut(t,r);{const n=r;return Ja(t,a=>n.from<=a&&a<=n.to)!==void 0}})}i(Nf,"findCode");function vl(e){const t=e.quantifier;return t&&t.atLeast===0?!0:e.value?re(e.value)?zt(e.value,vl):vl(e.value):!1}i(vl,"isWholeOptional");var wD=class extends Vl{static{i(this,"CharCodeFinder")}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){ut(this.targetCharCodes,e.value)&&(this.found=!0)}visitSet(e){e.complement?Nf(e,this.targetCharCodes)===void 0&&(this.found=!0):Nf(e,this.targetCharCodes)!==void 0&&(this.found=!0)}};function mu(e,t){if(t instanceof RegExp){const r=Zs(t),n=new wD(e);return n.visit(r),n.found}else return Ja(t,r=>ut(e,r.charCodeAt(0)))!==void 0}i(mu,"canMatchCharCode");var On="PATTERN",Zi="defaultMode",so="modes";function YA(e,t){t=Wp(t,{debug:!1,safeMode:!1,positionTracking:"full",lineTerminatorCharacters:["\r",` +`],tracer:i((I,R)=>R(),"tracer")});const r=t.tracer;r("initCharCodeToOptimizedIndexMap",()=>{yE()});let n;r("Reject Lexer.NA",()=>{n=du(e,I=>I[On]===at.NA)});let a=!1,s;r("Transform Patterns",()=>{a=!1,s=F(n,I=>{const R=I[On];if(Cr(R)){const P=R.source;return P.length===1&&P!=="^"&&P!=="$"&&P!=="."&&!R.ignoreCase?P:P.length===2&&P[0]==="\\"&&!ut(["d","D","s","S","t","r","n","t","0","c","b","B","f","v","w","W"],P[1])?P[1]:Pf(R)}else{if(Pr(R))return a=!0,{exec:R};if(typeof R=="object")return a=!0,R;if(typeof R=="string"){if(R.length===1)return R;{const P=R.replace(/[\\^$.*+?()[\]{}|]/g,"\\$&"),z=new RegExp(P);return Pf(z)}}else throw Error("non exhaustive match")}})});let o,l,u,c,f;r("misc mapping",()=>{o=F(n,I=>I.tokenTypeIdx),l=F(n,I=>{const R=I.GROUP;if(R!==at.SKIPPED){if(mt(R))return R;if(br(R))return!1;throw Error("non exhaustive match")}}),u=F(n,I=>{const R=I.LONGER_ALT;if(R)return re(R)?F(R,z=>Uh(n,z)):[Uh(n,R)]}),c=F(n,I=>I.PUSH_MODE),f=F(n,I=>B(I,"POP_MODE"))});let d;r("Line Terminator Handling",()=>{const I=Zp(t.lineTerminatorCharacters);d=F(n,R=>!1),t.positionTracking!=="onlyOffset"&&(d=F(n,R=>B(R,"LINE_BREAKS")?!!R.LINE_BREAKS:Jp(R,I)===!1&&mu(I,R.PATTERN)))});let m,g,v,b;r("Misc Mapping #2",()=>{m=F(n,Xp),g=F(s,mE),v=At(n,(I,R)=>{const P=R.GROUP;return mt(P)&&P!==at.SKIPPED&&(I[P]=[]),I},{}),b=F(s,(I,R)=>({pattern:s[R],longerAlt:u[R],canLineTerminator:d[R],isCustom:m[R],short:g[R],group:l[R],push:c[R],pop:f[R],tokenTypeIdx:o[R],tokenType:n[R]}))});let S=!0,w=[];return t.safeMode||r("First Char Optimization",()=>{w=At(n,(I,R,P)=>{if(typeof R.PATTERN=="string"){const z=R.PATTERN.charCodeAt(0),X=_r(z);Lo(I,X,b[P])}else if(re(R.START_CHARS_HINT)){let z;K(R.START_CHARS_HINT,X=>{const Z=typeof X=="string"?X.charCodeAt(0):X,ce=_r(Z);z!==ce&&(z=ce,Lo(I,ce,b[P]))})}else if(Cr(R.PATTERN))if(R.PATTERN.unicode)S=!1,t.ensureOptimizations&&hl(`${yl} Unable to analyze < ${R.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 z=qA(R.PATTERN,t.ensureOptimizations);me(z)&&(S=!1),K(z,X=>{Lo(I,X,b[P])})}else t.ensureOptimizations&&hl(`${yl} TokenType: <${R.name}> is using a custom token pattern without providing parameter. + This will disable the lexer's first char optimizations. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_OPTIMIZE`),S=!1;return I},[])}),{emptyGroups:v,patternIdxToConfig:b,charCodeToPatternIdxToConfig:w,hasCustom:a,canBeOptimized:S}}i(YA,"analyzeTokenTypes");function XA(e,t){let r=[];const n=ZA(e);r=r.concat(n.errors);const a=QA(n.valid),s=a.valid;return r=r.concat(a.errors),r=r.concat(JA(s)),r=r.concat(iE(s)),r=r.concat(sE(s,t)),r=r.concat(oE(s)),r}i(XA,"validatePatterns");function JA(e){let t=[];const r=Pt(e,n=>Cr(n[On]));return t=t.concat(eE(r)),t=t.concat(rE(r)),t=t.concat(nE(r)),t=t.concat(aE(r)),t=t.concat(tE(r)),t}i(JA,"validateRegExpPattern");function ZA(e){const t=Pt(e,a=>!B(a,On)),r=F(t,a=>({message:"Token Type: ->"+a.name+"<- missing static 'PATTERN' property",type:_e.MISSING_PATTERN,tokenTypes:[a]})),n=fu(e,t);return{errors:r,valid:n}}i(ZA,"findMissingPatterns");function QA(e){const t=Pt(e,a=>{const s=a[On];return!Cr(s)&&!Pr(s)&&!B(s,"exec")&&!mt(s)}),r=F(t,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:_e.INVALID_PATTERN,tokenTypes:[a]})),n=fu(e,t);return{errors:r,valid:n}}i(QA,"findInvalidPatterns");var ID=/[^\\][$]/;function eE(e){class t extends Vl{static{i(this,"EndAnchorFinder")}constructor(){super(...arguments),this.found=!1}visitEndAnchor(s){this.found=!0}}const r=Pt(e,a=>{const s=a.PATTERN;try{const o=Zs(s),l=new t;return l.visit(o),l.found}catch{return ID.test(s.source)}});return F(r,a=>({message:`Unexpected RegExp Anchor Error: + Token Type: ->`+a.name+`<- static 'PATTERN' cannot contain end of input anchor '$' + See chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:_e.EOI_ANCHOR_FOUND,tokenTypes:[a]}))}i(eE,"findEndOfInputAnchor");function tE(e){const t=Pt(e,n=>n.PATTERN.test(""));return F(t,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' must not match an empty string",type:_e.EMPTY_MATCH_PATTERN,tokenTypes:[n]}))}i(tE,"findEmptyMatchRegExps");var ND=/[^\\[][\^]|^\^/;function rE(e){class t extends Vl{static{i(this,"StartAnchorFinder")}constructor(){super(...arguments),this.found=!1}visitStartAnchor(s){this.found=!0}}const r=Pt(e,a=>{const s=a.PATTERN;try{const o=Zs(s),l=new t;return l.visit(o),l.found}catch{return ND.test(s.source)}});return F(r,a=>({message:`Unexpected RegExp Anchor Error: + Token Type: ->`+a.name+`<- static 'PATTERN' cannot contain start of input anchor '^' + See https://chevrotain.io/docs/guide/resolving_lexer_errors.html#ANCHORS for details.`,type:_e.SOI_ANCHOR_FOUND,tokenTypes:[a]}))}i(rE,"findStartOfInputAnchor");function nE(e){const t=Pt(e,n=>{const a=n[On];return a instanceof RegExp&&(a.multiline||a.global)});return F(t,n=>({message:"Token Type: ->"+n.name+"<- static 'PATTERN' may NOT contain global('g') or multiline('m')",type:_e.UNSUPPORTED_FLAGS_FOUND,tokenTypes:[n]}))}i(nE,"findUnsupportedFlags");function aE(e){const t=[];let r=F(e,s=>At(e,(o,l)=>(s.PATTERN.source===l.PATTERN.source&&!ut(t,l)&&l.PATTERN!==at.NA&&(t.push(l),o.push(l)),o),[]));r=Js(r);const n=Pt(r,s=>s.length>1);return F(n,s=>{const o=F(s,u=>u.name);return{message:`The same RegExp pattern ->${Bt(s).PATTERN}<-has been used in all of the following Token Types: ${o.join(", ")} <-`,type:_e.DUPLICATE_PATTERNS_FOUND,tokenTypes:s}})}i(aE,"findDuplicatePatterns");function iE(e){const t=Pt(e,n=>{if(!B(n,"GROUP"))return!1;const a=n.GROUP;return a!==at.SKIPPED&&a!==at.NA&&!mt(a)});return F(t,n=>({message:"Token Type: ->"+n.name+"<- static 'GROUP' can only be Lexer.SKIPPED/Lexer.NA/A String",type:_e.INVALID_GROUP_TYPE_FOUND,tokenTypes:[n]}))}i(iE,"findInvalidGroupType");function sE(e,t){const r=Pt(e,a=>a.PUSH_MODE!==void 0&&!ut(t,a.PUSH_MODE));return F(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:_e.PUSH_MODE_DOES_NOT_EXIST,tokenTypes:[a]}))}i(sE,"findModesThatDoNotExist");function oE(e){const t=[],r=At(e,(n,a,s)=>{const o=a.PATTERN;return o===at.NA||(mt(o)?n.push({str:o,idx:s,tokenType:a}):Cr(o)&&uE(o)&&n.push({str:o.source,idx:s,tokenType:a})),n},[]);return K(e,(n,a)=>{K(r,({str:s,idx:o,tokenType:l})=>{if(a${l.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`;t.push({message:u,type:_e.UNREACHABLE_PATTERN,tokenTypes:[n,l]})}})}),t}i(oE,"findUnreachablePatterns");function lE(e,t){if(Cr(t)){if(cE(t))return!1;const r=t.exec(e);return r!==null&&r.index===0}else{if(Pr(t))return t(e,0,[],{});if(B(t,"exec"))return t.exec(e,0,[],{});if(typeof t=="string")return t===e;throw Error("non exhaustive match")}}i(lE,"tryToMatchStrToPattern");function uE(e){return Ja([".","\\","[","]","|","^","$","(",")","?","*","+","{"],r=>e.source.indexOf(r)!==-1)===void 0}i(uE,"noMetaChar");function cE(e){return/(\(\?=)|(\(\?!)|(\(\?<=)|(\(\? property in its definition +`,type:_e.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE}),B(e,so)||n.push({message:"A MultiMode Lexer cannot be initialized without a <"+so+`> property in its definition +`,type:_e.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY}),B(e,so)&&B(e,Zi)&&!B(e.modes,e.defaultMode)&&n.push({message:`A MultiMode Lexer cannot be initialized with a ${Zi}: <${e.defaultMode}>which does not exist +`,type:_e.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST}),B(e,so)&&K(e.modes,(a,s)=>{K(a,(o,l)=>{if(br(o))n.push({message:`A Lexer cannot be initialized using an undefined Token Type. Mode:<${s}> at index: <${l}> +`,type:_e.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED});else if(B(o,"LONGER_ALT")){const u=re(o.LONGER_ALT)?o.LONGER_ALT:[o.LONGER_ALT];K(u,c=>{!br(c)&&!ut(a,c)&&n.push({message:`A MultiMode Lexer cannot be initialized with a longer_alt <${c.name}> on token <${o.name}> outside of mode <${s}> +`,type:_e.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE})})}})}),n}i(fE,"performRuntimeChecks");function dE(e,t,r){const n=[];let a=!1;const s=Js(Ft(Me(e.modes))),o=du(s,u=>u[On]===at.NA),l=Zp(r);return t&&K(o,u=>{const c=Jp(u,l);if(c!==!1){const d={message:hE(u,c),type:c.issue,tokenType:u};n.push(d)}else B(u,"LINE_BREAKS")?u.LINE_BREAKS===!0&&(a=!0):mu(l,u.PATTERN)&&(a=!0)}),t&&!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:_e.NO_LINE_BREAKS_FLAGS}),n}i(dE,"performWarningRuntimeChecks");function pE(e){const t={},r=$t(e);return K(r,n=>{const a=e[n];if(re(a))t[n]=[];else throw Error("non exhaustive match")}),t}i(pE,"cloneEmptyGroups");function Xp(e){const t=e.PATTERN;if(Cr(t))return!1;if(Pr(t))return!0;if(B(t,"exec"))return!0;if(mt(t))return!1;throw Error("non exhaustive match")}i(Xp,"isCustomPattern");function mE(e){return mt(e)&&e.length===1?e.charCodeAt(0):!1}i(mE,"isShortPattern");var PD={test:i(function(e){const t=e.length;for(let r=this.lastIndex;r Token Type + Root cause: ${t.errMsg}. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#IDENTIFY_TERMINATOR`;if(t.issue===_e.CUSTOM_LINE_BREAK)return`Warning: A Custom Token Pattern should specify the option. + The problem is in the <${e.name}> Token Type + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#CUSTOM_LINE_BREAK`;throw Error("non exhaustive match")}i(hE,"buildLineBreakIssueMessage");function Zp(e){return F(e,r=>mt(r)?r.charCodeAt(0):r)}i(Zp,"getCharCodes");function Lo(e,t,r){e[t]===void 0?e[t]=[r]:e[t].push(r)}i(Lo,"addToMapOfArrays");var Qi=256,Do=[];function _r(e){return e255?255+~~(e/255):e}}i(yE,"initCharCodeToOptimizedIndexMap");function si(e,t){const r=e.tokenTypeIdx;return r===t.tokenTypeIdx?!0:t.isParent===!0&&t.categoryMatchesMap[r]===!0}i(si,"tokenStructuredMatcher");function Ss(e,t){return e.tokenTypeIdx===t.tokenTypeIdx}i(Ss,"tokenStructuredMatcherNoCategories");var Wh=1,gE={};function oi(e){const t=vE(e);TE(t),RE(t),$E(t),K(t,r=>{r.isParent=r.categoryMatches.length>0})}i(oi,"augmentTokenTypes");function vE(e){let t=Ye(e),r=e,n=!0;for(;n;){r=Js(Ft(F(r,s=>s.CATEGORIES)));const a=fu(r,t);t=t.concat(a),me(a)?n=!1:r=a}return t}i(vE,"expandCategories");function TE(e){K(e,t=>{em(t)||(gE[Wh]=t,t.tokenTypeIdx=Wh++),kf(t)&&!re(t.CATEGORIES)&&(t.CATEGORIES=[t.CATEGORIES]),kf(t)||(t.CATEGORIES=[]),AE(t)||(t.categoryMatches=[]),EE(t)||(t.categoryMatchesMap={})})}i(TE,"assignTokenDefaultProps");function $E(e){K(e,t=>{t.categoryMatches=[],K(t.categoryMatchesMap,(r,n)=>{t.categoryMatches.push(gE[n].tokenTypeIdx)})})}i($E,"assignCategoriesTokensProp");function RE(e){K(e,t=>{Qp([],t)})}i(RE,"assignCategoriesMapProp");function Qp(e,t){K(e,r=>{t.categoryMatchesMap[r.tokenTypeIdx]=!0}),K(t.CATEGORIES,r=>{const n=e.concat(t);ut(n,r)||Qp(n,r)})}i(Qp,"singleAssignCategoriesToksMap");function em(e){return B(e,"tokenTypeIdx")}i(em,"hasShortKeyProperty");function kf(e){return B(e,"CATEGORIES")}i(kf,"hasCategoriesProperty");function AE(e){return B(e,"categoryMatches")}i(AE,"hasExtendingTokensTypesProperty");function EE(e){return B(e,"categoryMatchesMap")}i(EE,"hasExtendingTokensTypesMapProperty");function CE(e){return B(e,"tokenTypeIdx")}i(CE,"isTokenType");var Of={buildUnableToPopLexerModeMessage(e){return`Unable to pop Lexer Mode after encountering Token ->${e.image}<- The Mode Stack is empty`},buildUnexpectedCharactersMessage(e,t,r,n,a,s){return`unexpected character: ->${e.charAt(t)}<- at offset: ${t}, skipped ${r} characters.`}},_e;(function(e){e[e.MISSING_PATTERN=0]="MISSING_PATTERN",e[e.INVALID_PATTERN=1]="INVALID_PATTERN",e[e.EOI_ANCHOR_FOUND=2]="EOI_ANCHOR_FOUND",e[e.UNSUPPORTED_FLAGS_FOUND=3]="UNSUPPORTED_FLAGS_FOUND",e[e.DUPLICATE_PATTERNS_FOUND=4]="DUPLICATE_PATTERNS_FOUND",e[e.INVALID_GROUP_TYPE_FOUND=5]="INVALID_GROUP_TYPE_FOUND",e[e.PUSH_MODE_DOES_NOT_EXIST=6]="PUSH_MODE_DOES_NOT_EXIST",e[e.MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE=7]="MULTI_MODE_LEXER_WITHOUT_DEFAULT_MODE",e[e.MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY=8]="MULTI_MODE_LEXER_WITHOUT_MODES_PROPERTY",e[e.MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST=9]="MULTI_MODE_LEXER_DEFAULT_MODE_VALUE_DOES_NOT_EXIST",e[e.LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED=10]="LEXER_DEFINITION_CANNOT_CONTAIN_UNDEFINED",e[e.SOI_ANCHOR_FOUND=11]="SOI_ANCHOR_FOUND",e[e.EMPTY_MATCH_PATTERN=12]="EMPTY_MATCH_PATTERN",e[e.NO_LINE_BREAKS_FLAGS=13]="NO_LINE_BREAKS_FLAGS",e[e.UNREACHABLE_PATTERN=14]="UNREACHABLE_PATTERN",e[e.IDENTIFY_TERMINATOR=15]="IDENTIFY_TERMINATOR",e[e.CUSTOM_LINE_BREAK=16]="CUSTOM_LINE_BREAK",e[e.MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE=17]="MULTI_MODE_LEXER_LONGER_ALT_NOT_IN_CURRENT_MODE"})(_e||(_e={}));var es={deferDefinitionErrorsHandling:!1,positionTracking:"full",lineTerminatorsPattern:/\n|\r\n?/g,lineTerminatorCharacters:[` +`,"\r"],ensureOptimizations:!1,safeMode:!1,errorMessageProvider:Of,traceInitPerf:!1,skipValidations:!1,recoveryEnabled:!0};Object.freeze(es);var at=class{static{i(this,"Lexer")}constructor(e,t=es){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=(n,a)=>{if(this.traceInitPerf===!0){this.traceInitIndent++;const s=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <${n}>`);const{time:o,value:l}=Hp(a),u=o>10?console.warn:console.log;return this.traceInitIndent time: ${o}ms`),this.traceInitIndent--,l}else return a()},typeof t=="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=Rt({},es,t);const r=this.config.traceInitPerf;r===!0?(this.traceInitMaxIdent=1/0,this.traceInitPerf=!0):typeof r=="number"&&(this.traceInitMaxIdent=r,this.traceInitPerf=!0),this.traceInitIndent=-1,this.TRACE_INIT("Lexer Constructor",()=>{let n,a=!0;this.TRACE_INIT("Lexer Config handling",()=>{if(this.config.lineTerminatorsPattern===es.lineTerminatorsPattern)this.config.lineTerminatorsPattern=PD;else if(this.config.lineTerminatorCharacters===es.lineTerminatorCharacters)throw Error(`Error: Missing property on the Lexer config. + For details See: https://chevrotain.io/docs/guide/resolving_lexer_errors.html#MISSING_LINE_TERM_CHARS`);if(t.safeMode&&t.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),re(e)?n={modes:{defaultMode:Ye(e)},defaultMode:Zi}:(a=!1,n=Ye(e))}),this.config.skipValidations===!1&&(this.TRACE_INIT("performRuntimeChecks",()=>{this.lexerDefinitionErrors=this.lexerDefinitionErrors.concat(fE(n,this.trackStartLines,this.config.lineTerminatorCharacters))}),this.TRACE_INIT("performWarningRuntimeChecks",()=>{this.lexerDefinitionWarning=this.lexerDefinitionWarning.concat(dE(n,this.trackStartLines,this.config.lineTerminatorCharacters))})),n.modes=n.modes?n.modes:{},K(n.modes,(o,l)=>{n.modes[l]=du(o,u=>br(u))});const s=$t(n.modes);if(K(n.modes,(o,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(XA(o,s))}),me(this.lexerDefinitionErrors)){oi(o);let u;this.TRACE_INIT("analyzeTokenTypes",()=>{u=YA(o,{lineTerminatorCharacters:this.config.lineTerminatorCharacters,positionTracking:t.positionTracking,ensureOptimizations:t.ensureOptimizations,safeMode:t.safeMode,tracer:this.TRACE_INIT})}),this.patternIdxToConfig[l]=u.patternIdxToConfig,this.charCodeToPatternIdxToConfig[l]=u.charCodeToPatternIdxToConfig,this.emptyGroups=Rt({},this.emptyGroups,u.emptyGroups),this.hasCustom=u.hasCustom||this.hasCustom,this.canModeBeOptimized[l]=u.canBeOptimized}})}),this.defaultMode=n.defaultMode,!me(this.lexerDefinitionErrors)&&!this.config.deferDefinitionErrorsHandling){const l=F(this.lexerDefinitionErrors,u=>u.message).join(`----------------------- +`);throw new Error(`Errors detected in definition of Lexer: +`+l)}K(this.lexerDefinitionWarning,o=>{qp(o.message)}),this.TRACE_INIT("Choosing sub-methods implementations",()=>{if(a&&(this.handleModes=Fe),this.trackStartLines===!1&&(this.computeNewColumn=Ws),this.trackEndLines===!1&&(this.updateTokenEndLineColumnLocation=Fe),/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 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 o=At(this.canModeBeOptimized,(l,u,c)=>(u===!1&&l.push(c),l),[]);if(t.ensureOptimizations&&!me(o))throw Error(`Lexer Modes: < ${o.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",()=>{WA()}),this.TRACE_INIT("toFastProperties",()=>{Yp(this)})})}tokenize(e,t=this.defaultMode){if(!me(this.lexerDefinitionErrors)){const n=F(this.lexerDefinitionErrors,a=>a.message).join(`----------------------- +`);throw new Error(`Unable to Tokenize because Errors detected in definition of Lexer: +`+n)}return this.tokenizeInternal(e,t)}tokenizeInternal(e,t){let r,n,a,s,o,l,u,c,f,d,m,g,v,b,S;const w=e,I=w.length;let R=0,P=0;const z=this.hasCustom?0:Math.floor(e.length/10),X=new Array(z),Z=[];let ce=this.trackStartLines?1:void 0,se=this.trackStartLines?1:void 0;const Se=pE(this.emptyGroups),k=this.trackStartLines,C=this.config.lineTerminatorsPattern;let y=0,E=[],T=[];const $=[],_=[];Object.freeze(_);let O=!1;const x=i(Y=>{if($.length===1&&Y.tokenType.PUSH_MODE===void 0){const V=this.config.errorMessageProvider.buildUnableToPopLexerModeMessage(Y);Z.push({offset:Y.startOffset,line:Y.startLine,column:Y.startColumn,length:Y.image.length,message:V})}else{$.pop();const V=kn($);E=this.patternIdxToConfig[V],T=this.charCodeToPatternIdxToConfig[V],y=E.length;const Pe=this.canModeBeOptimized[V]&&this.config.safeMode===!1;T&&Pe?O=!0:O=!1}},"pop_mode");function D(Y){$.push(Y),T=this.charCodeToPatternIdxToConfig[Y],E=this.patternIdxToConfig[Y],y=E.length,y=E.length;const V=this.canModeBeOptimized[Y]&&this.config.safeMode===!1;T&&V?O=!0:O=!1}i(D,"push_mode"),D.call(this,t);let G;const W=this.config.recoveryEnabled;for(;Rl.length){l=s,f=s.length,u=c,G=ke;break}}}break}}if(f!==-1){if(d=G.group,d!==void 0&&(l=l!==null?l:e.substring(R,R+f),m=G.tokenTypeIdx,g=this.createTokenInstance(l,R,m,G.tokenType,ce,se,f),this.handlePayload(g,u),d===!1?P=this.addToken(X,P,g):Se[d].push(g)),k===!0&&G.canLineTerminator===!0){let oe=0,Le,De;C.lastIndex=0;do l=l!==null?l:e.substring(R,R+f),Le=C.test(l),Le===!0&&(De=C.lastIndex-1,oe++);while(Le===!0);oe!==0?(ce=ce+oe,se=f-De,this.updateTokenEndLineColumnLocation(g,d,De,oe,ce,se,f)):se=this.computeNewColumn(se,f)}else se=this.computeNewColumn(se,f);R=R+f,this.handleModes(G,x,D,g)}else{const oe=R,Le=ce,De=se;let ke=W===!1;for(;ke===!1&&R ${In(e)} <--`:`token of type --> ${e.name} <--`} but found --> '${t.image}' <--`},buildNotAllInputParsedMessage({firstRedundant:e,ruleName:t}){return"Redundant input, expecting EOF but found: "+e.image},buildNoViableAltMessage({expectedPathsPerAlt:e,actual:t,previous:r,customUserDescription:n,ruleName:a}){const s="Expecting: ",l=` +but found: '`+Bt(t).image+"'";if(n)return s+n+l;{const u=At(e,(m,g)=>m.concat(g),[]),c=F(u,m=>`[${F(m,g=>In(g)).join(", ")}]`),d=`one of these possible Token sequences: +${F(c,(m,g)=>` ${g+1}. ${m}`).join(` +`)}`;return s+d+l}},buildEarlyExitMessage({expectedIterationPaths:e,actual:t,customUserDescription:r,ruleName:n}){const a="Expecting: ",o=` +but found: '`+Bt(t).image+"'";if(r)return a+r+o;{const u=`expecting at least one iteration which starts with one of these possible Token sequences:: + <${F(e,c=>`[${F(c,f=>In(f)).join(",")}]`).join(" ,")}>`;return a+u+o}}};Object.freeze(Ga);var OD={buildRuleNotFoundError(e,t){return"Invalid grammar, reference to a rule which is not defined: ->"+t.nonTerminalName+`<- +inside top level rule: ->`+e.name+"<-"}},_n={buildDuplicateFoundError(e,t){function r(f){return f instanceof ve?f.terminalType.name:f instanceof st?f.nonTerminalName:""}i(r,"getExtraProductionArgument");const n=e.name,a=Bt(t),s=a.idx,o=Dt(a),l=r(a),u=s>0;let c=`->${o}${u?s:""}<- ${l?`with argument: ->${l}<-`:""} + appears more than once (${t.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(e){return`Namespace conflict found in grammar. +The grammar has both a Terminal(Token) and a Non-Terminal(Rule) named: <${e.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(e){const t=F(e.prefixPath,a=>In(a)).join(", "),r=e.alternation.idx===0?"":e.alternation.idx;return`Ambiguous alternatives: <${e.ambiguityIndices.join(" ,")}> due to common lookahead prefix +in inside <${e.topLevelRule.name}> Rule, +<${t}> 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(e){const t=e.alternation.idx===0?"":e.alternation.idx,r=e.prefixPath.length===0;let n=`Ambiguous Alternatives Detected: <${e.ambiguityIndices.join(" ,")}> in inside <${e.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=F(e.prefixPath,s=>In(s)).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(e){let t=Dt(e.repetition);return e.repetition.idx!==0&&(t+=e.repetition.idx),`The repetition <${t}> within Rule <${e.topLevelRule.name}> can never consume any tokens. +This could lead to an infinite loop.`},buildTokenNameError(e){return"deprecated"},buildEmptyAlternationError(e){return`Ambiguous empty alternative: <${e.emptyChoiceIdx+1}> in inside <${e.topLevelRule.name}> Rule. +Only the last alternative may be an empty alternative.`},buildTooManyAlternativesError(e){return`An Alternation cannot have more than 256 alternatives: + inside <${e.topLevelRule.name}> Rule. + has ${e.alternation.definition.length+1} alternatives.`},buildLeftRecursionError(e){const t=e.topLevelRule.name,r=F(e.leftRecursionPath,s=>s.name),n=`${t} --> ${r.concat([t]).join(" --> ")}`;return`Left Recursion found in grammar. +rule: <${t}> 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(e){return"deprecated"},buildDuplicateRuleNameError(e){let t;return e.topLevelRule instanceof ni?t=e.topLevelRule.name:t=e.topLevelRule,`Duplicate definition, rule: ->${t}<- is already defined in the grammar: ->${e.grammarName}<-`}};function _E(e,t){const r=new LD(e,t);return r.resolveRefs(),r.errors}i(_E,"resolveGrammar");var LD=class extends ai{static{i(this,"GastRefResolverVisitor")}constructor(e,t){super(),this.nameToTopRule=e,this.errMsgProvider=t,this.errors=[]}resolveRefs(){K(Me(this.nameToTopRule),e=>{this.currTopLevel=e,e.accept(this)})}visitNonTerminal(e){const t=this.nameToTopRule[e.nonTerminalName];if(t)e.referencedRule=t;else{const r=this.errMsgProvider.buildRuleNotFoundError(this.currTopLevel,e);this.errors.push({message:r,type:ot.UNRESOLVED_SUBRULE_REF,ruleName:this.currTopLevel.name,unresolvedRefName:e.nonTerminalName})}}},DD=class extends pu{static{i(this,"AbstractNextPossibleTokensWalker")}constructor(e,t){super(),this.topProd=e,this.path=t,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=Ye(this.path.ruleStack).reverse(),this.occurrenceStack=Ye(this.path.occurrenceStack).reverse(),this.ruleStack.pop(),this.occurrenceStack.pop(),this.updateExpectedNext(),this.walk(this.topProd),this.possibleTokTypes}walk(e,t=[]){this.found||super.walk(e,t)}walkProdRef(e,t,r){if(e.referencedRule.name===this.nextProductionName&&e.idx===this.nextProductionOccurrence){const n=t.concat(r);this.updateExpectedNext(),this.walk(e.referencedRule,n)}}updateExpectedNext(){me(this.ruleStack)?(this.nextProductionName="",this.nextProductionOccurrence=0,this.isAtEndOfPath=!0):(this.nextProductionName=this.ruleStack.pop(),this.nextProductionOccurrence=this.occurrenceStack.pop())}},xD=class extends DD{static{i(this,"NextAfterTokenWalker")}constructor(e,t){super(e,t),this.path=t,this.nextTerminalName="",this.nextTerminalOccurrence=0,this.nextTerminalName=this.path.lastTok.name,this.nextTerminalOccurrence=this.path.lastTokOccurrence}walkTerminal(e,t,r){if(this.isAtEndOfPath&&e.terminalType.name===this.nextTerminalName&&e.idx===this.nextTerminalOccurrence&&!this.found){const n=t.concat(r),a=new ht({definition:n});this.possibleTokTypes=ii(a),this.found=!0}}},hu=class extends pu{static{i(this,"AbstractNextTerminalAfterProductionWalker")}constructor(e,t){super(),this.topRule=e,this.occurrence=t,this.result={token:void 0,occurrence:void 0,isEndOfRule:void 0}}startWalking(){return this.walk(this.topRule),this.result}},MD=class extends hu{static{i(this,"NextTerminalAfterManyWalker")}walkMany(e,t,r){if(e.idx===this.occurrence){const n=Bt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkMany(e,t,r)}},ey=class extends hu{static{i(this,"NextTerminalAfterManySepWalker")}walkManySep(e,t,r){if(e.idx===this.occurrence){const n=Bt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkManySep(e,t,r)}},GD=class extends hu{static{i(this,"NextTerminalAfterAtLeastOneWalker")}walkAtLeastOne(e,t,r){if(e.idx===this.occurrence){const n=Bt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkAtLeastOne(e,t,r)}},ty=class extends hu{static{i(this,"NextTerminalAfterAtLeastOneSepWalker")}walkAtLeastOneSep(e,t,r){if(e.idx===this.occurrence){const n=Bt(t.concat(r));this.result.isEndOfRule=n===void 0,n instanceof ve&&(this.result.token=n.terminalType,this.result.occurrence=n.idx)}else super.walkAtLeastOneSep(e,t,r)}};function Tl(e,t,r=[]){r=Ye(r);let n=[],a=0;function s(l){return l.concat(qe(e,a+1))}i(s,"remainingPathWith");function o(l){const u=Tl(s(l),t,r);return n.concat(u)}for(i(o,"getAlternativesForProd");r.length{me(u.definition)===!1&&(n=o(u.definition))}),n;if(l instanceof ve)r.push(l.terminalType);else throw Error("non exhaustive match")}a++}return n.push({partialPath:r,suffixDef:qe(e,a)}),n}i(Tl,"possiblePathsFrom");function nm(e,t,r,n){const a="EXIT_NONE_TERMINAL",s=[a],o="EXIT_ALTERNATIVE";let l=!1;const u=t.length,c=u-n-1,f=[],d=[];for(d.push({idx:-1,def:e,ruleStack:[],occurrenceStack:[]});!me(d);){const m=d.pop();if(m===o){l&&kn(d).idx<=c&&d.pop();continue}const g=m.def,v=m.idx,b=m.ruleStack,S=m.occurrenceStack;if(me(g))continue;const w=g[0];if(w===a){const I={idx:v,def:qe(g),ruleStack:bs(b),occurrenceStack:bs(S)};d.push(I)}else if(w instanceof ve)if(v=0;I--){const R=w.definition[I],P={idx:v,def:R.definition.concat(qe(g)),ruleStack:b,occurrenceStack:S};d.push(P),d.push(o)}else if(w instanceof ht)d.push({idx:v,def:w.definition.concat(qe(g)),ruleStack:b,occurrenceStack:S});else if(w instanceof ni)d.push(SE(w,v,b,S));else throw Error("non exhaustive match")}return f}i(nm,"nextPossibleTokensAfter");function SE(e,t,r,n){const a=Ye(r);a.push(e.name);const s=Ye(n);return s.push(1),{idx:t,def:e.definition,ruleStack:a,occurrenceStack:s}}i(SE,"expandTopLevelRule");var Re;(function(e){e[e.OPTION=0]="OPTION",e[e.REPETITION=1]="REPETITION",e[e.REPETITION_MANDATORY=2]="REPETITION_MANDATORY",e[e.REPETITION_MANDATORY_WITH_SEPARATOR=3]="REPETITION_MANDATORY_WITH_SEPARATOR",e[e.REPETITION_WITH_SEPARATOR=4]="REPETITION_WITH_SEPARATOR",e[e.ALTERNATION=5]="ALTERNATION"})(Re||(Re={}));function yu(e){if(e instanceof He||e==="Option")return Re.OPTION;if(e instanceof be||e==="Repetition")return Re.REPETITION;if(e instanceof Et||e==="RepetitionMandatory")return Re.REPETITION_MANDATORY;if(e instanceof Ct||e==="RepetitionMandatoryWithSeparator")return Re.REPETITION_MANDATORY_WITH_SEPARATOR;if(e instanceof yt||e==="RepetitionWithSeparator")return Re.REPETITION_WITH_SEPARATOR;if(e instanceof gt||e==="Alternation")return Re.ALTERNATION;throw Error("non exhaustive match")}i(yu,"getProdType");function Lf(e){const{occurrence:t,rule:r,prodType:n,maxLookahead:a}=e,s=yu(n);return s===Re.ALTERNATION?eo(t,r,a):to(t,r,s,a)}i(Lf,"getLookaheadPaths");function wE(e,t,r,n,a,s){const o=eo(e,t,r),l=im(o)?Ss:si;return s(o,n,l,a)}i(wE,"buildLookaheadFuncForOr");function IE(e,t,r,n,a,s){const o=to(e,t,a,r),l=im(o)?Ss:si;return s(o[0],l,n)}i(IE,"buildLookaheadFuncForOptionalProd");function NE(e,t,r,n){const a=e.length,s=zt(e,o=>zt(o,l=>l.length===1));if(t)return function(o){const l=F(o,u=>u.GATE);for(let u=0;uFt(u)),l=At(o,(u,c,f)=>(K(c,d=>{B(u,d.tokenTypeIdx)||(u[d.tokenTypeIdx]=f),K(d.categoryMatches,m=>{B(u,m)||(u[m]=f)})}),u),{});return function(){const u=this.LA(1);return l[u.tokenTypeIdx]}}else return function(){for(let o=0;os.length===1),a=e.length;if(n&&!r){const s=Ft(e);if(s.length===1&&me(s[0].categoryMatches)){const l=s[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===l}}else{const o=At(s,(l,u,c)=>(l[u.tokenTypeIdx]=!0,K(u.categoryMatches,f=>{l[f]=!0}),l),[]);return function(){const l=this.LA(1);return o[l.tokenTypeIdx]===!0}}}else return function(){e:for(let s=0;sTl([o],1)),n=Df(r.length),a=F(r,o=>{const l={};return K(o,u=>{const c=xo(u.partialPath);K(c,f=>{l[f]=!0})}),l});let s=r;for(let o=1;o<=t;o++){const l=s;s=Df(l.length);for(let u=0;u{const w=xo(S.partialPath);K(w,I=>{a[u][I]=!0})})}}}}return n}i(am,"lookAheadSequenceFromAlternatives");function eo(e,t,r,n){const a=new kE(e,Re.ALTERNATION,n);return t.accept(a),am(a.result,r)}i(eo,"getLookaheadPathsForOr");function to(e,t,r,n){const a=new kE(e,r);t.accept(a);const s=a.result,l=new FD(t,e,r).startWalking(),u=new ht({definition:s}),c=new ht({definition:l});return am([u,c],n)}i(to,"getLookaheadPathsForOptionalProd");function $l(e,t){e:for(let r=0;r{const a=t[n];return r===a||a.categoryMatchesMap[r.tokenTypeIdx]})}i(LE,"isStrictPrefixOfPath");function im(e){return zt(e,t=>zt(t,r=>zt(r,n=>me(n.categoryMatches))))}i(im,"areTokenCategoriesNotUsed");function DE(e){const t=e.lookaheadStrategy.validate({rules:e.rules,tokenTypes:e.tokenTypes,grammarName:e.grammarName});return F(t,r=>Object.assign({type:ot.CUSTOM_LOOKAHEAD_VALIDATION},r))}i(DE,"validateLookahead");function xE(e,t,r,n){const a=St(e,u=>ME(u,r)),s=qE(e,t,r),o=St(e,u=>UE(u,r)),l=St(e,u=>FE(u,e,n,r));return a.concat(s,o,l)}i(xE,"validateGrammar");function ME(e,t){const r=new zD;e.accept(r);const n=r.allProductions,a=eD(n,GE),s=Ut(a,l=>l.length>1);return F(Me(s),l=>{const u=Bt(l),c=t.buildDuplicateFoundError(e,l),f=Dt(u),d={message:c,type:ot.DUPLICATE_PRODUCTIONS,ruleName:e.name,dslName:f,occurrence:u.idx},m=sm(u);return m&&(d.parameter=m),d})}i(ME,"validateDuplicateProductions");function GE(e){return`${Dt(e)}_#_${e.idx}_#_${sm(e)}`}i(GE,"identifyProductionForDuplicates");function sm(e){return e instanceof ve?e.terminalType.name:e instanceof st?e.nonTerminalName:""}i(sm,"getExtraProductionArgument");var zD=class extends ai{static{i(this,"OccurrenceValidationCollector")}constructor(){super(...arguments),this.allProductions=[]}visitNonTerminal(e){this.allProductions.push(e)}visitOption(e){this.allProductions.push(e)}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}visitAlternation(e){this.allProductions.push(e)}visitTerminal(e){this.allProductions.push(e)}};function FE(e,t,r,n){const a=[];if(At(t,(o,l)=>l.name===e.name?o+1:o,0)>1){const o=n.buildDuplicateRuleNameError({topLevelRule:e,grammarName:r});a.push({message:o,type:ot.DUPLICATE_RULE_NAME,ruleName:e.name})}return a}i(FE,"validateRuleDoesNotAlreadyExist");function zE(e,t,r){const n=[];let a;return ut(t,e)||(a=`Invalid rule override, rule: ->${e}<- cannot be overridden in the grammar: ->${r}<-as it is not defined in any of the super grammars `,n.push({message:a,type:ot.INVALID_RULE_OVERRIDE,ruleName:e})),n}i(zE,"validateRuleIsOverridden");function om(e,t,r,n=[]){const a=[],s=hs(t.definition);if(me(s))return[];{const o=e.name;ut(s,e)&&a.push({message:r.buildLeftRecursionError({topLevelRule:e,leftRecursionPath:n}),type:ot.LEFT_RECURSION,ruleName:o});const u=fu(s,n.concat([e])),c=St(u,f=>{const d=Ye(n);return d.push(f),om(e,f,r,d)});return a.concat(c)}}i(om,"validateNoLeftRecursion");function hs(e){let t=[];if(me(e))return t;const r=Bt(e);if(r instanceof st)t.push(r.referencedRule);else if(r instanceof ht||r instanceof He||r instanceof Et||r instanceof Ct||r instanceof yt||r instanceof be)t=t.concat(hs(r.definition));else if(r instanceof gt)t=Ft(F(r.definition,s=>hs(s.definition)));else if(!(r instanceof ve))throw Error("non exhaustive match");const n=_s(r),a=e.length>1;if(n&&a){const s=qe(e);return t.concat(hs(s))}else return t}i(hs,"getFirstNoneTerminal");var lm=class extends ai{static{i(this,"OrCollector")}constructor(){super(...arguments),this.alternations=[]}visitAlternation(e){this.alternations.push(e)}};function jE(e,t){const r=new lm;e.accept(r);const n=r.alternations;return St(n,s=>{const o=bs(s.definition);return St(o,(l,u)=>{const c=nm([l],[],si,1);return me(c)?[{message:t.buildEmptyAlternationError({topLevelRule:e,alternation:s,emptyChoiceIdx:u}),type:ot.NONE_LAST_EMPTY_ALT,ruleName:e.name,occurrence:s.idx,alternative:u+1}]:[]})})}i(jE,"validateEmptyOrAlternative");function BE(e,t,r){const n=new lm;e.accept(n);let a=n.alternations;return a=du(a,o=>o.ignoreAmbiguities===!0),St(a,o=>{const l=o.idx,u=o.maxLookahead||t,c=eo(l,e,u,o),f=WE(c,o,e,r),d=VE(c,o,e,r);return f.concat(d)})}i(BE,"validateAmbiguousAlternationAlternatives");var jD=class extends ai{static{i(this,"RepetitionCollector")}constructor(){super(...arguments),this.allProductions=[]}visitRepetitionWithSeparator(e){this.allProductions.push(e)}visitRepetitionMandatory(e){this.allProductions.push(e)}visitRepetitionMandatoryWithSeparator(e){this.allProductions.push(e)}visitRepetition(e){this.allProductions.push(e)}};function UE(e,t){const r=new lm;e.accept(r);const n=r.alternations;return St(n,s=>s.definition.length>255?[{message:t.buildTooManyAlternativesError({topLevelRule:e,alternation:s}),type:ot.TOO_MANY_ALTS,ruleName:e.name,occurrence:s.idx}]:[])}i(UE,"validateTooManyAlts");function KE(e,t,r){const n=[];return K(e,a=>{const s=new jD;a.accept(s);const o=s.allProductions;K(o,l=>{const u=yu(l),c=l.maxLookahead||t,f=l.idx,m=to(f,a,u,c)[0];if(me(Ft(m))){const g=r.buildEmptyRepetitionError({topLevelRule:a,repetition:l});n.push({message:g,type:ot.NO_NON_EMPTY_LOOKAHEAD,ruleName:a.name})}})}),n}i(KE,"validateSomeNonEmptyLookaheadPath");function WE(e,t,r,n){const a=[],s=At(e,(l,u,c)=>(t.definition[c].ignoreAmbiguities===!0||K(u,f=>{const d=[c];K(e,(m,g)=>{c!==g&&$l(m,f)&&t.definition[g].ignoreAmbiguities!==!0&&d.push(g)}),d.length>1&&!$l(a,f)&&(a.push(f),l.push({alts:d,path:f}))}),l),[]);return F(s,l=>{const u=F(l.alts,f=>f+1);return{message:n.buildAlternationAmbiguityError({topLevelRule:r,alternation:t,ambiguityIndices:u,prefixPath:l.path}),type:ot.AMBIGUOUS_ALTS,ruleName:r.name,occurrence:t.idx,alternatives:l.alts}})}i(WE,"checkAlternativesAmbiguities");function VE(e,t,r,n){const a=At(e,(o,l,u)=>{const c=F(l,f=>({idx:u,path:f}));return o.concat(c)},[]);return Js(St(a,o=>{if(t.definition[o.idx].ignoreAmbiguities===!0)return[];const u=o.idx,c=o.path,f=Pt(a,m=>t.definition[m.idx].ignoreAmbiguities!==!0&&m.idx{const g=[m.idx+1,u+1],v=t.idx===0?"":t.idx;return{message:n.buildAlternationPrefixAmbiguityError({topLevelRule:r,alternation:t,ambiguityIndices:g,prefixPath:m.path}),type:ot.AMBIGUOUS_PREFIX_ALTS,ruleName:r.name,occurrence:v,alternatives:g}})}))}i(VE,"checkPrefixAlternativesAmbiguities");function qE(e,t,r){const n=[],a=F(t,s=>s.name);return K(e,s=>{const o=s.name;if(ut(a,o)){const l=r.buildNamespaceConflictError(s);n.push({message:l,type:ot.CONFLICT_TOKENS_RULES_NAMESPACE,ruleName:o})}}),n}i(qE,"checkTerminalAndNoneTerminalsNameSpace");function HE(e){const t=Wp(e,{errMsgProvider:OD}),r={};return K(e.rules,n=>{r[n.name]=n}),_E(r,t.errMsgProvider)}i(HE,"resolveGrammar");function YE(e){return e=Wp(e,{errMsgProvider:_n}),xE(e.rules,e.tokenTypes,e.errMsgProvider,e.grammarName)}i(YE,"validateGrammar");var XE="MismatchedTokenException",JE="NoViableAltException",ZE="EarlyExitException",QE="NotAllInputParsedException",eC=[XE,JE,ZE,QE];Object.freeze(eC);function ws(e){return ut(eC,e.name)}i(ws,"isRecognitionException");var gu=class extends Error{static{i(this,"RecognitionException")}constructor(e,t){super(e),this.token=t,this.resyncedTokens=[],Object.setPrototypeOf(this,new.target.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}},tC=class extends gu{static{i(this,"MismatchedTokenException")}constructor(e,t,r){super(e,t),this.previousToken=r,this.name=XE}},BD=class extends gu{static{i(this,"NoViableAltException")}constructor(e,t,r){super(e,t),this.previousToken=r,this.name=JE}},UD=class extends gu{static{i(this,"NotAllInputParsedException")}constructor(e,t){super(e,t),this.name=QE}},KD=class extends gu{static{i(this,"EarlyExitException")}constructor(e,t,r){super(e,t),this.previousToken=r,this.name=ZE}},Hu={},rC="InRuleRecoveryException",WD=class extends Error{static{i(this,"InRuleRecoveryException")}constructor(e){super(e),this.name=rC}},VD=class{static{i(this,"Recoverable")}initRecoverable(e){this.firstAfterRepMap={},this.resyncFollows={},this.recoveryEnabled=B(e,"recoveryEnabled")?e.recoveryEnabled:Sr.recoveryEnabled,this.recoveryEnabled&&(this.attemptInRepetitionRecovery=nC)}getTokenToInsert(e){const t=Qs(e,"",NaN,NaN,NaN,NaN,NaN,NaN);return t.isInsertedInRecovery=!0,t}canTokenTypeBeInsertedInRecovery(e){return!0}canTokenTypeBeDeletedInRecovery(e){return!0}tryInRepetitionRecovery(e,t,r,n){const a=this.findReSyncTokenType(),s=this.exportLexerState(),o=[];let l=!1;const u=this.LA(1);let c=this.LA(1);const f=i(()=>{const d=this.LA(0),m=this.errorMessageProvider.buildMismatchTokenMessage({expected:n,actual:u,previous:d,ruleName:this.getCurrRuleFullName()}),g=new tC(m,u,this.LA(0));g.resyncedTokens=bs(o),this.SAVE_ERROR(g)},"generateErrorMessage");for(;!l;)if(this.tokenMatcher(c,n)){f();return}else if(r.call(this)){f(),e.apply(this,t);return}else this.tokenMatcher(c,a)?l=!0:(c=this.SKIP_TOKEN(),this.addToResyncTokens(c,o));this.importLexerState(s)}shouldInRepetitionRecoveryBeTried(e,t,r){return!(r===!1||this.tokenMatcher(this.LA(1),e)||this.isBackTracking()||this.canPerformInRuleRecovery(e,this.getFollowsForInRuleRecovery(e,t)))}getFollowsForInRuleRecovery(e,t){const r=this.getCurrentGrammarPath(e,t);return this.getNextPossibleTokenTypes(r)}tryInRuleRecovery(e,t){if(this.canRecoverWithSingleTokenInsertion(e,t))return this.getTokenToInsert(e);if(this.canRecoverWithSingleTokenDeletion(e)){const r=this.SKIP_TOKEN();return this.consumeToken(),r}throw new WD("sad sad panda")}canPerformInRuleRecovery(e,t){return this.canRecoverWithSingleTokenInsertion(e,t)||this.canRecoverWithSingleTokenDeletion(e)}canRecoverWithSingleTokenInsertion(e,t){if(!this.canTokenTypeBeInsertedInRecovery(e)||me(t))return!1;const r=this.LA(1);return Ja(t,a=>this.tokenMatcher(r,a))!==void 0}canRecoverWithSingleTokenDeletion(e){return this.canTokenTypeBeDeletedInRecovery(e)?this.tokenMatcher(this.LA(2),e):!1}isInCurrentRuleReSyncSet(e){const t=this.getCurrFollowKey(),r=this.getFollowSetFromFollowKey(t);return ut(r,e)}findReSyncTokenType(){const e=this.flattenFollowSet();let t=this.LA(1),r=2;for(;;){const n=Ja(e,a=>rm(t,a));if(n!==void 0)return n;t=this.LA(r),r++}}getCurrFollowKey(){if(this.RULE_STACK.length===1)return Hu;const e=this.getLastExplicitRuleShortName(),t=this.getLastExplicitRuleOccurrenceIndex(),r=this.getPreviousExplicitRuleShortName();return{ruleName:this.shortRuleNameToFullName(e),idxInCallingRule:t,inRule:this.shortRuleNameToFullName(r)}}buildFullFollowKeyStack(){const e=this.RULE_STACK,t=this.RULE_OCCURRENCE_STACK;return F(e,(r,n)=>n===0?Hu:{ruleName:this.shortRuleNameToFullName(r),idxInCallingRule:t[n],inRule:this.shortRuleNameToFullName(e[n-1])})}flattenFollowSet(){const e=F(this.buildFullFollowKeyStack(),t=>this.getFollowSetFromFollowKey(t));return Ft(e)}getFollowSetFromFollowKey(e){if(e===Hu)return[Ur];const t=e.ruleName+e.idxInCallingRule+BA+e.inRule;return this.resyncFollows[t]}addToResyncTokens(e,t){return this.tokenMatcher(e,Ur)||t.push(e),t}reSyncTo(e){const t=[];let r=this.LA(1);for(;this.tokenMatcher(r,e)===!1;)r=this.SKIP_TOKEN(),this.addToResyncTokens(r,t);return bs(t)}attemptInRepetitionRecovery(e,t,r,n,a,s,o){}getCurrentGrammarPath(e,t){const r=this.getHumanReadableRuleStack(),n=Ye(this.RULE_OCCURRENCE_STACK);return{ruleStack:r,occurrenceStack:n,lastTok:e,lastTokOccurrence:t}}getHumanReadableRuleStack(){return F(this.RULE_STACK,e=>this.shortRuleNameToFullName(e))}};function nC(e,t,r,n,a,s,o){const l=this.getKeyForAutomaticLookahead(n,a);let u=this.firstAfterRepMap[l];if(u===void 0){const m=this.getCurrRuleFullName(),g=this.getGAstProductions()[m];u=new s(g,a).startWalking(),this.firstAfterRepMap[l]=u}let c=u.token,f=u.occurrence;const d=u.isEndOfRule;this.RULE_STACK.length===1&&d&&c===void 0&&(c=Ur,f=1),!(c===void 0||f===void 0)&&this.shouldInRepetitionRecoveryBeTried(c,f,o)&&this.tryInRepetitionRecovery(e,t,r,c)}i(nC,"attemptInRepetitionRecovery");var qD=4,Yr=8,aC=1<om(t,t,_n))}validateEmptyOrAlternatives(e){return St(e,t=>jE(t,_n))}validateAmbiguousAlternationAlternatives(e,t){return St(e,r=>BE(r,t,_n))}validateSomeNonEmptyLookaheadPath(e,t){return KE(e,t,_n)}buildLookaheadForAlternation(e){return wE(e.prodOccurrence,e.rule,e.maxLookahead,e.hasPredicates,e.dynamicTokensEnabled,NE)}buildLookaheadForOptional(e){return IE(e.prodOccurrence,e.rule,e.maxLookahead,e.dynamicTokensEnabled,yu(e.prodType),PE)}},HD=class{static{i(this,"LooksAhead")}initLooksAhead(e){this.dynamicTokensEnabled=B(e,"dynamicTokensEnabled")?e.dynamicTokensEnabled:Sr.dynamicTokensEnabled,this.maxLookahead=B(e,"maxLookahead")?e.maxLookahead:Sr.maxLookahead,this.lookaheadStrategy=B(e,"lookaheadStrategy")?e.lookaheadStrategy:new um({maxLookahead:this.maxLookahead}),this.lookAheadFuncsCache=new Map}preComputeLookaheadFunctions(e){K(e,t=>{this.TRACE_INIT(`${t.name} Rule Lookahead`,()=>{const{alternation:r,repetition:n,option:a,repetitionMandatory:s,repetitionMandatoryWithSeparator:o,repetitionWithSeparator:l}=sC(t);K(r,u=>{const c=u.idx===0?"":u.idx;this.TRACE_INIT(`${Dt(u)}${c}`,()=>{const f=this.lookaheadStrategy.buildLookaheadForAlternation({prodOccurrence:u.idx,rule:t,maxLookahead:u.maxLookahead||this.maxLookahead,hasPredicates:u.hasPredicates,dynamicTokensEnabled:this.dynamicTokensEnabled}),d=Go(this.fullRuleNameToShort[t.name],aC,u.idx);this.setLaFuncCache(d,f)})}),K(n,u=>{this.computeLookaheadFunc(t,u.idx,xf,"Repetition",u.maxLookahead,Dt(u))}),K(a,u=>{this.computeLookaheadFunc(t,u.idx,iC,"Option",u.maxLookahead,Dt(u))}),K(s,u=>{this.computeLookaheadFunc(t,u.idx,Mf,"RepetitionMandatory",u.maxLookahead,Dt(u))}),K(o,u=>{this.computeLookaheadFunc(t,u.idx,Mo,"RepetitionMandatoryWithSeparator",u.maxLookahead,Dt(u))}),K(l,u=>{this.computeLookaheadFunc(t,u.idx,Gf,"RepetitionWithSeparator",u.maxLookahead,Dt(u))})})})}computeLookaheadFunc(e,t,r,n,a,s){this.TRACE_INIT(`${s}${t===0?"":t}`,()=>{const o=this.lookaheadStrategy.buildLookaheadForOptional({prodOccurrence:t,rule:e,maxLookahead:a||this.maxLookahead,dynamicTokensEnabled:this.dynamicTokensEnabled,prodType:n}),l=Go(this.fullRuleNameToShort[e.name],r,t);this.setLaFuncCache(l,o)})}getKeyForAutomaticLookahead(e,t){const r=this.getLastExplicitRuleShortName();return Go(r,e,t)}getLaFuncFromCache(e){return this.lookAheadFuncsCache.get(e)}setLaFuncCache(e,t){this.lookAheadFuncsCache.set(e,t)}},YD=class extends ai{static{i(this,"DslMethodsCollectorVisitor")}constructor(){super(...arguments),this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}reset(){this.dslMethods={option:[],alternation:[],repetition:[],repetitionWithSeparator:[],repetitionMandatory:[],repetitionMandatoryWithSeparator:[]}}visitOption(e){this.dslMethods.option.push(e)}visitRepetitionWithSeparator(e){this.dslMethods.repetitionWithSeparator.push(e)}visitRepetitionMandatory(e){this.dslMethods.repetitionMandatory.push(e)}visitRepetitionMandatoryWithSeparator(e){this.dslMethods.repetitionMandatoryWithSeparator.push(e)}visitRepetition(e){this.dslMethods.repetition.push(e)}visitAlternation(e){this.dslMethods.alternation.push(e)}},oo=new YD;function sC(e){oo.reset(),e.accept(oo);const t=oo.dslMethods;return oo.reset(),t}i(sC,"collectMethods");function Ff(e,t){isNaN(e.startOffset)===!0?(e.startOffset=t.startOffset,e.endOffset=t.endOffset):e.endOffseto.msg);throw Error(`Errors Detected in CST Visitor <${this.constructor.name}>: + ${s.join(` + +`).replace(/\n/g,` + `)}`)}},"validateVisitor")};return r.prototype=n,r.prototype.constructor=r,r._RULE_NAMES=t,r}i(cC,"createBaseSemanticVisitorConstructor");function fC(e,t,r){const n=i(function(){},"derivedConstructor");cm(n,e+"BaseSemanticsWithDefaults");const a=Object.create(r.prototype);return K(t,s=>{a[s]=uC}),n.prototype=a,n.prototype.constructor=n,n}i(fC,"createBaseVisitorConstructorWithDefaults");var jf;(function(e){e[e.REDUNDANT_METHOD=0]="REDUNDANT_METHOD",e[e.MISSING_METHOD=1]="MISSING_METHOD"})(jf||(jf={}));function dC(e,t){return pC(e,t)}i(dC,"validateVisitor");function pC(e,t){const r=Pt(t,a=>Pr(e[a])===!1),n=F(r,a=>({msg:`Missing visitor method: <${a}> on ${e.constructor.name} CST Visitor.`,type:jf.MISSING_METHOD,methodName:a}));return Js(n)}i(pC,"validateMissingCstMethods");var JD=class{static{i(this,"TreeBuilder")}initTreeBuilder(e){if(this.CST_STACK=[],this.outputCst=e.outputCst,this.nodeLocationTracking=B(e,"nodeLocationTracking")?e.nodeLocationTracking:Sr.nodeLocationTracking,!this.outputCst)this.cstInvocationStateUpdate=Fe,this.cstFinallyStateUpdate=Fe,this.cstPostTerminal=Fe,this.cstPostNonTerminal=Fe,this.cstPostRule=Fe;else if(/full/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=zf,this.setNodeLocationFromNode=zf,this.cstPostRule=Fe,this.setInitialNodeLocation=this.setInitialNodeLocationFullRecovery):(this.setNodeLocationFromToken=Fe,this.setNodeLocationFromNode=Fe,this.cstPostRule=this.cstPostRuleFull,this.setInitialNodeLocation=this.setInitialNodeLocationFullRegular);else if(/onlyOffset/i.test(this.nodeLocationTracking))this.recoveryEnabled?(this.setNodeLocationFromToken=Ff,this.setNodeLocationFromNode=Ff,this.cstPostRule=Fe,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRecovery):(this.setNodeLocationFromToken=Fe,this.setNodeLocationFromNode=Fe,this.cstPostRule=this.cstPostRuleOnlyOffset,this.setInitialNodeLocation=this.setInitialNodeLocationOnlyOffsetRegular);else if(/none/i.test(this.nodeLocationTracking))this.setNodeLocationFromToken=Fe,this.setNodeLocationFromNode=Fe,this.cstPostRule=Fe,this.setInitialNodeLocation=Fe;else throw Error(`Invalid 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 t=this.LA(1);e.location={startOffset:t.startOffset,startLine:t.startLine,startColumn:t.startColumn,endOffset:NaN,endLine:NaN,endColumn:NaN}}cstInvocationStateUpdate(e){const t={name:e,children:Object.create(null)};this.setInitialNodeLocation(t),this.CST_STACK.push(t)}cstFinallyStateUpdate(){this.CST_STACK.pop()}cstPostRuleFull(e){const t=this.LA(0),r=e.location;r.startOffset<=t.startOffset?(r.endOffset=t.endOffset,r.endLine=t.endLine,r.endColumn=t.endColumn):(r.startOffset=NaN,r.startLine=NaN,r.startColumn=NaN)}cstPostRuleOnlyOffset(e){const t=this.LA(0),r=e.location;r.startOffset<=t.startOffset?r.endOffset=t.endOffset:r.startOffset=NaN}cstPostTerminal(e,t){const r=this.CST_STACK[this.CST_STACK.length-1];oC(r,t,e),this.setNodeLocationFromToken(r.location,t)}cstPostNonTerminal(e,t){const r=this.CST_STACK[this.CST_STACK.length-1];lC(r,t,e),this.setNodeLocationFromNode(r.location,e.location)}getBaseCstVisitorConstructor(){if(br(this.baseCstVisitorConstructor)){const e=cC(this.className,$t(this.gastProductionsCache));return this.baseCstVisitorConstructor=e,e}return this.baseCstVisitorConstructor}getBaseCstVisitorConstructorWithDefaults(){if(br(this.baseCstVisitorWithDefaultsConstructor)){const e=fC(this.className,$t(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]}},ZD=class{static{i(this,"LexerAdapter")}initLexerAdapter(){this.tokVector=[],this.tokVectorLength=0,this.currIdx=-1}set input(e){if(this.selfAnalysisDone!==!0)throw Error("Missing 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)):Rl}LA(e){const t=this.currIdx+e;return t<0||this.tokVectorLength<=t?Rl:this.tokVector[t]}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()}},QD=class{static{i(this,"RecognizerApi")}ACTION(e){return e.call(this)}consume(e,t,r){return this.consumeInternal(t,e,r)}subrule(e,t,r){return this.subruleInternal(t,e,r)}option(e,t){return this.optionInternal(t,e)}or(e,t){return this.orInternal(t,e)}many(e,t){return this.manyInternal(e,t)}atLeastOne(e,t){return this.atLeastOneInternal(e,t)}CONSUME(e,t){return this.consumeInternal(e,0,t)}CONSUME1(e,t){return this.consumeInternal(e,1,t)}CONSUME2(e,t){return this.consumeInternal(e,2,t)}CONSUME3(e,t){return this.consumeInternal(e,3,t)}CONSUME4(e,t){return this.consumeInternal(e,4,t)}CONSUME5(e,t){return this.consumeInternal(e,5,t)}CONSUME6(e,t){return this.consumeInternal(e,6,t)}CONSUME7(e,t){return this.consumeInternal(e,7,t)}CONSUME8(e,t){return this.consumeInternal(e,8,t)}CONSUME9(e,t){return this.consumeInternal(e,9,t)}SUBRULE(e,t){return this.subruleInternal(e,0,t)}SUBRULE1(e,t){return this.subruleInternal(e,1,t)}SUBRULE2(e,t){return this.subruleInternal(e,2,t)}SUBRULE3(e,t){return this.subruleInternal(e,3,t)}SUBRULE4(e,t){return this.subruleInternal(e,4,t)}SUBRULE5(e,t){return this.subruleInternal(e,5,t)}SUBRULE6(e,t){return this.subruleInternal(e,6,t)}SUBRULE7(e,t){return this.subruleInternal(e,7,t)}SUBRULE8(e,t){return this.subruleInternal(e,8,t)}SUBRULE9(e,t){return this.subruleInternal(e,9,t)}OPTION(e){return this.optionInternal(e,0)}OPTION1(e){return this.optionInternal(e,1)}OPTION2(e){return this.optionInternal(e,2)}OPTION3(e){return this.optionInternal(e,3)}OPTION4(e){return this.optionInternal(e,4)}OPTION5(e){return this.optionInternal(e,5)}OPTION6(e){return this.optionInternal(e,6)}OPTION7(e){return this.optionInternal(e,7)}OPTION8(e){return this.optionInternal(e,8)}OPTION9(e){return this.optionInternal(e,9)}OR(e){return this.orInternal(e,0)}OR1(e){return this.orInternal(e,1)}OR2(e){return this.orInternal(e,2)}OR3(e){return this.orInternal(e,3)}OR4(e){return this.orInternal(e,4)}OR5(e){return this.orInternal(e,5)}OR6(e){return this.orInternal(e,6)}OR7(e){return this.orInternal(e,7)}OR8(e){return this.orInternal(e,8)}OR9(e){return this.orInternal(e,9)}MANY(e){this.manyInternal(0,e)}MANY1(e){this.manyInternal(1,e)}MANY2(e){this.manyInternal(2,e)}MANY3(e){this.manyInternal(3,e)}MANY4(e){this.manyInternal(4,e)}MANY5(e){this.manyInternal(5,e)}MANY6(e){this.manyInternal(6,e)}MANY7(e){this.manyInternal(7,e)}MANY8(e){this.manyInternal(8,e)}MANY9(e){this.manyInternal(9,e)}MANY_SEP(e){this.manySepFirstInternal(0,e)}MANY_SEP1(e){this.manySepFirstInternal(1,e)}MANY_SEP2(e){this.manySepFirstInternal(2,e)}MANY_SEP3(e){this.manySepFirstInternal(3,e)}MANY_SEP4(e){this.manySepFirstInternal(4,e)}MANY_SEP5(e){this.manySepFirstInternal(5,e)}MANY_SEP6(e){this.manySepFirstInternal(6,e)}MANY_SEP7(e){this.manySepFirstInternal(7,e)}MANY_SEP8(e){this.manySepFirstInternal(8,e)}MANY_SEP9(e){this.manySepFirstInternal(9,e)}AT_LEAST_ONE(e){this.atLeastOneInternal(0,e)}AT_LEAST_ONE1(e){return this.atLeastOneInternal(1,e)}AT_LEAST_ONE2(e){this.atLeastOneInternal(2,e)}AT_LEAST_ONE3(e){this.atLeastOneInternal(3,e)}AT_LEAST_ONE4(e){this.atLeastOneInternal(4,e)}AT_LEAST_ONE5(e){this.atLeastOneInternal(5,e)}AT_LEAST_ONE6(e){this.atLeastOneInternal(6,e)}AT_LEAST_ONE7(e){this.atLeastOneInternal(7,e)}AT_LEAST_ONE8(e){this.atLeastOneInternal(8,e)}AT_LEAST_ONE9(e){this.atLeastOneInternal(9,e)}AT_LEAST_ONE_SEP(e){this.atLeastOneSepFirstInternal(0,e)}AT_LEAST_ONE_SEP1(e){this.atLeastOneSepFirstInternal(1,e)}AT_LEAST_ONE_SEP2(e){this.atLeastOneSepFirstInternal(2,e)}AT_LEAST_ONE_SEP3(e){this.atLeastOneSepFirstInternal(3,e)}AT_LEAST_ONE_SEP4(e){this.atLeastOneSepFirstInternal(4,e)}AT_LEAST_ONE_SEP5(e){this.atLeastOneSepFirstInternal(5,e)}AT_LEAST_ONE_SEP6(e){this.atLeastOneSepFirstInternal(6,e)}AT_LEAST_ONE_SEP7(e){this.atLeastOneSepFirstInternal(7,e)}AT_LEAST_ONE_SEP8(e){this.atLeastOneSepFirstInternal(8,e)}AT_LEAST_ONE_SEP9(e){this.atLeastOneSepFirstInternal(9,e)}RULE(e,t,r=Al){if(ut(this.definedRulesNames,e)){const s={message:_n.buildDuplicateRuleNameError({topLevelRule:e,grammarName:this.className}),type:ot.DUPLICATE_RULE_NAME,ruleName:e};this.definitionErrors.push(s)}this.definedRulesNames.push(e);const n=this.defineRule(e,t,r);return this[e]=n,n}OVERRIDE_RULE(e,t,r=Al){const n=zE(e,this.definedRulesNames,this.className);this.definitionErrors=this.definitionErrors.concat(n);const a=this.defineRule(e,t,r);return this[e]=a,a}BACKTRACK(e,t){return function(){this.isBackTrackingStack.push(1);const r=this.saveRecogState();try{return e.apply(this,t),!0}catch(n){if(ws(n))return!1;throw n}finally{this.reloadRecogState(r),this.isBackTrackingStack.pop()}}}getGAstProductions(){return this.gastProductionsCache}getSerializedGastProductions(){return xA(Me(this.gastProductionsCache))}},ex=class{static{i(this,"RecognizerEngine")}initRecognizerEngine(e,t){if(this.className=this.constructor.name,this.shortRuleNameToFull={},this.fullRuleNameToShort={},this.ruleShortNameIdx=256,this.tokenMatcher=Ss,this.subruleIdx=0,this.definedRulesNames=[],this.tokensMap={},this.isBackTrackingStack=[],this.RULE_STACK=[],this.RULE_OCCURRENCE_STACK=[],this.gastProductionsCache={},B(t,"serializedGrammar"))throw Error(`The Parser's configuration can no longer contain a property. + See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_6-0-0 + For Further details.`);if(re(e)){if(me(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(re(e))this.tokensMap=At(e,(a,s)=>(a[s.name]=s,a),{});else if(B(e,"modes")&&zt(Ft(Me(e.modes)),CE)){const a=Ft(Me(e.modes)),s=Vp(a);this.tokensMap=At(s,(o,l)=>(o[l.name]=l,o),{})}else if(It(e))this.tokensMap=Ye(e);else throw new Error(" argument must be An Array of Token constructors, A dictionary of Token constructors or an IMultiModeLexerDefinition");this.tokensMap.EOF=Ur;const r=B(e,"modes")?Ft(Me(e.modes)):Me(e),n=zt(r,a=>me(a.categoryMatches));this.tokenMatcher=n?Ss:si,oi(Me(this.tokensMap))}defineRule(e,t,r){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 n=B(r,"resyncEnabled")?r.resyncEnabled:Al.resyncEnabled,a=B(r,"recoveryValueFunc")?r.recoveryValueFunc:Al.recoveryValueFunc,s=this.ruleShortNameIdx<s.call(this)&&o.call(this),"lookAheadFunc")}}else a=e;if(n.call(this)===!0)return a.call(this)}atLeastOneInternal(e,t){const r=this.getKeyForAutomaticLookahead(Mf,e);return this.atLeastOneInternalLogic(e,t,r)}atLeastOneInternalLogic(e,t,r){let n=this.getLaFuncFromCache(r),a;if(typeof t!="function"){a=t.DEF;const s=t.GATE;if(s!==void 0){const o=n;n=i(()=>s.call(this)&&o.call(this),"lookAheadFunc")}}else a=t;if(n.call(this)===!0){let s=this.doSingleRepetition(a);for(;n.call(this)===!0&&s===!0;)s=this.doSingleRepetition(a)}else throw this.raiseEarlyExitException(e,Re.REPETITION_MANDATORY,t.ERR_MSG);this.attemptInRepetitionRecovery(this.atLeastOneInternal,[e,t],n,Mf,e,GD)}atLeastOneSepFirstInternal(e,t){const r=this.getKeyForAutomaticLookahead(Mo,e);this.atLeastOneSepFirstInternalLogic(e,t,r)}atLeastOneSepFirstInternalLogic(e,t,r){const n=t.DEF,a=t.SEP;if(this.getLaFuncFromCache(r).call(this)===!0){n.call(this);const o=i(()=>this.tokenMatcher(this.LA(1),a),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),a)===!0;)this.CONSUME(a),n.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,a,o,n,ty],o,Mo,e,ty)}else throw this.raiseEarlyExitException(e,Re.REPETITION_MANDATORY_WITH_SEPARATOR,t.ERR_MSG)}manyInternal(e,t){const r=this.getKeyForAutomaticLookahead(xf,e);return this.manyInternalLogic(e,t,r)}manyInternalLogic(e,t,r){let n=this.getLaFuncFromCache(r),a;if(typeof t!="function"){a=t.DEF;const o=t.GATE;if(o!==void 0){const l=n;n=i(()=>o.call(this)&&l.call(this),"lookaheadFunction")}}else a=t;let s=!0;for(;n.call(this)===!0&&s===!0;)s=this.doSingleRepetition(a);this.attemptInRepetitionRecovery(this.manyInternal,[e,t],n,xf,e,MD,s)}manySepFirstInternal(e,t){const r=this.getKeyForAutomaticLookahead(Gf,e);this.manySepFirstInternalLogic(e,t,r)}manySepFirstInternalLogic(e,t,r){const n=t.DEF,a=t.SEP;if(this.getLaFuncFromCache(r).call(this)===!0){n.call(this);const o=i(()=>this.tokenMatcher(this.LA(1),a),"separatorLookAheadFunc");for(;this.tokenMatcher(this.LA(1),a)===!0;)this.CONSUME(a),n.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,a,o,n,ey],o,Gf,e,ey)}}repetitionSepSecondInternal(e,t,r,n,a){for(;r();)this.CONSUME(t),n.call(this);this.attemptInRepetitionRecovery(this.repetitionSepSecondInternal,[e,t,r,n,a],r,Mo,e,a)}doSingleRepetition(e){const t=this.getLexerPosition();return e.call(this),this.getLexerPosition()>t}orInternal(e,t){const r=this.getKeyForAutomaticLookahead(aC,t),n=re(e)?e:e.DEF,s=this.getLaFuncFromCache(r).call(this,n);if(s!==void 0)return n[s].ALT.call(this);this.raiseNoAltException(t,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),t=this.errorMessageProvider.buildNotAllInputParsedMessage({firstRedundant:e,ruleName:this.getCurrRuleFullName()});this.SAVE_ERROR(new UD(t,e))}}subruleInternal(e,t,r){let n;try{const a=r!==void 0?r.ARGS:void 0;return this.subruleIdx=t,n=e.apply(this,a),this.cstPostNonTerminal(n,r!==void 0&&r.LABEL!==void 0?r.LABEL:e.ruleName),n}catch(a){throw this.subruleInternalError(a,r,e.ruleName)}}subruleInternalError(e,t,r){throw ws(e)&&e.partialCstResult!==void 0&&(this.cstPostNonTerminal(e.partialCstResult,t!==void 0&&t.LABEL!==void 0?t.LABEL:r),delete e.partialCstResult),e}consumeInternal(e,t,r){let n;try{const a=this.LA(1);this.tokenMatcher(a,e)===!0?(this.consumeToken(),n=a):this.consumeInternalError(e,a,r)}catch(a){n=this.consumeInternalRecovery(e,t,a)}return this.cstPostTerminal(r!==void 0&&r.LABEL!==void 0?r.LABEL:e.name,n),n}consumeInternalError(e,t,r){let n;const a=this.LA(0);throw r!==void 0&&r.ERR_MSG?n=r.ERR_MSG:n=this.errorMessageProvider.buildMismatchTokenMessage({expected:e,actual:t,previous:a,ruleName:this.getCurrRuleFullName()}),this.SAVE_ERROR(new tC(n,t,a))}consumeInternalRecovery(e,t,r){if(this.recoveryEnabled&&r.name==="MismatchedTokenException"&&!this.isBackTracking()){const n=this.getFollowsForInRuleRecovery(e,t);try{return this.tryInRuleRecovery(e,n)}catch(a){throw a.name===rC?r:a}}else throw r}saveRecogState(){const e=this.errors,t=Ye(this.RULE_STACK);return{errors:e,lexerState:this.exportLexerState(),RULE_STACK:t,CST_STACK:this.CST_STACK}}reloadRecogState(e){this.errors=e.errors,this.importLexerState(e.lexerState),this.RULE_STACK=e.RULE_STACK}ruleInvocationStateUpdate(e,t,r){this.RULE_OCCURRENCE_STACK.push(r),this.RULE_STACK.push(e),this.cstInvocationStateUpdate(t)}isBackTracking(){return this.isBackTrackingStack.length!==0}getCurrRuleFullName(){const e=this.getLastExplicitRuleShortName();return this.shortRuleNameToFull[e]}shortRuleNameToFullName(e){return this.shortRuleNameToFull[e]}isAtEndOfInput(){return this.tokenMatcher(this.LA(1),Ur)}reset(){this.resetLexerState(),this.subruleIdx=0,this.isBackTrackingStack=[],this.errors=[],this.RULE_STACK=[],this.CST_STACK=[],this.RULE_OCCURRENCE_STACK=[]}},tx=class{static{i(this,"ErrorHandler")}initErrorHandler(e){this._errors=[],this.errorMessageProvider=B(e,"errorMessageProvider")?e.errorMessageProvider:Sr.errorMessageProvider}SAVE_ERROR(e){if(ws(e))return e.context={ruleStack:this.getHumanReadableRuleStack(),ruleOccurrenceStack:Ye(this.RULE_OCCURRENCE_STACK)},this._errors.push(e),e;throw Error("Trying to save an Error which is not a RecognitionException")}get errors(){return Ye(this._errors)}set errors(e){this._errors=e}raiseEarlyExitException(e,t,r){const n=this.getCurrRuleFullName(),a=this.getGAstProductions()[n],o=to(e,a,t,this.maxLookahead)[0],l=[];for(let c=1;c<=this.maxLookahead;c++)l.push(this.LA(c));const u=this.errorMessageProvider.buildEarlyExitMessage({expectedIterationPaths:o,actual:l,previous:this.LA(0),customUserDescription:r,ruleName:n});throw this.SAVE_ERROR(new KD(u,this.LA(1),this.LA(0)))}raiseNoAltException(e,t){const r=this.getCurrRuleFullName(),n=this.getGAstProductions()[r],a=eo(e,n,this.maxLookahead),s=[];for(let u=1;u<=this.maxLookahead;u++)s.push(this.LA(u));const o=this.LA(0),l=this.errorMessageProvider.buildNoViableAltMessage({expectedPathsPerAlt:a,actual:s,previous:o,customUserDescription:t,ruleName:this.getCurrRuleFullName()});throw this.SAVE_ERROR(new BD(l,this.LA(1),o))}},rx=class{static{i(this,"ContentAssist")}initContentAssist(){}computeContentAssist(e,t){const r=this.gastProductionsCache[e];if(br(r))throw Error(`Rule ->${e}<- does not exist in this grammar.`);return nm([r],t,this.tokenMatcher,this.maxLookahead)}getNextPossibleTokenTypes(e){const t=Bt(e.ruleStack),n=this.getGAstProductions()[t];return new xD(n,e).startWalking()}},vu={description:"This Object indicates the Parser is during Recording Phase"};Object.freeze(vu);var ry=!0,ny=Math.pow(2,Yr)-1,mC=ja({name:"RECORDING_PHASE_TOKEN",pattern:at.NA});oi([mC]);var hC=Qs(mC,`This IToken indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,-1,-1,-1,-1,-1,-1);Object.freeze(hC);var nx={name:`This CSTNode indicates the Parser is in Recording Phase + See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details`,children:{}},ax=class{static{i(this,"GastRecorder")}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 t=e>0?e:"";this[`CONSUME${t}`]=function(r,n){return this.consumeInternalRecord(r,e,n)},this[`SUBRULE${t}`]=function(r,n){return this.subruleInternalRecord(r,e,n)},this[`OPTION${t}`]=function(r){return this.optionInternalRecord(r,e)},this[`OR${t}`]=function(r){return this.orInternalRecord(r,e)},this[`MANY${t}`]=function(r){this.manyInternalRecord(e,r)},this[`MANY_SEP${t}`]=function(r){this.manySepFirstInternalRecord(e,r)},this[`AT_LEAST_ONE${t}`]=function(r){this.atLeastOneInternalRecord(e,r)},this[`AT_LEAST_ONE_SEP${t}`]=function(r){this.atLeastOneSepFirstInternalRecord(e,r)}}this.consume=function(e,t,r){return this.consumeInternalRecord(t,e,r)},this.subrule=function(e,t,r){return this.subruleInternalRecord(t,e,r)},this.option=function(e,t){return this.optionInternalRecord(t,e)},this.or=function(e,t){return this.orInternalRecord(t,e)},this.many=function(e,t){this.manyInternalRecord(e,t)},this.atLeastOne=function(e,t){this.atLeastOneInternalRecord(e,t)},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 t=0;t<10;t++){const r=t>0?t:"";delete e[`CONSUME${r}`],delete e[`SUBRULE${r}`],delete e[`OPTION${r}`],delete e[`OR${r}`],delete e[`MANY${r}`],delete e[`MANY_SEP${r}`],delete e[`AT_LEAST_ONE${r}`],delete e[`AT_LEAST_ONE_SEP${r}`]}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,t){return()=>!0}LA_RECORD(e){return Rl}topLevelRuleRecord(e,t){try{const r=new ni({definition:[],name:e});return r.name=e,this.recordingProdStack.push(r),t.call(this),this.recordingProdStack.pop(),r}catch(r){if(r.KNOWN_RECORDER_ERROR!==!0)try{r.message=r.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 r}throw r}}optionInternalRecord(e,t){return Ra.call(this,He,e,t)}atLeastOneInternalRecord(e,t){Ra.call(this,Et,t,e)}atLeastOneSepFirstInternalRecord(e,t){Ra.call(this,Ct,t,e,ry)}manyInternalRecord(e,t){Ra.call(this,be,t,e)}manySepFirstInternalRecord(e,t){Ra.call(this,yt,t,e,ry)}orInternalRecord(e,t){return yC.call(this,e,t)}subruleInternalRecord(e,t,r){if(Is(t),!e||B(e,"ruleName")===!1){const o=new Error(` argument is invalid expecting a Parser method reference but got: <${JSON.stringify(e)}> + inside top level rule: <${this.recordingProdStack[0].name}>`);throw o.KNOWN_RECORDER_ERROR=!0,o}const n=kn(this.recordingProdStack),a=e.ruleName,s=new st({idx:t,nonTerminalName:a,label:r?.LABEL,referencedRule:void 0});return n.definition.push(s),this.outputCst?nx:vu}consumeInternalRecord(e,t,r){if(Is(t),!em(e)){const s=new Error(` argument is invalid expecting a TokenType reference but got: <${JSON.stringify(e)}> + inside top level rule: <${this.recordingProdStack[0].name}>`);throw s.KNOWN_RECORDER_ERROR=!0,s}const n=kn(this.recordingProdStack),a=new ve({idx:t,terminalType:e,label:r?.LABEL});return n.definition.push(a),hC}};function Ra(e,t,r,n=!1){Is(r);const a=kn(this.recordingProdStack),s=Pr(t)?t:t.DEF,o=new e({definition:[],idx:r});return n&&(o.separator=t.SEP),B(t,"MAX_LOOKAHEAD")&&(o.maxLookahead=t.MAX_LOOKAHEAD),this.recordingProdStack.push(o),s.call(this),a.definition.push(o),this.recordingProdStack.pop(),vu}i(Ra,"recordProd");function yC(e,t){Is(t);const r=kn(this.recordingProdStack),n=re(e)===!1,a=n===!1?e:e.DEF,s=new gt({definition:[],idx:t,ignoreAmbiguities:n&&e.IGNORE_AMBIGUITIES===!0});B(e,"MAX_LOOKAHEAD")&&(s.maxLookahead=e.MAX_LOOKAHEAD);const o=PA(a,l=>Pr(l.GATE));return s.hasPredicates=o,r.definition.push(s),K(a,l=>{const u=new ht({definition:[]});s.definition.push(u),B(l,"IGNORE_AMBIGUITIES")?u.ignoreAmbiguities=l.IGNORE_AMBIGUITIES:B(l,"GATE")&&(u.ignoreAmbiguities=!0),this.recordingProdStack.push(u),l.ALT.call(this),this.recordingProdStack.pop()}),vu}i(yC,"recordOrProd");function Bf(e){return e===0?"":`${e}`}i(Bf,"getIdxSuffix");function Is(e){if(e<0||e>ny){const t=new Error(`Invalid DSL Method idx value: <${e}> + Idx value must be a none negative value smaller than ${ny+1}`);throw t.KNOWN_RECORDER_ERROR=!0,t}}i(Is,"assertMethodIdxIsValid");var ix=class{static{i(this,"PerformanceTracer")}initPerformanceTracer(e){if(B(e,"traceInitPerf")){const t=e.traceInitPerf,r=typeof t=="number";this.traceInitMaxIdent=r?t:1/0,this.traceInitPerf=r?t>0:t}else this.traceInitMaxIdent=0,this.traceInitPerf=Sr.traceInitPerf;this.traceInitIndent=-1}TRACE_INIT(e,t){if(this.traceInitPerf===!0){this.traceInitIndent++;const r=new Array(this.traceInitIndent+1).join(" ");this.traceInitIndent <${e}>`);const{time:n,value:a}=Hp(t),s=n>10?console.warn:console.log;return this.traceInitIndent time: ${n}ms`),this.traceInitIndent--,a}else return t()}};function gC(e,t){t.forEach(r=>{const n=r.prototype;Object.getOwnPropertyNames(n).forEach(a=>{if(a==="constructor")return;const s=Object.getOwnPropertyDescriptor(n,a);s&&(s.get||s.set)?Object.defineProperty(e.prototype,a,s):e.prototype[a]=r.prototype[a]})})}i(gC,"applyMixins");var Rl=Qs(Ur,"",NaN,NaN,NaN,NaN,NaN,NaN);Object.freeze(Rl);var Sr=Object.freeze({recoveryEnabled:!1,maxLookahead:3,dynamicTokensEnabled:!1,outputCst:!0,errorMessageProvider:Ga,nodeLocationTracking:"none",traceInitPerf:!1,skipValidations:!1}),Al=Object.freeze({recoveryValueFunc:i(()=>{},"recoveryValueFunc"),resyncEnabled:!0}),ot;(function(e){e[e.INVALID_RULE_NAME=0]="INVALID_RULE_NAME",e[e.DUPLICATE_RULE_NAME=1]="DUPLICATE_RULE_NAME",e[e.INVALID_RULE_OVERRIDE=2]="INVALID_RULE_OVERRIDE",e[e.DUPLICATE_PRODUCTIONS=3]="DUPLICATE_PRODUCTIONS",e[e.UNRESOLVED_SUBRULE_REF=4]="UNRESOLVED_SUBRULE_REF",e[e.LEFT_RECURSION=5]="LEFT_RECURSION",e[e.NONE_LAST_EMPTY_ALT=6]="NONE_LAST_EMPTY_ALT",e[e.AMBIGUOUS_ALTS=7]="AMBIGUOUS_ALTS",e[e.CONFLICT_TOKENS_RULES_NAMESPACE=8]="CONFLICT_TOKENS_RULES_NAMESPACE",e[e.INVALID_TOKEN_NAME=9]="INVALID_TOKEN_NAME",e[e.NO_NON_EMPTY_LOOKAHEAD=10]="NO_NON_EMPTY_LOOKAHEAD",e[e.AMBIGUOUS_PREFIX_ALTS=11]="AMBIGUOUS_PREFIX_ALTS",e[e.TOO_MANY_ALTS=12]="TOO_MANY_ALTS",e[e.CUSTOM_LOOKAHEAD_VALIDATION=13]="CUSTOM_LOOKAHEAD_VALIDATION"})(ot||(ot={}));function Uf(e=void 0){return function(){return e}}i(Uf,"EMPTY_ALT");var fm=class vC{static{i(this,"Parser")}static performSelfAnalysis(t){throw Error("The **static** `performSelfAnalysis` method has been deprecated. \nUse the **instance** method with the same name instead.")}performSelfAnalysis(){this.TRACE_INIT("performSelfAnalysis",()=>{let t;this.selfAnalysisDone=!0;const r=this.className;this.TRACE_INIT("toFastProps",()=>{Yp(this)}),this.TRACE_INIT("Grammar Recording",()=>{try{this.enableRecording(),K(this.definedRulesNames,a=>{const o=this[a].originalGrammarAction;let l;this.TRACE_INIT(`${a} Rule`,()=>{l=this.topLevelRuleRecord(a,o)}),this.gastProductionsCache[a]=l})}finally{this.disableRecording()}});let n=[];if(this.TRACE_INIT("Grammar Resolving",()=>{n=HE({rules:Me(this.gastProductionsCache)}),this.definitionErrors=this.definitionErrors.concat(n)}),this.TRACE_INIT("Grammar Validations",()=>{if(me(n)&&this.skipValidations===!1){const a=YE({rules:Me(this.gastProductionsCache),tokenTypes:Me(this.tokensMap),errMsgProvider:_n,grammarName:r}),s=DE({lookaheadStrategy:this.lookaheadStrategy,rules:Me(this.gastProductionsCache),tokenTypes:Me(this.tokensMap),grammarName:r});this.definitionErrors=this.definitionErrors.concat(a,s)}}),me(this.definitionErrors)&&(this.recoveryEnabled&&this.TRACE_INIT("computeAllProdsFollows",()=>{const a=UA(Me(this.gastProductionsCache));this.resyncFollows=a}),this.TRACE_INIT("ComputeLookaheadFunctions",()=>{var a,s;(s=(a=this.lookaheadStrategy).initialize)===null||s===void 0||s.call(a,{rules:Me(this.gastProductionsCache)}),this.preComputeLookaheadFunctions(Me(this.gastProductionsCache))})),!vC.DEFER_DEFINITION_ERRORS_HANDLING&&!me(this.definitionErrors))throw t=F(this.definitionErrors,a=>a.message),new Error(`Parser Definition Errors detected: + ${t.join(` +------------------------------- +`)}`)})}constructor(t,r){this.definitionErrors=[],this.selfAnalysisDone=!1;const n=this;if(n.initErrorHandler(r),n.initLexerAdapter(),n.initLooksAhead(r),n.initRecognizerEngine(t,r),n.initRecoverable(r),n.initTreeBuilder(r),n.initContentAssist(),n.initGastRecorder(r),n.initPerformanceTracer(r),B(r,"ignoredIssues"))throw new Error(`The IParserConfig property has been deprecated. + Please use the flag on the relevant DSL method instead. + See: https://chevrotain.io/docs/guide/resolving_grammar_errors.html#IGNORING_AMBIGUITIES + For further details.`);this.skipValidations=B(r,"skipValidations")?r.skipValidations:Sr.skipValidations}};fm.DEFER_DEFINITION_ERRORS_HANDLING=!1;gC(fm,[VD,HD,JD,ZD,ex,QD,tx,rx,ax,ix]);var sx=class extends fm{static{i(this,"EmbeddedActionsParser")}constructor(e,t=Sr){const r=Ye(t);r.outputCst=!1,super(e,r)}};function TC(e,t){for(var r=-1,n=e==null?0:e.length,a=Array(n);++r-1}i(SC,"listCacheHas");var dx=SC;function wC(e,t){var r=this.__data__,n=Tu(r,e);return n<0?(++this.size,r.push([e,t])):r[n][1]=t,this}i(wC,"listCacheSet");var px=wC;function Yn(e){var t=-1,r=e==null?0:e.length;for(this.clear();++tl))return!1;var c=s.get(e),f=s.get(t);if(c&&f)return c==t&&f==e;var d=-1,m=!0,g=r&TM?new ob:void 0;for(s.set(e,t),s.set(t,e);++d-1&&e%1==0&&e-1&&e%1==0&&e<=e1}i(Nb,"isLength");var mm=Nb,t1="[object Arguments]",r1="[object Array]",n1="[object Boolean]",a1="[object Date]",i1="[object Error]",s1="[object Function]",o1="[object Map]",l1="[object Number]",u1="[object Object]",c1="[object RegExp]",f1="[object Set]",d1="[object String]",p1="[object WeakMap]",m1="[object ArrayBuffer]",h1="[object DataView]",y1="[object Float32Array]",g1="[object Float64Array]",v1="[object Int8Array]",T1="[object Int16Array]",$1="[object Int32Array]",R1="[object Uint8Array]",A1="[object Uint8ClampedArray]",E1="[object Uint16Array]",C1="[object Uint32Array]",ge={};ge[y1]=ge[g1]=ge[v1]=ge[T1]=ge[$1]=ge[R1]=ge[A1]=ge[E1]=ge[C1]=!0;ge[t1]=ge[r1]=ge[m1]=ge[n1]=ge[h1]=ge[a1]=ge[i1]=ge[s1]=ge[o1]=ge[l1]=ge[u1]=ge[c1]=ge[f1]=ge[d1]=ge[p1]=!1;function Pb(e){return Za(e)&&mm(e.length)&&!!ge[li(e)]}i(Pb,"baseIsTypedArray");var b1=Pb;function kb(e){return function(t){return e(t)}}i(kb,"baseUnary");var _1=kb,Ob=typeof exports=="object"&&exports&&!exports.nodeType&&exports,ys=Ob&&typeof module=="object"&&module&&!module.nodeType&&module,S1=ys&&ys.exports===Ob,Ju=S1&&OC.process,w1=(function(){try{var e=ys&&ys.require&&ys.require("util").types;return e||Ju&&Ju.binding&&Ju.binding("util")}catch{}})(),py=w1,my=py&&py.isTypedArray,I1=my?_1(my):b1,hm=I1,N1=Object.prototype,P1=N1.hasOwnProperty;function Lb(e,t){var r=lt(e),n=!r&&Eu(e),a=!r&&!n&&El(e),s=!r&&!n&&!a&&hm(e),o=r||n||a||s,l=o?UM(e.length,String):[],u=l.length;for(var c in e)(t||P1.call(e,c))&&!(o&&(c=="length"||a&&(c=="offset"||c=="parent")||s&&(c=="buffer"||c=="byteLength"||c=="byteOffset")||Ib(c,u)))&&l.push(c);return l}i(Lb,"arrayLikeKeys");var k1=Lb,O1=Object.prototype;function Db(e){var t=e&&e.constructor,r=typeof t=="function"&&t.prototype||O1;return e===r}i(Db,"isPrototype");var xb=Db;function Mb(e,t){return function(r){return e(t(r))}}i(Mb,"overArg");var L1=Mb,D1=L1(Object.keys,Object),x1=D1,M1=Object.prototype,G1=M1.hasOwnProperty;function Gb(e){if(!xb(e))return x1(e);var t=[];for(var r in Object(e))G1.call(e,r)&&r!="constructor"&&t.push(r);return t}i(Gb,"baseKeys");var Fb=Gb;function zb(e){return e!=null&&mm(e.length)&&!zC(e)}i(zb,"isArrayLike");var Cu=zb;function jb(e){return Cu(e)?k1(e):Fb(e)}i(jb,"keys");var ym=jb;function Bb(e){return MM(e,ym,BM)}i(Bb,"getAllKeys");var hy=Bb,F1=1,z1=Object.prototype,j1=z1.hasOwnProperty;function Ub(e,t,r,n,a,s){var o=r&F1,l=hy(e),u=l.length,c=hy(t),f=c.length;if(u!=f&&!o)return!1;for(var d=u;d--;){var m=l[d];if(!(o?m in t:j1.call(t,m)))return!1}var g=s.get(e),v=s.get(t);if(g&&v)return g==t&&v==e;var b=!0;s.set(e,t),s.set(t,e);for(var S=o;++dCm(e,t,o));return ea(e,t,n,r,...a)}i(D_,"alternation");function x_(e,t,r){const n=Ge(e,t,r,{type:Kr});Or(e,n);const a=ea(e,t,n,r,Xr(e,t,r));return M_(e,t,r,a)}i(x_,"option");function Xr(e,t,r){const n=GG(Tr(r.definition,a=>Cm(e,t,a)),a=>a!==void 0);return n.length===1?n[0]:n.length===0?void 0:F_(e,n)}i(Xr,"block");function bm(e,t,r,n,a){const s=n.left,o=n.right,l=Ge(e,t,r,{type:UG});Or(e,l);const u=Ge(e,t,r,{type:S_});return s.loopback=l,u.loopback=l,e.decisionMap[Ln(t,a?"RepetitionMandatoryWithSeparator":"RepetitionMandatory",r.idx)]=l,Ie(o,l),a===void 0?(Ie(l,s),Ie(l,u)):(Ie(l,u),Ie(l,a.left),Ie(a.right,s)),{left:s,right:u}}i(bm,"plus");function _m(e,t,r,n,a){const s=n.left,o=n.right,l=Ge(e,t,r,{type:BG});Or(e,l);const u=Ge(e,t,r,{type:S_}),c=Ge(e,t,r,{type:jG});return l.loopback=c,u.loopback=c,Ie(l,s),Ie(l,u),Ie(o,c),a!==void 0?(Ie(c,u),Ie(c,a.left),Ie(a.right,s)):Ie(c,l),e.decisionMap[Ln(t,a?"RepetitionWithSeparator":"Repetition",r.idx)]=l,{left:l,right:u}}i(_m,"star");function M_(e,t,r,n){const a=n.left,s=n.right;return Ie(a,s),e.decisionMap[Ln(t,"Option",r.idx)]=a,n}i(M_,"optional");function Or(e,t){return e.decisionStates.push(t),t.decision=e.decisionStates.length-1,t.decision}i(Or,"defineDecisionState");function ea(e,t,r,n,...a){const s=Ge(e,t,n,{type:zG,start:r});r.end=s;for(const l of a)l!==void 0?(Ie(r,l.left),Ie(l.right,s)):Ie(r,s);const o={left:r,right:s};return e.decisionMap[Ln(t,G_(n),n.idx)]=r,o}i(ea,"makeAlts");function G_(e){if(e instanceof gt)return"Alternation";if(e instanceof He)return"Option";if(e instanceof be)return"Repetition";if(e instanceof yt)return"RepetitionWithSeparator";if(e instanceof Et)return"RepetitionMandatory";if(e instanceof Ct)return"RepetitionMandatoryWithSeparator";throw new Error("Invalid production type encountered")}i(G_,"getProdType");function F_(e,t){const r=t.length;for(let s=0;se.alt)}get key(){let e="";for(const t in this.map)e+=t+":";return e}};function Sm(e,t=!0){return`${t?`a${e.alt}`:""}s${e.state.stateNumber}:${e.stack.map(r=>r.stateNumber.toString()).join("_")}`}i(Sm,"getATNConfigKey");function U_(e,t,r){for(var n=-1,a=e.length;++n0&&r(l)?t>1?wm(l,t-1,r,n,a):gb(a,l):n||(a[a.length]=l)}return a}i(wm,"baseFlatten");var q_=wm;function H_(e,t){return q_(Tr(e,t),1)}i(H_,"flatMap");var HG=H_;function Y_(e,t,r,n){for(var a=e.length,s=r+(n?1:-1);n?s--:++s-1}i(Q_,"arrayIncludes");var QG=Q_;function eS(e,t,r){for(var n=-1,a=e==null?0:e.length;++n=iF){var c=t?null:aF(e);if(c)return pm(c);o=!1,a=cb,u=new ob}else u=t?[]:l;e:for(;++n{const a=n.toString();let s=r[a];return s!==void 0||(s={atnStartState:e,decision:t,states:{}},r[a]=s),s}}i(dS,"createDFACache");var pS=class{static{i(this,"PredicateSet")}constructor(){this.predicates=[]}is(e){return e>=this.predicates.length||this.predicates[e]}set(e,t){this.predicates[e]=t}toString(){let e="";const t=this.predicates.length;for(let r=0;rconsole.log(r))}initialize(e){this.atn=I_(e.rules),this.dfas=mS(this.atn)}validateAmbiguousAlternationAlternatives(){return[]}validateEmptyOrAlternatives(){return[]}buildLookaheadForAlternation(e){const{prodOccurrence:t,rule:r,hasPredicates:n,dynamicTokensEnabled:a}=e,s=this.dfas,o=this.logging,l=Ln(r,"Alternation",t),c=this.atn.decisionMap[l].decision,f=Tr(Lf({maxLookahead:1,occurrence:t,prodType:"Alternation",rule:r}),d=>Tr(d,m=>m[0]));if(Yf(f,!1)&&!a){const d=Sy(f,(m,g,v)=>(Zu(g,b=>{b&&(m[b.tokenTypeIdx]=v,Zu(b.categoryMatches,S=>{m[S]=v}))}),m),{});return n?function(m){var g;const v=this.LA(1),b=d[v.tokenTypeIdx];if(m!==void 0&&b!==void 0){const S=(g=m[b])===null||g===void 0?void 0:g.GATE;if(S!==void 0&&S.call(this)===!1)return}return b}:function(){const m=this.LA(1);return d[m.tokenTypeIdx]}}else return n?function(d){const m=new pS,g=d===void 0?0:d.length;for(let b=0;bTr(d,m=>m[0]));if(Yf(f)&&f[0][0]&&!a){const d=f[0],m=lF(d);if(m.length===1&&hF(m[0].categoryMatches)){const v=m[0].tokenTypeIdx;return function(){return this.LA(1).tokenTypeIdx===v}}else{const g=Sy(m,(v,b)=>(b!==void 0&&(v[b.tokenTypeIdx]=!0,Zu(b.categoryMatches,S=>{v[S]=!0})),v),{});return function(){const v=this.LA(1);return g[v.tokenTypeIdx]===!0}}}return function(){const d=zo.call(this,s,c,wy,o);return typeof d=="object"?!1:d===0}}};function Yf(e,t=!0){const r=new Set;for(const n of e){const a=new Set;for(const s of n){if(s===void 0){if(t)break;return!1}const o=[s.tokenTypeIdx].concat(s.categoryMatches);for(const l of o)if(r.has(l)){if(!a.has(l))return!1}else r.add(l),a.add(l)}}return!0}i(Yf,"isLL1Sequence");function mS(e){const t=e.decisionStates.length,r=Array(t);for(let n=0;nIn(a)).join(", "),r=e.production.idx===0?"":e.production.idx;let n=`Ambiguous Alternatives Detected: <${e.ambiguityIndices.join(", ")}> in <${TS(e.production)}${r}> inside <${e.topLevelRule.name}> Rule, +<${t}> 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}i(vS,"buildAmbiguityError");function TS(e){if(e instanceof st)return"SUBRULE";if(e instanceof He)return"OPTION";if(e instanceof gt)return"OR";if(e instanceof Et)return"AT_LEAST_ONE";if(e instanceof Ct)return"AT_LEAST_ONE_SEP";if(e instanceof yt)return"MANY_SEP";if(e instanceof be)return"MANY";if(e instanceof ve)return"CONSUME";throw Error("non exhaustive match")}i(TS,"getProductionDslName");function $S(e,t,r){const n=HG(t.configs.elements,s=>s.state.transitions),a=oF(n.filter(s=>s instanceof Am).map(s=>s.tokenType),s=>s.tokenTypeIdx);return{actualToken:r,possibleTokenTypes:a,tokenPath:e}}i($S,"buildAdaptivePredictError");function RS(e,t){return e.edges[t.tokenTypeIdx]}i(RS,"getExistingTargetState");function AS(e,t,r){const n=new Hf,a=[];for(const o of e.elements){if(r.is(o.alt)===!1)continue;if(o.state.type===ro){a.push(o);continue}const l=o.state.transitions.length;for(let u=0;u0&&!SS(s))for(const o of a)s.add(o);return s}i(AS,"computeReachSet");function ES(e,t){if(e instanceof Am&&rm(t,e.tokenType))return e.target}i(ES,"getReachableTarget");function CS(e,t){let r;for(const n of e.elements)if(t.is(n.alt)===!0){if(r===void 0)r=n.alt;else if(r!==n.alt)return}return r}i(CS,"getUniqueAlt");function Im(e){return{configs:e,edges:{},isAcceptState:!1,prediction:-1}}i(Im,"newDFAState");function Xf(e,t,r,n){return n=Nm(e,n),t.edges[r.tokenTypeIdx]=n,n}i(Xf,"addDFAEdge");function Nm(e,t){if(t===Cl)return t;const r=t.configs.key,n=e.states[r];return n!==void 0?n:(t.configs.finalize(),e.states[r]=t,t)}i(Nm,"addDFAState");function bS(e){const t=new Hf,r=e.transitions.length;for(let n=0;n0){const a=[...e.stack],o={state:a.pop(),alt:e.alt,stack:a};Os(o,t)}else t.add(e);return}r.epsilonOnlyTransitions||t.add(e);const n=r.transitions.length;for(let a=0;a1)return!0;return!1}i(PS,"hasConflictingAltSet");function kS(e){for(const t of Array.from(e.values()))if(Object.keys(t).length===1)return!0;return!1}i(kS,"hasStateAssociatedWithOneAlt");xs();var OS=class{static{i(this,"CstNodeBuilder")}constructor(){this.nodeStack=[]}get current(){return this.nodeStack[this.nodeStack.length-1]??this.rootNode}buildRootNode(e){return this.rootNode=new km(e),this.rootNode.root=this.rootNode,this.nodeStack=[this.rootNode],this.rootNode}buildCompositeNode(e){const t=new ku;return t.grammarSource=e,t.root=this.rootNode,this.current.content.push(t),this.nodeStack.push(t),t}buildLeafNode(e,t){const r=new bl(e.startOffset,e.image.length,$s(e),e.tokenType,!t);return r.grammarSource=t,r.root=this.rootNode,this.current.content.push(r),r}removeNode(e){const t=e.container;if(t){const r=t.content.indexOf(e);r>=0&&t.content.splice(r,1)}}addHiddenNodes(e){const t=[];for(const a of e){const s=new bl(a.startOffset,a.image.length,$s(a),a.tokenType,!0);s.root=this.rootNode,t.push(s)}let r=this.current,n=!1;if(r.content.length>0){r.content.push(...t);return}for(;r.container;){const a=r.container.content.indexOf(r);if(a>0){r.container.content.splice(a,0,...t),n=!0;break}r=r.container}n||this.rootNode.content.unshift(...t)}construct(e){const t=this.current;typeof e.$type=="string"&&!e.$infix&&(this.current.astNode=e),e.$cstNode=t;const r=this.nodeStack.pop();r?.content.length===0&&this.removeNode(r)}},Pm=class{static{i(this,"AbstractCstNode")}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)}},bl=class extends Pm{static{i(this,"LeafCstNodeImpl")}get offset(){return this._offset}get length(){return this._length}get end(){return this._offset+this._length}get hidden(){return this._hidden}get tokenType(){return this._tokenType}get range(){return this._range}constructor(e,t,r,n,a=!1){super(),this._hidden=a,this._offset=e,this._tokenType=n,this._length=t,this._range=r}},ku=class extends Pm{static{i(this,"CompositeCstNodeImpl")}constructor(){super(...arguments),this.content=new TF(this)}get offset(){return this.firstNonHiddenNode?.offset??0}get length(){return this.end-this.offset}get end(){return this.lastNonHiddenNode?.end??0}get range(){const e=this.firstNonHiddenNode,t=this.lastNonHiddenNode;if(e&&t){if(this._rangeCache===void 0){const{range:r}=e,{range:n}=t;this._rangeCache={start:r.start,end:n.end.line=0;e--){const t=this.content[e];if(!t.hidden)return t}return this.content[this.content.length-1]}},TF=class LS extends Array{static{i(this,"CstNodeContainer")}constructor(t){super(),this.parent=t,Object.setPrototypeOf(this,LS.prototype)}push(...t){return this.addParents(t),super.push(...t)}unshift(...t){return this.addParents(t),super.unshift(...t)}splice(t,r,...n){return this.addParents(n),super.splice(t,r,...n)}addParents(t){for(const r of t)r.container=this.parent}},km=class extends ku{static{i(this,"RootCstNodeImpl")}get text(){return this._text.substring(this.offset,this.end)}get fullText(){return this._text}constructor(e){super(),this._text="",this._text=e??""}},_l=Symbol("Datatype");function jo(e){return e.$type===_l}i(jo,"isDataTypeNode");var Iy="​",DS=i(e=>e.endsWith(Iy)?e:e+Iy,"withRuleSuffix"),Om=class{static{i(this,"AbstractLangiumParser")}constructor(e){this._unorderedGroups=new Map,this.allRules=new Map,this.lexer=e.parser.Lexer;const t=this.lexer.definition,r=e.LanguageMetaData.mode==="production";e.shared.profilers.LangiumProfiler?.isActive("parsing")?this.wrapper=new RF(t,{...e.parser.ParserConfig,skipValidations:r,errorMessageProvider:e.parser.ParserErrorMessageProvider},e.shared.profilers.LangiumProfiler.createTask("parsing",e.LanguageMetaData.languageId)):this.wrapper=new FS(t,{...e.parser.ParserConfig,skipValidations:r,errorMessageProvider:e.parser.ParserErrorMessageProvider})}alternatives(e,t){this.wrapper.wrapOr(e,t)}optional(e,t){this.wrapper.wrapOption(e,t)}many(e,t){this.wrapper.wrapMany(e,t)}atLeastOne(e,t){this.wrapper.wrapAtLeastOne(e,t)}getRule(e){return this.allRules.get(e)}isRecording(){return this.wrapper.IS_RECORDING}get unorderedGroups(){return this._unorderedGroups}getRuleStack(){return this.wrapper.RULE_STACK}finalize(){this.wrapper.wrapSelfAnalysis()}},xS=class extends Om{static{i(this,"LangiumParser")}get current(){return this.stack[this.stack.length-1]}constructor(e){super(e),this.nodeBuilder=new OS,this.stack=[],this.assignmentMap=new Map,this.operatorPrecedence=new Map,this.linker=e.references.Linker,this.converter=e.parser.ValueConverter,this.astReflection=e.shared.AstReflection}rule(e,t){const r=this.computeRuleType(e);let n;qa(e)&&(n=e.name,this.registerPrecedenceMap(e));const a=this.wrapper.DEFINE_RULE(DS(e.name),this.startImplementation(r,n,t).bind(this));return this.allRules.set(e.name,a),it(e)&&e.entry&&(this.mainRule=a),a}registerPrecedenceMap(e){const t=e.name,r=new Map;for(let n=0;n0&&(t=this.construct()),t===void 0)throw new Error("No result from parser");if(this.stack.length>0)throw new Error("Parser stack is not empty after parsing");return t}startImplementation(e,t,r){return n=>{const a=!this.isRecording()&&e!==void 0;if(a){const s={$type:e};this.stack.push(s),e===_l?s.value="":t!==void 0&&(s.$infixName=t)}return r(n),a?this.construct():void 0}}extractHiddenTokens(e){const t=this.lexerResult.hidden;if(!t.length)return[];const r=e.startOffset;for(let n=0;nr)return t.splice(0,n);return t.splice(0,t.length)}consume(e,t,r){const n=this.wrapper.wrapConsume(e,t);if(!this.isRecording()&&this.isValidToken(n)){const a=this.extractHiddenTokens(n);this.nodeBuilder.addHiddenNodes(a);const s=this.nodeBuilder.buildLeafNode(n,r),{assignment:o,crossRef:l}=this.getAssignment(r),u=this.current;if(o){const c=Ar(r)?n.image:this.converter.convert(n.image,s);this.assign(o.operator,o.feature,c,s,l)}else if(jo(u)){let c=n.image;Ar(r)||(c=this.converter.convert(c,s).toString()),u.value+=c}}}isValidToken(e){return!e.isInsertedInRecovery&&!isNaN(e.startOffset)&&typeof e.endOffset=="number"&&!isNaN(e.endOffset)}subrule(e,t,r,n,a){let s;!this.isRecording()&&!r&&(s=this.nodeBuilder.buildCompositeNode(n));let o;try{o=this.wrapper.wrapSubrule(e,t,a)}finally{this.isRecording()||(o===void 0&&!r&&(o=this.construct()),o!==void 0&&s&&s.length>0&&this.performSubruleAssignment(o,n,s))}}performSubruleAssignment(e,t,r){const{assignment:n,crossRef:a}=this.getAssignment(t);if(n)this.assign(n.operator,n.feature,e,r,a);else if(!n){const s=this.current;if(jo(s))s.value+=e.toString();else if(typeof e=="object"&&e){const l=this.assignWithoutOverride(e,s);this.stack.pop(),this.stack.push(l)}}}action(e,t){if(!this.isRecording()){let r=this.current;if(t.feature&&t.operator){r=this.construct(),this.nodeBuilder.removeNode(r.$cstNode),this.nodeBuilder.buildCompositeNode(t).content.push(r.$cstNode);const a={$type:e};this.stack.push(a),this.assign(t.operator,t.feature,r,r.$cstNode)}else r.$type=e}}construct(){if(this.isRecording())return;const e=this.stack.pop();return this.nodeBuilder.construct(e),"$infixName"in e?this.constructInfix(e,this.operatorPrecedence.get(e.$infixName)):jo(e)?this.converter.convert(e.value,e.$cstNode):(Pd(this.astReflection,e),e)}constructInfix(e,t){const r=e.parts;if(!Array.isArray(r)||r.length===0)return;const n=e.operators;if(!Array.isArray(n)||r.length<2)return r[0];let a=0,s=-1;for(let v=0;vs?(s=S.precedence,a=v):S.precedence===s&&(S.rightAssoc||(a=v))}const o=n.slice(0,a),l=n.slice(a+1),u=r.slice(0,a+1),c=r.slice(a+1),f={$infixName:e.$infixName,$type:e.$type,$cstNode:e.$cstNode,parts:u,operators:o},d={$infixName:e.$infixName,$type:e.$type,$cstNode:e.$cstNode,parts:c,operators:l},m=this.constructInfix(f,t),g=this.constructInfix(d,t);return{$type:e.$type,$cstNode:e.$cstNode,left:m,operator:n[a],right:g}}getAssignment(e){if(!this.assignmentMap.has(e)){const t=Mn(e,Rr);this.assignmentMap.set(e,{assignment:t,crossRef:t&&Fn(t.terminal)?t.terminal.isMulti?"multi":"single":void 0})}return this.assignmentMap.get(e)}assign(e,t,r,n,a){const s=this.current;let o;switch(a==="single"&&typeof r=="string"?o=this.linker.buildReference(s,t,n,r):a==="multi"&&typeof r=="string"?o=this.linker.buildMultiReference(s,t,n,r):o=r,e){case"=":{s[t]=o;break}case"?=":{s[t]=!0;break}case"+=":Array.isArray(s[t])||(s[t]=[]),s[t].push(o)}}assignWithoutOverride(e,t){for(const[n,a]of Object.entries(t)){const s=e[n];s===void 0?e[n]=a:Array.isArray(s)&&Array.isArray(a)&&(a.push(...s),e[n]=a)}const r=e.$cstNode;return r&&(r.astNode=void 0,e.$cstNode=void 0),e}get definitionErrors(){return this.wrapper.definitionErrors}},MS=class{static{i(this,"AbstractParserErrorMessageProvider")}buildMismatchTokenMessage(e){return Ga.buildMismatchTokenMessage(e)}buildNotAllInputParsedMessage(e){return Ga.buildNotAllInputParsedMessage(e)}buildNoViableAltMessage(e){return Ga.buildNoViableAltMessage(e)}buildEarlyExitMessage(e){return Ga.buildEarlyExitMessage(e)}},Lm=class extends MS{static{i(this,"LangiumParserErrorMessageProvider")}buildMismatchTokenMessage({expected:e,actual:t}){return`Expecting ${e.LABEL?"`"+e.LABEL+"`":e.name.endsWith(":KW")?`keyword '${e.name.substring(0,e.name.length-3)}'`:`token of type '${e.name}'`} but found \`${t.image}\`.`}buildNotAllInputParsedMessage({firstRedundant:e}){return`Expecting end of file but found \`${e.image}\`.`}},GS=class extends Om{static{i(this,"LangiumCompletionParser")}constructor(){super(...arguments),this.tokens=[],this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}action(){}construct(){}parse(e){this.resetState();const t=this.lexer.tokenize(e,{mode:"partial"});return this.tokens=t.tokens,this.wrapper.input=[...this.tokens],this.mainRule.call(this.wrapper,{}),this.unorderedGroups.clear(),{tokens:this.tokens,elementStack:[...this.lastElementStack],tokenIndex:this.nextTokenIndex}}rule(e,t){const r=this.wrapper.DEFINE_RULE(DS(e.name),this.startImplementation(t).bind(this));return this.allRules.set(e.name,r),e.entry&&(this.mainRule=r),r}resetState(){this.elementStack=[],this.lastElementStack=[],this.nextTokenIndex=0,this.stackSize=0}startImplementation(e){return t=>{const r=this.keepStackSize();try{e(t)}finally{this.resetStackSize(r)}}}removeUnexpectedElements(){this.elementStack.splice(this.stackSize)}keepStackSize(){const e=this.elementStack.length;return this.stackSize=e,e}resetStackSize(e){this.removeUnexpectedElements(),this.stackSize=e}consume(e,t,r){this.wrapper.wrapConsume(e,t),this.isRecording()||(this.lastElementStack=[...this.elementStack,r],this.nextTokenIndex=this.currIdx+1)}subrule(e,t,r,n,a){this.before(n),this.wrapper.wrapSubrule(e,t,a),this.after(n)}before(e){this.isRecording()||this.elementStack.push(e)}after(e){if(!this.isRecording()){const t=this.elementStack.lastIndexOf(e);t>=0&&this.elementStack.splice(t)}}get currIdx(){return this.wrapper.currIdx}},$F={recoveryEnabled:!0,nodeLocationTracking:"full",skipValidations:!0,errorMessageProvider:new Lm},FS=class extends sx{static{i(this,"ChevrotainWrapper")}constructor(e,t){const r=t&&"maxLookahead"in t;super(e,{...$F,lookaheadStrategy:r?new um({maxLookahead:t.maxLookahead}):new vF({logging:t.skipValidations?()=>{}:void 0}),...t})}get IS_RECORDING(){return this.RECORDING_PHASE}DEFINE_RULE(e,t,r){return this.RULE(e,t,r)}wrapSelfAnalysis(){this.performSelfAnalysis()}wrapConsume(e,t){return this.consume(e,t,void 0)}wrapSubrule(e,t,r){return this.subrule(e,t,{ARGS:[r]})}wrapOr(e,t){this.or(e,t)}wrapOption(e,t){this.option(e,t)}wrapMany(e,t){this.many(e,t)}wrapAtLeastOne(e,t){this.atLeastOne(e,t)}rule(e){return e.call(this,{})}},RF=class extends FS{static{i(this,"ProfilerWrapper")}constructor(e,t,r){super(e,t),this.task=r}rule(e){this.task.start(),this.task.startSubTask(this.ruleName(e));try{return super.rule(e)}finally{this.task.stopSubTask(this.ruleName(e)),this.task.stop()}}ruleName(e){return e.ruleName}subrule(e,t,r){this.task.startSubTask(this.ruleName(t));try{return super.subrule(e,t,r)}finally{this.task.stopSubTask(this.ruleName(t))}}};function Ou(e,t,r){return zS({parser:t,tokens:r,ruleNames:new Map},e),t}i(Ou,"createParser");function zS(e,t){const r=Hl(t,!1),n=ue(t.rules).filter(it).filter(s=>r.has(s));for(const s of n){const o={...e,consume:1,optional:1,subrule:1,many:1,or:1};e.parser.rule(s,Wr(o,s.definition))}const a=ue(t.rules).filter(qa).filter(s=>r.has(s));for(const s of a)e.parser.rule(s,jS(e,s))}i(zS,"buildRules");function jS(e,t){const r=t.call.rule.ref;if(!r)throw new Error("Could not resolve reference to infix operator rule: "+t.call.rule.$refText);if(Nt(r))throw new Error("Cannot use terminal rule in infix expression");const n=t.operators.precedences.flatMap(g=>g.operators),a={$type:"Group",elements:[]},s={$container:a,$type:"Assignment",feature:"parts",operator:"+=",terminal:t.call},o={$container:a,$type:"Group",elements:[],cardinality:"*"};a.elements.push(s,o);const u={$container:o,$type:"Assignment",feature:"operators",operator:"+=",terminal:{$type:"Alternatives",elements:n}},c={...s,$container:o};o.elements.push(u,c);const d=n.map(g=>e.tokens[g.value]).map((g,v)=>({ALT:i(()=>e.parser.consume(v,g,u),"ALT")}));let m;return g=>{m??(m=Lu(e,r)),e.parser.subrule(0,m,!1,s,g),e.parser.many(0,{DEF:i(()=>{e.parser.alternatives(0,d),e.parser.subrule(1,m,!1,c,g)},"DEF")})}}i(jS,"buildInfixRule");function Wr(e,t,r=!1){let n;if(Ar(t))n=HS(e,t);else if(jr(t))n=BS(e,t);else if(Rr(t))n=Wr(e,t.terminal);else if(Fn(t))n=Dm(e,t);else if(Er(t))n=US(e,t);else if(Fl(t))n=WS(e,t);else if(Ul(t))n=VS(e,t);else if(zn(t))n=qS(e,t);else if(Gd(t)){const a=e.consume++;n=i(()=>e.parser.consume(a,Ur,t),"method")}else throw new Wl(t.$cstNode,`Unexpected element type: ${t.$type}`);return xm(e,r?void 0:Ls(t),n,t.cardinality)}i(Wr,"buildElement");function BS(e,t){const r=Pn(t);return()=>e.parser.action(r,t)}i(BS,"buildAction");function US(e,t){const r=t.rule.ref;if(Gn(r)){const n=e.subrule++,a=it(r)&&r.fragment,s=t.arguments.length>0?KS(r,t.arguments):()=>({});let o;return l=>{o??(o=Lu(e,r)),e.parser.subrule(n,o,a,t,s(l))}}else if(Nt(r)){const n=e.consume++,a=Sl(e,r.name);return()=>e.parser.consume(n,a,t)}else if(r)qr();else throw new Wl(t.$cstNode,`Undefined rule: ${t.rule.$refText}`)}i(US,"buildRuleCall");function KS(e,t){if(t.some(n=>n.calledByName)){const n=t.map(a=>({parameterName:a.parameter?.ref?.name,predicate:xt(a.value)}));return a=>{const s={};for(const{parameterName:o,predicate:l}of n)o&&(s[o]=l(a));return s}}else{const n=t.map(a=>xt(a.value));return a=>{const s={};for(let o=0;ot(n)||r(n)}else if(xd(e)){const t=xt(e.left),r=xt(e.right);return n=>t(n)&&r(n)}else if(jd(e)){const t=xt(e.value);return r=>!t(r)}else if(Bd(e)){const t=e.parameter.ref.name;return r=>r!==void 0&&r[t]===!0}else if(Ld(e)){const t=!!e.true;return()=>t}qr()}i(xt,"buildPredicate");function WS(e,t){if(t.elements.length===1)return Wr(e,t.elements[0]);{const r=[];for(const a of t.elements){const s={ALT:Wr(e,a,!0)},o=Ls(a);o&&(s.GATE=xt(o)),r.push(s)}const n=e.or++;return a=>e.parser.alternatives(n,r.map(s=>{const o={ALT:i(()=>s.ALT(a),"ALT")},l=s.GATE;return l&&(o.GATE=()=>l(a)),o}))}}i(WS,"buildAlternatives");function VS(e,t){if(t.elements.length===1)return Wr(e,t.elements[0]);const r=[];for(const l of t.elements){const u={ALT:Wr(e,l,!0)},c=Ls(l);c&&(u.GATE=xt(c)),r.push(u)}const n=e.or++,a=i((l,u)=>{const c=u.getRuleStack().join("-");return`uGroup_${l}_${c}`},"idFunc"),s=i(l=>e.parser.alternatives(n,r.map((u,c)=>{const f={ALT:i(()=>!0,"ALT")},d=e.parser;f.ALT=()=>{if(u.ALT(l),!d.isRecording()){const g=a(n,d);d.unorderedGroups.get(g)||d.unorderedGroups.set(g,[]);const v=d.unorderedGroups.get(g);typeof v?.[c]>"u"&&(v[c]=!0)}};const m=u.GATE;return m?f.GATE=()=>m(l):f.GATE=()=>!d.unorderedGroups.get(a(n,d))?.[c],f})),"alternatives"),o=xm(e,Ls(t),s,"*");return l=>{o(l),e.parser.isRecording()||e.parser.unorderedGroups.delete(a(n,e.parser))}}i(VS,"buildUnorderedGroup");function qS(e,t){const r=t.elements.map(n=>Wr(e,n));return n=>r.forEach(a=>a(n))}i(qS,"buildGroup");function Ls(e){if(zn(e))return e.guardCondition}i(Ls,"getGuardCondition");function Dm(e,t,r=t.terminal){if(r)if(Er(r)&&it(r.rule.ref)){const n=r.rule.ref,a=e.subrule++;let s;return o=>{s??(s=Lu(e,n)),e.parser.subrule(a,s,!1,t,o)}}else if(Er(r)&&Nt(r.rule.ref)){const n=e.consume++,a=Sl(e,r.rule.ref.name);return()=>e.parser.consume(n,a,t)}else if(Ar(r)){const n=e.consume++,a=Sl(e,r.value);return()=>e.parser.consume(n,a,t)}else throw new Error("Could not build cross reference parser");else{if(!t.type.ref)throw new Error("Could not resolve reference to type: "+t.type.$refText);const a=Zl(t.type.ref)?.terminal;if(!a)throw new Error("Could not find name assignment for type: "+Pn(t.type.ref));return Dm(e,t,a)}}i(Dm,"buildCrossReference");function HS(e,t){const r=e.consume++,n=e.tokens[t.value];if(!n)throw new Error("Could not find token for keyword: "+t.value);return()=>e.parser.consume(r,n,t)}i(HS,"buildKeyword");function xm(e,t,r,n){const a=t&&xt(t);if(!n)if(a){const s=e.or++;return o=>e.parser.alternatives(s,[{ALT:i(()=>r(o),"ALT"),GATE:i(()=>a(o),"GATE")},{ALT:Uf(),GATE:i(()=>!a(o),"GATE")}])}else return r;if(n==="*"){const s=e.many++;return o=>e.parser.many(s,{DEF:i(()=>r(o),"DEF"),GATE:a?()=>a(o):void 0})}else if(n==="+"){const s=e.many++;if(a){const o=e.or++;return l=>e.parser.alternatives(o,[{ALT:i(()=>e.parser.atLeastOne(s,{DEF:i(()=>r(l),"DEF")}),"ALT"),GATE:i(()=>a(l),"GATE")},{ALT:Uf(),GATE:i(()=>!a(l),"GATE")}])}else return o=>e.parser.atLeastOne(s,{DEF:i(()=>r(o),"DEF")})}else if(n==="?"){const s=e.optional++;return o=>e.parser.optional(s,{DEF:i(()=>r(o),"DEF"),GATE:a?()=>a(o):void 0})}else qr()}i(xm,"wrap");function Lu(e,t){const r=YS(e,t),n=e.parser.getRule(r);if(!n)throw new Error(`Rule "${r}" not found."`);return n}i(Lu,"getRule");function YS(e,t){if(Gn(t))return t.name;if(e.ruleNames.has(t))return e.ruleNames.get(t);{let r=t,n=r.$container,a=t.$type;for(;!it(n);)(zn(n)||Fl(n)||Ul(n))&&(a=n.elements.indexOf(r).toString()+":"+a),r=n,n=n.$container;return a=n.name+":"+a,e.ruleNames.set(t,a),a}}i(YS,"getRuleName");function Sl(e,t){const r=e.tokens[t];if(!r)throw new Error(`Token "${t}" not found."`);return r}i(Sl,"getToken");function Mm(e){const t=e.Grammar,r=e.parser.Lexer,n=new GS(e);return Ou(t,n,r.definition),n.finalize(),n}i(Mm,"createCompletionParser");function Gm(e){const t=Fm(e);return t.finalize(),t}i(Gm,"createLangiumParser");function Fm(e){const t=e.Grammar,r=e.parser.Lexer,n=new xS(e);return Ou(t,n,r.definition)}i(Fm,"prepareLangiumParser");var Du=class{static{i(this,"DefaultTokenBuilder")}constructor(){this.diagnostics=[]}buildTokens(e,t){const r=ue(Hl(e,!1)),n=this.buildTerminalTokens(r),a=this.buildKeywordTokens(r,n,t);return a.push(...n),a}flushLexingReport(e){return{diagnostics:this.popDiagnostics()}}popDiagnostics(){const e=[...this.diagnostics];return this.diagnostics=[],e}buildTerminalTokens(e){return e.filter(Nt).filter(t=>!t.fragment).map(t=>this.buildTerminalToken(t)).toArray()}buildTerminalToken(e){const t=Bs(e),r=this.requiresCustomPattern(t)?this.regexPatternFunction(t):t,n={name:e.name,PATTERN:r};return typeof r=="function"&&(n.LINE_BREAKS=!0),e.hidden&&(n.GROUP=ql(t)?at.SKIPPED:"hidden"),n}requiresCustomPattern(e){return!!(e.flags.includes("u")||e.flags.includes("s"))}regexPatternFunction(e){const t=new RegExp(e,e.flags+"y");return(r,n)=>(t.lastIndex=n,t.exec(r))}buildKeywordTokens(e,t,r){return e.filter(Gn).flatMap(n=>Nr(n).filter(Ar)).distinct(n=>n.value).toArray().sort((n,a)=>a.value.length-n.value.length).map(n=>this.buildKeywordToken(n,t,!!r?.caseInsensitive))}buildKeywordToken(e,t,r){const n=this.buildKeywordPattern(e,r),a={name:e.value,PATTERN:n,LONGER_ALT:this.findLongerAlt(e,t)};return typeof n=="function"&&(a.LINE_BREAKS=!0),a}buildKeywordPattern(e,t){return t?new RegExp(ri(e.value),"i"):e.value}findLongerAlt(e,t){return t.reduce((r,n)=>{const a=n?.PATTERN;return a?.source&&cp("^"+a.source+"$",e.value)&&r.push(n),r},[])}},zm=class{static{i(this,"DefaultValueConverter")}convert(e,t){let r=t.grammarSource;if(Fn(r)&&(r=hp(r)),Er(r)){const n=r.rule.ref;if(!n)throw new Error("This cst node was not parsed by a rule.");return this.runConverter(n,e,t)}return e}runConverter(e,t,r){switch(e.name.toUpperCase()){case"INT":return Zt.convertInt(t);case"STRING":return Zt.convertString(t);case"ID":return Zt.convertID(t)}switch(Cp(e)?.toLowerCase()){case"number":return Zt.convertNumber(t);case"boolean":return Zt.convertBoolean(t);case"bigint":return Zt.convertBigint(t);case"date":return Zt.convertDate(t);default:return t}}},Zt;(function(e){function t(c){let f="";for(let d=1;d{typeof setImmediate>"u"?setTimeout(e,0):setImmediate(e)})}i(xu,"delayNextTick");var Bo=0,XS=10;function Mu(){return Bo=performance.now(),new pe.CancellationTokenSource}i(Mu,"startCancelableOperation");function jm(e){XS=e}i(jm,"setInterruptionPeriod");var tr=Symbol("OperationCancelled");function ta(e){return e===tr}i(ta,"isOperationCancelled");async function ze(e){if(e===pe.CancellationToken.None)return;const t=performance.now();if(t-Bo>=XS&&(Bo=t,await xu(),Bo=performance.now()),e.isCancellationRequested)throw tr}i(ze,"interruptAndCheck");var wr=class{static{i(this,"Deferred")}constructor(){this.promise=new Promise((e,t)=>{this.resolve=r=>(e(r),this),this.reject=r=>(t(r),this)})}},Ny=class Jf{static{i(this,"FullTextDocument")}constructor(t,r,n,a){this._uri=t,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(t){if(t){const r=this.offsetAt(t.start),n=this.offsetAt(t.end);return this._content.substring(r,n)}return this._content}update(t,r){for(const n of t)if(Jf.isIncremental(n)){const a=Um(n.range),s=this.offsetAt(a.start),o=this.offsetAt(a.end);this._content=this._content.substring(0,s)+n.text+this._content.substring(o,this._content.length);const l=Math.max(a.start.line,0),u=Math.max(a.end.line,0);let c=this._lineOffsets;const f=Zf(n.text,!1,s);if(u-l===f.length)for(let m=0,g=f.length;mt?a=o:n=o+1}const s=n-1;return t=this.ensureBeforeEOL(t,r[s]),{line:s,character:t-r[s]}}offsetAt(t){const r=this.getLineOffsets();if(t.line>=r.length)return this._content.length;if(t.line<0)return 0;const n=r[t.line];if(t.character<=0)return n;const a=t.line+1r&&Bm(this._content.charCodeAt(t-1));)t--;return t}get lineCount(){return this.getLineOffsets().length}static isIncremental(t){const r=t;return r!=null&&typeof r.text=="string"&&r.range!==void 0&&(r.rangeLength===void 0||typeof r.rangeLength=="number")}static isFull(t){const r=t;return r!=null&&typeof r.text=="string"&&r.range===void 0&&r.rangeLength===void 0}},wl;(function(e){function t(a,s,o,l){return new Ny(a,s,o,l)}i(t,"create"),e.create=t;function r(a,s,o){if(a instanceof Ny)return a.update(s,o),a;throw new Error("TextDocument.update: document must be created by TextDocument.create")}i(r,"update"),e.update=r;function n(a,s){const o=a.getText(),l=Il(s.map(JS),(f,d)=>{const m=f.range.start.line-d.range.start.line;return m===0?f.range.start.character-d.range.start.character:m});let u=0;const c=[];for(const f of l){const d=a.offsetAt(f.range.start);if(du&&c.push(o.substring(u,d)),f.newText.length&&c.push(f.newText),u=a.offsetAt(f.range.end)}return c.push(o.substr(u)),c.join("")}i(n,"applyEdits"),e.applyEdits=n})(wl||(wl={}));function Il(e,t){if(e.length<=1)return e;const r=e.length/2|0,n=e.slice(0,r),a=e.slice(r);Il(n,t),Il(a,t);let s=0,o=0,l=0;for(;sr.line||t.line===r.line&&t.character>r.character?{start:r,end:t}:e}i(Um,"getWellformedRange");function JS(e){const t=Um(e.range);return t!==e.range?{newText:e.newText,range:t}:e}i(JS,"getWellformedEdit");var ZS;(()=>{var e={975:k=>{function C(T){if(typeof T!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(T))}i(C,"e");function y(T,$){for(var _,O="",x=0,D=-1,G=0,W=0;W<=T.length;++W){if(W2){var Y=O.lastIndexOf("/");if(Y!==O.length-1){Y===-1?(O="",x=0):x=(O=O.slice(0,Y)).length-1-O.lastIndexOf("/"),D=W,G=0;continue}}else if(O.length===2||O.length===1){O="",x=0,D=W,G=0;continue}}$&&(O.length>0?O+="/..":O="..",x=2)}else O.length>0?O+="/"+T.slice(D+1,W):O=T.slice(D+1,W),x=W-D-1;D=W,G=0}else _===46&&G!==-1?++G:G=-1}return O}i(y,"r");var E={resolve:i(function(){for(var T,$="",_=!1,O=arguments.length-1;O>=-1&&!_;O--){var x;O>=0?x=arguments[O]:(T===void 0&&(T=process.cwd()),x=T),C(x),x.length!==0&&($=x+"/"+$,_=x.charCodeAt(0)===47)}return $=y($,!_),_?$.length>0?"/"+$:"/":$.length>0?$:"."},"resolve"),normalize:i(function(T){if(C(T),T.length===0)return".";var $=T.charCodeAt(0)===47,_=T.charCodeAt(T.length-1)===47;return(T=y(T,!$)).length!==0||$||(T="."),T.length>0&&_&&(T+="/"),$?"/"+T:T},"normalize"),isAbsolute:i(function(T){return C(T),T.length>0&&T.charCodeAt(0)===47},"isAbsolute"),join:i(function(){if(arguments.length===0)return".";for(var T,$=0;$0&&(T===void 0?T=_:T+="/"+_)}return T===void 0?".":E.normalize(T)},"join"),relative:i(function(T,$){if(C(T),C($),T===$||(T=E.resolve(T))===($=E.resolve($)))return"";for(var _=1;_W){if($.charCodeAt(D+V)===47)return $.slice(D+V+1);if(V===0)return $.slice(D+V)}else x>W&&(T.charCodeAt(_+V)===47?Y=V:V===0&&(Y=0));break}var Pe=T.charCodeAt(_+V);if(Pe!==$.charCodeAt(D+V))break;Pe===47&&(Y=V)}var oe="";for(V=_+Y+1;V<=O;++V)V!==O&&T.charCodeAt(V)!==47||(oe.length===0?oe+="..":oe+="/..");return oe.length>0?oe+$.slice(D+Y):(D+=Y,$.charCodeAt(D)===47&&++D,$.slice(D))},"relative"),_makeLong:i(function(T){return T},"_makeLong"),dirname:i(function(T){if(C(T),T.length===0)return".";for(var $=T.charCodeAt(0),_=$===47,O=-1,x=!0,D=T.length-1;D>=1;--D)if(($=T.charCodeAt(D))===47){if(!x){O=D;break}}else x=!1;return O===-1?_?"/":".":_&&O===1?"//":T.slice(0,O)},"dirname"),basename:i(function(T,$){if($!==void 0&&typeof $!="string")throw new TypeError('"ext" argument must be a string');C(T);var _,O=0,x=-1,D=!0;if($!==void 0&&$.length>0&&$.length<=T.length){if($.length===T.length&&$===T)return"";var G=$.length-1,W=-1;for(_=T.length-1;_>=0;--_){var Y=T.charCodeAt(_);if(Y===47){if(!D){O=_+1;break}}else W===-1&&(D=!1,W=_+1),G>=0&&(Y===$.charCodeAt(G)?--G==-1&&(x=_):(G=-1,x=W))}return O===x?x=W:x===-1&&(x=T.length),T.slice(O,x)}for(_=T.length-1;_>=0;--_)if(T.charCodeAt(_)===47){if(!D){O=_+1;break}}else x===-1&&(D=!1,x=_+1);return x===-1?"":T.slice(O,x)},"basename"),extname:i(function(T){C(T);for(var $=-1,_=0,O=-1,x=!0,D=0,G=T.length-1;G>=0;--G){var W=T.charCodeAt(G);if(W!==47)O===-1&&(x=!1,O=G+1),W===46?$===-1?$=G:D!==1&&(D=1):$!==-1&&(D=-1);else if(!x){_=G+1;break}}return $===-1||O===-1||D===0||D===1&&$===O-1&&$===_+1?"":T.slice($,O)},"extname"),format:i(function(T){if(T===null||typeof T!="object")throw new TypeError('The "pathObject" argument must be of type Object. Received type '+typeof T);return(function($,_){var O=_.dir||_.root,x=_.base||(_.name||"")+(_.ext||"");return O?O===_.root?O+x:O+"/"+x:x})(0,T)},"format"),parse:i(function(T){C(T);var $={root:"",dir:"",base:"",ext:"",name:""};if(T.length===0)return $;var _,O=T.charCodeAt(0),x=O===47;x?($.root="/",_=1):_=0;for(var D=-1,G=0,W=-1,Y=!0,V=T.length-1,Pe=0;V>=_;--V)if((O=T.charCodeAt(V))!==47)W===-1&&(Y=!1,W=V+1),O===46?D===-1?D=V:Pe!==1&&(Pe=1):D!==-1&&(Pe=-1);else if(!Y){G=V+1;break}return D===-1||W===-1||Pe===0||Pe===1&&D===W-1&&D===G+1?W!==-1&&($.base=$.name=G===0&&x?T.slice(1,W):T.slice(G,W)):(G===0&&x?($.name=T.slice(1,D),$.base=T.slice(1,W)):($.name=T.slice(G,D),$.base=T.slice(G,W)),$.ext=T.slice(D,W)),G>0?$.dir=T.slice(0,G-1):x&&($.dir="/"),$},"parse"),sep:"/",delimiter:":",win32:null,posix:null};E.posix=E,k.exports=E}},t={};function r(k){var C=t[k];if(C!==void 0)return C.exports;var y=t[k]={exports:{}};return e[k](y,y.exports,r),y.exports}i(r,"r"),r.d=(k,C)=>{for(var y in C)r.o(C,y)&&!r.o(k,y)&&Object.defineProperty(k,y,{enumerable:!0,get:C[y]})},r.o=(k,C)=>Object.prototype.hasOwnProperty.call(k,C),r.r=k=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(k,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(k,"__esModule",{value:!0})};var n={};let a;r.r(n),r.d(n,{URI:i(()=>m,"URI"),Utils:i(()=>Se,"Utils")}),typeof process=="object"?a=process.platform==="win32":typeof navigator=="object"&&(a=navigator.userAgent.indexOf("Windows")>=0);const s=/^\w[\w\d+.-]*$/,o=/^\//,l=/^\/\//;function u(k,C){if(!k.scheme&&C)throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${k.authority}", path: "${k.path}", query: "${k.query}", fragment: "${k.fragment}"}`);if(k.scheme&&!s.test(k.scheme))throw new Error("[UriError]: Scheme contains illegal characters.");if(k.path){if(k.authority){if(!o.test(k.path))throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character')}else if(l.test(k.path))throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")')}}i(u,"a");const c="",f="/",d=/^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;class m{static{i(this,"l")}static isUri(C){return C instanceof m||!!C&&typeof C.authority=="string"&&typeof C.fragment=="string"&&typeof C.path=="string"&&typeof C.query=="string"&&typeof C.scheme=="string"&&typeof C.fsPath=="string"&&typeof C.with=="function"&&typeof C.toString=="function"}scheme;authority;path;query;fragment;constructor(C,y,E,T,$,_=!1){typeof C=="object"?(this.scheme=C.scheme||c,this.authority=C.authority||c,this.path=C.path||c,this.query=C.query||c,this.fragment=C.fragment||c):(this.scheme=(function(O,x){return O||x?O:"file"})(C,_),this.authority=y||c,this.path=(function(O,x){switch(O){case"https":case"http":case"file":x?x[0]!==f&&(x=f+x):x=f}return x})(this.scheme,E||c),this.query=T||c,this.fragment=$||c,u(this,_))}get fsPath(){return I(this,!1)}with(C){if(!C)return this;let{scheme:y,authority:E,path:T,query:$,fragment:_}=C;return y===void 0?y=this.scheme:y===null&&(y=c),E===void 0?E=this.authority:E===null&&(E=c),T===void 0?T=this.path:T===null&&(T=c),$===void 0?$=this.query:$===null&&($=c),_===void 0?_=this.fragment:_===null&&(_=c),y===this.scheme&&E===this.authority&&T===this.path&&$===this.query&&_===this.fragment?this:new v(y,E,T,$,_)}static parse(C,y=!1){const E=d.exec(C);return E?new v(E[2]||c,X(E[4]||c),X(E[5]||c),X(E[7]||c),X(E[9]||c),y):new v(c,c,c,c,c)}static file(C){let y=c;if(a&&(C=C.replace(/\\/g,f)),C[0]===f&&C[1]===f){const E=C.indexOf(f,2);E===-1?(y=C.substring(2),C=f):(y=C.substring(2,E),C=C.substring(E)||f)}return new v("file",y,C,c,c)}static from(C){const y=new v(C.scheme,C.authority,C.path,C.query,C.fragment);return u(y,!0),y}toString(C=!1){return R(this,C)}toJSON(){return this}static revive(C){if(C){if(C instanceof m)return C;{const y=new v(C);return y._formatted=C.external,y._fsPath=C._sep===g?C.fsPath:null,y}}return C}}const g=a?1:void 0;class v extends m{static{i(this,"d")}_formatted=null;_fsPath=null;get fsPath(){return this._fsPath||(this._fsPath=I(this,!1)),this._fsPath}toString(C=!1){return C?R(this,!0):(this._formatted||(this._formatted=R(this,!1)),this._formatted)}toJSON(){const C={$mid:1};return this._fsPath&&(C.fsPath=this._fsPath,C._sep=g),this._formatted&&(C.external=this._formatted),this.path&&(C.path=this.path),this.scheme&&(C.scheme=this.scheme),this.authority&&(C.authority=this.authority),this.query&&(C.query=this.query),this.fragment&&(C.fragment=this.fragment),C}}const b={58:"%3A",47:"%2F",63:"%3F",35:"%23",91:"%5B",93:"%5D",64:"%40",33:"%21",36:"%24",38:"%26",39:"%27",40:"%28",41:"%29",42:"%2A",43:"%2B",44:"%2C",59:"%3B",61:"%3D",32:"%20"};function S(k,C,y){let E,T=-1;for(let $=0;$=97&&_<=122||_>=65&&_<=90||_>=48&&_<=57||_===45||_===46||_===95||_===126||C&&_===47||y&&_===91||y&&_===93||y&&_===58)T!==-1&&(E+=encodeURIComponent(k.substring(T,$)),T=-1),E!==void 0&&(E+=k.charAt($));else{E===void 0&&(E=k.substr(0,$));const O=b[_];O!==void 0?(T!==-1&&(E+=encodeURIComponent(k.substring(T,$)),T=-1),E+=O):T===-1&&(T=$)}}return T!==-1&&(E+=encodeURIComponent(k.substring(T))),E!==void 0?E:k}i(S,"m");function w(k){let C;for(let y=0;y1&&k.scheme==="file"?`//${k.authority}${k.path}`:k.path.charCodeAt(0)===47&&(k.path.charCodeAt(1)>=65&&k.path.charCodeAt(1)<=90||k.path.charCodeAt(1)>=97&&k.path.charCodeAt(1)<=122)&&k.path.charCodeAt(2)===58?C?k.path.substr(1):k.path[1].toLowerCase()+k.path.substr(2):k.path,a&&(y=y.replace(/\//g,"\\")),y}i(I,"v");function R(k,C){const y=C?w:S;let E="",{scheme:T,authority:$,path:_,query:O,fragment:x}=k;if(T&&(E+=T,E+=":"),($||T==="file")&&(E+=f,E+=f),$){let D=$.indexOf("@");if(D!==-1){const G=$.substr(0,D);$=$.substr(D+1),D=G.lastIndexOf(":"),D===-1?E+=y(G,!1,!1):(E+=y(G.substr(0,D),!1,!1),E+=":",E+=y(G.substr(D+1),!1,!0)),E+="@"}$=$.toLowerCase(),D=$.lastIndexOf(":"),D===-1?E+=y($,!1,!0):(E+=y($.substr(0,D),!1,!0),E+=$.substr(D))}if(_){if(_.length>=3&&_.charCodeAt(0)===47&&_.charCodeAt(2)===58){const D=_.charCodeAt(1);D>=65&&D<=90&&(_=`/${String.fromCharCode(D+32)}:${_.substr(3)}`)}else if(_.length>=2&&_.charCodeAt(1)===58){const D=_.charCodeAt(0);D>=65&&D<=90&&(_=`${String.fromCharCode(D+32)}:${_.substr(2)}`)}E+=y(_,!0,!1)}return O&&(E+="?",E+=y(O,!1,!1)),x&&(E+="#",E+=C?x:S(x,!1,!1)),E}i(R,"b");function P(k){try{return decodeURIComponent(k)}catch{return k.length>3?k.substr(0,3)+P(k.substr(3)):k}}i(P,"C");const z=/(%[0-9A-Za-z][0-9A-Za-z])+/g;function X(k){return k.match(z)?k.replace(z,(C=>P(C))):k}i(X,"w");var Z=r(975);const ce=Z.posix||Z,se="/";var Se;(function(k){k.joinPath=function(C,...y){return C.with({path:ce.join(C.path,...y)})},k.resolvePath=function(C,...y){let E=C.path,T=!1;E[0]!==se&&(E=se+E,T=!0);let $=ce.resolve(E,...y);return T&&$[0]===se&&!C.authority&&($=$.substring(1)),C.with({path:$})},k.dirname=function(C){if(C.path.length===0||C.path===se)return C;let y=ce.dirname(C.path);return y.length===1&&y.charCodeAt(0)===46&&(y=""),C.with({path:y})},k.basename=function(C){return ce.basename(C.path)},k.extname=function(C){return ce.extname(C.path)}})(Se||(Se={})),ZS=n})();var{URI:Tt,Utils:Di}=ZS,nt;(function(e){e.basename=Di.basename,e.dirname=Di.dirname,e.extname=Di.extname,e.joinPath=Di.joinPath,e.resolvePath=Di.resolvePath;const t=typeof process=="object"&&process?.platform==="win32";function r(o,l){return o?.toString()===l?.toString()}i(r,"equals"),e.equals=r;function n(o,l){const u=typeof o=="string"?Tt.parse(o).path:o.path,c=typeof l=="string"?Tt.parse(l).path:l.path,f=u.split("/").filter(b=>b.length>0),d=c.split("/").filter(b=>b.length>0);if(t){const b=/^[A-Z]:$/;if(f[0]&&b.test(f[0])&&(f[0]=f[0].toLowerCase()),d[0]&&b.test(d[0])&&(d[0]=d[0].toLowerCase()),f[0]!==d[0])return c.substring(1)}let m=0;for(;m({name:n.name,uri:nt.joinPath(Tt.parse(t),n.name).toString(),element:n.element})):[]}all(){return this.collectValues(this.root)}findAll(e){const t=this.getNode(nt.normalize(e),!1);return t?this.collectValues(t):[]}getNode(e,t){const r=e.split("/");e.charAt(e.length-1)==="/"&&r.pop();let n=this.root;for(const a of r){let s=n.children.get(a);if(!s)if(t)s={name:a,children:new Map,parent:n},n.children.set(a,s);else return;n=s}return n}collectValues(e){const t=[];e.element&&t.push(e.element);for(const r of e.children.values())t.push(...this.collectValues(r));return t}},J;(function(e){e[e.Changed=0]="Changed",e[e.Parsed=1]="Parsed",e[e.IndexedContent=2]="IndexedContent",e[e.ComputedScopes=3]="ComputedScopes",e[e.Linked=4]="Linked",e[e.IndexedReferences=5]="IndexedReferences",e[e.Validated=6]="Validated"})(J||(J={}));var QS=class{static{i(this,"DefaultLangiumDocumentFactory")}constructor(e){this.serviceRegistry=e.ServiceRegistry,this.textDocuments=e.workspace.TextDocuments,this.fileSystemProvider=e.workspace.FileSystemProvider}async fromUri(e,t=pe.CancellationToken.None){const r=await this.fileSystemProvider.readFile(e);return this.createAsync(e,r,t)}fromTextDocument(e,t,r){return t=t??Tt.parse(e.uri),pe.CancellationToken.is(r)?this.createAsync(t,e,r):this.create(t,e,r)}fromString(e,t,r){return pe.CancellationToken.is(r)?this.createAsync(t,e,r):this.create(t,e,r)}fromModel(e,t){return this.create(t,{$model:e})}create(e,t,r){if(typeof t=="string"){const n=this.parse(e,t,r);return this.createLangiumDocument(n,e,void 0,t)}else if("$model"in t){const n={value:t.$model,parserErrors:[],lexerErrors:[]};return this.createLangiumDocument(n,e)}else{const n=this.parse(e,t.getText(),r);return this.createLangiumDocument(n,e,t)}}async createAsync(e,t,r){if(typeof t=="string"){const n=await this.parseAsync(e,t,r);return this.createLangiumDocument(n,e,void 0,t)}else{const n=await this.parseAsync(e,t.getText(),r);return this.createLangiumDocument(n,e,t)}}createLangiumDocument(e,t,r,n){let a;if(r)a={parseResult:e,uri:t,state:J.Parsed,references:[],textDocument:r};else{const s=this.createTextDocumentGetter(t,n);a={parseResult:e,uri:t,state:J.Parsed,references:[],get textDocument(){return s()}}}return e.value.$document=a,a}async update(e,t){const r=e.parseResult.value.$cstNode?.root.fullText,n=this.textDocuments?.get(e.uri.toString()),a=n?n.getText():await this.fileSystemProvider.readFile(e.uri);if(n)Object.defineProperty(e,"textDocument",{value:n});else{const s=this.createTextDocumentGetter(e.uri,a);Object.defineProperty(e,"textDocument",{get:s})}return r!==a&&(e.parseResult=await this.parseAsync(e.uri,a,t),e.parseResult.value.$document=e),e.state=J.Parsed,e}parse(e,t,r){return this.serviceRegistry.getServices(e).parser.LangiumParser.parse(t,r)}parseAsync(e,t,r){return this.serviceRegistry.getServices(e).parser.AsyncParser.parse(t,r)}createTextDocumentGetter(e,t){const r=this.serviceRegistry;let n;return()=>n??(n=wl.create(e.toString(),r.getServices(e).LanguageMetaData.languageId,0,t??""))}},ew=class{static{i(this,"DefaultLangiumDocuments")}constructor(e){this.documentTrie=new Km,this.services=e,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory,this.documentBuilder=()=>e.workspace.DocumentBuilder}get all(){return ue(this.documentTrie.all())}addDocument(e){const t=e.uri.toString();if(this.documentTrie.has(t))throw new Error(`A document with the URI '${t}' is already present.`);this.documentTrie.insert(t,e)}getDocument(e){const t=e.toString();return this.documentTrie.find(t)}getDocuments(e){const t=e.toString();return this.documentTrie.findAll(t)}async getOrCreateDocument(e,t){let r=this.getDocument(e);return r||(r=await this.langiumDocumentFactory.fromUri(e,t),this.addDocument(r),r)}createDocument(e,t,r){if(r)return this.langiumDocumentFactory.fromString(t,e,r).then(n=>(this.addDocument(n),n));{const n=this.langiumDocumentFactory.fromString(t,e);return this.addDocument(n),n}}hasDocument(e){return this.documentTrie.has(e.toString())}invalidateDocument(e){const t=e.toString(),r=this.documentTrie.find(t);return r&&this.documentBuilder().resetToState(r,J.Changed),r}deleteDocument(e){const t=e.toString(),r=this.documentTrie.find(t);return r&&(r.state=J.Changed,this.documentTrie.delete(t)),r}deleteDocuments(e){const t=e.toString(),r=this.documentTrie.findAll(t);for(const n of r)n.state=J.Changed;return this.documentTrie.delete(t),r}},un=Symbol("RefResolving"),tw=class{static{i(this,"DefaultLinker")}constructor(e){this.reflection=e.shared.AstReflection,this.langiumDocuments=()=>e.shared.workspace.LangiumDocuments,this.scopeProvider=e.references.ScopeProvider,this.astNodeLocator=e.workspace.AstNodeLocator,this.profiler=e.shared.profilers.LangiumProfiler,this.languageId=e.LanguageMetaData.languageId}async link(e,t=pe.CancellationToken.None){if(this.profiler?.isActive("linking")){const r=this.profiler.createTask("linking",this.languageId);r.start();try{for(const n of Gt(e.parseResult.value))await ze(t),Va(n).forEach(a=>{const s=`${n.$type}:${a.property}`;r.startSubTask(s);try{this.doLink(a,e)}finally{r.stopSubTask(s)}})}finally{r.stop()}}else for(const r of Gt(e.parseResult.value))await ze(t),Va(r).forEach(n=>this.doLink(n,e))}doLink(e,t){const r=e.reference;if("_ref"in r&&r._ref===void 0){r._ref=un;try{const n=this.getCandidate(e);if(pn(n))r._ref=n;else{r._nodeDescription=n;const a=this.loadAstNode(n);r._ref=a??this.createLinkingError(e,n)}}catch(n){console.error(`An error occurred while resolving reference to '${r.$refText}':`,n);const a=n.message??String(n);r._ref={info:e,message:`An error occurred while resolving reference to '${r.$refText}': ${a}`}}t.references.push(r)}else if("_items"in r&&r._items===void 0){r._items=un;try{const n=this.getCandidates(e),a=[];if(pn(n))r._linkingError=n;else for(const s of n){const o=this.loadAstNode(s);o&&a.push({ref:o,$nodeDescription:s})}r._items=a}catch(n){r._linkingError={info:e,message:`An error occurred while resolving reference to '${r.$refText}': ${n}`},r._items=[]}t.references.push(r)}}unlink(e){for(const t of e.references)"_ref"in t?(t._ref=void 0,delete t._nodeDescription):"_items"in t&&(t._items=void 0,delete t._linkingError);e.references=[]}getCandidate(e){return this.scopeProvider.getScope(e).getElement(e.reference.$refText)??this.createLinkingError(e)}getCandidates(e){const r=this.scopeProvider.getScope(e).getElements(e.reference.$refText).distinct(n=>`${n.documentUri}#${n.path}`).toArray();return r.length>0?r:this.createLinkingError(e)}buildReference(e,t,r,n){const a=this,s={$refNode:r,$refText:n,_ref:void 0,get ref(){if(Oe(this._ref))return this._ref;if(wd(this._nodeDescription)){const o=a.loadAstNode(this._nodeDescription);this._ref=o??a.createLinkingError({reference:s,container:e,property:t},this._nodeDescription)}else if(this._ref===void 0){this._ref=un;const o=Fa(e).$document,l=a.getLinkedNode({reference:s,container:e,property:t});if(l.error&&o&&o.state0))return this._linkingError=a.createLinkingError({reference:s,container:e,property:t})}};return s}throwCyclicReferenceError(e,t,r){throw new Error(`Cyclic reference resolution detected: ${this.astNodeLocator.getAstNodePath(e)}/${t} (symbol '${r}')`)}getLinkedNode(e){try{const t=this.getCandidate(e);if(pn(t))return{error:t};const r=this.loadAstNode(t);return r?{node:r,descr:t}:{descr:t,error:this.createLinkingError(e,t)}}catch(t){console.error(`An error occurred while resolving reference to '${e.reference.$refText}':`,t);const r=t.message??String(t);return{error:{info:e,message:`An error occurred while resolving reference to '${e.reference.$refText}': ${r}`}}}}loadAstNode(e){if(e.node)return e.node;const t=this.langiumDocuments().getDocument(e.documentUri);if(t)return this.astNodeLocator.getAstNode(t.parseResult.value,e.path)}createLinkingError(e,t){const r=Fa(e.container).$document;r&&r.stateFn(t)&&t.isMulti)}findDeclarations(e){if(e){const t=Tp(e),r=e.astNode;if(t&&r){const n=r[t.feature];if(rt(n)||rr(n))return qo(n);if(Array.isArray(n)){for(const a of n)if((rt(a)||rr(a))&&a.$refNode&&a.$refNode.offset<=e.offset&&a.$refNode.end>=e.end)return qo(a)}}if(r){const n=this.nameProvider.getNameNode(r);if(n&&(n===e||Zd(e,n)))return this.getSelfNodes(r)}}return[]}getSelfNodes(e){if(this.hasMultiReference){const t=this.index.findAllReferences(e,this.nodeLocator.getAstNodePath(e)),r=this.getNodeFromReferenceDescription(t.head());if(r){for(const n of Va(r))if(rr(n.reference)&&n.reference.items.some(a=>a.ref===e))return n.reference.items.map(a=>a.ref)}return[e]}else return[e]}getNodeFromReferenceDescription(e){if(!e)return;const t=this.documents.getDocument(e.sourceUri);if(t)return this.nodeLocator.getAstNode(t.parseResult.value,e.sourcePath)}findDeclarationNodes(e){const t=this.findDeclarations(e),r=[];for(const n of t){const a=this.nameProvider.getNameNode(n)??n.$cstNode;a&&r.push(a)}return r}findReferences(e,t){const r=[];t.includeDeclaration&&r.push(...this.getSelfReferences(e));let n=this.index.findAllReferences(e,this.nodeLocator.getAstNodePath(e));return t.documentUri&&(n=n.filter(a=>nt.equals(a.sourceUri,t.documentUri))),r.push(...n),ue(r)}getSelfReferences(e){const t=this.getSelfNodes(e),r=[];for(const n of t){const a=this.nameProvider.getNameNode(n);if(a){const s=Mt(n),o=this.nodeLocator.getAstNodePath(n);r.push({sourceUri:s.uri,sourcePath:o,targetUri:s.uri,targetPath:o,segment:Ya(a),local:!0})}}return r}},Ir=class{static{i(this,"MultiMap")}constructor(e){if(this.map=new Map,e)for(const[t,r]of e)this.add(t,r)}get size(){return Ts.sum(ue(this.map.values()).map(e=>e.length))}clear(){this.map.clear()}delete(e,t){if(t===void 0)return this.map.delete(e);{const r=this.map.get(e);if(r){const n=r.indexOf(t);if(n>=0)return r.length===1?this.map.delete(e):r.splice(n,1),!0}return!1}}get(e){return this.map.get(e)??[]}getStream(e){const t=this.map.get(e);return t?ue(t):Ua}has(e,t){if(t===void 0)return this.map.has(e);{const r=this.map.get(e);return r?r.indexOf(t)>=0:!1}}add(e,t){return this.map.has(e)?this.map.get(e).push(t):this.map.set(e,[t]),this}addAll(e,t){return this.map.has(e)?this.map.get(e).push(...t):this.map.set(e,Array.from(t)),this}forEach(e){this.map.forEach((t,r)=>t.forEach(n=>e(n,r,this)))}[Symbol.iterator](){return this.entries().iterator()}entries(){return ue(this.map.entries()).flatMap(([e,t])=>t.map(r=>[e,r]))}keys(){return ue(this.map.keys())}values(){return ue(this.map.values()).flat()}entriesGroupedByKey(){return ue(this.map.entries())}},Nl=class{static{i(this,"BiMap")}get size(){return this.map.size}constructor(e){if(this.map=new Map,this.inverse=new Map,e)for(const[t,r]of e)this.set(t,r)}clear(){this.map.clear(),this.inverse.clear()}set(e,t){return this.map.set(e,t),this.inverse.set(t,e),this}get(e){return this.map.get(e)}getKey(e){return this.inverse.get(e)}delete(e){const t=this.map.get(e);return t!==void 0?(this.map.delete(e),this.inverse.delete(t),!0):!1}},aw=class{static{i(this,"DefaultScopeComputation")}constructor(e){this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider}async collectExportedSymbols(e,t=pe.CancellationToken.None){return this.collectExportedSymbolsForNode(e.parseResult.value,e,void 0,t)}async collectExportedSymbolsForNode(e,t,r=Gs,n=pe.CancellationToken.None){const a=[];this.addExportedSymbol(e,a,t);for(const s of r(e))await ze(n),this.addExportedSymbol(s,a,t);return a}addExportedSymbol(e,t,r){const n=this.nameProvider.getName(e);n&&t.push(this.descriptions.createDescription(e,n,r))}async collectLocalSymbols(e,t=pe.CancellationToken.None){const r=e.parseResult.value,n=new Ir;for(const a of Nr(r))await ze(t),this.addLocalSymbol(a,e,n);return n}addLocalSymbol(e,t,r){const n=e.$container;if(n){const a=this.nameProvider.getName(e);a&&r.add(n,this.descriptions.createDescription(e,a,t))}}},Qf=class{static{i(this,"StreamScope")}constructor(e,t,r){this.elements=e,this.outerScope=t,this.caseInsensitive=r?.caseInsensitive??!1,this.concatOuterScope=r?.concatOuterScope??!0}getAllElements(){return this.outerScope?this.elements.concat(this.outerScope.getAllElements()):this.elements}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.caseInsensitive?this.elements.find(n=>n.name.toLowerCase()===t):this.elements.find(n=>n.name===e);if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}getElements(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.caseInsensitive?this.elements.filter(n=>n.name.toLowerCase()===t):this.elements.filter(n=>n.name===e);return(this.concatOuterScope||r.isEmpty())&&this.outerScope?r.concat(this.outerScope.getElements(e)):r}},AF=class{static{i(this,"MapScope")}constructor(e,t,r){this.elements=new Map,this.caseInsensitive=r?.caseInsensitive??!1,this.concatOuterScope=r?.concatOuterScope??!0;for(const n of e){const a=this.caseInsensitive?n.name.toLowerCase():n.name;this.elements.set(a,n)}this.outerScope=t}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t);if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}getElements(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t),n=r?[r]:[];return(this.concatOuterScope||n.length>0)&&this.outerScope?ue(n).concat(this.outerScope.getElements(e)):ue(n)}getAllElements(){let e=ue(this.elements.values());return this.outerScope&&(e=e.concat(this.outerScope.getAllElements())),e}},iw=class{static{i(this,"MultiMapScope")}constructor(e,t,r){this.elements=new Ir,this.caseInsensitive=r?.caseInsensitive??!1,this.concatOuterScope=r?.concatOuterScope??!0;for(const n of e){const a=this.caseInsensitive?n.name.toLowerCase():n.name;this.elements.add(a,n)}this.outerScope=t}getElement(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t)[0];if(r)return r;if(this.outerScope)return this.outerScope.getElement(e)}getElements(e){const t=this.caseInsensitive?e.toLowerCase():e,r=this.elements.get(t);return(this.concatOuterScope||r.length===0)&&this.outerScope?ue(r).concat(this.outerScope.getElements(e)):ue(r)}getAllElements(){let e=ue(this.elements.values());return this.outerScope&&(e=e.concat(this.outerScope.getAllElements())),e}},EF={getElement(){},getElements(){return Ua},getAllElements(){return Ua}},Gu=class{static{i(this,"DisposableCache")}constructor(){this.toDispose=[],this.isDisposed=!1}onDispose(e){this.toDispose.push(e)}dispose(){this.throwIfDisposed(),this.clear(),this.isDisposed=!0,this.toDispose.forEach(e=>e.dispose())}throwIfDisposed(){if(this.isDisposed)throw new Error("This cache has already been disposed")}},Vm=class extends Gu{static{i(this,"SimpleCache")}constructor(){super(...arguments),this.cache=new Map}has(e){return this.throwIfDisposed(),this.cache.has(e)}set(e,t){this.throwIfDisposed(),this.cache.set(e,t)}get(e,t){if(this.throwIfDisposed(),this.cache.has(e))return this.cache.get(e);if(t){const r=t();return this.cache.set(e,r),r}else return}delete(e){return this.throwIfDisposed(),this.cache.delete(e)}clear(){this.throwIfDisposed(),this.cache.clear()}},Fu=class extends Gu{static{i(this,"ContextCache")}constructor(e){super(),this.cache=new Map,this.converter=e??(t=>t)}has(e,t){return this.throwIfDisposed(),this.cacheForContext(e).has(t)}set(e,t,r){this.throwIfDisposed(),this.cacheForContext(e).set(t,r)}get(e,t,r){this.throwIfDisposed();const n=this.cacheForContext(e);if(n.has(t))return n.get(t);if(r){const a=r();return n.set(t,a),a}else return}delete(e,t){return this.throwIfDisposed(),this.cacheForContext(e).delete(t)}clear(e){if(this.throwIfDisposed(),e){const t=this.converter(e);this.cache.delete(t)}else this.cache.clear()}cacheForContext(e){const t=this.converter(e);let r=this.cache.get(t);return r||(r=new Map,this.cache.set(t,r)),r}},sw=class extends Fu{static{i(this,"DocumentCache")}constructor(e,t){super(r=>r.toString()),t?(this.toDispose.push(e.workspace.DocumentBuilder.onDocumentPhase(t,r=>{this.clear(r.uri.toString())})),this.toDispose.push(e.workspace.DocumentBuilder.onUpdate((r,n)=>{for(const a of n)this.clear(a)}))):this.toDispose.push(e.workspace.DocumentBuilder.onUpdate((r,n)=>{const a=r.concat(n);for(const s of a)this.clear(s)}))}},qm=class extends Vm{static{i(this,"WorkspaceCache")}constructor(e,t){super(),t?(this.toDispose.push(e.workspace.DocumentBuilder.onBuildPhase(t,()=>{this.clear()})),this.toDispose.push(e.workspace.DocumentBuilder.onUpdate((r,n)=>{n.length>0&&this.clear()}))):this.toDispose.push(e.workspace.DocumentBuilder.onUpdate(()=>{this.clear()}))}},ow=class{static{i(this,"DefaultScopeProvider")}constructor(e){this.reflection=e.shared.AstReflection,this.nameProvider=e.references.NameProvider,this.descriptions=e.workspace.AstNodeDescriptionProvider,this.indexManager=e.shared.workspace.IndexManager,this.globalScopeCache=new qm(e.shared)}getScope(e){const t=[],r=this.reflection.getReferenceType(e),n=Mt(e.container).localSymbols;if(n){let s=e.container;do n.has(s)&&t.push(n.getStream(s).filter(o=>this.reflection.isSubtype(o.type,r))),s=s.$container;while(s)}let a=this.getGlobalScope(r,e);for(let s=t.length-1;s>=0;s--)a=this.createScope(t[s],a);return a}createScope(e,t,r){return new Qf(ue(e),t,r)}createScopeForNodes(e,t,r){const n=ue(e).map(a=>{const s=this.nameProvider.getName(a);if(s)return this.descriptions.createDescription(a,s)}).nonNullable();return new Qf(n,t,r)}getGlobalScope(e,t){return this.globalScopeCache.get(e,()=>new iw(this.indexManager.allElements(e)))}};function Hm(e){return typeof e.$comment=="string"}i(Hm,"isAstNodeWithComment");function ed(e){return typeof e=="object"&&!!e&&("$ref"in e||"$error"in e)}i(ed,"isIntermediateReference");var lw=class{static{i(this,"DefaultJsonSerializer")}constructor(e){this.ignoreProperties=new Set(["$container","$containerProperty","$containerIndex","$document","$cstNode"]),this.langiumDocuments=e.shared.workspace.LangiumDocuments,this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider,this.commentProvider=e.documentation.CommentProvider}serialize(e,t){const r=t??{},n=t?.replacer,a=i((o,l)=>this.replacer(o,l,r),"defaultReplacer"),s=n?(o,l)=>n(o,l,a):a;try{return this.currentDocument=Mt(e),JSON.stringify(e,s,t?.space)}finally{this.currentDocument=void 0}}deserialize(e,t){const r=t??{},n=JSON.parse(e);return this.linkNode(n,n,r),n}replacer(e,t,{refText:r,sourceText:n,textRegions:a,comments:s,uriConverter:o}){if(!this.ignoreProperties.has(e))if(rt(t)){const l=t.ref,u=r?t.$refText:void 0;if(l){const c=Mt(l);let f="";this.currentDocument&&this.currentDocument!==c&&(o?f=o(c.uri,l):f=c.uri.toString());const d=this.astNodeLocator.getAstNodePath(l);return{$ref:`${f}#${d}`,$refText:u}}else return{$error:t.error?.message??"Could not resolve reference",$refText:u}}else if(rr(t)){const l=r?t.$refText:void 0,u=[];for(const c of t.items){const f=c.ref,d=Mt(c.ref);let m="";this.currentDocument&&this.currentDocument!==d&&(o?m=o(d.uri,f):m=d.uri.toString());const g=this.astNodeLocator.getAstNodePath(f);u.push(`${m}#${g}`)}return{$refs:u,$refText:l}}else if(Oe(t)){let l;if(a&&(l=this.addAstNodeRegionWithAssignmentsTo({...t}),(!e||t.$document)&&l?.$textRegion&&(l.$textRegion.documentURI=this.currentDocument?.uri.toString())),n&&!e&&(l??(l={...t}),l.$sourceText=t.$cstNode?.text),s){l??(l={...t});const u=this.commentProvider.getComment(t);u&&(l.$comment=u.replace(/\r/g,""))}return l??t}else return t}addAstNodeRegionWithAssignmentsTo(e){const t=i(r=>({offset:r.offset,end:r.end,length:r.length,range:r.range}),"createDocumentSegment");if(e.$cstNode){const r=e.$textRegion=t(e.$cstNode),n=r.assignments={};return Object.keys(e).filter(a=>!a.startsWith("$")).forEach(a=>{const s=gp(e.$cstNode,a).map(t);s.length!==0&&(n[a]=s)}),e}}linkNode(e,t,r,n,a,s){for(const[l,u]of Object.entries(e))if(Array.isArray(u))for(let c=0;c{await this.handleException(()=>e.call(t,r,n,a),"An error occurred during validation",n,r)}}async handleException(e,t,r,n){try{await e()}catch(a){if(ta(a))throw a;console.error(`${t}:`,a),a instanceof Error&&a.stack&&console.error(a.stack);const s=a instanceof Error?a.message:String(a);r("error",`${t}: ${s}`,{node:n})}}addEntry(e,t){if(e==="AstNode"){this.entries.add("AstNode",t);return}for(const r of this.reflection.getAllSubTypes(e))this.entries.add(r,t)}getChecks(e,t){let r=ue(this.entries.get(e)).concat(this.entries.get("AstNode"));return t&&(r=r.filter(n=>t.includes(n.category))),r.map(n=>n.check)}registerBeforeDocument(e,t=this){this.entriesBefore.push(this.wrapPreparationException(e,"An error occurred during set-up of the validation",t))}registerAfterDocument(e,t=this){this.entriesAfter.push(this.wrapPreparationException(e,"An error occurred during tear-down of the validation",t))}wrapPreparationException(e,t,r){return async(n,a,s,o)=>{await this.handleException(()=>e.call(r,n,a,s,o),t,a,n)}}get checksBefore(){return this.entriesBefore}get checksAfter(){return this.entriesAfter}getAllValidationCategories(e){return this.knownCategories}},fw=Object.freeze({validateNode:!0,validateChildren:!0}),dw=class{static{i(this,"DefaultDocumentValidator")}constructor(e){this.validationRegistry=e.validation.ValidationRegistry,this.metadata=e.LanguageMetaData,this.profiler=e.shared.profilers.LangiumProfiler,this.languageId=e.LanguageMetaData.languageId}async validateDocument(e,t={},r=pe.CancellationToken.None){const n=e.parseResult,a=[];if(await ze(r),(!t.categories||t.categories.includes("built-in"))&&(this.processLexingErrors(n,a,t),t.stopAfterLexingErrors&&a.some(s=>s.data?.code===_t.LexingError)||(this.processParsingErrors(n,a,t),t.stopAfterParsingErrors&&a.some(s=>s.data?.code===_t.ParsingError))||(this.processLinkingErrors(e,a,t),t.stopAfterLinkingErrors&&a.some(s=>s.data?.code===_t.LinkingError))))return a;try{a.push(...await this.validateAst(n.value,t,r))}catch(s){if(ta(s))throw s;console.error("An error occurred during validation:",s)}return await ze(r),a}processLexingErrors(e,t,r){const n=[...e.lexerErrors,...e.lexerReport?.diagnostics??[]];for(const a of n){const s=a.severity??"error",o={severity:gs(s),range:{start:{line:a.line-1,character:a.column-1},end:{line:a.line-1,character:a.column+a.length-1}},message:a.message,data:Xm(s),source:this.getSource()};t.push(o)}}processParsingErrors(e,t,r){for(const n of e.parserErrors){let a;if(isNaN(n.token.startOffset)){if("previousToken"in n){const s=n.previousToken;if(isNaN(s.startOffset)){const o={line:0,character:0};a={start:o,end:o}}else{const o={line:s.endLine-1,character:s.endColumn};a={start:o,end:o}}}}else a=$s(n.token);if(a){const s={severity:gs("error"),range:a,message:n.message,data:Sn(_t.ParsingError),source:this.getSource()};t.push(s)}}}processLinkingErrors(e,t,r){for(const n of e.references){const a=n.error;if(a){const s={node:a.info.container,range:n.$refNode?.range,property:a.info.property,index:a.info.index,data:{code:_t.LinkingError,containerType:a.info.container.$type,property:a.info.property,refText:a.info.reference.$refText}};t.push(this.toDiagnostic("error",a.message,s))}}}async validateAst(e,t,r=pe.CancellationToken.None){const n=[],a=i((s,o,l)=>{n.push(this.toDiagnostic(s,o,l))},"acceptor");return await this.validateAstBefore(e,t,a,r),await this.validateAstNodes(e,t,a,r),await this.validateAstAfter(e,t,a,r),n}async validateAstBefore(e,t,r,n=pe.CancellationToken.None){const a=this.validationRegistry.checksBefore;for(const s of a)await ze(n),await s(e,r,t.categories??[],n)}async validateAstNodes(e,t,r,n=pe.CancellationToken.None){if(this.profiler?.isActive("validating")){const a=this.profiler.createTask("validating",this.languageId);a.start();try{const s=Gt(e).iterator();for(const o of s){a.startSubTask(o.$type);const l=this.validateSingleNodeOptions(o,t);if(l.validateNode)try{const u=this.validationRegistry.getChecks(o.$type,t.categories);for(const c of u)await c(o,r,n)}finally{a.stopSubTask(o.$type)}l.validateChildren||s.prune()}}finally{a.stop()}}else{const a=Gt(e).iterator();for(const s of a){await ze(n);const o=this.validateSingleNodeOptions(s,t);if(o.validateNode){const l=this.validationRegistry.getChecks(s.$type,t.categories);for(const u of l)await u(s,r,n)}o.validateChildren||a.prune()}}}validateSingleNodeOptions(e,t){return fw}async validateAstAfter(e,t,r,n=pe.CancellationToken.None){const a=this.validationRegistry.checksAfter;for(const s of a)await ze(n),await s(e,r,t.categories??[],n)}toDiagnostic(e,t,r){return{message:t,range:Ym(r),severity:gs(e),code:r.code,codeDescription:r.codeDescription,tags:r.tags,relatedInformation:r.relatedInformation,data:r.data,source:this.getSource()}}getSource(){return this.metadata.languageId}};function Ym(e){if(e.range)return e.range;let t;return typeof e.property=="string"?t=Yl(e.node.$cstNode,e.property,e.index):typeof e.keyword=="string"&&(t=vp(e.node.$cstNode,e.keyword,e.index)),t??(t=e.node.$cstNode),t?t.range:{start:{line:0,character:0},end:{line:0,character:0}}}i(Ym,"getDiagnosticRange");function gs(e){switch(e){case"error":return 1;case"warning":return 2;case"info":return 3;case"hint":return 4;default:throw new Error("Invalid diagnostic severity: "+e)}}i(gs,"toDiagnosticSeverity");function Xm(e){switch(e){case"error":return Sn(_t.LexingError);case"warning":return Sn(_t.LexingWarning);case"info":return Sn(_t.LexingInfo);case"hint":return Sn(_t.LexingHint);default:throw new Error("Invalid diagnostic severity: "+e)}}i(Xm,"toDiagnosticData");var _t;(function(e){e.LexingError="lexing-error",e.LexingWarning="lexing-warning",e.LexingInfo="lexing-info",e.LexingHint="lexing-hint",e.ParsingError="parsing-error",e.LinkingError="linking-error"})(_t||(_t={}));var pw=class{static{i(this,"DefaultAstNodeDescriptionProvider")}constructor(e){this.astNodeLocator=e.workspace.AstNodeLocator,this.nameProvider=e.references.NameProvider}createDescription(e,t,r){const n=r??Mt(e);t??(t=this.nameProvider.getName(e));const a=this.astNodeLocator.getAstNodePath(e);if(!t)throw new Error(`Node at path ${a} has no name.`);let s;const o=i(()=>s??(s=Ya(this.nameProvider.getNameNode(e)??e.$cstNode)),"nameSegmentGetter");return{node:e,name:t,get nameSegment(){return o()},selectionSegment:Ya(e.$cstNode),type:e.$type,documentUri:n.uri,path:a}}},mw=class{static{i(this,"DefaultReferenceDescriptionProvider")}constructor(e){this.nodeLocator=e.workspace.AstNodeLocator}async createDescriptions(e,t=pe.CancellationToken.None){const r=[],n=e.parseResult.value;for(const a of Gt(n))await ze(t),Va(a).forEach(s=>{s.reference.error||r.push(...this.createInfoDescriptions(s))});return r}createInfoDescriptions(e){const t=e.reference;if(t.error||!t.$refNode)return[];let r=[];rt(t)&&t.$nodeDescription?r=[t.$nodeDescription]:rr(t)&&(r=t.items.map(l=>l.$nodeDescription).filter(l=>l!==void 0));const n=Mt(e.container).uri,a=this.nodeLocator.getAstNodePath(e.container),s=[],o=Ya(t.$refNode);for(const l of r)s.push({sourceUri:n,sourcePath:a,targetUri:l.documentUri,targetPath:l.path,segment:o,local:nt.equals(l.documentUri,n)});return s}},hw=class{static{i(this,"DefaultAstNodeLocator")}constructor(){this.segmentSeparator="/",this.indexSeparator="@"}getAstNodePath(e){if(e.$container){const t=this.getAstNodePath(e.$container),r=this.getPathSegment(e);return t+this.segmentSeparator+r}return""}getPathSegment({$containerProperty:e,$containerIndex:t}){if(!e)throw new Error("Missing '$containerProperty' in AST node.");return t!==void 0?e+this.indexSeparator+t:e}getAstNode(e,t){return t.split(this.segmentSeparator).reduce((n,a)=>{if(!n||a.length===0)return n;const s=a.indexOf(this.indexSeparator);if(s>0){const o=a.substring(0,s),l=parseInt(a.substring(s+1));return n[o]?.[l]}return n[a]},e)}},zu={};Ll(zu,Cd(ei()));var yw=class{static{i(this,"DefaultConfigurationProvider")}constructor(e){this._ready=new wr,this.onConfigurationSectionUpdateEmitter=new zu.Emitter,this.settings={},this.workspaceConfig=!1,this.serviceRegistry=e.ServiceRegistry}get ready(){return this._ready.promise}initialize(e){this.workspaceConfig=e.capabilities.workspace?.configuration??!1}async initialized(e){if(this.workspaceConfig){if(e.register){const t=this.serviceRegistry.all;e.register({section:t.map(r=>this.toSectionName(r.LanguageMetaData.languageId))})}if(e.fetchConfiguration){const t=this.serviceRegistry.all.map(n=>({section:this.toSectionName(n.LanguageMetaData.languageId)})),r=await e.fetchConfiguration(t);t.forEach((n,a)=>{this.updateSectionConfiguration(n.section,r[a])})}}this._ready.resolve()}updateConfiguration(e){typeof e.settings!="object"||e.settings===null||Object.entries(e.settings).forEach(([t,r])=>{this.updateSectionConfiguration(t,r),this.onConfigurationSectionUpdateEmitter.fire({section:t,configuration:r})})}updateSectionConfiguration(e,t){this.settings[e]=t}async getConfiguration(e,t){await this.ready;const r=this.toSectionName(e);if(this.settings[r])return this.settings[r][t]}toSectionName(e){return`${e}`}get onConfigurationSectionUpdate(){return this.onConfigurationSectionUpdateEmitter.event}},uo=Cd(nN()),Nn;(function(e){function t(r){return{dispose:i(async()=>await r(),"dispose")}}i(t,"create"),e.create=t})(Nn||(Nn={}));var gw=class{static{i(this,"DefaultDocumentBuilder")}constructor(e){this.updateBuildOptions={validation:{categories:["built-in","fast"]}},this.updateListeners=[],this.buildPhaseListeners=new Ir,this.documentPhaseListeners=new Ir,this.buildState=new Map,this.documentBuildWaiters=new Map,this.currentState=J.Changed,this.langiumDocuments=e.workspace.LangiumDocuments,this.langiumDocumentFactory=e.workspace.LangiumDocumentFactory,this.textDocuments=e.workspace.TextDocuments,this.indexManager=e.workspace.IndexManager,this.fileSystemProvider=e.workspace.FileSystemProvider,this.workspaceManager=()=>e.workspace.WorkspaceManager,this.serviceRegistry=e.ServiceRegistry}async build(e,t={},r=pe.CancellationToken.None){for(const n of e){const a=n.uri.toString();if(n.state===J.Validated){if(typeof t.validation=="boolean"&&t.validation)this.resetToState(n,J.IndexedReferences);else if(typeof t.validation=="object"){const s=this.findMissingValidationCategories(n,t);s.length>0&&(this.buildState.set(a,{completed:!1,options:{validation:{categories:s}},result:this.buildState.get(a)?.result}),n.state=J.IndexedReferences)}}else this.buildState.delete(a)}this.currentState=J.Changed,await this.emitUpdate(e.map(n=>n.uri),[]),await this.buildDocuments(e,t,r)}async update(e,t,r=pe.CancellationToken.None){this.currentState=J.Changed;const n=[];for(const l of t){const u=this.langiumDocuments.deleteDocuments(l);for(const c of u)n.push(c.uri),this.cleanUpDeleted(c)}const a=(await Promise.all(e.map(l=>this.findChangedUris(l)))).flat();for(const l of a){let u=this.langiumDocuments.getDocument(l);u===void 0&&(u=this.langiumDocumentFactory.fromModel({$type:"INVALID"},l),u.state=J.Changed,this.langiumDocuments.addDocument(u)),this.resetToState(u,J.Changed)}const s=ue(a).concat(n).map(l=>l.toString()).toSet();this.langiumDocuments.all.filter(l=>!s.has(l.uri.toString())&&this.shouldRelink(l,s)).forEach(l=>this.resetToState(l,J.ComputedScopes)),await this.emitUpdate(a,n),await ze(r);const o=this.sortDocuments(this.langiumDocuments.all.filter(l=>l.state=1}findMissingValidationCategories(e,t){const r=this.buildState.get(e.uri.toString()),n=this.serviceRegistry.getServices(e.uri).validation.ValidationRegistry.getAllValidationCategories(e),a=r?.result?.validationChecks?new Set(r?.result?.validationChecks):r?.completed?n:new Set,s=t===void 0||t.validation===!0?n:typeof t.validation=="object"?t.validation.categories??n:[];return ue(s).filter(o=>!a.has(o)).toArray()}async findChangedUris(e){if(this.langiumDocuments.getDocument(e)??this.textDocuments?.get(e))return[e];try{const r=await this.fileSystemProvider.stat(e);if(r.isDirectory)return await this.workspaceManager().searchFolder(e);if(this.workspaceManager().shouldIncludeEntry(r))return[e]}catch{}return[]}async emitUpdate(e,t){await Promise.all(this.updateListeners.map(r=>r(e,t)))}sortDocuments(e){let t=0,r=e.length-1;for(;t=0&&!this.hasTextDocument(e[r]);)r--;tr.error!==void 0)?!0:this.indexManager.isAffected(e,t)}onUpdate(e){return this.updateListeners.push(e),Nn.create(()=>{const t=this.updateListeners.indexOf(e);t>=0&&this.updateListeners.splice(t,1)})}resetToState(e,t){switch(t){case J.Changed:case J.Parsed:this.indexManager.removeContent(e.uri);case J.IndexedContent:e.localSymbols=void 0;case J.ComputedScopes:this.serviceRegistry.getServices(e.uri).references.Linker.unlink(e);case J.Linked:this.indexManager.removeReferences(e.uri);case J.IndexedReferences:e.diagnostics=void 0,this.buildState.delete(e.uri.toString());case J.Validated:}e.state>t&&(e.state=t)}cleanUpDeleted(e){this.buildState.delete(e.uri.toString()),this.indexManager.remove(e.uri),e.state=J.Changed}async buildDocuments(e,t,r){this.prepareBuild(e,t),await this.runCancelable(e,J.Parsed,r,s=>this.langiumDocumentFactory.update(s,r)),await this.runCancelable(e,J.IndexedContent,r,s=>this.indexManager.updateContent(s,r)),await this.runCancelable(e,J.ComputedScopes,r,async s=>{const o=this.serviceRegistry.getServices(s.uri).references.ScopeComputation;s.localSymbols=await o.collectLocalSymbols(s,r)});const n=e.filter(s=>this.shouldLink(s));await this.runCancelable(n,J.Linked,r,s=>this.serviceRegistry.getServices(s.uri).references.Linker.link(s,r)),await this.runCancelable(n,J.IndexedReferences,r,s=>this.indexManager.updateReferences(s,r));const a=e.filter(s=>this.shouldValidate(s)?!0:(this.markAsCompleted(s),!1));await this.runCancelable(a,J.Validated,r,async s=>{await this.validate(s,r),this.markAsCompleted(s)})}markAsCompleted(e){const t=this.buildState.get(e.uri.toString());t&&(t.completed=!0)}prepareBuild(e,t){for(const r of e){const n=r.uri.toString(),a=this.buildState.get(n);(!a||a.completed)&&this.buildState.set(n,{completed:!1,options:t,result:a?.result})}}async runCancelable(e,t,r,n){for(const s of e)s.states.state===t);await this.notifyBuildPhase(a,t,r),this.currentState=t}onBuildPhase(e,t){return this.buildPhaseListeners.add(e,t),Nn.create(()=>{this.buildPhaseListeners.delete(e,t)})}onDocumentPhase(e,t){return this.documentPhaseListeners.add(e,t),Nn.create(()=>{this.documentPhaseListeners.delete(e,t)})}waitUntil(e,t,r){let n;return t&&"path"in t?n=t:r=t,r??(r=pe.CancellationToken.None),n?this.awaitDocumentState(e,n,r):this.awaitBuilderState(e,r)}awaitDocumentState(e,t,r){const n=this.langiumDocuments.getDocument(t);if(n){if(n.state>=e)return Promise.resolve(t);if(r.isCancellationRequested)return Promise.reject(tr);if(this.currentState>=e&&e>n.state)return Promise.reject(new uo.ResponseError(uo.LSPErrorCodes.RequestFailed,`Document state of ${t.toString()} is ${J[n.state]}, requiring ${J[e]}, but workspace state is already ${J[this.currentState]}. Returning undefined.`))}else return Promise.reject(new uo.ResponseError(uo.LSPErrorCodes.ServerCancelled,`No document found for URI: ${t.toString()}`));return new Promise((a,s)=>{const o=this.onDocumentPhase(e,u=>{nt.equals(u.uri,t)&&(o.dispose(),l.dispose(),a(u.uri))}),l=r.onCancellationRequested(()=>{o.dispose(),l.dispose(),s(tr)})})}awaitBuilderState(e,t){return this.currentState>=e?Promise.resolve():t.isCancellationRequested?Promise.reject(tr):new Promise((r,n)=>{const a=this.onBuildPhase(e,()=>{a.dispose(),s.dispose(),r()}),s=t.onCancellationRequested(()=>{a.dispose(),s.dispose(),n(tr)})})}async notifyDocumentPhase(e,t,r){const a=this.documentPhaseListeners.get(t).slice();for(const s of a)try{await ze(r),await s(e,r)}catch(o){if(!ta(o))throw o}}async notifyBuildPhase(e,t,r){if(e.length===0)return;const a=this.buildPhaseListeners.get(t).slice();for(const s of a)await ze(r),await s(e,r)}shouldLink(e){return this.getBuildOptions(e).eagerLinking??!0}shouldValidate(e){return!!this.getBuildOptions(e).validation}async validate(e,t){const r=this.serviceRegistry.getServices(e.uri).validation.DocumentValidator,n=this.getBuildOptions(e),a=typeof n.validation=="object"?{...n.validation}:{};a.categories=this.findMissingValidationCategories(e,n);const s=await r.validateDocument(e,a,t);e.diagnostics?e.diagnostics.push(...s):e.diagnostics=s;const o=this.buildState.get(e.uri.toString());o&&(o.result??(o.result={}),o.result.validationChecks?o.result.validationChecks=ue(o.result.validationChecks).concat(a.categories).distinct().toArray():o.result.validationChecks=[...a.categories])}getBuildOptions(e){return this.buildState.get(e.uri.toString())?.options??{}}},vw=class{static{i(this,"DefaultIndexManager")}constructor(e){this.symbolIndex=new Map,this.symbolByTypeIndex=new Fu,this.referenceIndex=new Map,this.documents=e.workspace.LangiumDocuments,this.serviceRegistry=e.ServiceRegistry,this.astReflection=e.AstReflection}findAllReferences(e,t){const r=Mt(e).uri,n=[];return this.referenceIndex.forEach(a=>{a.forEach(s=>{nt.equals(s.targetUri,r)&&s.targetPath===t&&n.push(s)})}),ue(n)}allElements(e,t){let r=ue(this.symbolIndex.keys());return t&&(r=r.filter(n=>!t||t.has(n))),r.map(n=>this.getFileDescriptions(n,e)).flat()}getFileDescriptions(e,t){return t?this.symbolByTypeIndex.get(e,t,()=>(this.symbolIndex.get(e)??[]).filter(a=>this.astReflection.isSubtype(a.type,t))):this.symbolIndex.get(e)??[]}remove(e){this.removeContent(e),this.removeReferences(e)}removeContent(e){const t=e.toString();this.symbolIndex.delete(t),this.symbolByTypeIndex.clear(t)}removeReferences(e){const t=e.toString();this.referenceIndex.delete(t)}async updateContent(e,t=pe.CancellationToken.None){const n=await this.serviceRegistry.getServices(e.uri).references.ScopeComputation.collectExportedSymbols(e,t),a=e.uri.toString();this.symbolIndex.set(a,n),this.symbolByTypeIndex.clear(a)}async updateReferences(e,t=pe.CancellationToken.None){const n=await this.serviceRegistry.getServices(e.uri).workspace.ReferenceDescriptionProvider.createDescriptions(e,t);this.referenceIndex.set(e.uri.toString(),n)}isAffected(e,t){const r=this.referenceIndex.get(e.uri.toString());return r?r.some(n=>!n.local&&t.has(n.targetUri.toString())):!1}},Tw=class{static{i(this,"DefaultWorkspaceManager")}constructor(e){this.initialBuildOptions={},this._ready=new wr,this.serviceRegistry=e.ServiceRegistry,this.langiumDocuments=e.workspace.LangiumDocuments,this.documentBuilder=e.workspace.DocumentBuilder,this.fileSystemProvider=e.workspace.FileSystemProvider,this.mutex=e.workspace.WorkspaceLock}get ready(){return this._ready.promise}get workspaceFolders(){return this.folders}initialize(e){this.folders=e.workspaceFolders??void 0}initialized(e){return this.mutex.write(t=>this.initializeWorkspace(this.folders??[],t))}async initializeWorkspace(e,t=pe.CancellationToken.None){const r=await this.performStartup(e);await ze(t),await this.documentBuilder.build(r,this.initialBuildOptions,t)}async performStartup(e){const t=[],r=i(s=>{t.push(s),this.langiumDocuments.hasDocument(s.uri)||this.langiumDocuments.addDocument(s)},"collector");await this.loadAdditionalDocuments(e,r);const n=[];await Promise.all(e.map(s=>this.getRootFolder(s)).map(async s=>this.traverseFolder(s,n)));const a=ue(n).distinct(s=>s.toString()).filter(s=>!this.langiumDocuments.hasDocument(s));return await this.loadWorkspaceDocuments(a,r),this._ready.resolve(),t}async loadWorkspaceDocuments(e,t){await Promise.all(e.map(async r=>{const n=await this.langiumDocuments.getOrCreateDocument(r);t(n)}))}loadAdditionalDocuments(e,t){return Promise.resolve()}getRootFolder(e){return Tt.parse(e.uri)}async traverseFolder(e,t){try{const r=await this.fileSystemProvider.readDirectory(e);await Promise.all(r.map(async n=>{this.shouldIncludeEntry(n)&&(n.isDirectory?await this.traverseFolder(n.uri,t):n.isFile&&t.push(n.uri))}))}catch(r){console.error("Failure to read directory content of "+e.toString(!0),r)}}async searchFolder(e){const t=[];return await this.traverseFolder(e,t),t}shouldIncludeEntry(e){const t=nt.basename(e.uri);return t.startsWith(".")?!1:e.isDirectory?t!=="node_modules"&&t!=="out":e.isFile?this.serviceRegistry.hasServices(e.uri):!1}},$w=class{static{i(this,"DefaultLexerErrorMessageProvider")}buildUnexpectedCharactersMessage(e,t,r,n,a){return Of.buildUnexpectedCharactersMessage(e,t,r,n,a)}buildUnableToPopLexerModeMessage(e){return Of.buildUnableToPopLexerModeMessage(e)}},Jm={mode:"full"},Zm=class{static{i(this,"DefaultLexer")}constructor(e){this.errorMessageProvider=e.parser.LexerErrorMessageProvider,this.tokenBuilder=e.parser.TokenBuilder;const t=this.tokenBuilder.buildTokens(e.Grammar,{caseInsensitive:e.LanguageMetaData.caseInsensitive});this.tokenTypes=this.toTokenTypeDictionary(t);const r=kl(t)?Object.values(t):t,n=e.LanguageMetaData.mode==="production";this.chevrotainLexer=new at(r,{positionTracking:"full",skipValidations:n,errorMessageProvider:this.errorMessageProvider})}get definition(){return this.tokenTypes}tokenize(e,t=Jm){const r=this.chevrotainLexer.tokenize(e);return{tokens:r.tokens,errors:r.errors,hidden:r.groups.hidden??[],report:this.tokenBuilder.flushLexingReport?.(e)}}toTokenTypeDictionary(e){if(kl(e))return e;const t=Bu(e)?Object.values(e.modes).flat():e,r={};return t.forEach(n=>r[n.name]=n),r}};function ju(e){return Array.isArray(e)&&(e.length===0||"name"in e[0])}i(ju,"isTokenTypeArray");function Bu(e){return e&&"modes"in e&&"defaultMode"in e}i(Bu,"isIMultiModeLexerDefinition");function kl(e){return!ju(e)&&!Bu(e)}i(kl,"isTokenTypeDictionary");xs();function Qm(e,t,r){let n,a;typeof e=="string"?(a=t,n=r):(a=e.range.start,n=t),a||(a=ie.create(0,0));const s=th(e),o=Uu(n),l=Rw({lines:s,position:a,options:o});return Cw({index:0,tokens:l,position:a})}i(Qm,"parseJSDoc");function eh(e,t){const r=Uu(t),n=th(e);if(n.length===0)return!1;const a=n[0],s=n[n.length-1],o=r.start,l=r.end;return!!o?.exec(a)&&!!l?.exec(s)}i(eh,"isJSDoc");function th(e){let t="";return typeof e=="string"?t=e:t=e.text,t.split(Ev)}i(th,"getLines");var Py=/\s*(@([\p{L}][\p{L}\p{N}]*)?)/uy,CF=/\{(@[\p{L}][\p{L}\p{N}]*)(\s*)([^\r\n}]+)?\}/gu;function Rw(e){const t=[];let r=e.position.line,n=e.position.character;for(let a=0;a=l.length){if(t.length>0){const f=ie.create(r,n);t.push({type:"break",content:"",range:Q.create(f,f)})}}else{Py.lastIndex=u;const f=Py.exec(l);if(f){const d=f[0],m=f[1],g=ie.create(r,n+u),v=ie.create(r,n+u+d.length);t.push({type:"tag",content:m,range:Q.create(g,v)}),u+=d.length,u=Ol(l,u)}if(u0&&t[t.length-1].type==="break"?t.slice(0,-1):t}i(Rw,"tokenize");function Aw(e,t,r,n){const a=[];if(e.length===0){const s=ie.create(r,n),o=ie.create(r,n+t.length);a.push({type:"text",content:t,range:Q.create(s,o)})}else{let s=0;for(const l of e){const u=l.index,c=t.substring(s,u);c.length>0&&a.push({type:"text",content:t.substring(s,u),range:Q.create(ie.create(r,s+n),ie.create(r,u+n))});let f=c.length+1;const d=l[1];if(a.push({type:"inline-tag",content:d,range:Q.create(ie.create(r,s+f+n),ie.create(r,s+f+d.length+n))}),f+=d.length,l.length===4){f+=l[2].length;const m=l[3];a.push({type:"text",content:m,range:Q.create(ie.create(r,s+f+n),ie.create(r,s+f+m.length+n))})}else a.push({type:"text",content:"",range:Q.create(ie.create(r,s+f+n),ie.create(r,s+f+n))});s=u+l[0].length}const o=t.substring(s);o.length>0&&a.push({type:"text",content:o,range:Q.create(ie.create(r,s+n),ie.create(r,s+n+o.length))})}return a}i(Aw,"buildInlineTokens");var bF=/\S/,_F=/\s*$/;function Ol(e,t){const r=e.substring(t).match(bF);return r?t+r.index:e.length}i(Ol,"skipWhitespace");function Ew(e){const t=e.match(_F);if(t&&typeof t.index=="number")return t.index}i(Ew,"lastCharacter");function Cw(e){const t=ie.create(e.position.line,e.position.character);if(e.tokens.length===0)return new ky([],Q.create(t,t));const r=[];for(;e.indext.name===e)}getTags(e){return this.getAllTags().filter(t=>t.name===e)}getAllTags(){return this.elements.filter(e=>"name"in e)}toString(){let e="";for(const t of this.elements)if(e.length===0)e=t.toString();else{const r=t.toString();e+=rd(e)+r}return e.trim()}toMarkdown(e){let t="";for(const r of this.elements)if(t.length===0)t=r.toMarkdown(e);else{const n=r.toMarkdown(e);t+=rd(t)+n}return t.trim()}},Qu=class{static{i(this,"JSDocTagImpl")}constructor(e,t,r,n){this.name=e,this.content=t,this.inline=r,this.range=n}toString(){let e=`@${this.name}`;const t=this.content.toString();return this.content.inlines.length===1?e=`${e} ${t}`:this.content.inlines.length>1&&(e=`${e} +${t}`),this.inline?`{${e}}`:e}toMarkdown(e){return e?.renderTag?.(this)??this.toMarkdownDefault(e)}toMarkdownDefault(e){const t=this.content.toMarkdown(e);if(this.inline){const a=ww(this.name,t,e??{});if(typeof a=="string")return a}let r="";e?.tag==="italic"||e?.tag===void 0?r="*":e?.tag==="bold"?r="**":e?.tag==="bold-italic"&&(r="***");let n=`${r}@${this.name}${r}`;return this.content.inlines.length===1?n=`${n} — ${t}`:this.content.inlines.length>1&&(n=`${n} +${t}`),this.inline?`{${n}}`:n}};function ww(e,t,r){if(e==="linkplain"||e==="linkcode"||e==="link"){const n=t.indexOf(" ");let a=t;if(n>0){const o=Ol(t,n);a=t.substring(o),t=t.substring(0,n)}return(e==="linkcode"||e==="link"&&r.link==="code")&&(a=`\`${a}\``),r.renderLink?.(t,a)??Iw(t,a)}}i(ww,"renderInlineTag");function Iw(e,t){try{return Tt.parse(e,!0),`[${t}](${e})`}catch{return e}}i(Iw,"renderLinkDefault");var td=class{static{i(this,"JSDocTextImpl")}constructor(e,t){this.inlines=e,this.range=t}toString(){let e="";for(let t=0;tr.range.start.line&&(e+=` +`)}return e}toMarkdown(e){let t="";for(let r=0;rn.range.start.line&&(t+=` +`)}return t}},Nw=class{static{i(this,"JSDocLineImpl")}constructor(e,t){this.text=e,this.range=t}toString(){return this.text}toMarkdown(){return this.text}};function rd(e){return e.endsWith(` +`)?` +`:` + +`}i(rd,"fillNewlines");var Pw=class{static{i(this,"JSDocDocumentationProvider")}constructor(e){this.indexManager=e.shared.workspace.IndexManager,this.commentProvider=e.documentation.CommentProvider}getDocumentation(e){const t=this.commentProvider.getComment(e);if(t&&eh(t))return Qm(t).toMarkdown({renderLink:i((n,a)=>this.documentationLinkRenderer(e,n,a),"renderLink"),renderTag:i(n=>this.documentationTagRenderer(e,n),"renderTag")})}documentationLinkRenderer(e,t,r){const n=this.findNameInLocalSymbols(e,t)??this.findNameInGlobalScope(e,t);if(n&&n.nameSegment){const a=n.nameSegment.range.start.line+1,s=n.nameSegment.range.start.character+1,o=n.documentUri.with({fragment:`L${a},${s}`});return`[${r}](${o.toString()})`}else return}documentationTagRenderer(e,t){}findNameInLocalSymbols(e,t){const n=Mt(e).localSymbols;if(!n)return;let a=e;do{const o=n.getStream(a).find(l=>l.name===t);if(o)return o;a=a.$container}while(a)}findNameInGlobalScope(e,t){return this.indexManager.allElements().find(n=>n.name===t)}},kw=class{static{i(this,"DefaultCommentProvider")}constructor(e){this.grammarConfig=()=>e.parser.GrammarConfig}getComment(e){return Hm(e)?e.$comment:rp(e.$cstNode,this.grammarConfig().multilineCommentRules)?.text}},Ow=class{static{i(this,"DefaultAsyncParser")}constructor(e){this.syncParser=e.parser.LangiumParser}parse(e,t){return Promise.resolve(this.syncParser.parse(e))}},SF=class{static{i(this,"AbstractThreadedAsyncParser")}constructor(e){this.threadCount=8,this.terminationDelay=200,this.workerPool=[],this.queue=[],this.hydrator=e.serializer.Hydrator}initializeWorkers(){for(;this.workerPool.length{if(this.queue.length>0){const t=this.queue.shift();t&&(e.lock(),t.resolve(e))}}),this.workerPool.push(e)}}async parse(e,t){const r=await this.acquireParserWorker(t),n=new wr;let a;const s=t.onCancellationRequested(()=>{a=setTimeout(()=>{this.terminateWorker(r)},this.terminationDelay)});return r.parse(e).then(o=>{const l=this.hydrator.hydrate(o);n.resolve(l)}).catch(o=>{n.reject(o)}).finally(()=>{s.dispose(),clearTimeout(a)}),n.promise}terminateWorker(e){e.terminate();const t=this.workerPool.indexOf(e);t>=0&&this.workerPool.splice(t,1)}async acquireParserWorker(e){this.initializeWorkers();for(const r of this.workerPool)if(r.ready)return r.lock(),r;const t=new wr;return e.onCancellationRequested(()=>{const r=this.queue.indexOf(t);r>=0&&this.queue.splice(r,1),t.reject(tr)}),this.queue.push(t),t.promise}},wF=class{static{i(this,"ParserWorker")}get ready(){return this._ready}get onReady(){return this.onReadyEmitter.event}constructor(e,t,r,n){this.onReadyEmitter=new zu.Emitter,this.deferred=new wr,this._ready=!0,this._parsing=!1,this.sendMessage=e,this._terminate=n,t(a=>{const s=a;this.deferred.resolve(s),this.unlock()}),r(a=>{this.deferred.reject(a),this.unlock()})}terminate(){this.deferred.reject(tr),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 wr,this.sendMessage(e),this.deferred.promise}},Lw=class{static{i(this,"DefaultWorkspaceLock")}constructor(){this.previousTokenSource=new pe.CancellationTokenSource,this.writeQueue=[],this.readQueue=[],this.done=!0}write(e){this.cancelWrite();const t=Mu();return this.previousTokenSource=t,this.enqueue(this.writeQueue,e,t.token)}read(e){return this.enqueue(this.readQueue,e)}enqueue(e,t,r=pe.CancellationToken.None){const n=new wr,a={action:t,deferred:n,cancellationToken:r};return e.push(a),this.performNextOperation(),n.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:t,deferred:r,cancellationToken:n})=>{try{const a=await Promise.resolve().then(()=>t(n));r.resolve(a)}catch(a){ta(a)?r.resolve(void 0):r.reject(a)}})),this.done=!0,this.performNextOperation()}cancelWrite(){this.previousTokenSource.cancel()}},Dw=class{static{i(this,"DefaultHydrator")}constructor(e){this.grammarElementIdMap=new Nl,this.tokenTypeIdMap=new Nl,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(t=>({...t,message:t.message})),value:this.dehydrateAstNode(e.value,this.createDehyrationContext(e.value))}}dehydrateLexerReport(e){return e}createDehyrationContext(e){const t=new Map,r=new Map;for(const n of Gt(e))t.set(n,{});if(e.$cstNode)for(const n of Ha(e.$cstNode))r.set(n,{});return{astNodes:t,cstNodes:r}}dehydrateAstNode(e,t){const r=t.astNodes.get(e);r.$type=e.$type,r.$containerIndex=e.$containerIndex,r.$containerProperty=e.$containerProperty,e.$cstNode!==void 0&&(r.$cstNode=this.dehydrateCstNode(e.$cstNode,t));for(const[n,a]of Object.entries(e))if(!n.startsWith("$"))if(Array.isArray(a)){const s=[];r[n]=s;for(const o of a)Oe(o)?s.push(this.dehydrateAstNode(o,t)):rt(o)?s.push(this.dehydrateReference(o,t)):s.push(o)}else Oe(a)?r[n]=this.dehydrateAstNode(a,t):rt(a)?r[n]=this.dehydrateReference(a,t):a!==void 0&&(r[n]=a);return r}dehydrateReference(e,t){const r={};return r.$refText=e.$refText,e.$refNode&&(r.$refNode=t.cstNodes.get(e.$refNode)),r}dehydrateCstNode(e,t){const r=t.cstNodes.get(e);return Ml(e)?r.fullText=e.fullText:r.grammarSource=this.getGrammarElementId(e.grammarSource),r.hidden=e.hidden,r.astNode=t.astNodes.get(e.astNode),$r(e)?r.content=e.content.map(n=>this.dehydrateCstNode(n,t)):xn(e)&&(r.tokenType=e.tokenType.name,r.offset=e.offset,r.length=e.length,r.startLine=e.range.start.line,r.startColumn=e.range.start.character,r.endLine=e.range.end.line,r.endColumn=e.range.end.character),r}hydrate(e){const t=e.value,r=this.createHydrationContext(t);return"$cstNode"in t&&this.hydrateCstNode(t.$cstNode,r),{lexerErrors:e.lexerErrors,lexerReport:e.lexerReport,parserErrors:e.parserErrors,value:this.hydrateAstNode(t,r)}}createHydrationContext(e){const t=new Map,r=new Map;for(const a of Gt(e))t.set(a,{});let n;if(e.$cstNode)for(const a of Ha(e.$cstNode)){let s;"fullText"in a?(s=new km(a.fullText),n=s):"content"in a?s=new ku:"tokenType"in a&&(s=this.hydrateCstLeafNode(a)),s&&(r.set(a,s),s.root=n)}return{astNodes:t,cstNodes:r}}hydrateAstNode(e,t){const r=t.astNodes.get(e);r.$type=e.$type,r.$containerIndex=e.$containerIndex,r.$containerProperty=e.$containerProperty,e.$cstNode&&(r.$cstNode=t.cstNodes.get(e.$cstNode));for(const[n,a]of Object.entries(e))if(!n.startsWith("$"))if(Array.isArray(a)){const s=[];r[n]=s;for(const o of a)Oe(o)?s.push(this.setParent(this.hydrateAstNode(o,t),r)):rt(o)?s.push(this.hydrateReference(o,r,n,t)):s.push(o)}else Oe(a)?r[n]=this.setParent(this.hydrateAstNode(a,t),r):rt(a)?r[n]=this.hydrateReference(a,r,n,t):a!==void 0&&(r[n]=a);return r}setParent(e,t){return e.$container=t,e}hydrateReference(e,t,r,n){return this.linker.buildReference(t,r,n.cstNodes.get(e.$refNode),e.$refText)}hydrateCstNode(e,t,r=0){const n=t.cstNodes.get(e);if(typeof e.grammarSource=="number"&&(n.grammarSource=this.getGrammarElement(e.grammarSource)),n.astNode=t.astNodes.get(e.astNode),$r(n))for(const a of e.content){const s=this.hydrateCstNode(a,t,r++);n.content.push(s)}return n}hydrateCstLeafNode(e){const t=this.getTokenType(e.tokenType),r=e.offset,n=e.length,a=e.startLine,s=e.startColumn,o=e.endLine,l=e.endColumn,u=e.hidden;return new bl(r,n,{start:{line:a,character:s},end:{line:o,character:l}},t,u)}getTokenType(e){return this.lexer.definition[e]}getGrammarElementId(e){if(e)return this.grammarElementIdMap.size===0&&this.createGrammarElementIdMap(),this.grammarElementIdMap.get(e)}getGrammarElement(e){return this.grammarElementIdMap.size===0&&this.createGrammarElementIdMap(),this.grammarElementIdMap.getKey(e)}createGrammarElementIdMap(){let e=0;for(const t of Gt(this.grammar))Gl(t)&&this.grammarElementIdMap.set(t,e++)}};function je(e){return{documentation:{CommentProvider:i(t=>new kw(t),"CommentProvider"),DocumentationProvider:i(t=>new Pw(t),"DocumentationProvider")},parser:{AsyncParser:i(t=>new Ow(t),"AsyncParser"),GrammarConfig:i(t=>_p(t),"GrammarConfig"),LangiumParser:i(t=>Gm(t),"LangiumParser"),CompletionParser:i(t=>Mm(t),"CompletionParser"),ValueConverter:i(()=>new zm,"ValueConverter"),TokenBuilder:i(()=>new Du,"TokenBuilder"),Lexer:i(t=>new Zm(t),"Lexer"),ParserErrorMessageProvider:i(()=>new Lm,"ParserErrorMessageProvider"),LexerErrorMessageProvider:i(()=>new $w,"LexerErrorMessageProvider")},workspace:{AstNodeLocator:i(()=>new hw,"AstNodeLocator"),AstNodeDescriptionProvider:i(t=>new pw(t),"AstNodeDescriptionProvider"),ReferenceDescriptionProvider:i(t=>new mw(t),"ReferenceDescriptionProvider")},references:{Linker:i(t=>new tw(t),"Linker"),NameProvider:i(()=>new rw,"NameProvider"),ScopeProvider:i(t=>new ow(t),"ScopeProvider"),ScopeComputation:i(t=>new aw(t),"ScopeComputation"),References:i(t=>new nw(t),"References")},serializer:{Hydrator:i(t=>new Dw(t),"Hydrator"),JsonSerializer:i(t=>new lw(t),"JsonSerializer")},validation:{DocumentValidator:i(t=>new dw(t),"DocumentValidator"),ValidationRegistry:i(t=>new cw(t),"ValidationRegistry")},shared:i(()=>e.shared,"shared")}}i(je,"createDefaultCoreModule");function Be(e){return{ServiceRegistry:i(t=>new uw(t),"ServiceRegistry"),workspace:{LangiumDocuments:i(t=>new ew(t),"LangiumDocuments"),LangiumDocumentFactory:i(t=>new QS(t),"LangiumDocumentFactory"),DocumentBuilder:i(t=>new gw(t),"DocumentBuilder"),IndexManager:i(t=>new vw(t),"IndexManager"),WorkspaceManager:i(t=>new Tw(t),"WorkspaceManager"),FileSystemProvider:i(t=>e.fileSystemProvider(t),"FileSystemProvider"),WorkspaceLock:i(()=>new Lw,"WorkspaceLock"),ConfigurationProvider:i(t=>new yw(t),"ConfigurationProvider")},profilers:{}}}i(Be,"createDefaultSharedCoreModule");var nd;(function(e){e.merge=(t,r)=>Qa(Qa({},t),r)})(nd||(nd={}));function ee(e,t,r,n,a,s,o,l,u){const c=[e,t,r,n,a,s,o,l,u].reduce(Qa,{});return sh(c)}i(ee,"inject");var xw=Symbol("isProxy");function ih(e){if(e&&e[xw])for(const t of Object.values(e))ih(t);return e}i(ih,"eagerLoad");function sh(e,t){const r=new Proxy({},{deleteProperty:i(()=>!1,"deleteProperty"),set:i(()=>{throw new Error("Cannot set property on injected service container")},"set"),get:i((n,a)=>a===xw?!0:ad(n,a,e,t||r),"get"),getOwnPropertyDescriptor:i((n,a)=>(ad(n,a,e,t||r),Object.getOwnPropertyDescriptor(n,a)),"getOwnPropertyDescriptor"),has:i((n,a)=>a in e,"has"),ownKeys:i(()=>[...Object.getOwnPropertyNames(e)],"ownKeys")});return r}i(sh,"_inject");var Oy=Symbol();function ad(e,t,r,n){if(t in e){if(e[t]instanceof Error)throw new Error("Construction failure. Please make sure that your dependencies are constructable. Cause: "+e[t]);if(e[t]===Oy)throw new Error('Cycle detected. Please make "'+String(t)+'" lazy. Visit https://langium.org/docs/reference/configuration-services/#resolving-cyclic-dependencies');return e[t]}else if(t in r){const a=r[t];e[t]=Oy;try{e[t]=typeof a=="function"?a(n):sh(a,n)}catch(s){throw e[t]=s instanceof Error?s:void 0,s}return e[t]}else return}i(ad,"_resolve");function Qa(e,t){if(t){for(const[r,n]of Object.entries(t))if(n!=null)if(typeof n=="object"){const a=e[r];typeof a=="object"&&a!==null?e[r]=Qa(a,n):e[r]=Qa({},n)}else e[r]=n}return e}i(Qa,"_merge");var id={indentTokenName:"INDENT",dedentTokenName:"DEDENT",whitespaceTokenName:"WS",ignoreIndentationDelimiters:[]},wn;(function(e){e.REGULAR="indentation-sensitive",e.IGNORE_INDENTATION="ignore-indentation"})(wn||(wn={}));var Mw=class extends Du{static{i(this,"IndentationAwareTokenBuilder")}constructor(e=id){super(),this.indentationStack=[0],this.whitespaceRegExp=/[ \t]+/y,this.options={...id,...e},this.indentTokenType=ja({name:this.options.indentTokenName,pattern:this.indentMatcher.bind(this),line_breaks:!1}),this.dedentTokenType=ja({name:this.options.dedentTokenName,pattern:this.dedentMatcher.bind(this),line_breaks:!1})}buildTokens(e,t){const r=super.buildTokens(e,t);if(!ju(r))throw new Error("Invalid tokens built by default builder");const{indentTokenName:n,dedentTokenName:a,whitespaceTokenName:s,ignoreIndentationDelimiters:o}=this.options;let l,u,c;const f=[];for(const d of r){for(const[m,g]of o)d.name===m?d.PUSH_MODE=wn.IGNORE_INDENTATION:d.name===g&&(d.POP_MODE=!0);d.name===a?l=d:d.name===n?u=d:d.name===s?c=d:f.push(d)}if(!l||!u||!c)throw new Error("Some indentation/whitespace tokens not found!");return o.length>0?{modes:{[wn.REGULAR]:[l,u,...f,c],[wn.IGNORE_INDENTATION]:[...f,c]},defaultMode:wn.REGULAR}:[l,u,c,...f]}flushLexingReport(e){return{...super.flushLexingReport(e),remainingDedents:this.flushRemainingDedents(e)}}isStartOfLine(e,t){return t===0||`\r +`.includes(e[t-1])}matchWhitespace(e,t,r,n){this.whitespaceRegExp.lastIndex=t;const a=this.whitespaceRegExp.exec(e);return{currIndentLevel:a?.[0].length??0,prevIndentLevel:this.indentationStack.at(-1),match:a}}createIndentationTokenInstance(e,t,r,n){const a=this.getLineNumber(t,n);return Qs(e,r,n,n+r.length,a,a,1,r.length)}getLineNumber(e,t){return e.substring(0,t).split(/\r\n|\r|\n/).length}indentMatcher(e,t,r,n){if(!this.isStartOfLine(e,t))return null;const{currIndentLevel:a,prevIndentLevel:s,match:o}=this.matchWhitespace(e,t,r,n);return a<=s?null:(this.indentationStack.push(a),o)}dedentMatcher(e,t,r,n){if(!this.isStartOfLine(e,t))return null;const{currIndentLevel:a,prevIndentLevel:s,match:o}=this.matchWhitespace(e,t,r,n);if(a>=s)return null;const l=this.indentationStack.lastIndexOf(a);if(l===-1)return this.diagnostics.push({severity:"error",message:`Invalid dedent level ${a} at offset: ${t}. Current indentation stack: ${this.indentationStack}`,offset:t,length:o?.[0]?.length??0,line:this.getLineNumber(e,t),column:1}),null;const u=this.indentationStack.length-l-1,c=e.substring(0,t).match(/[\r\n]+$/)?.[0].length??1;for(let f=0;f1;)t.push(this.createIndentationTokenInstance(this.dedentTokenType,e,"",e.length)),this.indentationStack.pop();return this.indentationStack=[0],t}},IF=class extends Zm{static{i(this,"IndentationAwareLexer")}constructor(e){if(super(e),e.parser.TokenBuilder instanceof Mw)this.indentationTokenBuilder=e.parser.TokenBuilder;else throw new Error("IndentationAwareLexer requires an accompanying IndentationAwareTokenBuilder")}tokenize(e,t=Jm){const r=super.tokenize(e),n=r.report;t?.mode==="full"&&r.tokens.push(...n.remainingDedents),n.remainingDedents=[];const{indentTokenType:a,dedentTokenType:s}=this.indentationTokenBuilder,o=a.tokenTypeIdx,l=s.tokenTypeIdx,u=[],c=r.tokens.length-1;for(let f=0;f=0&&u.push(r.tokens[c]),r.tokens=u,r}},oh={};Vr(oh,{AstUtils:()=>Nd,BiMap:()=>Nl,Cancellation:()=>pe,ContextCache:()=>Fu,CstUtils:()=>Sd,DONE_RESULT:()=>tt,Deferred:()=>wr,Disposable:()=>Nn,DisposableCache:()=>Gu,DocumentCache:()=>sw,EMPTY_STREAM:()=>Ua,ErrorWithLocation:()=>Wl,GrammarUtils:()=>sp,MultiMap:()=>Ir,OperationCancelled:()=>tr,Reduction:()=>Ts,RegExpUtils:()=>lp,SimpleCache:()=>Vm,StreamImpl:()=>er,TreeStreamImpl:()=>Ka,URI:()=>Tt,UriTrie:()=>Km,UriUtils:()=>nt,WorkspaceCache:()=>qm,assertCondition:()=>op,assertUnreachable:()=>qr,delayNextTick:()=>xu,interruptAndCheck:()=>ze,isOperationCancelled:()=>ta,loadGrammarFromJson:()=>Ue,setInterruptionPeriod:()=>jm,startCancelableOperation:()=>Mu,stream:()=>ue});Ll(oh,zu);var Gw=class{static{i(this,"EmptyFileSystemProvider")}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[]}},Xe={fileSystemProvider:i(()=>new Gw,"fileSystemProvider")},NF={Grammar:i(()=>{},"Grammar"),LanguageMetaData:i(()=>({caseInsensitive:!1,fileExtensions:[".langium"],languageId:"langium"}),"LanguageMetaData")},PF={AstReflection:i(()=>new Jd,"AstReflection")};function Fw(){const e=ee(Be(Xe),PF),t=ee(je({shared:e}),NF);return e.ServiceRegistry.register(t),t}i(Fw,"createMinimalGrammarServices");function Ue(e){const t=Fw(),r=t.serializer.JsonSerializer.deserialize(e);return t.shared.workspace.LangiumDocumentFactory.fromModel(r,Tt.parse(`memory:/${r.name??"grammar"}.langium`)),r}i(Ue,"loadGrammarFromJson");Ll(Hg,oh);var kF=class{static{i(this,"DefaultLangiumProfiler")}constructor(e){this.activeCategories=new Set,this.allCategories=new Set(["validating","parsing","linking"]),this.activeCategories=e??new Set(this.allCategories),this.records=new Ir}isActive(e){return this.activeCategories.has(e)}start(...e){e?e.forEach(t=>this.activeCategories.add(t)):this.activeCategories=new Set(this.allCategories)}stop(...e){e?e.forEach(t=>this.activeCategories.delete(t)):this.activeCategories.clear()}createTask(e,t){if(!this.isActive(e))throw new Error(`Category "${e}" is not active.`);return console.log(`Creating profiling task for '${e}.${t}'.`),new zw(r=>this.records.add(e,this.dumpRecord(e,r)),t)}dumpRecord(e,t){console.info(`Task ${e}.${t.identifier} executed in ${t.duration.toFixed(2)}ms and ended at ${t.date.toISOString()}`);const r=[];for(const s of t.entries.keys()){const o=t.entries.get(s),l=o.reduce((u,c)=>u+c);r.push({name:`${t.identifier}.${s}`,count:o.length,duration:l})}const n=t.duration-r.map(s=>s.duration).reduce((s,o)=>s+o,0);r.push({name:t.identifier,count:1,duration:n}),r.sort((s,o)=>o.duration-s.duration);function a(s){return Math.round(100*s)/100}return i(a,"Round"),console.table(r.map(s=>({Element:s.name,Count:s.count,"Self %":a(100*s.duration/t.duration),"Time (ms)":a(s.duration)}))),t}getRecords(...e){return e.length===0?this.records.values():this.records.entries().filter(t=>e.some(r=>r===t[0])).flatMap(t=>t[1])}},zw=class{static{i(this,"ProfilingTask")}constructor(e,t){this.stack=[],this.entries=new Ir,this.addRecord=e,this.identifier=t}start(){if(this.startTime!==void 0)throw new Error(`Task "${this.identifier}" is already started.`);this.startTime=performance.now()}stop(){if(this.startTime===void 0)throw new Error(`Task "${this.identifier}" was not started.`);if(this.stack.length!==0)throw new Error(`Task "${this.identifier}" cannot be stopped before sub-task(s): ${this.stack.map(t=>t.id).join(", ")}.`);const e={identifier:this.identifier,date:new Date,duration:performance.now()-this.startTime,entries:this.entries};this.addRecord(e),this.startTime=void 0,this.entries.clear()}startSubTask(e){this.stack.push({id:e,start:performance.now(),content:0})}stopSubTask(e){const t=this.stack.pop();if(!t)throw new Error(`Task "${this.identifier}.${e}" was not started.`);if(t.id!==e)throw new Error(`Sub-Task "${t.id}" is not already stopped.`);const r=performance.now()-t.start;this.stack.at(-1)!==void 0&&(this.stack[this.stack.length-1].content+=r);const n=r-t.content;this.entries.add(e,n)}},sd;(e=>{e.Terminals={ARROW_DIRECTION:/L|R|T|B/,ARROW_GROUP:/\{group\}/,ARROW_INTO:/<|>/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,ID:/[\w]([-\w]*\w)?/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,ARCH_ICON:/\([\w-:]+\)/,ARCH_TITLE:/\[(?:"([^"\\]|\\.)*"|'([^'\\]|\\.)*'|[\w ]+)\]/}})(sd||(sd={}));var od;(e=>{e.Terminals={DOMAIN_NAME:/complex|complicated|clear|chaotic|confusion/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(od||(od={}));var ld;(e=>{e.Terminals={EM_ID:/[_a-zA-Z][\w_]*/,EM_FID:/\d{1,3}/,EM_DATA_INLINE:/\{(.*)\}|"(.*)"|'(.*)'/,EM_DATA_BLOCK:/\{[\t ]*\r?\n(?:[\S\s]*?\r?\n)?\}(?:\r?\n|(?!\S))/,EM_ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,EM_ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,EM_TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,EM_WS:/\s+/,EM_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,EM_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,EM_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,EM_ML_COMMENT:/\/\*[\s\S]*?\*\//,EM_SL_COMMENT:/\/\/[^\n\r]*/}})(ld||(ld={}));var ud;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,INT:/0|[1-9][0-9]*(?!\.)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,REFERENCE:/\w([-\./\w]*[-\w])?/}})(ud||(ud={}));var cd;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(cd||(cd={}));var fd;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,INT:/0|[1-9][0-9]*(?!\.)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(fd||(fd={}));var dd;(e=>{e.Terminals={NUMBER_PIE:/(?:-?[0-9]+\.[0-9]+(?!\.))|(?:-?(0|[1-9][0-9]*)(?!\.))/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(dd||(dd={}));var pd;(e=>{e.Terminals={GRATICULE:/circle|polygon/,BOOLEAN:/true|false/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,NUMBER:/(?:[0-9]+\.[0-9]+(?!\.))|(?:0|[1-9][0-9]*(?!\.))/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,ID:/[\w]([-\w]*\w)?/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})(pd||(pd={}));var md;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ABNF_RULENAME:/[A-Za-z][A-Za-z0-9-]*/,ABNF_STRING:/"[^"]*"/,ABNF_NUMVAL:/%[xXdDbB][0-9A-Fa-f]+(?:-[0-9A-Fa-f]+|\.[0-9A-Fa-f]+)*/,ABNF_REPEAT:/[0-9]*\*[0-9]*/,ABNF_EXACT_REPEAT:/[0-9]+/,ABNF_WHITESPACE:/[\t \r\n]+/,ABNF_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,ABNF_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,ABNF_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,ABNF_COMMENT:/;[^\n\r]*/}})(md||(md={}));var hd;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,EBNF_ID:/[A-Z_a-z][\w-]*/,EBNF_STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,EBNF_SPECIAL_SEQUENCE:/\?(?=[^?;]*[^?\s;][^?;]*\?)[^?;]*\?/,EBNF_WHITESPACE:/[\t \r\n]+/,EBNF_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,EBNF_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,EBNF_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,EBNF_BLOCK_COMMENT:/\/\*[\s\S]*?\*\//,EBNF_ISO_COMMENT:/\(\*[\s\S]*?\*\)/}})(hd||(hd={}));var yd;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,RR_ID:/[A-Z_a-z][\w-]*/,RR_STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,RR_WHITESPACE:/[\t \r\n]+/,RR_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,RR_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,RR_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,RR_BLOCK_COMMENT:/\/\*[\s\S]*?\*\//}})(yd||(yd={}));var gd;(e=>{e.Terminals={TITLE:/title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,ACC_TITLE:/accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,ACC_DESCR:/accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,PEG_ID:/[A-Z_a-z][\w-]*/,PEG_STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,PEG_WHITESPACE:/[\t \r\n]+/,PEG_YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,PEG_DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,PEG_SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/,PEG_LINE_COMMENT:/#[^\n\r]*/}})(gd||(gd={}));var vd;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,TREEMAP_KEYWORD:/treemap-beta|treemap/,CLASS_DEF:/classDef\s+([a-zA-Z_][a-zA-Z0-9_]+)(?:\s+([^;\r\n]*))?(?:;)?/,STYLE_SEPARATOR:/:::/,SEPARATOR:/:/,COMMA:/,/,INDENTATION:/[ \t]{1,}/,WS:/[ \t]+/,ML_COMMENT:/\%\%[^\n]*/,NL:/\r?\n/,ID2:/[a-zA-Z_][a-zA-Z0-9_]*/,NUMBER2:/[0-9_\.\,]+/,STRING2:/"[^"]*"|'[^']*'/}})(vd||(vd={}));var Td;(e=>{e.Terminals={ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,CLASS_ANNOTATION:/[ \t]+:::[ \t]*[A-Za-z_][\w-]*/,ICON_ANNOTATION:/[ \t]+icon\([\w-]*(?::[\w-]+)?\)/,DESC_ANNOTATION:/[ \t]+##[^\n\r]*/,INDENTATION:/[ \t]{1,}/,QUOTED_NAME:/"[^"]*"|'[^']*'/,WS:/[ \t]+/,ML_COMMENT:/\%\%[^\n]*/,NL:/\r?\n/,BARE_NAME:/(?!:::|icon\(|##)[^ \t\n\r"'](?:(?![ \t]+:::[ \t]*[A-Za-z_]|[ \t]+icon\(|[ \t]+##)[^\n\r])*/}})(Td||(Td={}));var $d;(e=>{e.Terminals={WARDLEY_NUMBER:/[0-9]+\.[0-9]+/,ARROW:/->/,LINK_PORT:/\+<>|\+>|\+|-\.->|>|\+'[^']*'<>|\+'[^']*'<|\+'[^']*'>/,LINK_LABEL:/;[^\n\r]+/,STRATEGY:/build|buy|outsource|market/,KW_WARDLEY:/wardley-beta/,KW_SIZE:/size/,KW_EVOLUTION:/evolution/,KW_ANCHOR:/anchor/,KW_COMPONENT:/component/,KW_LABEL:/label/,KW_INERTIA:/inertia/,KW_EVOLVE:/evolve/,KW_PIPELINE:/pipeline/,KW_NOTE:/note/,KW_ANNOTATIONS:/annotations/,KW_ANNOTATION:/annotation/,KW_ACCELERATOR:/accelerator/,KW_DEACCELERATOR:/deaccelerator/,NAME_WITH_SPACES:/(?!title\s|accTitle|accDescr)[A-Za-z](?:[A-Za-z0-9_()&]|-(?!>))*(?:[ \t]+[A-Za-z(](?:[A-Za-z0-9_()&]|-(?!>))*)*/,WS:/[ \t]+/,ACC_DESCR:/[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/,ACC_TITLE:/[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/,TITLE:/[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/,INT:/0|[1-9][0-9]*(?!\.)/,STRING:/"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,ID:/[\w]([-\w]*\w)?/,NEWLINE:/\r?\n/,WHITESPACE:/[\t ]+/,YAML:/---[\t ]*\r?\n(?:[\S\s]*?\r?\n)?---(?:\r?\n|(?!\S))/,DIRECTIVE:/[\t ]*%%{[\S\s]*?}%%(?:\r?\n|(?!\S))/,SINGLE_LINE_COMMENT:/[\t ]*%%[^\n\r]*/}})($d||($d={}));({...sd.Terminals,...od.Terminals,...ld.Terminals,...ud.Terminals,...cd.Terminals,...fd.Terminals,...dd.Terminals,...pd.Terminals,...md.Terminals,...hd.Terminals,...yd.Terminals,...gd.Terminals,...Td.Terminals,...vd.Terminals,...$d.Terminals});var Ly={$type:"AbnfAlternation",alternatives:"alternatives"},Dy={$type:"AbnfConcatenation",elements:"elements"},ec={$type:"AbnfElement",primary:"primary",repeat:"repeat"},xy={$type:"AbnfGroup",element:"element"},My={$type:"AbnfNumVal",value:"value"},Gy={$type:"AbnfOptionalGroup",element:"element"},ca={$type:"AbnfPrimary"},tc={$type:"AbnfRule",definition:"definition",name:"name"},Fy={$type:"AbnfRuleName",name:"name"},zy={$type:"AbnfStringLiteral",value:"value"},co={$type:"Accelerator",name:"name",x:"x",y:"y"},rc={$type:"Alignment",direction:"direction",members:"members"},fo={$type:"Anchor",evolution:"evolution",name:"name",visibility:"visibility"},xi={$type:"Annotation",number:"number",text:"text",x:"x",y:"y"},nc={$type:"Annotations",x:"x",y:"y"},Xt={$type:"Architecture",accDescr:"accDescr",accTitle:"accTitle",alignments:"alignments",edges:"edges",groups:"groups",junctions:"junctions",services:"services",title:"title"};function OF(e){return Ne.isInstance(e,Xt.$type)}i(OF,"isArchitecture");var po={$type:"Axis",label:"label",name:"name"},Ko={$type:"Branch",name:"name",order:"order"};function LF(e){return Ne.isInstance(e,Ko.$type)}i(LF,"isBranch");var jy={$type:"Checkout",branch:"branch"},mo={$type:"CherryPicking",id:"id",parent:"parent",tags:"tags"},ac={$type:"ClassDefStatement",className:"className",styleText:"styleText"},Aa={$type:"Commit",id:"id",message:"message",tags:"tags",type:"type"};function DF(e){return Ne.isInstance(e,Aa.$type)}i(DF,"isCommit");var ho={$type:"Common",accDescr:"accDescr",accTitle:"accTitle",title:"title"},Zr={$type:"Component",decorator:"decorator",evolution:"evolution",inertia:"inertia",label:"label",name:"name",visibility:"visibility"},yo={$type:"Curve",entries:"entries",label:"label",name:"name"},cn={$type:"Cynefin",accDescr:"accDescr",accTitle:"accTitle",domains:"domains",title:"title",transitions:"transitions"};function xF(e){return Ne.isInstance(e,cn.$type)}i(xF,"isCynefin");var go={$type:"Deaccelerator",name:"name",x:"x",y:"y"},By={$type:"Decorator",strategy:"strategy"},fa={$type:"Direction",accDescr:"accDescr",accTitle:"accTitle",dir:"dir",statements:"statements",title:"title"},Wo={$type:"DomainBlock",domain:"domain",items:"items"};function MF(e){return Ne.isInstance(e,Wo.$type)}i(MF,"isDomainBlock");var Rd={$type:"DomainItem",label:"label"};function GF(e){return Ne.isInstance(e,Rd.$type)}i(GF,"isDomainItem");var Uy={$type:"EbnfChoice",alternatives:"alternatives"},Ky={$type:"EbnfExceptionPostfix",except:"except"},Wy={$type:"EbnfGroup",element:"element"},Vy={$type:"EbnfNonTerminal",name:"name"},qy={$type:"EbnfOneOrMorePostfix",operator:"operator"},Hy={$type:"EbnfOptional",element:"element"},Yy={$type:"EbnfOptionalPostfix",operator:"operator"},Mi={$type:"EbnfPostfix"},Qr={$type:"EbnfPrimary"},Xy={$type:"EbnfRepetition",element:"element"},ic={$type:"EbnfRule",definition:"definition",name:"name"},Jy={$type:"EbnfSequence",elements:"elements"},Zy={$type:"EbnfSpecial",text:"text"},sc={$type:"EbnfTerm",base:"base",postfixes:"postfixes"},Qy={$type:"EbnfTerminal",value:"value"},eg={$type:"EbnfZeroOrMorePostfix",operator:"operator"},Ht={$type:"Edge",lhsDir:"lhsDir",lhsGroup:"lhsGroup",lhsId:"lhsId",lhsInto:"lhsInto",rhsDir:"rhsDir",rhsGroup:"rhsGroup",rhsId:"rhsId",rhsInto:"rhsInto",title:"title"},da={$type:"EmDataEntity",dataBlockValue:"dataBlockValue",dataType:"dataType",name:"name"},en={$type:"EmFrame"},Gi={$type:"EmGwt",givenStatements:"givenStatements",sourceFrame:"sourceFrame",thenStatements:"thenStatements",whenStatements:"whenStatements"},tg={$type:"EmGwtStatement",entityIdentifier:"entityIdentifier"},oc={$type:"EmModelEntity",name:"name"};function FF(e){return e==="rmo"||e==="readmodel"||e==="ui"||e==="cmd"||e==="command"||e==="evt"||e==="event"||e==="pcr"||e==="processor"}i(FF,"isEmModelEntityType");var vo={$type:"EmNoteEntity",dataBlockValue:"dataBlockValue",dataType:"dataType",sourceFrame:"sourceFrame"},yr={$type:"EmResetFrame",dataInlineValue:"dataInlineValue",dataReference:"dataReference",dataType:"dataType",entityIdentifier:"entityIdentifier",modelEntityType:"modelEntityType",name:"name",sourceFrames:"sourceFrames"};function zF(e){return Ne.isInstance(e,yr.$type)}i(zF,"isEmResetFrame");var Dr={$type:"EmTimeFrame",dataInlineValue:"dataInlineValue",dataReference:"dataReference",dataType:"dataType",entityIdentifier:"entityIdentifier",modelEntityType:"modelEntityType",name:"name",sourceFrames:"sourceFrames"},lc={$type:"Entry",axis:"axis",value:"value"},dr={$type:"EventModel",accDescr:"accDescr",accTitle:"accTitle",dataEntities:"dataEntities",frames:"frames",gwtEntities:"gwtEntities",modelEntities:"modelEntities",noteEntities:"noteEntities",title:"title"},rg={$type:"Evolution",stages:"stages"},To={$type:"EvolutionStage",boundary:"boundary",name:"name",secondName:"secondName"},uc={$type:"Evolve",component:"component",target:"target"},fn={$type:"GitGraph",accDescr:"accDescr",accTitle:"accTitle",statements:"statements",title:"title"};function jF(e){return Ne.isInstance(e,fn.$type)}i(jF,"isGitGraph");var Fi={$type:"Group",icon:"icon",id:"id",in:"in",title:"title"},ts={$type:"Info",accDescr:"accDescr",accTitle:"accTitle",title:"title"};function BF(e){return Ne.isInstance(e,ts.$type)}i(BF,"isInfo");var zi={$type:"Item",classSelector:"classSelector",name:"name"},cc={$type:"Junction",id:"id",in:"in"},ji={$type:"Label",negX:"negX",negY:"negY",offsetX:"offsetX",offsetY:"offsetY"},$o={$type:"Leaf",classSelector:"classSelector",name:"name",value:"value"},tn={$type:"Link",arrow:"arrow",from:"from",fromPort:"fromPort",linkLabel:"linkLabel",to:"to",toPort:"toPort"},Ea={$type:"Merge",branch:"branch",id:"id",tags:"tags",type:"type"};function UF(e){return Ne.isInstance(e,Ea.$type)}i(UF,"isMerge");var Ro={$type:"Note",evolution:"evolution",text:"text",visibility:"visibility"},fc={$type:"Option",name:"name",value:"value"},Ca={$type:"Packet",accDescr:"accDescr",accTitle:"accTitle",blocks:"blocks",title:"title"};function KF(e){return Ne.isInstance(e,Ca.$type)}i(KF,"isPacket");var ba={$type:"PacketBlock",bits:"bits",end:"end",label:"label",start:"start"};function WF(e){return Ne.isInstance(e,ba.$type)}i(WF,"isPacketBlock");var ng={$type:"PegAny",dot:"dot"},ag={$type:"PegGroup",element:"element"},ig={$type:"PegIdentifier",name:"name"},sg={$type:"PegLiteral",value:"value"},og={$type:"PegOrderedChoice",alternatives:"alternatives"},dc={$type:"PegPrefix",operator:"operator",suffix:"suffix"},Bi={$type:"PegPrimary"},pc={$type:"PegRule",definition:"definition",name:"name"},lg={$type:"PegSequence",elements:"elements"},mc={$type:"PegSuffix",operator:"operator",primary:"primary"},dn={$type:"Pie",accDescr:"accDescr",accTitle:"accTitle",sections:"sections",showData:"showData",title:"title"};function VF(e){return Ne.isInstance(e,dn.$type)}i(VF,"isPie");var Vo={$type:"PieSection",label:"label",value:"value"};function qF(e){return Ne.isInstance(e,Vo.$type)}i(qF,"isPieSection");var hc={$type:"Pipeline",components:"components",parent:"parent"},Ao={$type:"PipelineComponent",evolution:"evolution",label:"label",name:"name"},rn={$type:"Radar",accDescr:"accDescr",accTitle:"accTitle",axes:"axes",curves:"curves",options:"options",title:"title"},_a={$type:"Railroad",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function HF(e){return Ne.isInstance(e,_a.$type)}i(HF,"isRailroad");var Sa={$type:"RailroadAbnf",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function YF(e){return Ne.isInstance(e,Sa.$type)}i(YF,"isRailroadAbnf");var ug={$type:"RailroadChoiceExpr",alternatives:"alternatives"},wa={$type:"RailroadEbnf",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function XF(e){return Ne.isInstance(e,wa.$type)}i(XF,"isRailroadEbnf");var pr={$type:"RailroadExpression"},cg={$type:"RailroadNonTerminalExpr",name:"name"},fg={$type:"RailroadOneOrMoreExpr",element:"element"},dg={$type:"RailroadOptionalExpr",element:"element"},Ia={$type:"RailroadPeg",accDescr:"accDescr",accTitle:"accTitle",rules:"rules",title:"title"};function JF(e){return Ne.isInstance(e,Ia.$type)}i(JF,"isRailroadPeg");var yc={$type:"RailroadRule",definition:"definition",name:"name"},pg={$type:"RailroadSequenceExpr",elements:"elements"},mg={$type:"RailroadSpecialExpr",text:"text"},hg={$type:"RailroadTerminalExpr",value:"value"},yg={$type:"RailroadZeroOrMoreExpr",element:"element"},gc={$type:"Section",classSelector:"classSelector",name:"name"},pa={$type:"Service",icon:"icon",iconText:"iconText",id:"id",in:"in",title:"title"},vc={$type:"Size",height:"height",width:"width"},ma={$type:"Statement"},rs={$type:"Transition",from:"from",label:"label",to:"to"};function ZF(e){return Ne.isInstance(e,rs.$type)}i(ZF,"isTransition");var Na={$type:"Treemap",accDescr:"accDescr",accTitle:"accTitle",title:"title",TreemapRows:"TreemapRows"};function QF(e){return Ne.isInstance(e,Na.$type)}i(QF,"isTreemap");var Tc={$type:"TreemapRow",indent:"indent",item:"item"},ha={$type:"TreeNode",classAnnotation:"classAnnotation",descAnnotation:"descAnnotation",iconAnnotation:"iconAnnotation",indent:"indent",name:"name"},Ui={$type:"TreeView",accDescr:"accDescr",accTitle:"accTitle",nodes:"nodes",title:"title"},We={$type:"Wardley",accDescr:"accDescr",accelerators:"accelerators",accTitle:"accTitle",anchors:"anchors",annotation:"annotation",annotations:"annotations",components:"components",deaccelerators:"deaccelerators",evolution:"evolution",evolves:"evolves",links:"links",notes:"notes",pipelines:"pipelines",size:"size",title:"title"};function ez(e){return Ne.isInstance(e,We.$type)}i(ez,"isWardley");var jw=class extends Id{constructor(){super(...arguments),this.types={AbnfAlternation:{name:Ly.$type,properties:{alternatives:{name:Ly.alternatives,defaultValue:[]}},superTypes:[]},AbnfConcatenation:{name:Dy.$type,properties:{elements:{name:Dy.elements,defaultValue:[]}},superTypes:[]},AbnfElement:{name:ec.$type,properties:{primary:{name:ec.primary},repeat:{name:ec.repeat}},superTypes:[]},AbnfGroup:{name:xy.$type,properties:{element:{name:xy.element}},superTypes:[ca.$type]},AbnfNumVal:{name:My.$type,properties:{value:{name:My.value}},superTypes:[ca.$type]},AbnfOptionalGroup:{name:Gy.$type,properties:{element:{name:Gy.element}},superTypes:[ca.$type]},AbnfPrimary:{name:ca.$type,properties:{},superTypes:[]},AbnfRule:{name:tc.$type,properties:{definition:{name:tc.definition},name:{name:tc.name}},superTypes:[]},AbnfRuleName:{name:Fy.$type,properties:{name:{name:Fy.name}},superTypes:[ca.$type]},AbnfStringLiteral:{name:zy.$type,properties:{value:{name:zy.value}},superTypes:[ca.$type]},Accelerator:{name:co.$type,properties:{name:{name:co.name},x:{name:co.x},y:{name:co.y}},superTypes:[]},Alignment:{name:rc.$type,properties:{direction:{name:rc.direction},members:{name:rc.members,defaultValue:[]}},superTypes:[]},Anchor:{name:fo.$type,properties:{evolution:{name:fo.evolution},name:{name:fo.name},visibility:{name:fo.visibility}},superTypes:[]},Annotation:{name:xi.$type,properties:{number:{name:xi.number},text:{name:xi.text},x:{name:xi.x},y:{name:xi.y}},superTypes:[]},Annotations:{name:nc.$type,properties:{x:{name:nc.x},y:{name:nc.y}},superTypes:[]},Architecture:{name:Xt.$type,properties:{accDescr:{name:Xt.accDescr},accTitle:{name:Xt.accTitle},alignments:{name:Xt.alignments,defaultValue:[]},edges:{name:Xt.edges,defaultValue:[]},groups:{name:Xt.groups,defaultValue:[]},junctions:{name:Xt.junctions,defaultValue:[]},services:{name:Xt.services,defaultValue:[]},title:{name:Xt.title}},superTypes:[]},Axis:{name:po.$type,properties:{label:{name:po.label},name:{name:po.name}},superTypes:[]},Branch:{name:Ko.$type,properties:{name:{name:Ko.name},order:{name:Ko.order}},superTypes:[ma.$type]},Checkout:{name:jy.$type,properties:{branch:{name:jy.branch}},superTypes:[ma.$type]},CherryPicking:{name:mo.$type,properties:{id:{name:mo.id},parent:{name:mo.parent},tags:{name:mo.tags,defaultValue:[]}},superTypes:[ma.$type]},ClassDefStatement:{name:ac.$type,properties:{className:{name:ac.className},styleText:{name:ac.styleText}},superTypes:[]},Commit:{name:Aa.$type,properties:{id:{name:Aa.id},message:{name:Aa.message},tags:{name:Aa.tags,defaultValue:[]},type:{name:Aa.type}},superTypes:[ma.$type]},Common:{name:ho.$type,properties:{accDescr:{name:ho.accDescr},accTitle:{name:ho.accTitle},title:{name:ho.title}},superTypes:[]},Component:{name:Zr.$type,properties:{decorator:{name:Zr.decorator},evolution:{name:Zr.evolution},inertia:{name:Zr.inertia,defaultValue:!1},label:{name:Zr.label},name:{name:Zr.name},visibility:{name:Zr.visibility}},superTypes:[]},Curve:{name:yo.$type,properties:{entries:{name:yo.entries,defaultValue:[]},label:{name:yo.label},name:{name:yo.name}},superTypes:[]},Cynefin:{name:cn.$type,properties:{accDescr:{name:cn.accDescr},accTitle:{name:cn.accTitle},domains:{name:cn.domains,defaultValue:[]},title:{name:cn.title},transitions:{name:cn.transitions,defaultValue:[]}},superTypes:[]},Deaccelerator:{name:go.$type,properties:{name:{name:go.name},x:{name:go.x},y:{name:go.y}},superTypes:[]},Decorator:{name:By.$type,properties:{strategy:{name:By.strategy}},superTypes:[]},Direction:{name:fa.$type,properties:{accDescr:{name:fa.accDescr},accTitle:{name:fa.accTitle},dir:{name:fa.dir},statements:{name:fa.statements,defaultValue:[]},title:{name:fa.title}},superTypes:[fn.$type]},DomainBlock:{name:Wo.$type,properties:{domain:{name:Wo.domain},items:{name:Wo.items,defaultValue:[]}},superTypes:[]},DomainItem:{name:Rd.$type,properties:{label:{name:Rd.label}},superTypes:[]},EbnfChoice:{name:Uy.$type,properties:{alternatives:{name:Uy.alternatives,defaultValue:[]}},superTypes:[]},EbnfExceptionPostfix:{name:Ky.$type,properties:{except:{name:Ky.except}},superTypes:[Mi.$type]},EbnfGroup:{name:Wy.$type,properties:{element:{name:Wy.element}},superTypes:[Qr.$type]},EbnfNonTerminal:{name:Vy.$type,properties:{name:{name:Vy.name}},superTypes:[Qr.$type]},EbnfOneOrMorePostfix:{name:qy.$type,properties:{operator:{name:qy.operator}},superTypes:[Mi.$type]},EbnfOptional:{name:Hy.$type,properties:{element:{name:Hy.element}},superTypes:[Qr.$type]},EbnfOptionalPostfix:{name:Yy.$type,properties:{operator:{name:Yy.operator}},superTypes:[Mi.$type]},EbnfPostfix:{name:Mi.$type,properties:{},superTypes:[]},EbnfPrimary:{name:Qr.$type,properties:{},superTypes:[]},EbnfRepetition:{name:Xy.$type,properties:{element:{name:Xy.element}},superTypes:[Qr.$type]},EbnfRule:{name:ic.$type,properties:{definition:{name:ic.definition},name:{name:ic.name}},superTypes:[]},EbnfSequence:{name:Jy.$type,properties:{elements:{name:Jy.elements,defaultValue:[]}},superTypes:[]},EbnfSpecial:{name:Zy.$type,properties:{text:{name:Zy.text}},superTypes:[Qr.$type]},EbnfTerm:{name:sc.$type,properties:{base:{name:sc.base},postfixes:{name:sc.postfixes,defaultValue:[]}},superTypes:[]},EbnfTerminal:{name:Qy.$type,properties:{value:{name:Qy.value}},superTypes:[Qr.$type]},EbnfZeroOrMorePostfix:{name:eg.$type,properties:{operator:{name:eg.operator}},superTypes:[Mi.$type]},Edge:{name:Ht.$type,properties:{lhsDir:{name:Ht.lhsDir},lhsGroup:{name:Ht.lhsGroup,defaultValue:!1},lhsId:{name:Ht.lhsId},lhsInto:{name:Ht.lhsInto,defaultValue:!1},rhsDir:{name:Ht.rhsDir},rhsGroup:{name:Ht.rhsGroup,defaultValue:!1},rhsId:{name:Ht.rhsId},rhsInto:{name:Ht.rhsInto,defaultValue:!1},title:{name:Ht.title}},superTypes:[]},EmDataEntity:{name:da.$type,properties:{dataBlockValue:{name:da.dataBlockValue},dataType:{name:da.dataType},name:{name:da.name}},superTypes:[]},EmFrame:{name:en.$type,properties:{},superTypes:[]},EmGwt:{name:Gi.$type,properties:{givenStatements:{name:Gi.givenStatements,defaultValue:[]},sourceFrame:{name:Gi.sourceFrame,referenceType:en.$type},thenStatements:{name:Gi.thenStatements,defaultValue:[]},whenStatements:{name:Gi.whenStatements,defaultValue:[]}},superTypes:[]},EmGwtStatement:{name:tg.$type,properties:{entityIdentifier:{name:tg.entityIdentifier,referenceType:oc.$type}},superTypes:[]},EmModelEntity:{name:oc.$type,properties:{name:{name:oc.name}},superTypes:[]},EmNoteEntity:{name:vo.$type,properties:{dataBlockValue:{name:vo.dataBlockValue},dataType:{name:vo.dataType},sourceFrame:{name:vo.sourceFrame,referenceType:en.$type}},superTypes:[]},EmResetFrame:{name:yr.$type,properties:{dataInlineValue:{name:yr.dataInlineValue},dataReference:{name:yr.dataReference,referenceType:da.$type},dataType:{name:yr.dataType},entityIdentifier:{name:yr.entityIdentifier},modelEntityType:{name:yr.modelEntityType},name:{name:yr.name},sourceFrames:{name:yr.sourceFrames,defaultValue:[],referenceType:en.$type}},superTypes:[en.$type]},EmTimeFrame:{name:Dr.$type,properties:{dataInlineValue:{name:Dr.dataInlineValue},dataReference:{name:Dr.dataReference,referenceType:da.$type},dataType:{name:Dr.dataType},entityIdentifier:{name:Dr.entityIdentifier},modelEntityType:{name:Dr.modelEntityType},name:{name:Dr.name},sourceFrames:{name:Dr.sourceFrames,defaultValue:[],referenceType:en.$type}},superTypes:[en.$type]},Entry:{name:lc.$type,properties:{axis:{name:lc.axis,referenceType:po.$type},value:{name:lc.value}},superTypes:[]},EventModel:{name:dr.$type,properties:{accDescr:{name:dr.accDescr},accTitle:{name:dr.accTitle},dataEntities:{name:dr.dataEntities,defaultValue:[]},frames:{name:dr.frames,defaultValue:[]},gwtEntities:{name:dr.gwtEntities,defaultValue:[]},modelEntities:{name:dr.modelEntities,defaultValue:[]},noteEntities:{name:dr.noteEntities,defaultValue:[]},title:{name:dr.title}},superTypes:[]},Evolution:{name:rg.$type,properties:{stages:{name:rg.stages,defaultValue:[]}},superTypes:[]},EvolutionStage:{name:To.$type,properties:{boundary:{name:To.boundary},name:{name:To.name},secondName:{name:To.secondName}},superTypes:[]},Evolve:{name:uc.$type,properties:{component:{name:uc.component},target:{name:uc.target}},superTypes:[]},GitGraph:{name:fn.$type,properties:{accDescr:{name:fn.accDescr},accTitle:{name:fn.accTitle},statements:{name:fn.statements,defaultValue:[]},title:{name:fn.title}},superTypes:[]},Group:{name:Fi.$type,properties:{icon:{name:Fi.icon},id:{name:Fi.id},in:{name:Fi.in},title:{name:Fi.title}},superTypes:[]},Info:{name:ts.$type,properties:{accDescr:{name:ts.accDescr},accTitle:{name:ts.accTitle},title:{name:ts.title}},superTypes:[]},Item:{name:zi.$type,properties:{classSelector:{name:zi.classSelector},name:{name:zi.name}},superTypes:[]},Junction:{name:cc.$type,properties:{id:{name:cc.id},in:{name:cc.in}},superTypes:[]},Label:{name:ji.$type,properties:{negX:{name:ji.negX,defaultValue:!1},negY:{name:ji.negY,defaultValue:!1},offsetX:{name:ji.offsetX},offsetY:{name:ji.offsetY}},superTypes:[]},Leaf:{name:$o.$type,properties:{classSelector:{name:$o.classSelector},name:{name:$o.name},value:{name:$o.value}},superTypes:[zi.$type]},Link:{name:tn.$type,properties:{arrow:{name:tn.arrow},from:{name:tn.from},fromPort:{name:tn.fromPort},linkLabel:{name:tn.linkLabel},to:{name:tn.to},toPort:{name:tn.toPort}},superTypes:[]},Merge:{name:Ea.$type,properties:{branch:{name:Ea.branch},id:{name:Ea.id},tags:{name:Ea.tags,defaultValue:[]},type:{name:Ea.type}},superTypes:[ma.$type]},Note:{name:Ro.$type,properties:{evolution:{name:Ro.evolution},text:{name:Ro.text},visibility:{name:Ro.visibility}},superTypes:[]},Option:{name:fc.$type,properties:{name:{name:fc.name},value:{name:fc.value,defaultValue:!1}},superTypes:[]},Packet:{name:Ca.$type,properties:{accDescr:{name:Ca.accDescr},accTitle:{name:Ca.accTitle},blocks:{name:Ca.blocks,defaultValue:[]},title:{name:Ca.title}},superTypes:[]},PacketBlock:{name:ba.$type,properties:{bits:{name:ba.bits},end:{name:ba.end},label:{name:ba.label},start:{name:ba.start}},superTypes:[]},PegAny:{name:ng.$type,properties:{dot:{name:ng.dot}},superTypes:[Bi.$type]},PegGroup:{name:ag.$type,properties:{element:{name:ag.element}},superTypes:[Bi.$type]},PegIdentifier:{name:ig.$type,properties:{name:{name:ig.name}},superTypes:[Bi.$type]},PegLiteral:{name:sg.$type,properties:{value:{name:sg.value}},superTypes:[Bi.$type]},PegOrderedChoice:{name:og.$type,properties:{alternatives:{name:og.alternatives,defaultValue:[]}},superTypes:[]},PegPrefix:{name:dc.$type,properties:{operator:{name:dc.operator},suffix:{name:dc.suffix}},superTypes:[]},PegPrimary:{name:Bi.$type,properties:{},superTypes:[]},PegRule:{name:pc.$type,properties:{definition:{name:pc.definition},name:{name:pc.name}},superTypes:[]},PegSequence:{name:lg.$type,properties:{elements:{name:lg.elements,defaultValue:[]}},superTypes:[]},PegSuffix:{name:mc.$type,properties:{operator:{name:mc.operator},primary:{name:mc.primary}},superTypes:[]},Pie:{name:dn.$type,properties:{accDescr:{name:dn.accDescr},accTitle:{name:dn.accTitle},sections:{name:dn.sections,defaultValue:[]},showData:{name:dn.showData,defaultValue:!1},title:{name:dn.title}},superTypes:[]},PieSection:{name:Vo.$type,properties:{label:{name:Vo.label},value:{name:Vo.value}},superTypes:[]},Pipeline:{name:hc.$type,properties:{components:{name:hc.components,defaultValue:[]},parent:{name:hc.parent}},superTypes:[]},PipelineComponent:{name:Ao.$type,properties:{evolution:{name:Ao.evolution},label:{name:Ao.label},name:{name:Ao.name}},superTypes:[]},Radar:{name:rn.$type,properties:{accDescr:{name:rn.accDescr},accTitle:{name:rn.accTitle},axes:{name:rn.axes,defaultValue:[]},curves:{name:rn.curves,defaultValue:[]},options:{name:rn.options,defaultValue:[]},title:{name:rn.title}},superTypes:[]},Railroad:{name:_a.$type,properties:{accDescr:{name:_a.accDescr},accTitle:{name:_a.accTitle},rules:{name:_a.rules,defaultValue:[]},title:{name:_a.title}},superTypes:[]},RailroadAbnf:{name:Sa.$type,properties:{accDescr:{name:Sa.accDescr},accTitle:{name:Sa.accTitle},rules:{name:Sa.rules,defaultValue:[]},title:{name:Sa.title}},superTypes:[]},RailroadChoiceExpr:{name:ug.$type,properties:{alternatives:{name:ug.alternatives,defaultValue:[]}},superTypes:[pr.$type]},RailroadEbnf:{name:wa.$type,properties:{accDescr:{name:wa.accDescr},accTitle:{name:wa.accTitle},rules:{name:wa.rules,defaultValue:[]},title:{name:wa.title}},superTypes:[]},RailroadExpression:{name:pr.$type,properties:{},superTypes:[]},RailroadNonTerminalExpr:{name:cg.$type,properties:{name:{name:cg.name}},superTypes:[pr.$type]},RailroadOneOrMoreExpr:{name:fg.$type,properties:{element:{name:fg.element}},superTypes:[pr.$type]},RailroadOptionalExpr:{name:dg.$type,properties:{element:{name:dg.element}},superTypes:[pr.$type]},RailroadPeg:{name:Ia.$type,properties:{accDescr:{name:Ia.accDescr},accTitle:{name:Ia.accTitle},rules:{name:Ia.rules,defaultValue:[]},title:{name:Ia.title}},superTypes:[]},RailroadRule:{name:yc.$type,properties:{definition:{name:yc.definition},name:{name:yc.name}},superTypes:[]},RailroadSequenceExpr:{name:pg.$type,properties:{elements:{name:pg.elements,defaultValue:[]}},superTypes:[pr.$type]},RailroadSpecialExpr:{name:mg.$type,properties:{text:{name:mg.text}},superTypes:[pr.$type]},RailroadTerminalExpr:{name:hg.$type,properties:{value:{name:hg.value}},superTypes:[pr.$type]},RailroadZeroOrMoreExpr:{name:yg.$type,properties:{element:{name:yg.element}},superTypes:[pr.$type]},Section:{name:gc.$type,properties:{classSelector:{name:gc.classSelector},name:{name:gc.name}},superTypes:[zi.$type]},Service:{name:pa.$type,properties:{icon:{name:pa.icon},iconText:{name:pa.iconText},id:{name:pa.id},in:{name:pa.in},title:{name:pa.title}},superTypes:[]},Size:{name:vc.$type,properties:{height:{name:vc.height},width:{name:vc.width}},superTypes:[]},Statement:{name:ma.$type,properties:{},superTypes:[]},Transition:{name:rs.$type,properties:{from:{name:rs.from},label:{name:rs.label},to:{name:rs.to}},superTypes:[]},TreeNode:{name:ha.$type,properties:{classAnnotation:{name:ha.classAnnotation},descAnnotation:{name:ha.descAnnotation},iconAnnotation:{name:ha.iconAnnotation},indent:{name:ha.indent},name:{name:ha.name}},superTypes:[]},TreeView:{name:Ui.$type,properties:{accDescr:{name:Ui.accDescr},accTitle:{name:Ui.accTitle},nodes:{name:Ui.nodes,defaultValue:[]},title:{name:Ui.title}},superTypes:[]},Treemap:{name:Na.$type,properties:{accDescr:{name:Na.accDescr},accTitle:{name:Na.accTitle},title:{name:Na.title},TreemapRows:{name:Na.TreemapRows,defaultValue:[]}},superTypes:[]},TreemapRow:{name:Tc.$type,properties:{indent:{name:Tc.indent},item:{name:Tc.item}},superTypes:[]},Wardley:{name:We.$type,properties:{accDescr:{name:We.accDescr},accelerators:{name:We.accelerators,defaultValue:[]},accTitle:{name:We.accTitle},anchors:{name:We.anchors,defaultValue:[]},annotation:{name:We.annotation,defaultValue:[]},annotations:{name:We.annotations,defaultValue:[]},components:{name:We.components,defaultValue:[]},deaccelerators:{name:We.deaccelerators,defaultValue:[]},evolution:{name:We.evolution},evolves:{name:We.evolves,defaultValue:[]},links:{name:We.links,defaultValue:[]},notes:{name:We.notes,defaultValue:[]},pipelines:{name:We.pipelines,defaultValue:[]},size:{name:We.size},title:{name:We.title}},superTypes:[]}}}static{i(this,"MermaidAstReflection")}},Ne=new jw,gg,tz=i(()=>gg??(gg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"ArchitectureGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Architecture","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"architecture-beta"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"groups","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"services","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"junctions","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Assignment","feature":"edges","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"alignments","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"LeftPort","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"lhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"RightPort","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"rhsDir","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Keyword","value":":"}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Arrow","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]},{"$type":"Assignment","feature":"lhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"--"},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]}},{"$type":"Keyword","value":"-"}]}]},{"$type":"Assignment","feature":"rhsInto","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"Group","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"group"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Service","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"service"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"iconText","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]}},{"$type":"Assignment","feature":"icon","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]}}],"cardinality":"?"},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]},"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Junction","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"junction"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"in"},{"$type":"Assignment","feature":"in","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Edge","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"lhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"lhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Assignment","feature":"rhsId","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"rhsGroup","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Alignment","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"align"},{"$type":"Assignment","feature":"direction","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"row"},{"$type":"Keyword","value":"column"}]}},{"$type":"Assignment","feature":"members","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Assignment","feature":"members","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]},"cardinality":"+"},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"ARROW_DIRECTION","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"L"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"R"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"T"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"B"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_GROUP","definition":{"$type":"RegexToken","regex":"/\\\\{group\\\\}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW_INTO","definition":{"$type":"RegexToken","regex":"/<|>/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@19"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@20"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","name":"ARCH_ICON","definition":{"$type":"RegexToken","regex":"/\\\\([\\\\w-:]+\\\\)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARCH_TITLE","definition":{"$type":"RegexToken","regex":"/\\\\[(?:\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'|[\\\\w ]+)\\\\]/","parenthesized":false},"fragment":false,"hidden":false}],"interfaces":[],"types":[]}`)),"ArchitectureGrammarGrammar"),vg,rz=i(()=>vg??(vg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"CynefinGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Cynefin","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"cynefin-beta"},{"$type":"Keyword","value":"cynefin-beta:"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"Assignment","feature":"domains","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"transitions","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"DomainBlock","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"domain","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Assignment","feature":"items","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"DomainItem","definition":{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Transition","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"from","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":"-->"},{"$type":"Assignment","feature":"to","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"DOMAIN_NAME","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"complex"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"complicated"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"clear"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"chaotic"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"confusion"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@11"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@12"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"CynefinGrammarGrammar"),Tg,nz=i(()=>Tg??(Tg=Ue('{"$type":"Grammar","isDeclared":true,"name":"EventModeling","interfaces":[{"$type":"Interface","name":"Common","attributes":[{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"rules":[{"$type":"ParserRule","entry":true,"name":"EventModel","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"eventmodeling"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]}},{"$type":"Assignment","feature":"modelEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"frames","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"dataEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"noteEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"gwtEntities","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmModelEntityType","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"rmo"},{"$type":"Keyword","value":"readmodel"},{"$type":"Keyword","value":"ui"},{"$type":"Keyword","value":"cmd"},{"$type":"Keyword","value":"command"},{"$type":"Keyword","value":"evt"},{"$type":"Keyword","value":"event"},{"$type":"Keyword","value":"pcr"},{"$type":"Keyword","value":"processor"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmDataType","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"json"},{"$type":"Keyword","value":"jsobj"},{"$type":"Keyword","value":"figma"},{"$type":"Keyword","value":"salt"},{"$type":"Keyword","value":"uri"},{"$type":"Keyword","value":"md"},{"$type":"Keyword","value":"html"},{"$type":"Keyword","value":"text"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"EmDataInline","definition":{"$type":"Group","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"`"},{"$type":"Assignment","feature":"dataType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Keyword","value":"`"}],"cardinality":"?"},{"$type":"Assignment","feature":"dataInlineValue","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"EmDataBlock","definition":{"$type":"Group","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"`"},{"$type":"Assignment","feature":"dataType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Keyword","value":"`"}],"cardinality":"?"},{"$type":"Assignment","feature":"dataBlockValue","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"QualifiedName","dataType":"string","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"Group","elements":[{"$type":"Keyword","value":"."},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmTimeFrame","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"tf"},{"$type":"Keyword","value":"timeframe"}]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Assignment","feature":"modelEntityType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"entityIdentifier","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"->>"},{"$type":"Assignment","feature":"sourceFrames","operator":"+=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}}],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"[["},{"$type":"Assignment","feature":"dataReference","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@10"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":"]]"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmResetFrame","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"rf"},{"$type":"Keyword","value":"resetframe"}]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Assignment","feature":"modelEntityType","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"entityIdentifier","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"->>"},{"$type":"Assignment","feature":"sourceFrames","operator":"+=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}}],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"[["},{"$type":"Assignment","feature":"dataReference","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@10"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":"]]"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmFrame","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmModelEntity","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"entity"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmDataEntity","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"data"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmNoteEntity","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"note"},{"$type":"Assignment","feature":"sourceFrame","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmGwt","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"gwt"},{"$type":"Assignment","feature":"sourceFrame","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@8"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":"given"},{"$type":"Assignment","feature":"givenStatements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"+"},{"$type":"Group","elements":[{"$type":"Keyword","value":"when"},{"$type":"Assignment","feature":"whenStatements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"+"}],"cardinality":"?"},{"$type":"Keyword","value":"then"},{"$type":"Assignment","feature":"thenStatements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"+"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EmGwtStatement","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]},{"$type":"Assignment","feature":"entityIdentifier","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@9"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EM_EID","dataType":"string","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EM_FI","dataType":"string","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"EM_ID","definition":{"$type":"RegexToken","regex":"/[_a-zA-Z][\\\\w_]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_FID","definition":{"$type":"RegexToken","regex":"/\\\\d{1,3}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_DATA_INLINE","definition":{"$type":"RegexToken","regex":"/\\\\{(.*)\\\\}|\\"(.*)\\"|\'(.*)\'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_DATA_BLOCK","definition":{"$type":"RegexToken","regex":"/\\\\{[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?\\\\}(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EM_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"EM_WS","definition":{"$type":"RegexToken","regex":"/\\\\s+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_ML_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EM_SL_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\/[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"imports":[],"types":[]}')),"EventModelingGrammar"),$g,az=i(()=>$g??($g=Ue(`{"$type":"Grammar","isDeclared":true,"name":"GitGraphGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"GitGraph","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"Keyword","value":":"}]},{"$type":"Keyword","value":"gitGraph:"},{"$type":"Group","elements":[{"$type":"Keyword","value":"gitGraph"},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]},{"$type":"Keyword","value":":"}]}]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]},{"$type":"Assignment","feature":"statements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Direction","definition":{"$type":"Assignment","feature":"dir","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"LR"},{"$type":"Keyword","value":"TB"},{"$type":"Keyword","value":"BT"}]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Commit","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"commit"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"msg:","cardinality":"?"},{"$type":"Assignment","feature":"message","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Branch","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"branch"},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"order:"},{"$type":"Assignment","feature":"order","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Merge","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"merge"},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]}},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"type:"},{"$type":"Assignment","feature":"type","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"NORMAL"},{"$type":"Keyword","value":"REVERSE"},{"$type":"Keyword","value":"HIGHLIGHT"}]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Checkout","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"checkout"},{"$type":"Keyword","value":"switch"}]},{"$type":"Assignment","feature":"branch","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"CherryPicking","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"cherry-pick"},{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Keyword","value":"id:"},{"$type":"Assignment","feature":"id","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"tag:"},{"$type":"Assignment","feature":"tags","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"parent:"},{"$type":"Assignment","feature":"parent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@14"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@15"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","name":"REFERENCE","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\\\w([-\\\\./\\\\w]*[-\\\\w])?/","parenthesized":false},"fragment":false,"hidden":false}],"interfaces":[],"types":[]}`)),"GitGraphGrammarGrammar"),Rg,iz=i(()=>Rg??(Rg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"InfoGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Info","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"info"},{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"*"},{"$type":"Group","elements":[{"$type":"Keyword","value":"showInfo"},{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"*"}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[],"cardinality":"?"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@7"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@8"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"InfoGrammarGrammar"),Ag,sz=i(()=>Ag??(Ag=Ue(`{"$type":"Grammar","isDeclared":true,"name":"PacketGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Packet","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"packet"},{"$type":"Keyword","value":"packet-beta"}]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]},{"$type":"Assignment","feature":"blocks","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PacketBlock","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Assignment","feature":"start","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"end","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}],"cardinality":"?"}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"+"},{"$type":"Assignment","feature":"bits","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}}]}]},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@8"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@9"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"PacketGrammarGrammar"),Eg,oz=i(()=>Eg??(Eg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"PieGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Pie","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"*"},{"$type":"Keyword","value":"pie"},{"$type":"Assignment","feature":"showData","operator":"?=","terminal":{"$type":"Keyword","value":"showData"},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"Assignment","feature":"sections","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PieSection","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":":"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"FLOAT_PIE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/-?[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT_PIE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/-?(0|[1-9][0-9]*)(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER_PIE","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@2"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@3"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@11"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@12"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"PieGrammarGrammar"),Cg,lz=i(()=>Cg??(Cg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RadarGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Radar","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"radar-beta"},{"$type":"Keyword","value":"radar-beta:"},{"$type":"Group","elements":[{"$type":"Keyword","value":"radar-beta"},{"$type":"Keyword","value":":"}]}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]},{"$type":"Group","elements":[{"$type":"Keyword","value":"axis"},{"$type":"Assignment","feature":"axes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"axes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"Keyword","value":"curve"},{"$type":"Assignment","feature":"curves","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"curves","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}}],"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"options","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"options","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}],"cardinality":"*"}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Label","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"Axis","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Curve","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[],"cardinality":"?"},{"$type":"Keyword","value":"{"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]},{"$type":"Keyword","value":"}"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Entries","definition":{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"}]},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"},{"$type":"Assignment","feature":"entries","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}}],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"*"}]}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"DetailedEntry","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"axis","operator":"=","terminal":{"$type":"CrossReference","type":{"$ref":"#/rules@2"},"terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},"deprecatedSyntax":false,"isMulti":false}},{"$type":"Keyword","value":":","cardinality":"?"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"NumberEntry","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Option","definition":{"$type":"Alternatives","elements":[{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"showLegend"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"ticks"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"max"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"min"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Keyword","value":"graticule"}},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]}}]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"GRATICULE","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"circle"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"polygon"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@15"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@16"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[{"$type":"Interface","name":"Entry","attributes":[{"$type":"TypeAttribute","name":"axis","isOptional":true,"type":{"$type":"ReferenceType","referenceType":{"$type":"SimpleType","typeRef":{"$ref":"#/rules@2"}},"isMulti":false}},{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"number"},"isOptional":false}],"superTypes":[]}],"types":[]}`)),"RadarGrammarGrammar"),bg,uz=i(()=>bg??(bg=Ue('{"$type":"Grammar","isDeclared":true,"name":"RailroadAbnfGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_RULENAME","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Za-z][A-Za-z0-9-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_NUMVAL","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/%[xXdDbB][0-9A-Fa-f]+(?:-[0-9A-Fa-f]+|\\\\.[0-9A-Fa-f]+)*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_REPEAT","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[0-9]*\\\\*[0-9]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ABNF_EXACT_REPEAT","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[0-9]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ABNF_COMMENT","definition":{"$type":"RegexToken","regex":"/;[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"RailroadAbnf","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-abnf-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Keyword","value":"="},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfAlternation","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"/"},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfConcatenation","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},"cardinality":"+"},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfElement","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"repeat","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"repeat","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}],"cardinality":"?"},{"$type":"Assignment","feature":"primary","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfPrimary","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfStringLiteral","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfNumVal","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfRuleName","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfGroup","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"AbnfOptionalGroup","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"RailroadAbnf","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfAlternation","attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@3"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfConcatenation","attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@4"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfElement","attributes":[{"$type":"TypeAttribute","name":"repeat","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"primary","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"AbnfPrimary","attributes":[],"superTypes":[]},{"$type":"Interface","name":"AbnfStringLiteral","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"AbnfNumVal","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"AbnfRuleName","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"AbnfGroup","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"AbnfOptionalGroup","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]}],"imports":[],"types":[]}')),"RailroadAbnfGrammarGrammar"),_g,cz=i(()=>_g??(_g=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RailroadEbnfGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EBNF_ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Z_a-z][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EBNF_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"EBNF_SPECIAL_SEQUENCE","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\\\?(?=[^?;]*[^?\\\\s;][^?;]*\\\\?)[^?;]*\\\\?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_BLOCK_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"EBNF_ISO_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\(\\\\*[\\\\s\\\\S]*?\\\\*\\\\)/","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"RailroadEbnf","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-ebnf-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Keyword","value":"="},{"$type":"Keyword","value":"::="}]},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfChoice","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"|"},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfSequence","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":",","cardinality":"?"},{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfTerm","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"base","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"Assignment","feature":"postfixes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]},"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfPrimary","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfTerminal","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfNonTerminal","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfSpecial","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfGroup","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfOptional","returnType":{"$ref":"#/interfaces@11"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfRepetition","returnType":{"$ref":"#/interfaces@12"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"{"},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Keyword","value":"}"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfPostfix","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@25"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@26"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@27"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@28"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfOptionalPostfix","returnType":{"$ref":"#/interfaces@13"},"definition":{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"?"}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfZeroOrMorePostfix","returnType":{"$ref":"#/interfaces@14"},"definition":{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"*"}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfOneOrMorePostfix","returnType":{"$ref":"#/interfaces@15"},"definition":{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"+"}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EbnfExceptionPostfix","returnType":{"$ref":"#/interfaces@16"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"-"},{"$type":"Assignment","feature":"except","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"RailroadEbnf","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfChoice","attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@3"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfSequence","attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@4"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfTerm","attributes":[{"$type":"TypeAttribute","name":"base","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false},{"$type":"TypeAttribute","name":"postfixes","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@6"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"EbnfPrimary","attributes":[],"superTypes":[]},{"$type":"Interface","name":"EbnfPostfix","attributes":[],"superTypes":[]},{"$type":"Interface","name":"EbnfTerminal","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfNonTerminal","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfSpecial","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"text","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfGroup","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"EbnfOptional","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"EbnfRepetition","superTypes":[{"$ref":"#/interfaces@5"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"EbnfOptionalPostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"operator","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfZeroOrMorePostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"operator","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfOneOrMorePostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"operator","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"EbnfExceptionPostfix","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"except","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false}]}],"imports":[],"types":[]}`)),"RailroadEbnfGrammarGrammar"),Sg,fz=i(()=>Sg??(Sg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RailroadGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"RR_ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Z_a-z][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"RR_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"RR_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"RR_BLOCK_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"Railroad","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Keyword","value":"="},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadExpression","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadSequenceExpr","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"sequence"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"*"},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadChoiceExpr","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"choice"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}}],"cardinality":"*"},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadOptionalExpr","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"optional"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadOneOrMoreExpr","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"oneOrMore"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadZeroOrMoreExpr","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"zeroOrMore"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadTerminalExpr","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"terminal"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadNonTerminalExpr","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"nonterminal"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"RailroadSpecialExpr","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"special"},{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"Railroad","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"RailroadRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"RailroadExpression","attributes":[],"superTypes":[]},{"$type":"Interface","name":"RailroadSequenceExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}}},"isOptional":false}]},{"$type":"Interface","name":"RailroadChoiceExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}}},"isOptional":false}]},{"$type":"Interface","name":"RailroadOptionalExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"RailroadOneOrMoreExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"RailroadZeroOrMoreExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"RailroadTerminalExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"RailroadNonTerminalExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"RailroadSpecialExpr","superTypes":[{"$ref":"#/interfaces@2"}],"attributes":[{"$type":"TypeAttribute","name":"text","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]}],"imports":[],"types":[]}`)),"RailroadGrammarGrammar"),wg,dz=i(()=>wg??(wg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"RailroadPegGrammar","rules":[{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"PEG_ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[A-Z_a-z][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"PEG_STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t \\\\r\\\\n]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"PEG_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/#[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false},{"$type":"ParserRule","entry":true,"name":"RailroadPeg","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"railroad-peg-beta"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"*"},{"$type":"Assignment","feature":"rules","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegRule","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Keyword","value":"<-"},{"$type":"Assignment","feature":"definition","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":";"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegOrderedChoice","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"/"},{"$type":"Assignment","feature":"alternatives","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegSequence","returnType":{"$ref":"#/interfaces@3"},"definition":{"$type":"Assignment","feature":"elements","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"+"},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegPrefix","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"&"}},{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"!"}}],"cardinality":"?"},{"$type":"Assignment","feature":"suffix","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegSuffix","returnType":{"$ref":"#/interfaces@5"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"primary","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"?"}},{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"*"}},{"$type":"Assignment","feature":"operator","operator":"=","terminal":{"$type":"Keyword","value":"+"}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegPrimary","returnType":{"$ref":"#/interfaces@6"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegLiteral","returnType":{"$ref":"#/interfaces@7"},"definition":{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegIdentifier","returnType":{"$ref":"#/interfaces@8"},"definition":{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegGroup","returnType":{"$ref":"#/interfaces@9"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"element","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PegAny","returnType":{"$ref":"#/interfaces@10"},"definition":{"$type":"Assignment","feature":"dot","operator":"=","terminal":{"$type":"Keyword","value":"."}},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"RailroadPeg","attributes":[{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"rules","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@1"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegRule","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"definition","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegOrderedChoice","attributes":[{"$type":"TypeAttribute","name":"alternatives","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@3"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegSequence","attributes":[{"$type":"TypeAttribute","name":"elements","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@4"}}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegPrefix","attributes":[{"$type":"TypeAttribute","name":"operator","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"suffix","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@5"}},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"PegSuffix","attributes":[{"$type":"TypeAttribute","name":"primary","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@6"}},"isOptional":false},{"$type":"TypeAttribute","name":"operator","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]},{"$type":"Interface","name":"PegPrimary","attributes":[],"superTypes":[]},{"$type":"Interface","name":"PegLiteral","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"PegIdentifier","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]},{"$type":"Interface","name":"PegGroup","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"element","type":{"$type":"SimpleType","typeRef":{"$ref":"#/interfaces@2"}},"isOptional":false}]},{"$type":"Interface","name":"PegAny","superTypes":[{"$ref":"#/interfaces@6"}],"attributes":[{"$type":"TypeAttribute","name":"dot","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}]}],"imports":[],"types":[]}`)),"RailroadPegGrammarGrammar"),Ig,pz=i(()=>Ig??(Ig=Ue(`{"$type":"Grammar","isDeclared":true,"name":"TreemapGrammar","rules":[{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","entry":true,"name":"Treemap","returnType":{"$ref":"#/interfaces@4"},"definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]},{"$type":"Assignment","feature":"TreemapRows","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"TREEMAP_KEYWORD","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"treemap-beta"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"treemap"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"CLASS_DEF","definition":{"$type":"RegexToken","regex":"/classDef\\\\s+([a-zA-Z_][a-zA-Z0-9_]+)(?:\\\\s+([^;\\\\r\\\\n]*))?(?:;)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STYLE_SEPARATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":":::"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"SEPARATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":":"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"COMMA","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":","},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INDENTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]{1,}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WS","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ML_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\%\\\\%[^\\\\n]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"NL","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false},{"$type":"ParserRule","name":"TreemapRow","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"indent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"item","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"ClassDef","dataType":"string","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Item","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Section","returnType":{"$ref":"#/interfaces@1"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},{"$type":"Assignment","feature":"classSelector","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Leaf","returnType":{"$ref":"#/interfaces@2"},"definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[],"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[],"cardinality":"?"},{"$type":"Assignment","feature":"value","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},{"$type":"Assignment","feature":"classSelector","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"ID2","definition":{"$type":"RegexToken","regex":"/[a-zA-Z_][a-zA-Z0-9_]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER2","definition":{"$type":"RegexToken","regex":"/[0-9_\\\\.\\\\,]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"MyNumber","dataType":"number","definition":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"STRING2","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|'[^']*'/","parenthesized":false},"fragment":false,"hidden":false}],"interfaces":[{"$type":"Interface","name":"Item","attributes":[{"$type":"TypeAttribute","name":"name","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"classSelector","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]},{"$type":"Interface","name":"Section","superTypes":[{"$ref":"#/interfaces@0"}],"attributes":[]},{"$type":"Interface","name":"Leaf","superTypes":[{"$ref":"#/interfaces@0"}],"attributes":[{"$type":"TypeAttribute","name":"value","type":{"$type":"SimpleType","primitiveType":"number"},"isOptional":false}]},{"$type":"Interface","name":"ClassDefStatement","attributes":[{"$type":"TypeAttribute","name":"className","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false},{"$type":"TypeAttribute","name":"styleText","type":{"$type":"SimpleType","primitiveType":"string"},"isOptional":false}],"superTypes":[]},{"$type":"Interface","name":"Treemap","attributes":[{"$type":"TypeAttribute","name":"TreemapRows","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/rules@15"}}},"isOptional":false},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"imports":[],"types":[],"$comment":"/**\\n * Treemap grammar for Langium\\n * Converted from mindmap grammar\\n *\\n * The ML_COMMENT and NL hidden terminals handle whitespace, comments, and newlines\\n * before the treemap keyword, allowing for empty lines and comments before the\\n * treemap declaration.\\n */"}`)),"TreemapGrammarGrammar"),Ng,mz=i(()=>Ng??(Ng=Ue(`{"$type":"Grammar","isDeclared":true,"name":"TreeViewGrammar","rules":[{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","entry":true,"name":"TreeView","returnType":{"$ref":"#/interfaces@0"},"definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"treeView-beta"},{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[],"cardinality":"?"},{"$type":"Assignment","feature":"nodes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]},"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@0"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"CLASS_ANNOTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+:::[ \\\\t]*[A-Za-z_][\\\\w-]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ICON_ANNOTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+icon\\\\([\\\\w-]*(?::[\\\\w-]+)?\\\\)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"DESC_ANNOTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+##[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INDENTATION","definition":{"$type":"RegexToken","regex":"/[ \\\\t]{1,}/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"QUOTED_NAME","definition":{"$type":"RegexToken","regex":"/\\"[^\\"]*\\"|'[^']*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WS","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"ML_COMMENT","definition":{"$type":"RegexToken","regex":"/\\\\%\\\\%[^\\\\n]*/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"NL","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","name":"BARE_NAME","definition":{"$type":"RegexToken","regex":"/(?!:::|icon\\\\(|##)[^ \\\\t\\\\n\\\\r\\"'](?:(?![ \\\\t]+:::[ \\\\t]*[A-Za-z_]|[ \\\\t]+icon\\\\(|[ \\\\t]+##)[^\\\\n\\\\r])*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"ParserRule","name":"TreeNode","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"indent","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}}]},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"classAnnotation","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"iconAnnotation","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"descAnnotation","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]}}],"cardinality":"*"}]},"entry":false,"fragment":false,"parameters":[]}],"interfaces":[{"$type":"Interface","name":"TreeView","attributes":[{"$type":"TypeAttribute","name":"nodes","type":{"$type":"ArrayType","elementType":{"$type":"SimpleType","typeRef":{"$ref":"#/rules@14"}}},"isOptional":false},{"$type":"TypeAttribute","name":"title","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accTitle","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}},{"$type":"TypeAttribute","name":"accDescr","isOptional":true,"type":{"$type":"SimpleType","primitiveType":"string"}}],"superTypes":[]}],"imports":[],"types":[],"$comment":"/**\\n * TreeView grammar for Langium\\n *\\n * Supports both quoted labels (\\"my file\\") and bare labels (index.js).\\n * Annotations (:::class, icon(), ## description) are parsed directly into\\n * AST fields by the grammar. Value conversion for stripping quotes, extracting\\n * class names, icon names, and description text happens in valueConverter.ts.\\n *\\n * The ML_COMMENT and NL hidden terminals handle whitespace, comments, and newlines\\n * before the treeView keyword, allowing for empty lines and comments before the\\n * treeView declaration.\\n */"}`)),"TreeViewGrammarGrammar"),Pg,hz=i(()=>Pg??(Pg=Ue(`{"$type":"Grammar","isDeclared":true,"name":"WardleyGrammar","imports":[],"rules":[{"$type":"ParserRule","entry":true,"name":"Wardley","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[],"cardinality":"*"},{"$type":"RuleCall","rule":{"$ref":"#/rules@25"},"arguments":[]},{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@42"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@1"},"arguments":[]}],"cardinality":"*"}]},"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"Statement","definition":{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"size","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@2"},"arguments":[]}},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@3"},"arguments":[]}},{"$type":"Assignment","feature":"anchors","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@5"},"arguments":[]}},{"$type":"Assignment","feature":"components","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@6"},"arguments":[]}},{"$type":"Assignment","feature":"links","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@9"},"arguments":[]}},{"$type":"Assignment","feature":"evolves","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@10"},"arguments":[]}},{"$type":"Assignment","feature":"pipelines","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@11"},"arguments":[]}},{"$type":"Assignment","feature":"notes","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@13"},"arguments":[]}},{"$type":"Assignment","feature":"annotations","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@14"},"arguments":[]}},{"$type":"Assignment","feature":"annotation","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@15"},"arguments":[]}},{"$type":"Assignment","feature":"accelerators","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@17"},"arguments":[]}},{"$type":"Assignment","feature":"deaccelerators","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@18"},"arguments":[]}}]},"entry":false,"parameters":[]},{"$type":"ParserRule","name":"Size","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@26"},"arguments":[]},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"width","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"height","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Evolution","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@27"},"arguments":[]},{"$type":"Assignment","feature":"stages","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]},{"$type":"Assignment","feature":"stages","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@4"},"arguments":[]}}],"cardinality":"+"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"EvolutionStage","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"@"},{"$type":"Assignment","feature":"boundary","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}}],"cardinality":"?"},{"$type":"Group","elements":[{"$type":"Keyword","value":"/"},{"$type":"Assignment","feature":"secondName","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}}],"cardinality":"?"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Anchor","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@28"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"visibility","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Component","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"visibility","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"decorator","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@8"},"arguments":[]},"cardinality":"?"},{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"inertia","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@31"},"arguments":[]}},{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"inertia","operator":"?=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@31"},"arguments":[]}},{"$type":"Keyword","value":")"}]}],"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Label","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@30"},"arguments":[]},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"negX","operator":"?=","terminal":{"$type":"Keyword","value":"-"},"cardinality":"?"},{"$type":"Assignment","feature":"offsetX","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"negY","operator":"?=","terminal":{"$type":"Keyword","value":"-"},"cardinality":"?"},{"$type":"Assignment","feature":"offsetY","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":"]"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Decorator","definition":{"$type":"Group","elements":[{"$type":"Keyword","value":"("},{"$type":"Assignment","feature":"strategy","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@24"},"arguments":[]}},{"$type":"Keyword","value":")"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Link","definition":{"$type":"Group","elements":[{"$type":"Assignment","feature":"from","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Assignment","feature":"fromPort","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"arrow","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@22"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@20"},"arguments":[]}]},"cardinality":"?"},{"$type":"Assignment","feature":"to","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Assignment","feature":"toPort","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@21"},"arguments":[]},"cardinality":"?"},{"$type":"Assignment","feature":"linkLabel","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@23"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Evolve","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@32"},"arguments":[]},{"$type":"Assignment","feature":"component","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Assignment","feature":"target","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Pipeline","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@33"},"arguments":[]},{"$type":"Assignment","feature":"parent","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"{"},{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[],"cardinality":"+"},{"$type":"Assignment","feature":"components","operator":"+=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@12"},"arguments":[]},"cardinality":"+"},{"$type":"Keyword","value":"}"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"PipelineComponent","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@29"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"Assignment","feature":"label","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@7"},"arguments":[]},"cardinality":"?"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Note","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@34"},"arguments":[]},{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"visibility","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"evolution","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Annotations","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@35"},"arguments":[]},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Annotation","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@36"},"arguments":[]},{"$type":"Assignment","feature":"number","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@16"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"Assignment","feature":"text","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]}},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"CoordinateValue","dataType":"number","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@48"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Accelerator","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@37"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","name":"Deaccelerator","definition":{"$type":"Group","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@38"},"arguments":[]},{"$type":"Assignment","feature":"name","operator":"=","terminal":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@50"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@51"},"arguments":[]},{"$type":"RuleCall","rule":{"$ref":"#/rules@39"},"arguments":[]}]}},{"$type":"Keyword","value":"["},{"$type":"Assignment","feature":"x","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":","},{"$type":"Assignment","feature":"y","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@19"},"arguments":[]}},{"$type":"Keyword","value":"]"},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"TerminalRule","name":"WARDLEY_NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ARROW","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"->"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"LINK_PORT","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"+<>"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"+>"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"+<"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"LINK_ARROW","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"-->"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"-.->"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":">"},"parenthesized":false}],"parenthesized":false},{"$type":"RegexToken","regex":"/\\\\+'[^']*'<>/","parenthesized":false}],"parenthesized":false},{"$type":"RegexToken","regex":"/\\\\+'[^']*'/","parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"LINK_LABEL","definition":{"$type":"RegexToken","regex":"/;[^\\\\n\\\\r]+/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRATEGY","definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"build"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"buy"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"outsource"},"parenthesized":false}],"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"market"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_WARDLEY","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"wardley-beta"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_SIZE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"size"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_EVOLUTION","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"evolution"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ANCHOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"anchor"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_COMPONENT","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"component"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_LABEL","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"label"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_INERTIA","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"inertia"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_EVOLVE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"evolve"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_PIPELINE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"pipeline"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_NOTE","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"note"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ANNOTATIONS","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"annotations"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ANNOTATION","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"annotation"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_ACCELERATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"accelerator"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"KW_DEACCELERATOR","definition":{"$type":"CharacterRange","left":{"$type":"Keyword","value":"deaccelerator"},"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NAME_WITH_SPACES","definition":{"$type":"RegexToken","regex":"/(?!title\\\\s|accTitle|accDescr)[A-Za-z](?:[A-Za-z0-9_()&]|-(?!>))*(?:[ \\\\t]+[A-Za-z(](?:[A-Za-z0-9_()&]|-(?!>))*)*/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WS","definition":{"$type":"RegexToken","regex":"/[ \\\\t]+/","parenthesized":false},"fragment":false},{"$type":"ParserRule","name":"EOL","dataType":"string","definition":{"$type":"Alternatives","elements":[{"$type":"RuleCall","rule":{"$ref":"#/rules@52"},"arguments":[],"cardinality":"+"},{"$type":"EndOfFile"}]},"entry":false,"fragment":false,"parameters":[]},{"$type":"ParserRule","fragment":true,"name":"TitleAndAccessibilities","definition":{"$type":"Group","elements":[{"$type":"Alternatives","elements":[{"$type":"Assignment","feature":"accDescr","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@44"},"arguments":[]}},{"$type":"Assignment","feature":"accTitle","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@45"},"arguments":[]}},{"$type":"Assignment","feature":"title","operator":"=","terminal":{"$type":"RuleCall","rule":{"$ref":"#/rules@46"},"arguments":[]}}]},{"$type":"RuleCall","rule":{"$ref":"#/rules@41"},"arguments":[]}],"cardinality":"+"},"entry":false,"parameters":[]},{"$type":"TerminalRule","name":"BOOLEAN","type":{"$type":"ReturnType","name":"boolean"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"CharacterRange","left":{"$type":"Keyword","value":"true"},"parenthesized":false},{"$type":"CharacterRange","left":{"$type":"Keyword","value":"false"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_DESCR","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accDescr(?:[\\\\t ]*:([^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)|\\\\s*{([^}]*)})/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ACC_TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*accTitle[\\\\t ]*:(?:[^\\\\n\\\\r]*?(?=%%)|[^\\\\n\\\\r]*)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"TITLE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*title(?:[\\\\t ][^\\\\n\\\\r]*?(?=%%)|[\\\\t ][^\\\\n\\\\r]*|)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"FLOAT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/[0-9]+\\\\.[0-9]+(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"INT","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"RegexToken","regex":"/0|[1-9][0-9]*(?!\\\\.)/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NUMBER","type":{"$type":"ReturnType","name":"number"},"definition":{"$type":"TerminalAlternatives","elements":[{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@47"},"parenthesized":false},{"$type":"TerminalRuleCall","rule":{"$ref":"#/rules@48"},"parenthesized":false}],"parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"STRING","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\"|'([^'\\\\\\\\]|\\\\\\\\.)*'/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"ID","type":{"$type":"ReturnType","name":"string"},"definition":{"$type":"RegexToken","regex":"/[\\\\w]([-\\\\w]*\\\\w)?/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","name":"NEWLINE","definition":{"$type":"RegexToken","regex":"/\\\\r?\\\\n/","parenthesized":false},"fragment":false,"hidden":false},{"$type":"TerminalRule","hidden":true,"name":"WHITESPACE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]+/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"YAML","definition":{"$type":"RegexToken","regex":"/---[\\\\t ]*\\\\r?\\\\n(?:[\\\\S\\\\s]*?\\\\r?\\\\n)?---(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"DIRECTIVE","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%{[\\\\S\\\\s]*?}%%(?:\\\\r?\\\\n|(?!\\\\S))/","parenthesized":false},"fragment":false},{"$type":"TerminalRule","hidden":true,"name":"SINGLE_LINE_COMMENT","definition":{"$type":"RegexToken","regex":"/[\\\\t ]*%%[^\\\\n\\\\r]*/","parenthesized":false},"fragment":false}],"interfaces":[],"types":[]}`)),"WardleyGrammarGrammar"),yz={languageId:"architecture",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},gz={languageId:"cynefin",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},vz={languageId:"eventmodeling",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Tz={languageId:"gitGraph",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},$z={languageId:"info",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Rz={languageId:"packet",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Az={languageId:"pie",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Ez={languageId:"radar",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Cz={languageId:"railroadAbnf",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},bz={languageId:"railroadEbnf",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},_z={languageId:"railroad",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Sz={languageId:"railroadPeg",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},wz={languageId:"treemap",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Iz={languageId:"treeView",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},Nz={languageId:"wardley",fileExtensions:[".mmd",".mermaid"],caseInsensitive:!1,mode:"production"},ct={AstReflection:i(()=>new jw,"AstReflection")},Pz={Grammar:i(()=>tz(),"Grammar"),LanguageMetaData:i(()=>yz,"LanguageMetaData"),parser:{}},kz={Grammar:i(()=>rz(),"Grammar"),LanguageMetaData:i(()=>gz,"LanguageMetaData"),parser:{}},Oz={Grammar:i(()=>nz(),"Grammar"),LanguageMetaData:i(()=>vz,"LanguageMetaData"),parser:{}},Lz={Grammar:i(()=>az(),"Grammar"),LanguageMetaData:i(()=>Tz,"LanguageMetaData"),parser:{}},Dz={Grammar:i(()=>iz(),"Grammar"),LanguageMetaData:i(()=>$z,"LanguageMetaData"),parser:{}},xz={Grammar:i(()=>sz(),"Grammar"),LanguageMetaData:i(()=>Rz,"LanguageMetaData"),parser:{}},Mz={Grammar:i(()=>oz(),"Grammar"),LanguageMetaData:i(()=>Az,"LanguageMetaData"),parser:{}},Gz={Grammar:i(()=>lz(),"Grammar"),LanguageMetaData:i(()=>Ez,"LanguageMetaData"),parser:{}},Fz={Grammar:i(()=>uz(),"Grammar"),LanguageMetaData:i(()=>Cz,"LanguageMetaData"),parser:{}},zz={Grammar:i(()=>cz(),"Grammar"),LanguageMetaData:i(()=>bz,"LanguageMetaData"),parser:{}},jz={Grammar:i(()=>fz(),"Grammar"),LanguageMetaData:i(()=>_z,"LanguageMetaData"),parser:{}},Bz={Grammar:i(()=>dz(),"Grammar"),LanguageMetaData:i(()=>Sz,"LanguageMetaData"),parser:{}},Uz={Grammar:i(()=>pz(),"Grammar"),LanguageMetaData:i(()=>wz,"LanguageMetaData"),parser:{}},Kz={Grammar:i(()=>mz(),"Grammar"),LanguageMetaData:i(()=>Iz,"LanguageMetaData"),parser:{}},Wz={Grammar:i(()=>hz(),"Grammar"),LanguageMetaData:i(()=>Nz,"LanguageMetaData"),parser:{}},Vz=/accDescr(?:[\t ]*:([^\n\r]*)|\s*{([^}]*)})/,qz=/accTitle[\t ]*:([^\n\r]*)/,Hz=/title([\t ][^\n\r]*|)/,Yz={ACC_DESCR:Vz,ACC_TITLE:qz,TITLE:Hz},ur=class extends zm{static{i(this,"AbstractMermaidValueConverter")}runConverter(e,t,r){let n=this.runCommonConverter(e,t,r);return n===void 0&&(n=this.runCustomConverter(e,t,r)),n===void 0?super.runConverter(e,t,r):n}runCommonConverter(e,t,r){const n=Yz[e.name];if(n===void 0)return;const a=n.exec(t);if(a!==null){if(a[1]!==void 0)return a[1].trim().replace(/[\t ]{2,}/gm," ");if(a[2]!==void 0)return a[2].replace(/^\s*/gm,"").replace(/\s+$/gm,"").replace(/[\t ]{2,}/gm," ").replace(/[\n\r]{2,}/gm,` +`)}}},ci=class extends ur{static{i(this,"CommonValueConverter")}runCustomConverter(e,t,r){}},ft=class extends Du{static{i(this,"AbstractMermaidTokenBuilder")}constructor(e){super(),this.keywords=new Set(e)}buildKeywordTokens(e,t,r){const n=super.buildKeywordTokens(e,t,r);return n.forEach(a=>{this.keywords.has(a.name)&&a.PATTERN!==void 0&&(a.PATTERN=new RegExp(a.PATTERN.toString()+"(?:(?=%%)|(?!\\S))"))}),n}};(class extends ft{static{i(this,"CommonTokenBuilder")}});/*! Bundled license information: + +lodash-es/lodash.js: + (** + * @license + * Lodash (Custom Build) + * Build: `lodash modularize exports="es" -o ./` + * Copyright OpenJS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + *) +*/var Xz=class extends ft{static{i(this,"RadarTokenBuilder")}constructor(){super(["radar-beta"])}},Bw={parser:{TokenBuilder:i(()=>new Xz,"TokenBuilder"),ValueConverter:i(()=>new ci,"ValueConverter")}};function Uw(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Gz,Bw);return t.ServiceRegistry.register(r),{shared:t,Radar:r}}i(Uw,"createRadarServices");var Jz=class extends ft{static{i(this,"RailroadTokenBuilder")}constructor(){super(["railroad-beta"])}},kg=i(e=>{const t=e.slice(1,-1);let r="";for(let n=0;nnew Jz,"TokenBuilder"),ValueConverter:i(()=>new Zz,"ValueConverter")}};function Ww(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),jz,Kw);return t.ServiceRegistry.register(r),{shared:t,Railroad:r}}i(Ww,"createRailroadServices");var Qz=class extends ft{static{i(this,"RailroadEbnfTokenBuilder")}constructor(){super(["railroad-ebnf-beta"])}},Og=i(e=>{const t=e.slice(1,-1);let r="";for(let n=0;nnew Qz,"TokenBuilder"),ValueConverter:i(()=>new ej,"ValueConverter")}};function qw(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),zz,Vw);return t.ServiceRegistry.register(r),{shared:t,RailroadEbnf:r}}i(qw,"createRailroadEbnfServices");var tj=class extends ft{static{i(this,"RailroadAbnfTokenBuilder")}constructor(){super(["railroad-abnf-beta"])}},rj=class extends ur{static{i(this,"RailroadAbnfValueConverter")}runConverter(e,t,r){const n=super.runConverter(e,t,r);if(e.name==="TITLE"&&typeof n=="string"){const a=n.trim();if(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))return a.slice(1,-1)}return n}runCustomConverter(e,t,r){if(e.name==="ABNF_STRING")return t.slice(1,-1)}},Hw={parser:{TokenBuilder:i(()=>new tj,"TokenBuilder"),ValueConverter:i(()=>new rj,"ValueConverter")}};function Yw(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Fz,Hw);return t.ServiceRegistry.register(r),{shared:t,RailroadAbnf:r}}i(Yw,"createRailroadAbnfServices");var nj=class extends ft{static{i(this,"RailroadPegTokenBuilder")}constructor(){super(["railroad-peg-beta"])}},Lg=i(e=>{const t=e.slice(1,-1);let r="";for(let n=0;nnew nj,"TokenBuilder"),ValueConverter:i(()=>new aj,"ValueConverter")}};function Jw(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Bz,Xw);return t.ServiceRegistry.register(r),{shared:t,RailroadPeg:r}}i(Jw,"createRailroadPegServices");var ij=class extends ft{static{i(this,"TreemapTokenBuilder")}constructor(){super(["treemap"])}},sj=/classDef\s+([A-Z_a-z]\w+)(?:\s+([^\n\r;]*))?;?/,oj=class extends ur{static{i(this,"TreemapValueConverter")}runCustomConverter(e,t,r){if(e.name==="NUMBER2")return parseFloat(t.replace(/,/g,""));if(e.name==="SEPARATOR")return t.substring(1,t.length-1);if(e.name==="STRING2")return t.substring(1,t.length-1);if(e.name==="INDENTATION")return t.length;if(e.name==="ClassDef"){if(typeof t!="string")return t;const n=sj.exec(t);if(n)return{$type:"ClassDefStatement",className:n[1],styleText:n[2]||void 0}}}};function Zw(e){const t=e.validation.TreemapValidator,r=e.validation.ValidationRegistry;if(r){const n={Treemap:t.checkSingleRoot.bind(t)};r.register(n,t)}}i(Zw,"registerValidationChecks");var lj=class{static{i(this,"TreemapValidator")}checkSingleRoot(e,t){let r;for(const n of e.TreemapRows)n.item&&(r===void 0&&n.indent===void 0?r=0:n.indent===void 0?t("error","Multiple root nodes are not allowed in a treemap.",{node:n,property:"item"}):r!==void 0&&r>=parseInt(n.indent,10)&&t("error","Multiple root nodes are not allowed in a treemap.",{node:n,property:"item"}))}},Qw={parser:{TokenBuilder:i(()=>new ij,"TokenBuilder"),ValueConverter:i(()=>new oj,"ValueConverter")},validation:{TreemapValidator:i(()=>new lj,"TreemapValidator")}};function eI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Uz,Qw);return t.ServiceRegistry.register(r),Zw(r),{shared:t,Treemap:r}}i(eI,"createTreemapServices");var uj=class extends ur{static{i(this,"WardleyValueConverter")}runCustomConverter(e,t,r){switch(e.name.toUpperCase()){case"LINK_LABEL":return t.substring(1).trim();default:return}}},tI={parser:{ValueConverter:i(()=>new uj,"ValueConverter")}};function rI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Wz,tI);return t.ServiceRegistry.register(r),{shared:t,Wardley:r}}i(rI,"createWardleyServices");var cj=class extends ft{static{i(this,"CynefinTokenBuilder")}constructor(){super(["cynefin-beta"])}},nI={parser:{TokenBuilder:i(()=>new cj,"TokenBuilder"),ValueConverter:i(()=>new ci,"ValueConverter")}};function aI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),kz,nI);return t.ServiceRegistry.register(r),{shared:t,Cynefin:r}}i(aI,"createCynefinServices");var fj=class extends ft{static{i(this,"GitGraphTokenBuilder")}constructor(){super(["gitGraph"])}},iI={parser:{TokenBuilder:i(()=>new fj,"TokenBuilder"),ValueConverter:i(()=>new ci,"ValueConverter")}};function sI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Lz,iI);return t.ServiceRegistry.register(r),{shared:t,GitGraph:r}}i(sI,"createGitGraphServices");var dj=class extends ft{static{i(this,"InfoTokenBuilder")}constructor(){super(["info","showInfo"])}},oI={parser:{TokenBuilder:i(()=>new dj,"TokenBuilder"),ValueConverter:i(()=>new ci,"ValueConverter")}};function lI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Dz,oI);return t.ServiceRegistry.register(r),{shared:t,Info:r}}i(lI,"createInfoServices");var pj=class extends ft{static{i(this,"PacketTokenBuilder")}constructor(){super(["packet"])}},uI={parser:{TokenBuilder:i(()=>new pj,"TokenBuilder"),ValueConverter:i(()=>new ci,"ValueConverter")}};function cI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),xz,uI);return t.ServiceRegistry.register(r),{shared:t,Packet:r}}i(cI,"createPacketServices");var mj=class extends ft{static{i(this,"PieTokenBuilder")}constructor(){super(["pie","showData"])}},hj=class extends ur{static{i(this,"PieValueConverter")}runCustomConverter(e,t,r){if(e.name==="PIE_SECTION_LABEL")return t.replace(/"/g,"").trim()}},fI={parser:{TokenBuilder:i(()=>new mj,"TokenBuilder"),ValueConverter:i(()=>new hj,"ValueConverter")}};function dI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Mz,fI);return t.ServiceRegistry.register(r),{shared:t,Pie:r}}i(dI,"createPieServices");var yj=class extends ur{static{i(this,"TreeViewValueConverter")}runCustomConverter(e,t,r){if(e.name==="INDENTATION")return t?.length||0;if(e.name==="QUOTED_NAME")return t.substring(1,t.length-1);if(e.name==="BARE_NAME")return t.replace(/[\t ]+$/,"");if(e.name==="CLASS_ANNOTATION")return t.trim().substring(3).trim();if(e.name==="ICON_ANNOTATION"){const n=t.trim();return n.substring(5,n.length-1)}if(e.name==="DESC_ANNOTATION")return t.trim().substring(2).trim()}},gj=class extends ft{static{i(this,"TreeViewTokenBuilder")}constructor(){super(["treeView-beta"])}},pI={parser:{TokenBuilder:i(()=>new gj,"TokenBuilder"),ValueConverter:i(()=>new yj,"ValueConverter")}};function mI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Kz,pI);return t.ServiceRegistry.register(r),{shared:t,TreeView:r}}i(mI,"createTreeViewServices");var vj=class extends ft{static{i(this,"ArchitectureTokenBuilder")}constructor(){super(["architecture"])}},Tj=class extends ur{static{i(this,"ArchitectureValueConverter")}runCustomConverter(e,t,r){if(e.name==="ARCH_ICON")return t.replace(/[()]/g,"").trim();if(e.name==="ARCH_TEXT_ICON")return t.replace(/["()]/g,"");if(e.name==="ARCH_TITLE"){let n=t.replace(/^\[|]$/g,"").trim();return(n.startsWith('"')&&n.endsWith('"')||n.startsWith("'")&&n.endsWith("'"))&&(n=n.slice(1,-1),n=n.replace(/\\"/g,'"').replace(/\\'/g,"'")),n.trim()}}},hI={parser:{TokenBuilder:i(()=>new vj,"TokenBuilder"),ValueConverter:i(()=>new Tj,"ValueConverter")}};function yI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Pz,hI);return t.ServiceRegistry.register(r),{shared:t,Architecture:r}}i(yI,"createArchitectureServices");var $j=class extends ft{static{i(this,"EventModelingTokenBuilder")}constructor(){super(["eventmodeling"])}},Dg=new Set(["cmd","command"]),xg=new Set(["evt","event"]),$c=new Set(["rmo","readmodel"]),Mg=new Set(["pcr","processor"]),Gg=new Set(["ui"]);function gI(e){const t=e.validation.EventModelingValidator,r=e.validation.ValidationRegistry;if(r){const n={EmTimeFrame:t.checkSourceFrameTypes.bind(t),EmResetFrame:t.checkSourceFrameTypes.bind(t)};r.register(n,t)}}i(gI,"registerValidationChecks");var Rj=class{static{i(this,"EventModelingValidator")}checkSourceFrameTypes(e,t){e.sourceFrames.length!==0&&(Dg.has(e.modelEntityType)?this.validateSources(e,new Set([...Gg,...Mg]),"command","ui or processor",t):xg.has(e.modelEntityType)?this.validateSources(e,Dg,"event","command",t):$c.has(e.modelEntityType)?this.validateSources(e,xg,"read model","event",t):Mg.has(e.modelEntityType)?this.validateSources(e,$c,"processor","read model",t):Gg.has(e.modelEntityType)&&this.validateSources(e,$c,"ui","read model",t))}validateSources(e,t,r,n,a){for(const s of e.sourceFrames){const o=s.ref;o!==void 0&&!t.has(o.modelEntityType)&&a("error",`A ${r} can only receive input from a ${n}, not from '${o.modelEntityType}'.`,{node:e,property:"sourceFrames"})}}},vI={parser:{TokenBuilder:i(()=>new $j,"TokenBuilder"),ValueConverter:i(()=>new ci,"ValueConverter")},validation:{EventModelingValidator:i(()=>new Rj,"EventModelingValidator")}};function TI(e=Xe){const t=ee(Be(e),ct),r=ee(je({shared:t}),Oz,vI);return t.ServiceRegistry.register(r),gI(r),{shared:t,EventModel:r}}i(TI,"createEventModelingServices");var Ve={},Aj={info:i(async()=>{const{createInfoServices:e}=await et(async()=>{const{createInfoServices:r}=await Promise.resolve().then(()=>bj);return{createInfoServices:r}},void 0),t=e().Info.parser.LangiumParser;Ve.info=t},"info"),packet:i(async()=>{const{createPacketServices:e}=await et(async()=>{const{createPacketServices:r}=await Promise.resolve().then(()=>_j);return{createPacketServices:r}},void 0),t=e().Packet.parser.LangiumParser;Ve.packet=t},"packet"),pie:i(async()=>{const{createPieServices:e}=await et(async()=>{const{createPieServices:r}=await Promise.resolve().then(()=>Sj);return{createPieServices:r}},void 0),t=e().Pie.parser.LangiumParser;Ve.pie=t},"pie"),treeView:i(async()=>{const{createTreeViewServices:e}=await et(async()=>{const{createTreeViewServices:r}=await Promise.resolve().then(()=>wj);return{createTreeViewServices:r}},void 0),t=e().TreeView.parser.LangiumParser;Ve.treeView=t},"treeView"),architecture:i(async()=>{const{createArchitectureServices:e}=await et(async()=>{const{createArchitectureServices:r}=await Promise.resolve().then(()=>Ij);return{createArchitectureServices:r}},void 0),t=e().Architecture.parser.LangiumParser;Ve.architecture=t},"architecture"),gitGraph:i(async()=>{const{createGitGraphServices:e}=await et(async()=>{const{createGitGraphServices:r}=await Promise.resolve().then(()=>Nj);return{createGitGraphServices:r}},void 0),t=e().GitGraph.parser.LangiumParser;Ve.gitGraph=t},"gitGraph"),eventmodeling:i(async()=>{const{createEventModelingServices:e}=await et(async()=>{const{createEventModelingServices:r}=await Promise.resolve().then(()=>Pj);return{createEventModelingServices:r}},void 0),t=e().EventModel.parser.LangiumParser;Ve.eventmodeling=t},"eventmodeling"),radar:i(async()=>{const{createRadarServices:e}=await et(async()=>{const{createRadarServices:r}=await Promise.resolve().then(()=>kj);return{createRadarServices:r}},void 0),t=e().Radar.parser.LangiumParser;Ve.radar=t},"radar"),railroad:i(async()=>{const{createRailroadServices:e}=await et(async()=>{const{createRailroadServices:r}=await Promise.resolve().then(()=>Oj);return{createRailroadServices:r}},void 0),t=e().Railroad.parser.LangiumParser;Ve.railroad=t},"railroad"),railroadEbnf:i(async()=>{const{createRailroadEbnfServices:e}=await et(async()=>{const{createRailroadEbnfServices:r}=await Promise.resolve().then(()=>Lj);return{createRailroadEbnfServices:r}},void 0),t=e().RailroadEbnf.parser.LangiumParser;Ve.railroadEbnf=t},"railroadEbnf"),railroadAbnf:i(async()=>{const{createRailroadAbnfServices:e}=await et(async()=>{const{createRailroadAbnfServices:r}=await Promise.resolve().then(()=>Dj);return{createRailroadAbnfServices:r}},void 0),t=e().RailroadAbnf.parser.LangiumParser;Ve.railroadAbnf=t},"railroadAbnf"),railroadPeg:i(async()=>{const{createRailroadPegServices:e}=await et(async()=>{const{createRailroadPegServices:r}=await Promise.resolve().then(()=>xj);return{createRailroadPegServices:r}},void 0),t=e().RailroadPeg.parser.LangiumParser;Ve.railroadPeg=t},"railroadPeg"),treemap:i(async()=>{const{createTreemapServices:e}=await et(async()=>{const{createTreemapServices:r}=await Promise.resolve().then(()=>Mj);return{createTreemapServices:r}},void 0),t=e().Treemap.parser.LangiumParser;Ve.treemap=t},"treemap"),wardley:i(async()=>{const{createWardleyServices:e}=await et(async()=>{const{createWardleyServices:r}=await Promise.resolve().then(()=>Gj);return{createWardleyServices:r}},void 0),t=e().Wardley.parser.LangiumParser;Ve.wardley=t},"wardley"),cynefin:i(async()=>{const{createCynefinServices:e}=await et(async()=>{const{createCynefinServices:r}=await Promise.resolve().then(()=>Fj);return{createCynefinServices:r}},void 0),t=e().Cynefin.parser.LangiumParser;Ve.cynefin=t},"cynefin")};async function Ej(e,t){const r=Aj[e];if(!r)throw new Error(`Unknown diagram type: ${e}`);Ve[e]||await r();const a=Ve[e].parse(t);if(a.lexerErrors.length>0||a.parserErrors.length>0)throw new Cj(a);return a.value}i(Ej,"parse");var Cj=class extends Error{constructor(e){const t=e.lexerErrors.map(n=>{const a=n.line!==void 0&&!isNaN(n.line)?n.line:"?",s=n.column!==void 0&&!isNaN(n.column)?n.column:"?";return`Lexer error on line ${a}, column ${s}: ${n.message}`}).join(` +`),r=e.parserErrors.map(n=>{const a=n.token.startLine!==void 0&&!isNaN(n.token.startLine)?n.token.startLine:"?",s=n.token.startColumn!==void 0&&!isNaN(n.token.startColumn)?n.token.startColumn:"?";return`Parse error on line ${a}, column ${s}: ${n.message}`}).join(` +`);super(`Parsing failed: ${t} ${r}`),this.result=e}static{i(this,"MermaidParseError")}};const bj=Object.freeze(Object.defineProperty({__proto__:null,InfoModule:oI,createInfoServices:lI},Symbol.toStringTag,{value:"Module"})),_j=Object.freeze(Object.defineProperty({__proto__:null,PacketModule:uI,createPacketServices:cI},Symbol.toStringTag,{value:"Module"})),Sj=Object.freeze(Object.defineProperty({__proto__:null,PieModule:fI,createPieServices:dI},Symbol.toStringTag,{value:"Module"})),wj=Object.freeze(Object.defineProperty({__proto__:null,TreeViewModule:pI,createTreeViewServices:mI},Symbol.toStringTag,{value:"Module"})),Ij=Object.freeze(Object.defineProperty({__proto__:null,ArchitectureModule:hI,createArchitectureServices:yI},Symbol.toStringTag,{value:"Module"})),Nj=Object.freeze(Object.defineProperty({__proto__:null,GitGraphModule:iI,createGitGraphServices:sI},Symbol.toStringTag,{value:"Module"})),Pj=Object.freeze(Object.defineProperty({__proto__:null,EventModelingModule:vI,createEventModelingServices:TI},Symbol.toStringTag,{value:"Module"})),kj=Object.freeze(Object.defineProperty({__proto__:null,RadarModule:Bw,createRadarServices:Uw},Symbol.toStringTag,{value:"Module"})),Oj=Object.freeze(Object.defineProperty({__proto__:null,RailroadModule:Kw,createRailroadServices:Ww},Symbol.toStringTag,{value:"Module"})),Lj=Object.freeze(Object.defineProperty({__proto__:null,RailroadEbnfModule:Vw,createRailroadEbnfServices:qw},Symbol.toStringTag,{value:"Module"})),Dj=Object.freeze(Object.defineProperty({__proto__:null,RailroadAbnfModule:Hw,createRailroadAbnfServices:Yw},Symbol.toStringTag,{value:"Module"})),xj=Object.freeze(Object.defineProperty({__proto__:null,RailroadPegModule:Xw,createRailroadPegServices:Jw},Symbol.toStringTag,{value:"Module"})),Mj=Object.freeze(Object.defineProperty({__proto__:null,TreemapModule:Qw,createTreemapServices:eI},Symbol.toStringTag,{value:"Module"})),Gj=Object.freeze(Object.defineProperty({__proto__:null,WardleyModule:tI,createWardleyServices:rI},Symbol.toStringTag,{value:"Module"})),Fj=Object.freeze(Object.defineProperty({__proto__:null,CynefinModule:nI,createCynefinServices:aI},Symbol.toStringTag,{value:"Module"}));export{Cj as M,qw as a,Yw as b,Ww as c,Jw as d,zF as i,Ej as p}; diff --git a/apps/kimi-code/dist-web/assets/dagre-VKFMJZFB-BT-klNzv.js b/apps/kimi-code/dist-web/assets/dagre-VKFMJZFB-BT-klNzv.js new file mode 100644 index 0000000000000000000000000000000000000000..2e7d06a5172aae7cfa53d5cdcce63b1631d5cc96 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/dagre-VKFMJZFB-BT-klNzv.js @@ -0,0 +1,4 @@ +import{c as O,w as I,a as J,f as P,b as E,s as A}from"./chunk-RYQCIY6F-pV91xl4J.js";import{_ as w,am as v,an as D,ao as H,ap as Y,l,c as _,aq as W,ar as $,ag as j,as as q,ah as R,af as F,at as z,au as K,av as G}from"./mermaid.core-CCxZmhet.js";import{G as Q}from"./graph-DOmOIIwC.js";import{l as U}from"./layout-D-LzfAck.js";import"./map-DxJ2ADlA.js";import"./index-Baap3_X9.js";import"./_commonjsHelpers-CqkleIqs.js";var C=w((s,t,g)=>Math.max(t,Math.min(g,s)),"clamp"),B=w((s="TB")=>{switch(s){case"BT":return"bottom";case"LR":return"right";case"RL":return"left";case"TB":default:return"top"}},"getDefaultSelfLoopSide"),V=w(s=>s==="flowchart"||s==="flowchart-v2"||s==="stateDiagram","shouldMergeSelfLoopSegments"),Z=w((s,t,g,m,c)=>{const o=[],r=new Set;if(g.forEach(({start:i,end:n})=>{i!==m&&r.add(i),n!==m&&r.add(n)}),r.forEach(i=>{const n=s.node(i);typeof n?.x=="number"&&typeof n?.y=="number"&&o.push(n)}),o.length===0&&g.forEach(({edge:i})=>{(i.points??[]).forEach(n=>{typeof n?.x=="number"&&typeof n?.y=="number"&&o.push(n)})}),o.length===0)return B(c);const f=o.reduce((i,n)=>({x:i.x+n.x/o.length,y:i.y+n.y/o.length}),{x:0,y:0}),h=f.x-t.x,a=f.y-t.y;return Math.abs(h)>Math.abs(a)?h>0?"right":"left":Math.abs(a)>0?a>0?"bottom":"top":B(c)},"getSelfLoopSide"),ee=w((s,t="top",g=0,m=0)=>{const c=s.x,o=s.y-g,r=s.width/2,f=s.height/2,h=Math.max(36,Math.min(100,s.width*.8)),a=C(Math.max(m,s.width*.35),36,h),i=C(Math.min(s.width,s.height)*.45,24,48);switch(t){case"bottom":{const n=o+f;return[{x:c-a/2,y:n},{x:c-a/2,y:n+i},{x:c+a/2,y:n+i},{x:c+a/2,y:n}]}case"right":{const n=c+r;return[{x:n,y:o-a/2},{x:n+i,y:o-a/2},{x:n+i,y:o+a/2},{x:n,y:o+a/2}]}case"left":{const n=c-r;return[{x:n,y:o-a/2},{x:n-i,y:o-a/2},{x:n-i,y:o+a/2},{x:n,y:o+a/2}]}case"top":default:{const n=o-f;return[{x:c-a/2,y:n},{x:c-a/2,y:n-i},{x:c+a/2,y:n-i},{x:c+a/2,y:n}]}}},"getSelfLoopPoints"),te=w((s,t,g="top",m=0,c={})=>{const r=s.x,f=s.y-m,h=c.width??0,a=c.height??0;switch(g){case"bottom":return{x:r,y:Math.max(...t.map(i=>i.y))+a/2+4};case"right":return{x:Math.max(...t.map(i=>i.x))+h/2+4,y:f};case"left":return{x:Math.min(...t.map(i=>i.x))-h/2-4,y:f};case"top":default:return{x:r,y:Math.min(...t.map(i=>i.y))-a/2-4}}},"getSelfLoopLabelPosition"),ne=w((s,t=0,{mergeSelfLoops:g=!0}={})=>{const m=new Map,c=[],o=s.graph()?.rankdir;return s.edges().forEach(r=>{const f=s.edge(r);if(g&&f.selfLoop){const h=f.selfLoop.id;m.has(h)||m.set(h,[]),m.get(h).push({edge:f,start:r.v,end:r.w})}else c.push({edge:f,start:r.v,end:r.w})}),m.forEach(r=>{if(r.length!==3){r.forEach(L=>c.push(L));return}r.sort((L,d)=>L.edge.selfLoop.order-d.edge.selfLoop.order);const[f,h,a]=r,i=f.edge.originalEdge??h.edge.originalEdge??a.edge.originalEdge??h.edge,n=s.node(i.start);if(!n){r.forEach(L=>c.push(L));return}const p={width:h.edge.width,height:h.edge.height},y=Z(s,n,r,i.start,o),X=ee(n,y,t,p.width??0),S=te(n,X,y,t,p),b={...h.edge,...i,id:i.id,points:X,start:i.start,end:i.end,x:S.x,y:S.y,width:p.width,height:p.height,labelStyle:h.edge.labelStyle,fromCluster:f.edge.fromCluster??h.edge.fromCluster??a.edge.fromCluster,toCluster:f.edge.toCluster??h.edge.toCluster??a.edge.toCluster};delete b.selfLoop,delete b.originalEdge,c.push({edge:b,start:b.start,end:b.end})}),c},"getEdgesToRender"),T=w(async(s,t,g,m,c,o)=>{l.warn("Graph in recursive render:XAX",I(t),c);const r=t.graph().rankdir;l.trace("Dir in recursive render - dir:",r);const f=s.insert("g").attr("class","root");t.nodes()?l.info("Recursive render XXX",t.nodes()):l.info("No nodes found for",t),t.edges().length>0&&l.info("Recursive edges",t.edge(t.edges()[0]));const h=f.insert("g").attr("class","clusters"),a=f.insert("g").attr("class","edgePaths"),i=f.insert("g").attr("class","edgeLabels"),n=f.insert("g").attr("class","nodes"),p=V(g);await Promise.all(t.nodes().map(async function(d){const e=t.node(d);if(c!==void 0){const u=JSON.parse(JSON.stringify(c.clusterData));l.trace(`Setting data for parent cluster XXX + Node.id = `,d,` + data=`,u.height,` +Parent cluster`,c.height),t.setNode(c.id,u),t.parent(d)||(l.trace("Setting parent",d,c.id),t.setParent(d,c.id,u))}if(l.info("(Insert) Node XXX"+d+": "+JSON.stringify(t.node(d))),e?.clusterNode){l.info("Cluster identified XBX",d,e.width,t.node(d));const{ranksep:u,nodesep:x}=t.graph();e.graph.setGraph({...e.graph.graph(),ranksep:u+25,nodesep:x});const N=await T(n,e.graph,g,m,t.node(d),o),M=N.elem;W(e,M),e.diff=N.diff||0,l.info("New compound node after recursive render XAX",d,"width",e.width,"height",e.height),$(M,e)}else t.children(d).length>0?(l.trace("Cluster - the non recursive path XBX",d,e.id,e,e.width,"Graph:",t),l.trace(P(e.id,t)),E.set(e.id,{id:P(e.id,t),node:e})):(l.trace("Node - the non recursive path XAX",d,n,t.node(d),r),await j(n,t.node(d),{config:o,dir:r}))})),await w(async()=>{const d=t.edges().map(async function(e){const u=t.edge(e.v,e.w,e.name);if(l.info("Edge "+e.v+" -> "+e.w+": "+JSON.stringify(e)),l.info("Edge "+e.v+" -> "+e.w+": ",e," ",JSON.stringify(t.edge(e))),l.info("Fix",E,"ids:",e.v,e.w,"Translating: ",E.get(e.v),E.get(e.w)),p&&u.selfLoop){if(u.selfLoop.order!==1)return;const x=u.id;u.id=u.selfLoop.id,await G(i,u),u.id=x;return}await G(i,u)});await Promise.all(d)},"processEdges")(),l.info("Graph before layout:",JSON.stringify(I(t))),l.info("############################################# XXX"),l.info("### Layout ### XXX"),l.info("############################################# XXX"),U(t),l.info("Graph after layout:",JSON.stringify(I(t)));let X=0,{subGraphTitleTotalMargin:S}=q(o);await Promise.all(A(t).map(async function(d){const e=t.node(d);if(l.info("Position XBX => "+d+": ("+e.x,","+e.y,") width: ",e.width," height: ",e.height),e?.clusterNode)e.y+=S,l.info("A tainted cluster node XBX1",d,e.id,e.width,e.height,e.x,e.y,t.parent(d)),E.get(e.id).node=e,R(e);else if(t.children(d).length>0){l.info("A pure cluster node XBX1",d,e.id,e.x,e.y,e.width,e.height,t.parent(d)),e.height+=S,t.node(e.parentId);const u=e?.padding/2||0,x=e?.labelBBox?.height||0,N=x-u||0;l.debug("OffsetY",N,"labelHeight",x,"halfPadding",u),await F(h,e),E.get(e.id).node=e}else{const u=t.node(e.parentId);e.y+=S/2,l.info("A regular node XBX1 - using the padding",e.id,"parent",e.parentId,e.width,e.height,e.x,e.y,"offsetY",e.offsetY,"parent",u,u?.offsetY,e),R(e)}}));const b=S/2;return ne(t,b,{mergeSelfLoops:p}).forEach(function({edge:d,start:e,end:u}){l.info("Edge "+e+" -> "+u+": "+JSON.stringify(d),d),d.points.forEach(k=>k.y+=b);const x=t.node(e),N=t.node(u),M=z(a,d,E,g,x,N,m);K(d,M)}),t.nodes().forEach(function(d){const e=t.node(d);l.info(d,e.type,e.diff),e.isGroup&&(X=e.diff)}),l.warn("Returning from recursive render XAX",f,X),{elem:f,diff:X}},"recursiveRender"),le=w(async(s,t)=>{const g=new Q({multigraph:!0,compound:!0}).setGraph({rankdir:s.direction,nodesep:s.config?.nodeSpacing||s.config?.flowchart?.nodeSpacing||s.nodeSpacing,ranksep:s.config?.rankSpacing||s.config?.flowchart?.rankSpacing||s.rankSpacing,marginx:8,marginy:8}).setDefaultEdgeLabel(function(){return{}}),m=t.select("g");v(m,s.markers,s.type,s.diagramId),D(),H(),Y(),O(),s.nodes.forEach(o=>{g.setNode(o.id,{...o}),o.parentId&&g.setParent(o.id,o.parentId)}),l.debug("Edges:",s.edges),s.edges.forEach(o=>{if(o.start===o.end){const r=o.start,f=r+"---"+r+"---1",h=r+"---"+r+"---2",a=g.node(r);g.setNode(f,{domId:f,id:f,parentId:a.parentId,labelStyle:"",label:"",padding:0,shape:"labelRect",style:"",width:10,height:10}),g.setParent(f,a.parentId),g.setNode(h,{domId:h,id:h,parentId:a.parentId,labelStyle:"",padding:0,shape:"labelRect",label:"",style:"",width:10,height:10}),g.setParent(h,a.parentId);const i=structuredClone(o),n=structuredClone(o),p=structuredClone(o),y=structuredClone(o);n.originalEdge=i,n.selfLoop={id:i.id,order:0},p.originalEdge=i,p.selfLoop={id:i.id,order:1},y.originalEdge=i,y.selfLoop={id:i.id,order:2},n.label="",n.arrowTypeEnd="none",n.endLabelLeft="",n.endLabelRight="",n.startLabelLeft="",n.id=r+"-cyclic-special-1",p.startLabelRight="",p.startLabelLeft="",p.endLabelLeft="",p.endLabelRight="",p.arrowTypeStart="none",p.arrowTypeEnd="none",p.id=r+"-cyclic-special-mid",y.label="",y.startLabelRight="",y.startLabelLeft="",y.arrowTypeStart="none",a.isGroup&&(n.fromCluster=r,y.toCluster=r),y.id=r+"-cyclic-special-2",y.arrowTypeStart="none",g.setEdge(r,f,n,r+"-cyclic-special-0"),g.setEdge(f,h,p,r+"-cyclic-special-1"),g.setEdge(h,r,y,r+"-cyclic-special-2")}else g.setEdge(o.start,o.end,{...o},o.id)}),l.warn("Graph at first:",JSON.stringify(I(g))),J(g),l.warn("Graph after XAX:",JSON.stringify(I(g)));const c=_();await T(m,g,s.type,s.diagramId,void 0,c)},"render");export{ne as getEdgesToRender,le as render}; diff --git a/apps/kimi-code/dist-web/assets/diagram-WEI45ONY-aTjaDb2N.js b/apps/kimi-code/dist-web/assets/diagram-WEI45ONY-aTjaDb2N.js new file mode 100644 index 0000000000000000000000000000000000000000..60985cc42597b5581f30adf6218a7fbab681a1e9 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/diagram-WEI45ONY-aTjaDb2N.js @@ -0,0 +1,41 @@ +import{p as k}from"./chunk-JWPE2WC7-BT01S0dy.js";import{s as R,g as E,o as I,n as _,a as D,b as F,_ as c,D as P,p as z,A as y,y as C,B as G,l as B,E as W,e as V}from"./mermaid.core-CCxZmhet.js";import{p as H}from"./cynefin-VYW2F7L2-DZANU5FS.js";import"./index-Baap3_X9.js";import"./_commonjsHelpers-CqkleIqs.js";var m={showLegend:!0,ticks:5,max:null,min:0,graticule:"circle"},w={axes:[],curves:[],options:m},x=structuredClone(w),j=G.radar,N=c(()=>y({...j,...C().radar}),"getConfig"),b=c(()=>x.axes,"getAxes"),U=c(()=>x.curves,"getCurves"),X=c(()=>x.options,"getOptions"),Y=c(a=>{x.axes=a.map(t=>({name:t.name,label:t.label??t.name}))},"setAxes"),Z=c(a=>{x.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=b();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),{});x.options={showLegend:t.showLegend?.value??m.showLegend,ticks:t.ticks?.value??m.ticks,max:t.max?.value??m.max,min:t.min?.value??m.min,graticule:t.graticule?.value??m.graticule}},"setOptions"),K=c(()=>{z(),x=structuredClone(w)},"clear"),$={getAxes:b,getCurves:U,getOptions:X,setAxes:Y,setCurves:Z,setOptions:J,getConfig:N,clear:K,setAccTitle:F,getAccTitle:D,setDiagramTitle:_,getDiagramTitle:I,getAccDescription:E,setAccDescription:R},Q=c(a=>{k(a,$);const{axes:t,curves:e,options:r}=a;$.setAxes(t),$.setCurves(e),$.setOptions(r)},"populate"),tt={parse:c(async a=>{const t=await H("radar",a);B.debug(t),Q(t)},"parse")},et=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=P(t),u=at(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;rt(u,i,v,n.ticks,n.graticule),st(u,i,v,o),A(u,i,l,h,g,n.graticule,o),T(u,l,n.showLegend,o),u.append("text").attr("class","radarTitle").text(d).attr("x",0).attr("y",-o.height/2-o.marginTop)},"draw"),at=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 V(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"),rt=c((a,t,e,r,s)=>{if(s==="circle")for(let i=0;i{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"),st=c((a,t,e,r)=>{const s=t.length;for(let i=0;i.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 A(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=M(g,r,s,o),S=f*Math.cos(v),O=f*Math.sin(v);return{x:S,y:O}});i==="circle"?a.append("path").attr("d",L(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(A,"drawCurves");function M(a,t,e,r){const s=Math.min(Math.max(a,t),e);return r*(s-t)/(e-t)}c(M,"relativeRadius");function L(a,t){const e=a.length;let r=`M${a[0].x},${a[0].y}`;for(let s=0;s{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(T,"drawLegend");var nt={draw:et},ot=c((a,t)=>{let e="";for(let r=0;r{const t=W(),e=C(),r=y(t,e.themeVariables),s=y(r.radar,a);return{themeVariables:r,radarOptions:s}},"buildRadarStyleOptions"),lt=c(({radar:a}={})=>{const{themeVariables:t,radarOptions:e}=it(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; + } + ${ot(t,e)} + `},"styles"),xt={parser:tt,db:$,renderer:nt,styles:lt};export{xt as diagram}; diff --git a/apps/kimi-code/dist-web/assets/diagram-WEI45ONY-fzoSDldI.js b/apps/kimi-code/dist-web/assets/diagram-WEI45ONY-fzoSDldI.js new file mode 100644 index 0000000000000000000000000000000000000000..d81bb9cbbfc053583a56a158cedc862e9fd95121 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/diagram-WEI45ONY-fzoSDldI.js @@ -0,0 +1,41 @@ +import{p as k}from"./chunk-JWPE2WC7-K16PVern.js";import{s as R,g as E,o as I,n as _,a as D,b as F,_ as c,D as P,p as z,A as y,y as C,B as G,l as B,E as W,e as V}from"./mermaidParser.worker-BFSlSHEW.js";import{p as H}from"./cynefin-VYW2F7L2-C-EfYT07.js";var h={showLegend:!0,ticks:5,max:null,min:0,graticule:"circle"},w={axes:[],curves:[],options:h},x=structuredClone(w),j=G.radar,N=c(()=>y({...j,...C().radar}),"getConfig"),b=c(()=>x.axes,"getAxes"),U=c(()=>x.curves,"getCurves"),X=c(()=>x.options,"getOptions"),Y=c(a=>{x.axes=a.map(t=>({name:t.name,label:t.label??t.name}))},"setAxes"),Z=c(a=>{x.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=b();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),{});x.options={showLegend:t.showLegend?.value??h.showLegend,ticks:t.ticks?.value??h.ticks,max:t.max?.value??h.max,min:t.min?.value??h.min,graticule:t.graticule?.value??h.graticule}},"setOptions"),K=c(()=>{z(),x=structuredClone(w)},"clear"),$={getAxes:b,getCurves:U,getOptions:X,setAxes:Y,setCurves:Z,setOptions:J,getConfig:N,clear:K,setAccTitle:F,getAccTitle:D,setDiagramTitle:_,getDiagramTitle:I,getAccDescription:E,setAccDescription:R},Q=c(a=>{k(a,$);const{axes:t,curves:e,options:r}=a;$.setAxes(t),$.setCurves(e),$.setOptions(r)},"populate"),tt={parse:c(async a=>{const t=await H("radar",a);B.debug(t),Q(t)},"parse")},et=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=P(t),u=at(p,o),g=n.max??Math.max(...l.map(f=>Math.max(...f.entries))),m=n.min,v=Math.min(o.width,o.height)/2;rt(u,i,v,n.ticks,n.graticule),st(u,i,v,o),A(u,i,l,m,g,n.graticule,o),T(u,l,n.showLegend,o),u.append("text").attr("class","radarTitle").text(d).attr("x",0).attr("y",-o.height/2-o.marginTop)},"draw"),at=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 V(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"),rt=c((a,t,e,r,s)=>{if(s==="circle")for(let i=0;i{const u=2*p*Math.PI/i-Math.PI/2,g=n*Math.cos(u),m=n*Math.sin(u);return`${g},${m}`}).join(" ");a.append("polygon").attr("points",o).attr("class","radarGraticule")}}},"drawGraticule"),st=c((a,t,e,r)=>{const s=t.length;for(let i=0;i.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 A(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,m)=>{const v=2*Math.PI*m/n-Math.PI/2,f=M(g,r,s,o),S=f*Math.cos(v),O=f*Math.sin(v);return{x:S,y:O}});i==="circle"?a.append("path").attr("d",L(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(A,"drawCurves");function M(a,t,e,r){const s=Math.min(Math.max(a,t),e);return r*(s-t)/(e-t)}c(M,"relativeRadius");function L(a,t){const e=a.length;let r=`M${a[0].x},${a[0].y}`;for(let s=0;s{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(T,"drawLegend");var nt={draw:et},ot=c((a,t)=>{let e="";for(let r=0;r{const t=W(),e=C(),r=y(t,e.themeVariables),s=y(r.radar,a);return{themeVariables:r,radarOptions:s}},"buildRadarStyleOptions"),lt=c(({radar:a}={})=>{const{themeVariables:t,radarOptions:e}=it(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; + } + ${ot(t,e)} + `},"styles"),pt={parser:tt,db:$,renderer:nt,styles:lt};export{pt as diagram}; diff --git a/apps/kimi-code/dist-web/assets/edge-FbVlp4U3.js b/apps/kimi-code/dist-web/assets/edge-FbVlp4U3.js new file mode 100644 index 0000000000000000000000000000000000000000..d056744f18e398e7b18c4b3cbce5f08a1051bfc9 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/edge-FbVlp4U3.js @@ -0,0 +1 @@ +import e from"./typescript-BPQ3VLAy.js";import t from"./html-pp8916En.js";import n from"./html-derivative-DlHx6ybY.js";import"./javascript-wDzz0qaB.js";import"./css-CLj8gQPS.js";const a=Object.freeze(JSON.parse('{"displayName":"Edge","injections":{"text.html.edge - (meta.embedded | meta.tag | comment.block.edge), L:(text.html.edge meta.tag - (comment.block.edge | meta.embedded.block.edge)), L:(source.ts.embedded.html - (comment.block.edge | meta.embedded.block.edge))":{"patterns":[{"include":"#comment"},{"include":"#escapedMustache"},{"include":"#safeMustache"},{"include":"#mustache"},{"include":"#nonSeekableTag"},{"include":"#tag"}]}},"name":"edge","patterns":[{"include":"text.html.basic"},{"include":"text.html.derivative"}],"repository":{"comment":{"begin":"\\\\{\\\\{--","beginCaptures":{"0":{"name":"punctuation.definition.comment.begin.edge"}},"end":"--}}","endCaptures":{"0":{"name":"punctuation.definition.comment.end.edge"}},"name":"comment.block"},"escapedMustache":{"begin":"@\\\\{\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.comment.begin.edge"}},"end":"}}","endCaptures":{"0":{"name":"punctuation.definition.comment.end.edge"}},"name":"comment.block"},"mustache":{"begin":"\\\\{\\\\{","beginCaptures":{"0":{"name":"punctuation.mustache.begin"}},"end":"}}","endCaptures":{"0":{"name":"punctuation.mustache.end"}},"name":"meta.embedded.block.javascript","patterns":[{"include":"source.ts#expression"}]},"nonSeekableTag":{"captures":{"2":{"name":"support.function.edge"}},"match":"^(\\\\s*)((@{1,2})(!)?([.A-Z_a-z]+))(~)?$","name":"meta.embedded.block.javascript","patterns":[{"include":"source.ts#expression"}]},"safeMustache":{"begin":"\\\\{\\\\{\\\\{","beginCaptures":{"0":{"name":"punctuation.mustache.begin"}},"end":"}}}","endCaptures":{"0":{"name":"punctuation.mustache.end"}},"name":"meta.embedded.block.javascript","patterns":[{"include":"source.ts#expression"}]},"tag":{"begin":"^(\\\\s*)((@{1,2})(!)?([.A-Z_a-z]+)(\\\\s{0,2}))(\\\\()","beginCaptures":{"2":{"name":"support.function.edge"},"7":{"name":"punctuation.paren.open"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.paren.close"}},"name":"meta.embedded.block.javascript","patterns":[{"include":"source.ts#expression"}]}},"scopeName":"text.html.edge","embeddedLangs":["typescript","html","html-derivative"]}')),o=[...e,...t,...n,a];export{o as default}; diff --git a/apps/kimi-code/dist-web/assets/elm-DbKCFpqz.js b/apps/kimi-code/dist-web/assets/elm-DbKCFpqz.js new file mode 100644 index 0000000000000000000000000000000000000000..744c1db2ae522587321f3a39fd4093a71705a84c --- /dev/null +++ b/apps/kimi-code/dist-web/assets/elm-DbKCFpqz.js @@ -0,0 +1 @@ +import e from"./glsl-DplSGwfg.js";import"./c-BIGW1oBm.js";const a=Object.freeze(JSON.parse(`{"displayName":"Elm","fileTypes":["elm"],"name":"elm","patterns":[{"include":"#import"},{"include":"#module"},{"include":"#debug"},{"include":"#comments"},{"match":"\\\\b(_)\\\\b","name":"keyword.unused.elm"},{"include":"#type-signature"},{"include":"#type-declaration"},{"include":"#type-alias-declaration"},{"include":"#string-triple"},{"include":"#string-quote"},{"include":"#char"},{"match":"\\\\b([0-9]+\\\\.[0-9]+([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)\\\\b","name":"constant.numeric.float.elm"},{"match":"\\\\b([0-9]+)\\\\b","name":"constant.numeric.elm"},{"match":"\\\\b(0x\\\\h+)\\\\b","name":"constant.numeric.elm"},{"include":"#glsl"},{"include":"#record-prefix"},{"include":"#module-prefix"},{"include":"#constructor"},{"captures":{"1":{"name":"punctuation.bracket.elm"},"2":{"name":"record.name.elm"},"3":{"name":"keyword.pipe.elm"},"4":{"name":"entity.name.record.field.elm"}},"match":"(\\\\{)\\\\s+([a-z][0-9A-Z_a-z]*)\\\\s+(\\\\|)\\\\s+([a-z][0-9A-Z_a-z]*)","name":"meta.record.field.update.elm"},{"captures":{"1":{"name":"keyword.pipe.elm"},"2":{"name":"entity.name.record.field.elm"},"3":{"name":"keyword.operator.assignment.elm"}},"match":"(\\\\|)\\\\s+([a-z][0-9A-Z_a-z]*)\\\\s+(=)","name":"meta.record.field.update.elm"},{"captures":{"1":{"name":"punctuation.bracket.elm"},"2":{"name":"record.name.elm"}},"match":"(\\\\{)\\\\s+([a-z][0-9A-Z_a-z]*)\\\\s+$","name":"meta.record.field.update.elm"},{"captures":{"1":{"name":"punctuation.bracket.elm"},"2":{"name":"entity.name.record.field.elm"},"3":{"name":"keyword.operator.assignment.elm"}},"match":"(\\\\{)\\\\s+([a-z][0-9A-Z_a-z]*)\\\\s+(=)","name":"meta.record.field.elm"},{"captures":{"1":{"name":"punctuation.separator.comma.elm"},"2":{"name":"entity.name.record.field.elm"},"3":{"name":"keyword.operator.assignment.elm"}},"match":"(,)\\\\s+([a-z][0-9A-Z_a-z]*)\\\\s+(=)","name":"meta.record.field.elm"},{"match":"([{}])","name":"punctuation.bracket.elm"},{"include":"#unit"},{"include":"#comma"},{"include":"#parens"},{"match":"(->)","name":"keyword.operator.arrow.elm"},{"include":"#infix_op"},{"match":"([:=\\\\\\\\|])","name":"keyword.other.elm"},{"match":"\\\\b(type|as|port|exposing|alias|infixl|infixr?)\\\\s+","name":"keyword.other.elm"},{"match":"\\\\b(if|then|else|case|of|let|in)\\\\s+","name":"keyword.control.elm"},{"include":"#record-accessor"},{"include":"#top_level_value"},{"include":"#value"},{"include":"#period"},{"include":"#square_brackets"}],"repository":{"block_comment":{"applyEndPatternLast":1,"begin":"\\\\{-(?!#)","captures":{"0":{"name":"punctuation.definition.comment.elm"}},"end":"-}","name":"comment.block.elm","patterns":[{"include":"#block_comment"}]},"char":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.char.begin.elm"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.char.end.elm"}},"name":"string.quoted.single.elm","patterns":[{"match":"\\\\\\\\(NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|[\\"\\\\&'\\\\\\\\abfnrtv]|x\\\\h{1,5})","name":"constant.character.escape.elm"},{"match":"\\\\^[@-_]","name":"constant.character.escape.control.elm"}]},"comma":{"match":"(,)","name":"punctuation.separator.comma.elm"},"comments":{"patterns":[{"begin":"--","captures":{"1":{"name":"punctuation.definition.comment.elm"}},"end":"$","name":"comment.line.double-dash.elm"},{"include":"#block_comment"}]},"constructor":{"match":"\\\\b[A-Z][0-9A-Z_a-z]*\\\\b","name":"constant.type-constructor.elm"},"debug":{"match":"\\\\b(Debug)\\\\b","name":"invalid.illegal.debug.elm"},"glsl":{"begin":"(\\\\[)(glsl)(\\\\|)","beginCaptures":{"1":{"name":"entity.glsl.bracket.elm"},"2":{"name":"entity.glsl.name.elm"},"3":{"name":"entity.glsl.bracket.elm"}},"end":"(\\\\|])","endCaptures":{"1":{"name":"entity.glsl.bracket.elm"}},"name":"meta.embedded.block.glsl","patterns":[{"include":"source.glsl"}]},"import":{"begin":"^\\\\b(import)\\\\s+","beginCaptures":{"1":{"name":"keyword.control.import.elm"}},"end":"\\\\n(?!\\\\s)","name":"meta.import.elm","patterns":[{"match":"(as|exposing)","name":"keyword.control.elm"},{"include":"#module_chunk"},{"include":"#period"},{"match":"\\\\s+","name":"punctuation.spaces.elm"},{"include":"#module-exports"}]},"infix_op":{"match":"(|<\\\\?>|<\\\\||<=|\\\\|\\\\||&&|>=|\\\\|>|\\\\|=|\\\\|\\\\.|\\\\+\\\\+|::|/=|==|//|>>|<<|[-*+/<>^])","name":"keyword.operator.elm"},"module":{"begin":"^\\\\b((port |effect )?module)\\\\s+","beginCaptures":{"1":{"name":"keyword.other.elm"}},"end":"\\\\n(?!\\\\s)","endCaptures":{"1":{"name":"keyword.other.elm"}},"name":"meta.declaration.module.elm","patterns":[{"include":"#module_chunk"},{"include":"#period"},{"match":"(exposing)","name":"keyword.other.elm"},{"match":"\\\\s+","name":"punctuation.spaces.elm"},{"include":"#module-exports"}]},"module-exports":{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.parens.module-export.elm"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.parens.module-export.elm"}},"name":"meta.declaration.exports.elm","patterns":[{"match":"\\\\b[a-z]['0-9A-Z_a-z]*","name":"entity.name.function.elm"},{"match":"\\\\b[A-Z]['0-9A-Z_a-z]*","name":"storage.type.elm"},{"match":",","name":"punctuation.separator.comma.elm"},{"match":"\\\\s+","name":"punctuation.spaces.elm"},{"include":"#comma"},{"match":"\\\\(\\\\.\\\\.\\\\)","name":"punctuation.parens.ellipses.elm"},{"match":"\\\\.\\\\.","name":"punctuation.parens.ellipses.elm"},{"include":"#infix_op"},{"match":"\\\\(.*?\\\\)","name":"meta.other.unknown.elm"}]},"module-prefix":{"captures":{"1":{"name":"support.module.elm"},"2":{"name":"keyword.other.period.elm"}},"match":"([A-Z][0-9A-Z_a-z]*)(\\\\.)","name":"meta.module.name.elm"},"module_chunk":{"match":"[A-Z][0-9A-Z_a-z]*","name":"support.module.elm"},"parens":{"match":"([()])","name":"punctuation.parens.elm"},"period":{"match":"\\\\.","name":"keyword.other.period.elm"},"record-accessor":{"captures":{"1":{"name":"keyword.other.period.elm"},"2":{"name":"entity.name.record.field.accessor.elm"}},"match":"(\\\\.)([a-z][0-9A-Z_a-z]*)","name":"meta.record.accessor"},"record-prefix":{"captures":{"1":{"name":"record.name.elm"},"2":{"name":"keyword.other.period.elm"},"3":{"name":"entity.name.record.field.accessor.elm"}},"match":"([a-z][0-9A-Z_a-z]*)(\\\\.)([a-z][0-9A-Z_a-z]*)","name":"record.accessor.elm"},"square_brackets":{"match":"[]\\\\[]","name":"punctuation.definition.list.elm"},"string-quote":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.elm"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.elm"}},"name":"string.quoted.double.elm","patterns":[{"match":"\\\\\\\\(NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|[\\"\\\\&'\\\\\\\\abfnrtv]|x\\\\h{1,5})","name":"constant.character.escape.elm"},{"match":"\\\\^[@-_]","name":"constant.character.escape.control.elm"}]},"string-triple":{"begin":"\\"\\"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.elm"}},"end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.elm"}},"name":"string.quoted.triple.elm","patterns":[{"match":"\\\\\\\\(NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC1|DC2|DC3|DC4|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL|[\\"\\\\&'\\\\\\\\abfnrtv]|x\\\\h{1,5})","name":"constant.character.escape.elm"},{"match":"\\\\^[@-_]","name":"constant.character.escape.control.elm"}]},"top_level_value":{"match":"^[a-z][0-9A-Z_a-z]*\\\\b","name":"entity.name.function.top_level.elm"},"type-alias-declaration":{"begin":"^(type\\\\s+)(alias\\\\s+)([A-Z]['0-9A-Z_a-z]*)\\\\s+","beginCaptures":{"1":{"name":"keyword.type.elm"},"2":{"name":"keyword.type-alias.elm"},"3":{"name":"storage.type.elm"}},"end":"^(?=\\\\S)","name":"meta.function.type-declaration.elm","patterns":[{"match":"\\\\n\\\\s+","name":"punctuation.spaces.elm"},{"match":"=","name":"keyword.operator.assignment.elm"},{"include":"#module-prefix"},{"match":"\\\\b[A-Z][0-9A-Z_a-z]*\\\\b","name":"storage.type.elm"},{"match":"\\\\b[a-z][0-9A-Z_a-z]*\\\\b","name":"variable.type.elm"},{"include":"#comments"},{"include":"#type-record"}]},"type-declaration":{"begin":"^(type\\\\s+)([A-Z]['0-9A-Z_a-z]*)\\\\s+","beginCaptures":{"1":{"name":"keyword.type.elm"},"2":{"name":"storage.type.elm"}},"end":"^(?=\\\\S)","name":"meta.function.type-declaration.elm","patterns":[{"captures":{"1":{"name":"constant.type-constructor.elm"}},"match":"^\\\\s*([A-Z][0-9A-Z_a-z]*)\\\\b","name":"meta.record.field.elm"},{"match":"\\\\s+","name":"punctuation.spaces.elm"},{"captures":{"1":{"name":"keyword.operator.assignment.elm"},"2":{"name":"constant.type-constructor.elm"}},"match":"([=|])\\\\s+([A-Z][0-9A-Z_a-z]*)\\\\b","name":"meta.record.field.elm"},{"match":"=","name":"keyword.operator.assignment.elm"},{"match":"->","name":"keyword.operator.arrow.elm"},{"include":"#module-prefix"},{"match":"\\\\b[a-z][0-9A-Z_a-z]*\\\\b","name":"variable.type.elm"},{"match":"\\\\b[A-Z][0-9A-Z_a-z]*\\\\b","name":"storage.type.elm"},{"include":"#comments"},{"include":"#type-record"}]},"type-record":{"begin":"(\\\\{)","beginCaptures":{"1":{"name":"punctuation.section.braces.begin"}},"end":"(})","endCaptures":{"1":{"name":"punctuation.section.braces.end"}},"name":"meta.function.type-record.elm","patterns":[{"match":"\\\\s+","name":"punctuation.spaces.elm"},{"match":"->","name":"keyword.operator.arrow.elm"},{"captures":{"1":{"name":"entity.name.record.field.elm"},"2":{"name":"keyword.other.elm"}},"match":"([a-z][0-9A-Z_a-z]*)\\\\s+(:)","name":"meta.record.field.elm"},{"match":",","name":"punctuation.separator.comma.elm"},{"include":"#module-prefix"},{"match":"\\\\b[a-z][0-9A-Z_a-z]*\\\\b","name":"variable.type.elm"},{"match":"\\\\b[A-Z][0-9A-Z_a-z]*\\\\b","name":"storage.type.elm"},{"include":"#comments"},{"include":"#type-record"}]},"type-signature":{"begin":"^(port\\\\s+)?([_a-z]['0-9A-Z_a-z]*)\\\\s+(:)","beginCaptures":{"1":{"name":"keyword.other.port.elm"},"2":{"name":"entity.name.function.elm"},"3":{"name":"keyword.other.colon.elm"}},"end":"^(((?=[a-z]))|$)","name":"meta.function.type-declaration.elm","patterns":[{"include":"#type-signature-chunk"}]},"type-signature-chunk":{"patterns":[{"match":"->","name":"keyword.operator.arrow.elm"},{"match":"\\\\s+","name":"punctuation.spaces.elm"},{"include":"#module-prefix"},{"match":"\\\\b[a-z][0-9A-Z_a-z]*\\\\b","name":"variable.type.elm"},{"match":"\\\\b[A-Z][0-9A-Z_a-z]*\\\\b","name":"storage.type.elm"},{"match":"\\\\(\\\\)","name":"constant.unit.elm"},{"include":"#comma"},{"include":"#parens"},{"include":"#comments"},{"include":"#type-record"}]},"unit":{"match":"\\\\(\\\\)","name":"constant.unit.elm"},"value":{"match":"\\\\b[a-z][0-9A-Z_a-z]*\\\\b","name":"meta.value.elm"}},"scopeName":"source.elm","embeddedLangs":["glsl"]}`)),m=[...e,a];export{m as default}; diff --git a/apps/kimi-code/dist-web/assets/fluent-C4IJs8-o.js b/apps/kimi-code/dist-web/assets/fluent-C4IJs8-o.js new file mode 100644 index 0000000000000000000000000000000000000000..74b54740ab9a58d06789ebba152009109c79b3b1 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/fluent-C4IJs8-o.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"displayName":"Fluent","name":"fluent","patterns":[{"include":"#comment"},{"include":"#message"},{"include":"#wrong-line"}],"repository":{"attributes":{"begin":"\\\\s*(\\\\.[A-Za-z][-0-9A-Z_a-z]*\\\\s*=\\\\s*)","beginCaptures":{"1":{"name":"support.class.attribute-begin.fluent"}},"end":"^(?=\\\\s*[^.])","patterns":[{"include":"#placeable"}]},"comment":{"match":"^##?#?\\\\s.*$","name":"comment.fluent"},"function-comma":{"match":",","name":"support.function.function-comma.fluent"},"function-named-argument":{"begin":"([0-9A-Za-z]+:)\\\\s*([\\"0-9A-Za-z]+)","beginCaptures":{"1":{"name":"support.function.named-argument.name.fluent"},"2":{"name":"variable.other.named-argument.value.fluent"}},"end":"(?=[),\\\\s])","name":"variable.other.named-argument.fluent"},"function-positional-argument":{"match":"\\\\$[-0-9A-Z_a-z]+","name":"variable.other.function.positional-argument.fluent"},"invalid-placeable-string-missing-end-quote":{"match":"\\"[^\\"]+$","name":"invalid.illegal.wrong-placeable-missing-end-quote.fluent"},"invalid-placeable-wrong-placeable-missing-end":{"match":"([^A-Z}]*|[^-][^>])$\\\\b","name":"invalid.illegal.wrong-placeable-missing-end.fluent"},"message":{"begin":"^(-?[A-Za-z][-0-9A-Z_a-z]*\\\\s*=\\\\s*)","beginCaptures":{"1":{"name":"support.class.message-identifier.fluent"}},"contentName":"string.fluent","end":"^(?=\\\\S)","patterns":[{"include":"#attributes"},{"include":"#placeable"}]},"placeable":{"begin":"(\\\\{)","beginCaptures":{"1":{"name":"keyword.placeable.begin.fluent"}},"contentName":"variable.other.placeable.content.fluent","end":"(})","endCaptures":{"1":{"name":"keyword.placeable.end.fluent"}},"patterns":[{"include":"#placeable-string"},{"include":"#placeable-function"},{"include":"#placeable-reference-or-number"},{"include":"#selector"},{"include":"#invalid-placeable-wrong-placeable-missing-end"},{"include":"#invalid-placeable-string-missing-end-quote"},{"include":"#invalid-placeable-wrong-function-name"}]},"placeable-function":{"begin":"([A-Z][-0-9A-Z_]*\\\\()","beginCaptures":{"1":{"name":"support.function.placeable-function.call.begin.fluent"}},"contentName":"string.placeable-function.fluent","end":"(\\\\))","endCaptures":{"1":{"name":"support.function.placeable-function.call.end.fluent"}},"patterns":[{"include":"#function-comma"},{"include":"#function-positional-argument"},{"include":"#function-named-argument"}]},"placeable-reference-or-number":{"match":"(([-$])[-0-9A-Z_a-z]+|[A-Za-z][-0-9A-Z_a-z]*|[0-9]+)","name":"variable.other.placeable.reference-or-number.fluent"},"placeable-string":{"begin":"(\\")(?=[^\\\\n]*\\")","beginCaptures":{"1":{"name":"variable.other.placeable-string-begin.fluent"}},"contentName":"string.placeable-string-content.fluent","end":"(\\")","endCaptures":{"1":{"name":"variable.other.placeable-string-end.fluent"}}},"selector":{"begin":"(->)","beginCaptures":{"1":{"name":"support.function.selector.begin.fluent"}},"contentName":"string.selector.content.fluent","end":"^(?=\\\\s*})","patterns":[{"include":"#selector-item"}]},"selector-item":{"begin":"(\\\\s*\\\\*?\\\\[)([-0-9A-Z_a-z]+)(]\\\\s*)","beginCaptures":{"1":{"name":"support.function.selector-item.begin.fluent"},"2":{"name":"variable.other.selector-item.begin.fluent"},"3":{"name":"support.function.selector-item.begin.fluent"}},"contentName":"string.selector-item.content.fluent","end":"^(?=(\\\\s*})|(\\\\s*\\\\[)|(\\\\s*\\\\*))","patterns":[{"include":"#placeable"}]},"wrong-line":{"match":".*","name":"invalid.illegal.wrong-line.fluent"}},"scopeName":"source.ftl","aliases":["ftl"]}')),n=[e];export{n as default}; diff --git a/apps/kimi-code/dist-web/assets/fortran-free-form-BxgE0vQu.js b/apps/kimi-code/dist-web/assets/fortran-free-form-BxgE0vQu.js new file mode 100644 index 0000000000000000000000000000000000000000..86d1d4aa9a1d81685c347ef7d8e78e66f886c087 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/fortran-free-form-BxgE0vQu.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"Fortran (Free Form)","fileTypes":["f90","F90","f95","F95","f03","F03","f08","F08","f18","F18","fpp","FPP",".pf",".PF"],"firstLineMatch":"(?i)-\\\\*- mode: fortran free -\\\\*-","injections":{"source.fortran.free - ( string | comment | meta.preprocessor )":{"patterns":[{"include":"#line-continuation-operator"},{"include":"#preprocessor"}]},"string.quoted.double.fortran":{"patterns":[{"include":"#string-line-continuation-operator"}]},"string.quoted.single.fortran":{"patterns":[{"include":"#string-line-continuation-operator"}]}},"name":"fortran-free-form","patterns":[{"include":"#preprocessor"},{"include":"#comments"},{"include":"#constants"},{"include":"#operators"},{"include":"#array-constructor"},{"include":"#parentheses"},{"include":"#include-statement"},{"include":"#import-statement"},{"include":"#block-data-definition"},{"include":"#function-definition"},{"include":"#module-definition"},{"include":"#program-definition"},{"include":"#submodule-definition"},{"include":"#subroutine-definition"},{"include":"#procedure-definition"},{"include":"#derived-type-definition"},{"include":"#enum-block-construct"},{"include":"#interface-block-constructs"},{"include":"#procedure-specification-statement"},{"include":"#type-specification-statements"},{"include":"#specification-statements"},{"include":"#control-constructs"},{"include":"#control-statements"},{"include":"#execution-statements"},{"include":"#intrinsic-functions"},{"include":"#variable"}],"repository":{"IO-item-list":{"begin":"(?i)(?=\\\\s*[\\"'0-9a-z])","contentName":"meta.name-list.fortran","end":"(?=[\\\\n!);])","patterns":[{"include":"#constants"},{"include":"#operators"},{"include":"#intrinsic-functions"},{"include":"#array-constructor"},{"include":"#parentheses"},{"include":"#brackets"},{"include":"#assignment-keyword"},{"include":"#operator-keyword"},{"include":"#variable"}]},"IO-keywords":{"begin":"(?i)\\\\G\\\\s*\\\\b(?:(read)|(write))\\\\s*(\\\\()","beginCaptures":{"1":{"name":"keyword.control.generic-spec.read.fortran"},"2":{"name":"keyword.control.generic-spec.write.fortran"},"3":{"name":"punctuation.parentheses.left.fortran"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.parentheses.right.fortran"}},"patterns":[{"captures":{"1":{"name":"keyword.control.generic-spec.formatted.fortran"},"2":{"name":"keyword.control.generic-spec.unformatted.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(?:(formatted)|(unformatted))\\\\b"},{"include":"#invalid-word"}]},"IO-statements":{"patterns":[{"begin":"(?i)\\\\b(format)(?=\\\\s*[!\\\\&(])","beginCaptures":{"1":{"name":"keyword.control.format.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.IO.fortran","patterns":[{"include":"#comments"},{"include":"#line-continuation-operator"},{"include":"#format-parentheses"}]},{"begin":"(?i)\\\\b(?:(backspace)|(close)|(endfile)|(inquire)|(open)|(read)|(rewind)|(write))\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"keyword.control.backspace.fortran"},"2":{"name":"keyword.control.close.fortran"},"3":{"name":"keyword.control.endfile.fortran"},"4":{"name":"keyword.control.inquire.fortran"},"5":{"name":"keyword.control.open.fortran"},"6":{"name":"keyword.control.read.fortran"},"7":{"name":"keyword.control.rewind.fortran"},"8":{"name":"keyword.control.write.fortran"},"9":{"name":"punctuation.parentheses.left.fortran"}},"end":"(?=[\\\\n!;])","endCaptures":{"1":{"name":"punctuation.parentheses.right.fortran"}},"name":"meta.statement.IO.fortran","patterns":[{"include":"#parentheses-dummy-variables"},{"include":"#IO-item-list"}]},{"captures":{"1":{"name":"keyword.control.backspace.fortran"},"2":{"name":"keyword.control.endfile.fortran"},"3":{"name":"keyword.control.format.fortran"},"4":{"name":"keyword.control.print.fortran"},"5":{"name":"keyword.control.read.fortran"},"6":{"name":"keyword.control.rewind.fortran"}},"match":"(?i)\\\\b(?:(backspace)|(endfile)|(format)|(print)|(read)|(rewind))\\\\b"},{"begin":"(?i)\\\\b(?:(flush)|(wait))\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"keyword.control.flush.fortran"},"2":{"name":"keyword.control.wait.fortran"},"3":{"name":"punctuation.parentheses.left.fortran"}},"end":"(?])(=)(?![=>])","name":"keyword.operator.assignment.fortran"},"associate-construct":{"begin":"(?i)\\\\b(associate)\\\\b(?=\\\\s*\\\\()","beginCaptures":{"1":{"name":"keyword.control.associate.fortran"}},"contentName":"meta.block.associate.fortran","end":"(?i)\\\\b(end\\\\s*associate)\\\\b","endCaptures":{"1":{"name":"keyword.control.endassociate.fortran"}},"patterns":[{"include":"$base"}]},"asynchronous-attribute":{"captures":{"1":{"name":"storage.modifier.asynchronous.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(asynchronous)\\\\b"},"attribute-specification-statement":{"begin":"(?i)(?=\\\\b(?:allocatable|asynchronous|contiguous|external|intrinsic|optional|parameter|pointer|private|protected|public|save|target|value|volatile)\\\\b|(bind|dimension|intent)\\\\s*\\\\(|(codimension)\\\\s*\\\\[)","end":"(?=[\\\\n!;])","name":"meta.statement.attribute-specification.fortran","patterns":[{"include":"#access-attribute"},{"include":"#allocatable-attribute"},{"include":"#asynchronous-attribute"},{"include":"#codimension-attribute"},{"include":"#contiguous-attribute"},{"include":"#dimension-attribute"},{"include":"#external-attribute"},{"include":"#intent-attribute"},{"include":"#intrinsic-attribute"},{"include":"#language-binding-attribute"},{"include":"#optional-attribute"},{"include":"#parameter-attribute"},{"include":"#pointer-attribute"},{"include":"#protected-attribute"},{"include":"#save-attribute"},{"include":"#target-attribute"},{"include":"#value-attribute"},{"include":"#volatile-attribute"},{"begin":"(?=\\\\s*::)","contentName":"meta.attribute-list.normal.fortran","end":"(::)|(?=[\\\\n!;])","endCaptures":{"1":{"name":"keyword.operator.double-colon.fortran"}},"patterns":[{"include":"#invalid-word"}]},{"include":"#name-list"}]},"block-construct":{"begin":"(?i)\\\\b(block)\\\\b(?!\\\\s*\\\\bdata\\\\b)","beginCaptures":{"1":{"name":"keyword.control.associate.fortran"}},"contentName":"meta.block.block.fortran","end":"(?i)\\\\b(end\\\\s*block)\\\\b","endCaptures":{"1":{"name":"keyword.control.endassociate.fortran"}},"patterns":[{"include":"$base"}]},"block-data-definition":{"begin":"(?i)\\\\b(block\\\\s*data)\\\\b(?:\\\\s+([a-z]\\\\w*)\\\\b)?","beginCaptures":{"1":{"name":"keyword.control.block-data.fortran"},"2":{"name":"entity.name.block-data.fortran"}},"end":"(?i)\\\\b(?:(end\\\\s*block\\\\s*data)(?:\\\\s+(\\\\2))?|(end))\\\\b(?:\\\\s*(\\\\S((?!\\\\n).)*))?","endCaptures":{"1":{"name":"keyword.control.end-block-data.fortran"},"2":{"name":"entity.name.block-data.fortran"},"3":{"name":"keyword.control.end-block-data.fortran"},"4":{"name":"invalid.error.block-data-definition.fortran"}},"name":"meta.block-data.fortran","patterns":[{"include":"$base"}]},"brackets":{"begin":"\\\\s*(\\\\[)","beginCaptures":{"1":{"name":"punctuation.bracket.left.fortran"}},"end":"(])","endCaptures":{"1":{"name":"punctuation.bracket.left.fortran"}},"patterns":[{"include":"#comments"},{"include":"#constants"},{"include":"#operators"},{"include":"#array-constructor"},{"include":"#parentheses"},{"include":"#intrinsic-functions"},{"include":"#variable"}]},"call-statement":{"patterns":[{"applyEndPatternLast":1,"begin":"(?i)\\\\s*\\\\b(call)\\\\b","beginCaptures":{"1":{"name":"keyword.control.call.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.control.call.fortran","patterns":[{"begin":"(?i)(?=\\\\s*[a-z]\\\\w*\\\\s*%)","end":"(?=[\\\\n!;])","patterns":[{"include":"#comments"},{"include":"#line-continuation-operator"},{"captures":{"1":{"name":"variable.other.fortran"},"2":{"name":"keyword.accessor.fortran"}},"match":"(?i)\\\\s*([a-z]\\\\w*)\\\\s*(%)"},{"captures":{"1":{"name":"entity.name.function.subroutine.fortran"}},"match":"(?i)\\\\s*([a-z]\\\\w*)"},{"include":"#parentheses-dummy-variables"}]},{"include":"#intrinsic-subroutines"},{"begin":"(?i)\\\\G\\\\s*\\\\b([a-z]\\\\w*)\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"entity.name.function.subroutine.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"end":"(?=|[<>]|<=|[-+/]|//|\\\\*\\\\*?)|(\\\\S.*))\\\\s*(\\\\))","beginCaptures":{"1":{"name":"keyword.other.operator.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"},"3":{"name":"keyword.operator.fortran"},"4":{"name":"invalid.error.generic-interface-block-op.fortran"},"5":{"name":"punctuation.parentheses.right.fortran"}},"end":"(?i)\\\\b(end\\\\s*interface)\\\\b(?:\\\\s*\\\\b(\\\\1)\\\\b\\\\s*(\\\\()\\\\s*(?:(\\\\3)|(\\\\S.*))\\\\s*(\\\\)))?","endCaptures":{"1":{"name":"keyword.control.endinterface.fortran"},"2":{"name":"keyword.other.operator.fortran"},"3":{"name":"punctuation.parentheses.left.fortran"},"4":{"name":"keyword.operator.fortran"},"5":{"name":"invalid.error.generic-interface-block-op-end.fortran"},"6":{"name":"punctuation.parentheses.right.fortran"}},"patterns":[{"include":"#interface-procedure-statement"},{"include":"$base"}]},{"begin":"(?i)\\\\G\\\\s*\\\\b(?:(read)|(write))\\\\s*(\\\\()\\\\s*(?:(formatted)|(unformatted)|(\\\\S.*))\\\\s*(\\\\))","beginCaptures":{"1":{"name":"keyword.other.read.fortran"},"2":{"name":"keyword.other.write.fortran"},"3":{"name":"punctuation.parentheses.left.fortran"},"4":{"name":"keyword.other.formatted.fortran"},"5":{"name":"keyword.other.unformatted.fortran"},"6":{"name":"invalid.error.generic-interface-block.fortran"},"7":{"name":"punctuation.parentheses.right.fortran"}},"end":"(?i)\\\\b(end\\\\s*interface)\\\\b(?:\\\\s*\\\\b(?:(\\\\2)|(\\\\3))\\\\b\\\\s*(\\\\()\\\\s*(?:(\\\\4)|(\\\\5)|(\\\\S.*))\\\\s*(\\\\)))?","endCaptures":{"1":{"name":"keyword.control.endinterface.fortran"},"2":{"name":"keyword.other.read.fortran"},"3":{"name":"keyword.other.write.fortran"},"4":{"name":"punctuation.parentheses.left.fortran"},"5":{"name":"keyword.other.formatted.fortran"},"6":{"name":"keyword.other.unformatted.fortran"},"7":{"name":"invalid.error.generic-interface-block-end.fortran"},"8":{"name":"punctuation.parentheses.right.fortran"}},"patterns":[{"include":"#interface-procedure-statement"},{"include":"$base"}]},{"begin":"(?i)\\\\G\\\\s*\\\\b([a-z]\\\\w*)\\\\b","beginCaptures":{"1":{"name":"entity.name.function.fortran"}},"end":"(?i)\\\\b(end\\\\s*interface)\\\\b(?:\\\\s*\\\\b(\\\\1)\\\\b)?","endCaptures":{"1":{"name":"keyword.control.endinterface.fortran"},"2":{"name":"entity.name.function.fortran"}},"patterns":[{"include":"#interface-procedure-statement"},{"include":"$base"}]}]},"goto-statement":{"begin":"(?i)\\\\s*\\\\b(go\\\\s*to)\\\\b","beginCaptures":{"1":{"name":"keyword.control.goto.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.control.goto.fortran","patterns":[{"include":"$base"}]},"if-construct":{"patterns":[{"begin":"(?i)\\\\b(if)\\\\b","beginCaptures":{"1":{"name":"keyword.control.if.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"include":"#logical-control-expression"},{"begin":"(?i)\\\\s*\\\\b(then)\\\\b","beginCaptures":{"1":{"name":"keyword.control.then.fortran"}},"contentName":"meta.block.if.fortran","end":"(?i)\\\\b(end\\\\s*if)\\\\b","endCaptures":{"1":{"name":"keyword.control.endif.fortran"}},"patterns":[{"begin":"(?i)\\\\b(else\\\\s*if)\\\\b","beginCaptures":{"1":{"name":"keyword.control.elseif.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"include":"#parentheses"},{"captures":{"1":{"name":"keyword.control.then.fortran"},"2":{"name":"meta.label.elseif.fortran"}},"match":"(?i)\\\\b(then)\\\\b(\\\\s*[a-z]\\\\w*)?"},{"include":"#invalid-word"}]},{"begin":"(?i)\\\\b(else)\\\\b","beginCaptures":{"1":{"name":"keyword.control.else.fortran"}},"end":"(?i)(?=\\\\b(end\\\\s*if)\\\\b)","patterns":[{"begin":"(?!(\\\\s*([\\\\n!;])))","end":"\\\\s*(?=[\\\\n!;])","patterns":[{"captures":{"1":{"name":"meta.label.else.fortran"},"2":{"name":"invalid.error.label.else.fortran"}},"match":"(?i)\\\\s*([a-z]\\\\w*)?\\\\s*\\\\b(\\\\w*)\\\\b"},{"include":"#invalid-word"}]},{"begin":"(?i)(?!\\\\b(end\\\\s*if)\\\\b)","end":"(?i)(?=\\\\b(end\\\\s*if)\\\\b)","patterns":[{"include":"$base"}]}]},{"include":"$base"}]},{"begin":"(?i)(?=\\\\s*[a-z])","end":"(?=[\\\\n!;])","name":"meta.statement.control.if.fortran","patterns":[{"include":"$base"}]}]}]},"image-control-statement":{"patterns":[{"include":"#sync-all-statement"},{"include":"#sync-statement"},{"include":"#event-statement"},{"include":"#form-team-statement"},{"include":"#fail-image-statement"}]},"implicit-statement":{"begin":"(?i)\\\\b(implicit)\\\\b","beginCaptures":{"1":{"name":"keyword.other.implicit.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.implicit.fortran","patterns":[{"captures":{"1":{"name":"keyword.other.none.fortran"}},"match":"(?i)\\\\s*\\\\b(none)\\\\b"},{"include":"$base"}]},"import-statement":{"begin":"(?i)\\\\b(import)\\\\b","beginCaptures":{"1":{"name":"keyword.control.include.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.include.fortran","patterns":[{"begin":"(?i)\\\\G\\\\s*(?:(::)|(?=[a-z]))","beginCaptures":{"1":{"name":"keyword.operator.double-colon.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"include":"#name-list"}]},{"begin":"\\\\G\\\\s*(,)","beginCaptures":{"1":{"name":"punctuation.comma.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"captures":{"1":{"name":"keyword.other.all.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(all)\\\\b"},{"captures":{"1":{"name":"keyword.other.none.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(none)\\\\b"},{"begin":"(?i)\\\\G\\\\s*\\\\b(only)\\\\s*(:)","beginCaptures":{"1":{"name":"keyword.other.only.fortran"},"2":{"name":"keyword.other.colon.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"include":"#name-list"}]},{"include":"#invalid-word"}]}]},"include-statement":{"begin":"(?i)\\\\b(include)\\\\b","beginCaptures":{"1":{"name":"keyword.control.include.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.include.fortran","patterns":[{"include":"#string-constant"},{"include":"#invalid-character"}]},"intent-attribute":{"begin":"(?i)\\\\s*\\\\b(intent)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"storage.modifier.intent.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"end":"(\\\\))|(?=[\\\\n!;])","endCaptures":{"1":{"name":"punctuation.parentheses.left.fortran"}},"patterns":[{"captures":{"1":{"name":"storage.modifier.intent.in-out.fortran"},"2":{"name":"storage.modifier.intent.in.fortran"},"3":{"name":"storage.modifier.intent.out.fortran"}},"match":"(?i)\\\\b(?:(in\\\\s*out)|(in)|(out))\\\\b"},{"include":"#invalid-word"}]},"interface-block-constructs":{"patterns":[{"include":"#abstract-interface-block-construct"},{"include":"#explicit-interface-block-construct"},{"include":"#generic-interface-block-construct"}]},"interface-procedure-statement":{"begin":"(?i)(?=[^\\\\n!\\"';]*\\\\bprocedure\\\\b)","end":"(?=[\\\\n!;])","name":"meta.statement.procedure.fortran","patterns":[{"begin":"(?i)(?=\\\\G\\\\s*(?!\\\\bprocedure\\\\b))","end":"(?i)(?=\\\\bprocedure\\\\b)","name":"meta.attribute-list.interface.fortran","patterns":[{"include":"#module-attribute"},{"include":"#invalid-word"}]},{"begin":"(?i)\\\\s*\\\\b(procedure)\\\\b","beginCaptures":{"1":{"name":"keyword.other.procedure.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"captures":{"1":{"name":"keyword.operator.double-colon.fortran"}},"match":"\\\\G\\\\s*(::)"},{"include":"#procedure-name-list"}]}]},"intrinsic-attribute":{"captures":{"1":{"name":"storage.modifier.intrinsic.fortran"}},"match":"(?i)\\\\s*\\\\b(intrinsic)\\\\b"},"intrinsic-functions":{"patterns":[{"begin":"(?i)\\\\b(acosh|asinh|atanh|bge|bgt|ble|blt|dshiftl|dshiftr|findloc|hypot|iall|iany|image_index|iparity|is_contiguous|lcobound|leadz|mask[lr]|merge_bits|norm2|num_images|parity|popcnt|poppar|shift[alr]|storage_size|this_image|trailz|ucobound)\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"support.function.intrinsic.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"end":"(?=|(?|<=?)","name":"keyword.logical.fortran.modern"}]},"logical-type":{"patterns":[{"begin":"(?i)\\\\b(logical)\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"storage.type.logical.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"contentName":"meta.type-spec.fortran","end":"(?)","name":"keyword.other.point.fortran"},"preprocessor":{"begin":"^\\\\s*(#:?)","beginCaptures":{"1":{"name":"keyword.control.preprocessor.indicator.fortran"}},"end":"\\\\n","name":"meta.preprocessor","patterns":[{"include":"#preprocessor-if-construct"},{"include":"#preprocessor-statements"}]},"preprocessor-arithmetic-operators":{"captures":{"1":{"name":"keyword.operator.subtraction.fortran"},"2":{"name":"keyword.operator.addition.fortran"},"3":{"name":"keyword.operator.division.fortran"},"4":{"name":"keyword.operator.multiplication.fortran"}},"match":"(-)|(\\\\+)|(/)|(\\\\*)"},"preprocessor-assignment-operator":{"match":"(?","endCaptures":{"0":{"name":"punctuation.definition.string.end.preprocessor.fortran"}},"name":"string.quoted.other.lt-gt.include.preprocessor.fortran"},{"include":"#line-continuation-operator"}]},"preprocessor-line-continuation-operator":{"begin":"\\\\s*(\\\\\\\\)","beginCaptures":{"1":{"name":"constant.character.escape.line-continuation.preprocessor.fortran"}},"end":"(?i)^"},"preprocessor-logical-operators":{"captures":{"1":{"name":"keyword.operator.logical.preprocessor.and.fortran"},"2":{"name":"keyword.operator.logical.preprocessor.equals.fortran"},"3":{"name":"keyword.operator.logical.preprocessor.not_equals.fortran"},"4":{"name":"keyword.operator.logical.preprocessor.or.fortran"},"5":{"name":"keyword.operator.logical.preprocessor.less_eq.fortran"},"6":{"name":"keyword.operator.logical.preprocessor.more_eq.fortran"},"7":{"name":"keyword.operator.logical.preprocessor.less.fortran"},"8":{"name":"keyword.operator.logical.preprocessor.more.fortran"},"9":{"name":"keyword.operator.logical.preprocessor.complementary.fortran"},"10":{"name":"keyword.operator.logical.preprocessor.xor.fortran"},"11":{"name":"keyword.operator.logical.preprocessor.bitand.fortran"},"12":{"name":"keyword.operator.logical.preprocessor.not.fortran"},"13":{"name":"keyword.operator.logical.preprocessor.bitor.fortran"}},"match":"(&&)|(==)|(!=)|(\\\\|\\\\|)|(<=)|(>=)|(<)|(>)|(~)|(\\\\^)|(&)|(!)|(\\\\|)","name":"keyword.operator.logical.preprocessor.fortran"},"preprocessor-operators":{"patterns":[{"include":"#preprocessor-line-continuation-operator"},{"include":"#preprocessor-logical-operators"},{"include":"#preprocessor-arithmetic-operators"}]},"preprocessor-pragma-statement":{"begin":"(?i)\\\\G\\\\s*\\\\b(pragma)\\\\b","beginCaptures":{"1":{"name":"keyword.control.preprocessor.pragma.fortran"}},"end":"(?=\\\\n)","name":"meta.preprocessor.pragma.fortran","patterns":[{"include":"#preprocessor-comments"},{"include":"#preprocessor-string-constant"}]},"preprocessor-statements":{"patterns":[{"include":"#preprocessor-define-statement"},{"include":"#preprocessor-error-statement"},{"include":"#preprocessor-include-statement"},{"include":"#preprocessor-preprocessor-pragma-statement"},{"include":"#preprocessor-undefine-statement"}]},"preprocessor-string-constant":{"patterns":[{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.preprocessor.fortran"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.preprocessor.fortran"}},"name":"string.quoted.double.include.preprocessor.fortran"},{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.preprocessor.fortran"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.preprocessor.fortran"}},"name":"string.quoted.single.include.preprocessor.fortran"}]},"preprocessor-undefine-statement":{"begin":"(?i)\\\\G\\\\s*\\\\b(undef)\\\\b","beginCaptures":{"1":{"name":"keyword.control.preprocessor.undef.fortran"}},"end":"(?=\\\\n)","name":"meta.preprocessor.undef.fortran","patterns":[{"include":"#preprocessor-comments"},{"include":"#preprocessor-line-continuation-operator"}]},"private-attribute":{"captures":{"1":{"name":"storage.modifier.private.fortran"}},"match":"(?i)\\\\s*\\\\b(private)\\\\b"},"procedure-call-dummy-variable":{"match":"(?i)\\\\s*([a-z]\\\\w*)(?=\\\\s*=)(?!\\\\s*==)","name":"variable.parameter.dummy-variable.fortran.modern"},"procedure-definition":{"begin":"(?i)(?=[^\\\\n!\\"';]*\\\\bmodule\\\\s+procedure\\\\b)","end":"(?=[\\\\n!;])","name":"meta.procedure.fortran","patterns":[{"begin":"(?i)\\\\s*\\\\b(module\\\\s+procedure)\\\\b","beginCaptures":{"1":{"name":"keyword.other.procedure.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"begin":"(?i)\\\\G\\\\s*\\\\b([a-z]\\\\w*)\\\\b","beginCaptures":{"1":{"name":"entity.name.function.procedure.fortran"}},"end":"(?i)\\\\s*\\\\b(?:(end\\\\s*procedure)(?:\\\\s+([_a-z]\\\\w*))?|(end))\\\\b\\\\s*([^\\\\n!;]+)?(?=[\\\\n!;])","endCaptures":{"1":{"name":"keyword.other.endprocedure.fortran"},"2":{"name":"entity.name.function.procedure.fortran"},"3":{"name":"keyword.other.endprocedure.fortran"},"4":{"name":"invalid.error.procedure-definition.fortran"}},"patterns":[{"begin":"\\\\G(?!\\\\s*[\\\\n!;])","end":"(?=[\\\\n!;])","name":"meta.first-line.fortran","patterns":[{"include":"#invalid-character"}]},{"begin":"(?i)(?!\\\\s*(?:contains\\\\b|end\\\\s*[\\\\n!;]|end\\\\s*procedure\\\\b))","end":"(?i)(?=\\\\s*(?:contains\\\\b|end\\\\s*[\\\\n!;]|end\\\\s*procedure\\\\b))","name":"meta.block.specification.procedure.fortran","patterns":[{"include":"$self"}]},{"begin":"(?i)\\\\s*(contains)\\\\b","beginCaptures":{"1":{"name":"keyword.control.contains.fortran"}},"end":"(?i)(?=\\\\s*end(?:\\\\s*[\\\\n!;]|\\\\s*procedure\\\\b))","name":"meta.block.contains.fortran","patterns":[{"include":"$self"}]}]}]}]},"procedure-name":{"captures":{"1":{"name":"entity.name.function.procedure.fortran"}},"match":"(?i)\\\\s*\\\\b([a-z]\\\\w*)\\\\b"},"procedure-name-list":{"begin":"(?i)(?=\\\\s*[a-z])","contentName":"meta.name-list.fortran","end":"(?=[\\\\n!;])","patterns":[{"begin":"(?!\\\\s*\\\\n)","end":"(,)|(?=[\\\\n!;])","endCaptures":{"1":{"name":"punctuation.comma.fortran"}},"patterns":[{"include":"#procedure-name"},{"include":"#pointer-operators"}]}]},"procedure-specification-statement":{"begin":"(?i)(?=\\\\bprocedure\\\\b)","end":"(?=[\\\\n!;])","name":"meta.specification.procedure.fortran","patterns":[{"include":"#procedure-type"},{"begin":"(?=\\\\s*(,|::|\\\\())","contentName":"meta.attribute-list.procedure.fortran","end":"(::)|(?=[\\\\n!;])","endCaptures":{"1":{"name":"keyword.operator.double-colon.fortran"}},"patterns":[{"begin":"(,)|^|(?<=&)","beginCaptures":{"1":{"name":"punctuation.comma.fortran"}},"end":"(?=::|[\\\\n!\\\\&,;])","patterns":[{"include":"#access-attribute"},{"include":"#intent-attribute"},{"include":"#optional-attribute"},{"include":"#pointer-attribute"},{"include":"#protected-attribute"},{"include":"#save-attribute"},{"include":"#invalid-word"}]}]},{"include":"#procedure-name-list"}]},"procedure-type":{"patterns":[{"begin":"(?i)\\\\b(procedure)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"storage.type.procedure.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"contentName":"meta.type-spec.fortran","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.parentheses.right.fortran"}},"patterns":[{"include":"#types"},{"include":"#procedure-name"}]},{"captures":{"1":{"name":"storage.type.procedure.fortran"}},"match":"(?i)\\\\b(procedure)\\\\b"}]},"program-definition":{"begin":"(?i)(?=\\\\b(program)\\\\b)","end":"(?=[\\\\n!;])","name":"meta.program.fortran","patterns":[{"captures":{"1":{"name":"keyword.control.program.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(program)\\\\b"},{"applyEndPatternLast":1,"begin":"(?i)\\\\s*\\\\b([a-z]\\\\w*)\\\\b","beginCaptures":{"1":{"name":"entity.name.program.fortran"}},"end":"(?i)\\\\b(?:(end\\\\s*program)(?:\\\\s+([_a-z]\\\\w*))?|(end))\\\\b\\\\s*([^\\\\n!;]+)?(?=[\\\\n!;])","endCaptures":{"1":{"name":"keyword.control.endprogram.fortran"},"2":{"name":"entity.name.program.fortran"},"3":{"name":"keyword.control.endprogram.fortran"},"4":{"name":"invalid.error.program-definition.fortran"}},"patterns":[{"begin":"\\\\G","end":"(?i)(?=\\\\bend(?:\\\\s*[\\\\n!;]|\\\\s*program\\\\b))","name":"meta.block.specification.program.fortran","patterns":[{"begin":"(?i)\\\\b(contains)\\\\b","beginCaptures":{"1":{"name":"keyword.control.contains.fortran"}},"end":"(?i)(?=end(?:\\\\s*[\\\\n!;]|\\\\s*program\\\\b))","name":"meta.block.contains.fortran","patterns":[{"include":"$base"}]},{"include":"$base"}]}]}]},"protected-attribute":{"captures":{"1":{"name":"storage.modifier.protected.fortran"}},"match":"(?i)\\\\s*\\\\b(protected)\\\\b"},"public-attribute":{"captures":{"1":{"name":"storage.modifier.public.fortran"}},"match":"(?i)\\\\s*\\\\b(public)\\\\b"},"pure-attribute":{"captures":{"1":{"name":"storage.modifier.impure.fortran"},"2":{"name":"storage.modifier.pure.fortran"}},"match":"(?i)\\\\s*\\\\b(?:(impure)|(pure))\\\\b"},"recursive-attribute":{"captures":{"1":{"name":"storage.modifier.non_recursive.fortran"},"2":{"name":"storage.modifier.recursive.fortran"}},"match":"(?i)\\\\s*\\\\b(?:(non_recursive)|(recursive))\\\\b"},"result-statement":{"begin":"(?i)\\\\s*\\\\b(result)\\\\s*(\\\\()","beginCaptures":{"1":{"name":"keyword.control.result.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.parentheses.right.fortran"}},"patterns":[{"include":"#dummy-variable"}]},"return-statement":{"begin":"(?i)\\\\s*\\\\b(return)\\\\b","beginCaptures":{"1":{"name":"keyword.control.return.fortran"}},"end":"(?=[\\\\n!;])","name":"meta.statement.control.return.fortran","patterns":[{"include":"#invalid-character"}]},"save-attribute":{"captures":{"1":{"name":"storage.modifier.save.fortran"}},"match":"(?i)\\\\s*\\\\b(save)\\\\b"},"select-case-construct":{"begin":"(?i)\\\\b(select\\\\s*case)\\\\b","beginCaptures":{"1":{"name":"keyword.control.selectcase.fortran"}},"end":"(?i)\\\\b(end\\\\s*select)\\\\b","endCaptures":{"1":{"name":"keyword.control.endselect.fortran"}},"name":"meta.block.select.case.fortran","patterns":[{"include":"#parentheses"},{"begin":"(?i)\\\\b(case)\\\\b","beginCaptures":{"1":{"name":"keyword.control.case.fortran"}},"end":"(?i)(?=[\\\\n!;])","patterns":[{"captures":{"1":{"name":"keyword.control.default.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(default)\\\\b"},{"include":"#parentheses"},{"include":"#invalid-word"}]},{"include":"$base"}]},"select-rank-construct":{"begin":"(?i)\\\\b(select\\\\s*rank)\\\\b","beginCaptures":{"1":{"name":"keyword.control.selectrank.fortran"}},"end":"(?i)\\\\b(end\\\\s*select)\\\\b","endCaptures":{"1":{"name":"keyword.control.endselect.fortran"}},"name":"meta.block.select.rank.fortran","patterns":[{"include":"#parentheses"},{"begin":"(?i)\\\\b(rank)\\\\b","beginCaptures":{"1":{"name":"keyword.control.rank.fortran"}},"end":"(?i)(?=[\\\\n!;])","patterns":[{"captures":{"1":{"name":"keyword.control.default.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(default)\\\\b"},{"include":"#parentheses"},{"include":"#invalid-word"}]},{"include":"$base"}]},"select-type-construct":{"begin":"(?i)\\\\b(select\\\\s*type)\\\\b","beginCaptures":{"1":{"name":"keyword.control.selecttype.fortran"}},"end":"(?i)\\\\b(end\\\\s*select)\\\\b","endCaptures":{"1":{"name":"keyword.control.endselect.fortran"}},"name":"meta.block.select.type.fortran","patterns":[{"include":"#parentheses"},{"begin":"(?i)\\\\b(?:(class)|(type))\\\\b","beginCaptures":{"1":{"name":"keyword.control.class.fortran"},"2":{"name":"keyword.control.type.fortran"}},"end":"(?i)(?=[\\\\n!;])","patterns":[{"captures":{"1":{"name":"keyword.control.default.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(default)\\\\b"},{"captures":{"1":{"name":"keyword.control.is.fortran"}},"match":"(?i)\\\\G\\\\s*\\\\b(is)\\\\b"},{"include":"#parentheses"},{"include":"#invalid-word"}]},{"include":"$base"}]},"sequence-attribute":{"captures":{"1":{"name":"storage.modifier.sequence.fortran"}},"match":"(?i)\\\\s*\\\\b(sequence)\\\\b"},"specification-statements":{"patterns":[{"include":"#attribute-specification-statement"},{"include":"#common-statement"},{"include":"#data-statement"},{"include":"#equivalence-statement"},{"include":"#implicit-statement"},{"include":"#namelist-statement"},{"include":"#use-statement"}]},"stop-statement":{"begin":"(?i)\\\\s*\\\\b(stop)\\\\b(?:\\\\s*\\\\b([a-z]\\\\w*)\\\\b)?","beginCaptures":{"1":{"name":"keyword.control.stop.fortran"},"2":{"name":"meta.label.stop.stop"}},"end":"(?=[\\\\n!;])","name":"meta.statement.control.stop.fortran","patterns":[{"include":"#constants"},{"include":"#string-operators"},{"include":"#invalid-character"}]},"string-constant":{"patterns":[{"applyEndPatternLast":1,"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.fortran"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.fortran"}},"name":"string.quoted.single.fortran","patterns":[{"match":"''","name":"constant.character.escape.apostrophe.fortran"}]},{"applyEndPatternLast":1,"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.fortran"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.fortran"}},"name":"string.quoted.double.fortran","patterns":[{"match":"\\"\\"","name":"constant.character.escape.quote.fortran"}]}]},"string-line-continuation-operator":{"begin":"(&)(?=\\\\s*\\\\n)","beginCaptures":{"1":{"name":"keyword.operator.line-continuation.fortran"}},"end":"(?i)^(?:(?=\\\\s*[^!\\\\&\\\\s])|\\\\s*(&))","endCaptures":{"1":{"name":"keyword.operator.line-continuation.fortran"}},"patterns":[{"include":"#comments"},{"match":"\\\\S.*","name":"invalid.error.string-line-cont.fortran"}]},"string-operators":{"match":"(//)","name":"keyword.other.concatination.fortran"},"submodule-definition":{"begin":"(?i)(?=\\\\b(submodule)\\\\s*\\\\()","end":"(?=[\\\\n!;])","name":"meta.submodule.fortran","patterns":[{"begin":"(?i)\\\\G\\\\s*\\\\b(submodule)\\\\s*(\\\\()\\\\s*(\\\\w+)","beginCaptures":{"1":{"name":"keyword.other.submodule.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"},"3":{"name":"entity.name.class.submodule.fortran"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.parentheses.left.fortran"}},"patterns":[]},{"applyEndPatternLast":1,"begin":"(?i)\\\\s*\\\\b([a-z]\\\\w*)\\\\b","beginCaptures":{"1":{"name":"entity.name.module.submodule.fortran"}},"end":"(?i)\\\\s*\\\\b(?:(end\\\\s*submodule)(?:\\\\s+([_a-z]\\\\w*))?|(end))\\\\b\\\\s*([^\\\\n!;]+)?(?=[\\\\n!;])","endCaptures":{"1":{"name":"keyword.other.endsubmodule.fortran"},"2":{"name":"entity.name.module.submodule.fortran"},"3":{"name":"keyword.other.endsubmodule.fortran"},"4":{"name":"invalid.error.submodule.fortran"}},"patterns":[{"begin":"\\\\G","end":"(?i)(?=\\\\bend(?:\\\\s*[\\\\n!;]|\\\\s*submodule\\\\b))","name":"meta.block.specification.submodule.fortran","patterns":[{"begin":"(?i)\\\\b(contains)\\\\b","beginCaptures":{"1":{"name":"keyword.control.contains.fortran"}},"end":"(?i)(?=\\\\s*end(?:\\\\s*[\\\\n!;]|\\\\s*submodule\\\\b))","name":"meta.block.contains.fortran","patterns":[{"include":"$base"}]},{"include":"$base"}]}]}]},"subroutine-definition":{"begin":"(?i)(?=([^\\\\n!\\"':;](?!\\\\bend))*\\\\bsubroutine\\\\b)","end":"(?=[\\\\n!;])","name":"meta.subroutine.fortran","patterns":[{"begin":"(?i)(?=\\\\G\\\\s*(?!\\\\bsubroutine\\\\b))","end":"(?i)(?=\\\\bsubroutine\\\\b)","name":"meta.attribute-list.subroutine.fortran","patterns":[{"include":"#elemental-attribute"},{"include":"#module-attribute"},{"include":"#pure-attribute"},{"include":"#recursive-attribute"},{"include":"#invalid-word"}]},{"begin":"(?i)\\\\s*\\\\b(subroutine)\\\\b","beginCaptures":{"1":{"name":"keyword.other.subroutine.fortran"}},"end":"(?=[\\\\n!;])","patterns":[{"begin":"(?i)\\\\G\\\\s*\\\\b([a-z]\\\\w*)\\\\b","beginCaptures":{"1":{"name":"entity.name.function.subroutine.fortran"}},"end":"(?i)\\\\b(?:(end\\\\s*subroutine)(?:\\\\s+([_a-z]\\\\w*))?|(end))\\\\b\\\\s*([^\\\\n!;]+)?(?=[\\\\n!;])","endCaptures":{"1":{"name":"keyword.other.endsubroutine.fortran"},"2":{"name":"entity.name.function.subroutine.fortran"},"3":{"name":"keyword.other.endsubroutine.fortran"},"4":{"name":"invalid.error.subroutine.fortran"}},"patterns":[{"begin":"\\\\G(?!\\\\s*[\\\\n!;])","end":"(?=[\\\\n!;])","name":"meta.first-line.fortran","patterns":[{"include":"#dummy-variable-list"},{"include":"#language-binding-attribute"}]},{"begin":"(?i)(?!\\\\bend(?:\\\\s*[\\\\n!;]|\\\\s*subroutine\\\\b))","end":"(?i)(?=\\\\bend(?:\\\\s*[\\\\n!;]|\\\\s*subroutine\\\\b))","name":"meta.block.specification.subroutine.fortran","patterns":[{"begin":"(?i)\\\\b(contains)\\\\b","beginCaptures":{"1":{"name":"keyword.control.contains.fortran"}},"end":"(?i)(?=end(?:\\\\s*[\\\\n!;]|\\\\s*subroutine\\\\b))","name":"meta.block.contains.fortran","patterns":[{"include":"$base"}]},{"include":"$base"}]}]}]}]},"sync-all-statement":{"begin":"(?i)\\\\b(sync (?:all|memory))(\\\\s*(?=\\\\())?","beginCaptures":{"1":{"name":"keyword.control.sync-all-memory.fortran"},"2":{"name":"punctuation.parentheses.left.fortran"}},"end":"(?=r)&&(n=r);else{let r=-1;for(let i of t)(i=e(i,++r,t))!=null&&(n=i)&&(n=i)}return n}function rr(t,e){let n;if(e===void 0)for(const r of t)r!=null&&(n>r||n===void 0&&r>=r)&&(n=r);else{let r=-1;for(let i of t)(i=e(i,++r,t))!=null&&(n>i||n===void 0&&i>=i)&&(n=i)}return n}function ir(t){return t}var Gt=1,le=2,xe=3,Xt=4,Pe=1e-6;function sr(t){return"translate("+t+",0)"}function ar(t){return"translate(0,"+t+")"}function or(t){return e=>+t(e)}function cr(t,e){return e=Math.max(0,t.bandwidth()-e*2)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function ur(){return!this.__axis}function fn(t,e){var n=[],r=null,i=null,s=6,a=6,y=3,F=typeof window<"u"&&window.devicePixelRatio>1?0:.5,S=t===Gt||t===Xt?-1:1,w=t===Xt||t===le?"x":"y",P=t===Gt||t===xe?sr:ar;function _(Y){var X=r??(e.ticks?e.ticks.apply(e,n):e.domain()),B=i??(e.tickFormat?e.tickFormat.apply(e,n):ir),v=Math.max(s,0)+y,U=e.range(),R=+U[0]+F,E=+U[U.length-1]+F,z=(e.bandwidth?cr:or)(e.copy(),F),G=Y.selection?Y.selection():Y,T=G.selectAll(".domain").data([null]),k=G.selectAll(".tick").data(X,e).order(),p=k.exit(),L=k.enter().append("g").attr("class","tick"),x=k.select("line"),C=k.select("text");T=T.merge(T.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),k=k.merge(L),x=x.merge(L.append("line").attr("stroke","currentColor").attr(w+"2",S*s)),C=C.merge(L.append("text").attr("fill","currentColor").attr(w,S*v).attr("dy",t===Gt?"0em":t===xe?"0.71em":"0.32em")),Y!==G&&(T=T.transition(Y),k=k.transition(Y),x=x.transition(Y),C=C.transition(Y),p=p.transition(Y).attr("opacity",Pe).attr("transform",function(M){return isFinite(M=z(M))?P(M+F):this.getAttribute("transform")}),L.attr("opacity",Pe).attr("transform",function(M){var D=this.parentNode.__axis;return P((D&&isFinite(D=D(M))?D:z(M))+F)})),p.remove(),T.attr("d",t===Xt||t===le?a?"M"+S*a+","+R+"H"+F+"V"+E+"H"+S*a:"M"+F+","+R+"V"+E:a?"M"+R+","+S*a+"V"+F+"H"+E+"V"+S*a:"M"+R+","+F+"H"+E),k.attr("opacity",1).attr("transform",function(M){return P(z(M)+F)}),x.attr(w+"2",S*s),C.attr(w,S*v).text(B),G.filter(ur).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===le?"start":t===Xt?"end":"middle"),G.each(function(){this.__axis=z})}return _.scale=function(Y){return arguments.length?(e=Y,_):e},_.ticks=function(){return n=Array.from(arguments),_},_.tickArguments=function(Y){return arguments.length?(n=Y==null?[]:Array.from(Y),_):n.slice()},_.tickValues=function(Y){return arguments.length?(r=Y==null?null:Array.from(Y),_):r&&r.slice()},_.tickFormat=function(Y){return arguments.length?(i=Y,_):i},_.tickSize=function(Y){return arguments.length?(s=a=+Y,_):s},_.tickSizeInner=function(Y){return arguments.length?(s=+Y,_):s},_.tickSizeOuter=function(Y){return arguments.length?(a=+Y,_):a},_.tickPadding=function(Y){return arguments.length?(y=+Y,_):y},_.offset=function(Y){return arguments.length?(F=+Y,_):F},_}function lr(t){return fn(Gt,t)}function fr(t){return fn(xe,t)}const dr=Math.PI/180,hr=180/Math.PI,ne=18,dn=.96422,hn=1,mn=.82521,gn=4/29,Ft=6/29,yn=3*Ft*Ft,mr=Ft*Ft*Ft;function kn(t){if(t instanceof ft)return new ft(t.l,t.a,t.b,t.opacity);if(t instanceof ht)return pn(t);t instanceof on||(t=On(t));var e=me(t.r),n=me(t.g),r=me(t.b),i=fe((.2225045*e+.7168786*n+.0606169*r)/hn),s,a;return e===n&&n===r?s=a=i:(s=fe((.4360747*e+.3850649*n+.1430804*r)/dn),a=fe((.0139322*e+.0971045*n+.7141733*r)/mn)),new ft(116*i-16,500*(s-i),200*(i-a),t.opacity)}function gr(t,e,n,r){return arguments.length===1?kn(t):new ft(t,e,n,r??1)}function ft(t,e,n,r){this.l=+t,this.a=+e,this.b=+n,this.opacity=+r}cn(ft,gr,un(ln,{brighter(t){return new ft(this.l+ne*(t??1),this.a,this.b,this.opacity)},darker(t){return new ft(this.l-ne*(t??1),this.a,this.b,this.opacity)},rgb(){var t=(this.l+16)/116,e=isNaN(this.a)?t:t+this.a/500,n=isNaN(this.b)?t:t-this.b/200;return e=dn*de(e),t=hn*de(t),n=mn*de(n),new on(he(3.1338561*e-1.6168667*t-.4906146*n),he(-.9787684*e+1.9161415*t+.033454*n),he(.0719453*e-.2289914*t+1.4052427*n),this.opacity)}}));function fe(t){return t>mr?Math.pow(t,1/3):t/yn+gn}function de(t){return t>Ft?t*t*t:yn*(t-gn)}function he(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function me(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function yr(t){if(t instanceof ht)return new ht(t.h,t.c,t.l,t.opacity);if(t instanceof ft||(t=kn(t)),t.a===0&&t.b===0)return new ht(NaN,0(t(s=new Date(+s)),s),i.ceil=s=>(t(s=new Date(s-1)),e(s,1),t(s),s),i.round=s=>{const a=i(s),y=i.ceil(s);return s-a(e(s=new Date(+s),a==null?1:Math.floor(a)),s),i.range=(s,a,y)=>{const F=[];if(s=i.ceil(s),y=y==null?1:Math.floor(y),!(s0))return F;let S;do F.push(S=new Date(+s)),e(s,y),t(s);while(Snt(a=>{if(a>=a)for(;t(a),!s(a);)a.setTime(a-1)},(a,y)=>{if(a>=a)if(y<0)for(;++y<=0;)for(;e(a,-1),!s(a););else for(;--y>=0;)for(;e(a,1),!s(a););}),n&&(i.count=(s,a)=>(ge.setTime(+s),ye.setTime(+a),t(ge),t(ye),Math.floor(n(ge,ye))),i.every=s=>(s=Math.floor(s),!isFinite(s)||!(s>0)?null:s>1?i.filter(r?a=>r(a)%s===0:a=>i.count(0,a)%s===0):i)),i}const Et=nt(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);Et.every=t=>(t=Math.floor(t),!isFinite(t)||!(t>0)?null:t>1?nt(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):Et);Et.range;const mt=1e3,ct=mt*60,gt=ct*60,yt=gt*24,Se=yt*7,Ve=yt*30,ke=yt*365,vt=nt(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*mt)},(t,e)=>(e-t)/mt,t=>t.getUTCSeconds());vt.range;const Nt=nt(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*mt)},(t,e)=>{t.setTime(+t+e*ct)},(t,e)=>(e-t)/ct,t=>t.getMinutes());Nt.range;const Tr=nt(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*ct)},(t,e)=>(e-t)/ct,t=>t.getUTCMinutes());Tr.range;const Pt=nt(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*mt-t.getMinutes()*ct)},(t,e)=>{t.setTime(+t+e*gt)},(t,e)=>(e-t)/gt,t=>t.getHours());Pt.range;const xr=nt(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*gt)},(t,e)=>(e-t)/gt,t=>t.getUTCHours());xr.range;const xt=nt(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*ct)/yt,t=>t.getDate()-1);xt.range;const _e=nt(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/yt,t=>t.getUTCDate()-1);_e.range;const br=nt(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/yt,t=>Math.floor(t/yt));br.range;function Dt(t){return nt(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(e,n)=>{e.setDate(e.getDate()+n*7)},(e,n)=>(n-e-(n.getTimezoneOffset()-e.getTimezoneOffset())*ct)/Se)}const zt=Dt(0),Vt=Dt(1),vn=Dt(2),Tn=Dt(3),bt=Dt(4),xn=Dt(5),bn=Dt(6);zt.range;Vt.range;vn.range;Tn.range;bt.range;xn.range;bn.range;function Mt(t){return nt(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCDate(e.getUTCDate()+n*7)},(e,n)=>(n-e)/Se)}const wn=Mt(0),re=Mt(1),wr=Mt(2),Dr=Mt(3),It=Mt(4),Mr=Mt(5),Cr=Mt(6);wn.range;re.range;wr.range;Dr.range;It.range;Mr.range;Cr.range;const Rt=nt(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+(e.getFullYear()-t.getFullYear())*12,t=>t.getMonth());Rt.range;const Sr=nt(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+(e.getUTCFullYear()-t.getUTCFullYear())*12,t=>t.getUTCMonth());Sr.range;const kt=nt(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());kt.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:nt(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)});kt.range;const wt=nt(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());wt.every=t=>!isFinite(t=Math.floor(t))||!(t>0)?null:nt(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)});wt.range;function _r(t,e,n,r,i,s){const a=[[vt,1,mt],[vt,5,5*mt],[vt,15,15*mt],[vt,30,30*mt],[s,1,ct],[s,5,5*ct],[s,15,15*ct],[s,30,30*ct],[i,1,gt],[i,3,3*gt],[i,6,6*gt],[i,12,12*gt],[r,1,yt],[r,2,2*yt],[n,1,Se],[e,1,Ve],[e,3,3*Ve],[t,1,ke]];function y(S,w,P){const _=wv).right(a,_);if(Y===a.length)return t.every(Ne(S/ke,w/ke,P));if(Y===0)return Et.every(Math.max(Ne(S,w,P),1));const[X,B]=a[_/a[Y-1][2]53)return null;"w"in f||(f.w=1),"Z"in f?(A=ve($t(f.y,0,1)),Q=A.getUTCDay(),A=Q>4||Q===0?re.ceil(A):re(A),A=_e.offset(A,(f.V-1)*7),f.y=A.getUTCFullYear(),f.m=A.getUTCMonth(),f.d=A.getUTCDate()+(f.w+6)%7):(A=pe($t(f.y,0,1)),Q=A.getDay(),A=Q>4||Q===0?Vt.ceil(A):Vt(A),A=xt.offset(A,(f.V-1)*7),f.y=A.getFullYear(),f.m=A.getMonth(),f.d=A.getDate()+(f.w+6)%7)}else("W"in f||"U"in f)&&("w"in f||(f.w="u"in f?f.u%7:"W"in f?1:0),Q="Z"in f?ve($t(f.y,0,1)).getUTCDay():pe($t(f.y,0,1)).getDay(),f.m=0,f.d="W"in f?(f.w+6)%7+f.W*7-(Q+5)%7:f.w+f.U*7-(Q+6)%7);return"Z"in f?(f.H+=f.Z/100|0,f.M+=f.Z%100,ve(f)):pe(f)}}function p(h,N,V,f){for(var tt=0,A=N.length,Q=V.length,Z,st;tt=Q)return-1;if(Z=N.charCodeAt(tt++),Z===37){if(Z=N.charAt(tt++),st=G[Z in Re?N.charAt(tt++):Z],!st||(f=st(h,V,f))<0)return-1}else if(Z!=V.charCodeAt(f++))return-1}return f}function L(h,N,V){var f=S.exec(N.slice(V));return f?(h.p=w.get(f[0].toLowerCase()),V+f[0].length):-1}function x(h,N,V){var f=Y.exec(N.slice(V));return f?(h.w=X.get(f[0].toLowerCase()),V+f[0].length):-1}function C(h,N,V){var f=P.exec(N.slice(V));return f?(h.w=_.get(f[0].toLowerCase()),V+f[0].length):-1}function M(h,N,V){var f=U.exec(N.slice(V));return f?(h.m=R.get(f[0].toLowerCase()),V+f[0].length):-1}function D(h,N,V){var f=B.exec(N.slice(V));return f?(h.m=v.get(f[0].toLowerCase()),V+f[0].length):-1}function c(h,N,V){return p(h,e,N,V)}function g(h,N,V){return p(h,n,N,V)}function b(h,N,V){return p(h,r,N,V)}function m(h){return a[h.getDay()]}function I(h){return s[h.getDay()]}function o(h){return F[h.getMonth()]}function W(h){return y[h.getMonth()]}function u(h){return i[+(h.getHours()>=12)]}function K(h){return 1+~~(h.getMonth()/3)}function l(h){return a[h.getUTCDay()]}function $(h){return s[h.getUTCDay()]}function O(h){return F[h.getUTCMonth()]}function j(h){return y[h.getUTCMonth()]}function H(h){return i[+(h.getUTCHours()>=12)]}function J(h){return 1+~~(h.getUTCMonth()/3)}return{format:function(h){var N=T(h+="",E);return N.toString=function(){return h},N},parse:function(h){var N=k(h+="",!1);return N.toString=function(){return h},N},utcFormat:function(h){var N=T(h+="",z);return N.toString=function(){return h},N},utcParse:function(h){var N=k(h+="",!0);return N.toString=function(){return h},N}}}var Re={"-":"",_:" ",0:"0"},rt=/^\s*\d+/,Er=/^%/,Ir=/[\\^$*+?|[\]().{}]/g;function q(t,e,n){var r=t<0?"-":"",i=(r?-t:t)+"",s=i.length;return r+(s[e.toLowerCase(),n]))}function Ar(t,e,n){var r=rt.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Wr(t,e,n){var r=rt.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function $r(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Or(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function Hr(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function ze(t,e,n){var r=rt.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function qe(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function Nr(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function Pr(t,e,n){var r=rt.exec(e.slice(n,n+1));return r?(t.q=r[0]*3-3,n+r[0].length):-1}function Vr(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function Be(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function Rr(t,e,n){var r=rt.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function Ze(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function zr(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function qr(t,e,n){var r=rt.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function Br(t,e,n){var r=rt.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function Zr(t,e,n){var r=rt.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function Xr(t,e,n){var r=Er.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function Gr(t,e,n){var r=rt.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function jr(t,e,n){var r=rt.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function Xe(t,e){return q(t.getDate(),e,2)}function Qr(t,e){return q(t.getHours(),e,2)}function Jr(t,e){return q(t.getHours()%12||12,e,2)}function Kr(t,e){return q(1+xt.count(kt(t),t),e,3)}function Dn(t,e){return q(t.getMilliseconds(),e,3)}function ti(t,e){return Dn(t,e)+"000"}function ei(t,e){return q(t.getMonth()+1,e,2)}function ni(t,e){return q(t.getMinutes(),e,2)}function ri(t,e){return q(t.getSeconds(),e,2)}function ii(t){var e=t.getDay();return e===0?7:e}function si(t,e){return q(zt.count(kt(t)-1,t),e,2)}function Mn(t){var e=t.getDay();return e>=4||e===0?bt(t):bt.ceil(t)}function ai(t,e){return t=Mn(t),q(bt.count(kt(t),t)+(kt(t).getDay()===4),e,2)}function oi(t){return t.getDay()}function ci(t,e){return q(Vt.count(kt(t)-1,t),e,2)}function ui(t,e){return q(t.getFullYear()%100,e,2)}function li(t,e){return t=Mn(t),q(t.getFullYear()%100,e,2)}function fi(t,e){return q(t.getFullYear()%1e4,e,4)}function di(t,e){var n=t.getDay();return t=n>=4||n===0?bt(t):bt.ceil(t),q(t.getFullYear()%1e4,e,4)}function hi(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+q(e/60|0,"0",2)+q(e%60,"0",2)}function Ge(t,e){return q(t.getUTCDate(),e,2)}function mi(t,e){return q(t.getUTCHours(),e,2)}function gi(t,e){return q(t.getUTCHours()%12||12,e,2)}function yi(t,e){return q(1+_e.count(wt(t),t),e,3)}function Cn(t,e){return q(t.getUTCMilliseconds(),e,3)}function ki(t,e){return Cn(t,e)+"000"}function pi(t,e){return q(t.getUTCMonth()+1,e,2)}function vi(t,e){return q(t.getUTCMinutes(),e,2)}function Ti(t,e){return q(t.getUTCSeconds(),e,2)}function xi(t){var e=t.getUTCDay();return e===0?7:e}function bi(t,e){return q(wn.count(wt(t)-1,t),e,2)}function Sn(t){var e=t.getUTCDay();return e>=4||e===0?It(t):It.ceil(t)}function wi(t,e){return t=Sn(t),q(It.count(wt(t),t)+(wt(t).getUTCDay()===4),e,2)}function Di(t){return t.getUTCDay()}function Mi(t,e){return q(re.count(wt(t)-1,t),e,2)}function Ci(t,e){return q(t.getUTCFullYear()%100,e,2)}function Si(t,e){return t=Sn(t),q(t.getUTCFullYear()%100,e,2)}function _i(t,e){return q(t.getUTCFullYear()%1e4,e,4)}function Yi(t,e){var n=t.getUTCDay();return t=n>=4||n===0?It(t):It.ceil(t),q(t.getUTCFullYear()%1e4,e,4)}function Fi(){return"+0000"}function je(){return"%"}function Qe(t){return+t}function Je(t){return Math.floor(+t/1e3)}var St,ie;Ui({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});function Ui(t){return St=Ur(t),ie=St.format,St.parse,St.utcFormat,St.utcParse,St}function Ei(t){return new Date(t)}function Ii(t){return t instanceof Date?+t:+new Date(+t)}function _n(t,e,n,r,i,s,a,y,F,S){var w=Jn(),P=w.invert,_=w.domain,Y=S(".%L"),X=S(":%S"),B=S("%I:%M"),v=S("%I %p"),U=S("%a %d"),R=S("%b %d"),E=S("%B"),z=S("%Y");function G(T){return(F(T)4&&(Y+=7),_.add(Y,n));return X.diff(B,"week")+1},y.isoWeekday=function(S){return this.$utils().u(S)?this.day()||7:this.day(this.day()%7?S:S-7)};var F=y.startOf;y.startOf=function(S,w){var P=this.$utils(),_=!!P.u(w)||w;return P.p(S)==="isoweek"?_?this.date(this.date()-(this.isoWeekday()-1)).startOf("day"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf("day"):F.bind(this)(S,w)}}}))})(jt)),jt.exports}var $i=Wi(),Oi=oe($i),Qt={exports:{}},Hi=Qt.exports,tn;function Ni(){return tn||(tn=1,(function(t,e){(function(n,r){t.exports=r()})(Hi,(function(){var n={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},r=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,i=/\d/,s=/\d\d/,a=/\d\d?/,y=/\d*[^-_:/,()\s\d]+/,F={},S=function(v){return(v=+v)+(v>68?1900:2e3)},w=function(v){return function(U){this[v]=+U}},P=[/[+-]\d\d:?(\d\d)?|Z/,function(v){(this.zone||(this.zone={})).offset=(function(U){if(!U||U==="Z")return 0;var R=U.match(/([+-]|\d\d)/g),E=60*R[1]+(+R[2]||0);return E===0?0:R[0]==="+"?-E:E})(v)}],_=function(v){var U=F[v];return U&&(U.indexOf?U:U.s.concat(U.f))},Y=function(v,U){var R,E=F.meridiem;if(E){for(var z=1;z<=24;z+=1)if(v.indexOf(E(z,0,U))>-1){R=z>12;break}}else R=v===(U?"pm":"PM");return R},X={A:[y,function(v){this.afternoon=Y(v,!1)}],a:[y,function(v){this.afternoon=Y(v,!0)}],Q:[i,function(v){this.month=3*(v-1)+1}],S:[i,function(v){this.milliseconds=100*+v}],SS:[s,function(v){this.milliseconds=10*+v}],SSS:[/\d{3}/,function(v){this.milliseconds=+v}],s:[a,w("seconds")],ss:[a,w("seconds")],m:[a,w("minutes")],mm:[a,w("minutes")],H:[a,w("hours")],h:[a,w("hours")],HH:[a,w("hours")],hh:[a,w("hours")],D:[a,w("day")],DD:[s,w("day")],Do:[y,function(v){var U=F.ordinal,R=v.match(/\d+/);if(this.day=R[0],U)for(var E=1;E<=31;E+=1)U(E).replace(/\[|\]/g,"")===v&&(this.day=E)}],w:[a,w("week")],ww:[s,w("week")],M:[a,w("month")],MM:[s,w("month")],MMM:[y,function(v){var U=_("months"),R=(_("monthsShort")||U.map((function(E){return E.slice(0,3)}))).indexOf(v)+1;if(R<1)throw new Error;this.month=R%12||R}],MMMM:[y,function(v){var U=_("months").indexOf(v)+1;if(U<1)throw new Error;this.month=U%12||U}],Y:[/[+-]?\d+/,w("year")],YY:[s,function(v){this.year=S(v)}],YYYY:[/\d{4}/,w("year")],Z:P,ZZ:P};function B(v){var U,R;U=v,R=F&&F.formats;for(var E=(v=U.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(x,C,M){var D=M&&M.toUpperCase();return C||R[M]||n[M]||R[D].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(c,g,b){return g||b.slice(1)}))}))).match(r),z=E.length,G=0;G-1)return new Date((I==="X"?1e3:1)*m);var u=B(I)(m),K=u.year,l=u.month,$=u.day,O=u.hours,j=u.minutes,H=u.seconds,J=u.milliseconds,h=u.zone,N=u.week,V=new Date,f=$||(K||l?1:V.getDate()),tt=K||V.getFullYear(),A=0;K&&!l||(A=l>0?l-1:V.getMonth());var Q,Z=O||0,st=j||0,at=H||0,pt=J||0;return h?new Date(Date.UTC(tt,A,f,Z,st,at,pt+60*h.offset*1e3)):o?new Date(Date.UTC(tt,A,f,Z,st,at,pt)):(Q=new Date(tt,A,f,Z,st,at,pt),N&&(Q=W(Q).week(N).toDate()),Q)}catch{return new Date("")}})(T,L,k,R),this.init(),D&&D!==!0&&(this.$L=this.locale(D).$L),M&&T!=this.format(L)&&(this.$d=new Date("")),F={}}else if(L instanceof Array)for(var c=L.length,g=1;g<=c;g+=1){p[1]=L[g-1];var b=R.apply(this,p);if(b.isValid()){this.$d=b.$d,this.$L=b.$L,this.init();break}g===c&&(this.$d=new Date(""))}else z.call(this,G)}}}))})(Qt)),Qt.exports}var Pi=Ni(),Vi=oe(Pi),Jt={exports:{}},Ri=Jt.exports,en;function zi(){return en||(en=1,(function(t,e){(function(n,r){t.exports=r()})(Ri,(function(){return function(n,r){var i=r.prototype,s=i.format;i.format=function(a){var y=this,F=this.$locale();if(!this.isValid())return s.bind(this)(a);var S=this.$utils(),w=(a||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,(function(P){switch(P){case"Q":return Math.ceil((y.$M+1)/3);case"Do":return F.ordinal(y.$D);case"gggg":return y.weekYear();case"GGGG":return y.isoWeekYear();case"wo":return F.ordinal(y.week(),"W");case"w":case"ww":return S.s(y.week(),P==="w"?1:2,"0");case"W":case"WW":return S.s(y.isoWeek(),P==="W"?1:2,"0");case"k":case"kk":return S.s(String(y.$H===0?24:y.$H),P==="k"?1:2,"0");case"X":return Math.floor(y.$d.getTime()/1e3);case"x":return y.$d.getTime();case"z":return"["+y.offsetName()+"]";case"zzz":return"["+y.offsetName("long")+"]";default:return P}}));return s.bind(this)(w)}}}))})(Jt)),Jt.exports}var qi=zi(),Bi=oe(qi),Kt={exports:{}},Zi=Kt.exports,nn;function Xi(){return nn||(nn=1,(function(t,e){(function(n,r){t.exports=r()})(Zi,(function(){var n,r,i=1e3,s=6e4,a=36e5,y=864e5,F=31536e6,S=2628e6,w=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/,P=/\[([^\]]+)]|YYYY|YY|Y|M{1,2}|D{1,2}|H{1,2}|m{1,2}|s{1,2}|SSS/g,_={years:F,months:S,days:y,hours:a,minutes:s,seconds:i,milliseconds:1,weeks:6048e5},Y=function(T){return T instanceof z},X=function(T,k,p){return new z(T,p,k.$l)},B=function(T){return r.p(T)+"s"},v=function(T){return T<0},U=function(T){return v(T)?Math.ceil(T):Math.floor(T)},R=function(T){return Math.abs(T)},E=function(T,k){return T?v(T)?{negative:!0,format:""+R(T)+k}:{negative:!1,format:""+T+k}:{negative:!1,format:""}},z=(function(){function T(p,L,x){var C=this;if(this.$d={},this.$l=x,p===void 0&&(this.$ms=0,this.parseFromMilliseconds()),L)return X(p*_[B(L)],this);if(typeof p=="number")return this.$ms=p,this.parseFromMilliseconds(),this;if(typeof p=="object")return Object.keys(p).forEach((function(c){C.$d[B(c)]=p[c]})),this.calMilliseconds(),this;if(typeof p=="string"){var M=p.match(w);if(M){var D=M.slice(2).map((function(c){return c!=null?Number(c):0}));return this.$d.years=D[0],this.$d.months=D[1],this.$d.weeks=D[2],this.$d.days=D[3],this.$d.hours=D[4],this.$d.minutes=D[5],this.$d.seconds=D[6],this.calMilliseconds(),this}}return this}var k=T.prototype;return k.calMilliseconds=function(){var p=this;this.$ms=Object.keys(this.$d).reduce((function(L,x){return L+(p.$d[x]||0)*_[x]}),0)},k.parseFromMilliseconds=function(){var p=this.$ms;this.$d.years=U(p/F),p%=F,this.$d.months=U(p/S),p%=S,this.$d.days=U(p/y),p%=y,this.$d.hours=U(p/a),p%=a,this.$d.minutes=U(p/s),p%=s,this.$d.seconds=U(p/i),p%=i,this.$d.milliseconds=p},k.toISOString=function(){var p=E(this.$d.years,"Y"),L=E(this.$d.months,"M"),x=+this.$d.days||0;this.$d.weeks&&(x+=7*this.$d.weeks);var C=E(x,"D"),M=E(this.$d.hours,"H"),D=E(this.$d.minutes,"M"),c=this.$d.seconds||0;this.$d.milliseconds&&(c+=this.$d.milliseconds/1e3,c=Math.round(1e3*c)/1e3);var g=E(c,"S"),b=p.negative||L.negative||C.negative||M.negative||D.negative||g.negative,m=M.format||D.format||g.format?"T":"",I=(b?"-":"")+"P"+p.format+L.format+C.format+m+M.format+D.format+g.format;return I==="P"||I==="-P"?"P0D":I},k.toJSON=function(){return this.toISOString()},k.format=function(p){var L=p||"YYYY-MM-DDTHH:mm:ss",x={Y:this.$d.years,YY:r.s(this.$d.years,2,"0"),YYYY:r.s(this.$d.years,4,"0"),M:this.$d.months,MM:r.s(this.$d.months,2,"0"),D:this.$d.days,DD:r.s(this.$d.days,2,"0"),H:this.$d.hours,HH:r.s(this.$d.hours,2,"0"),m:this.$d.minutes,mm:r.s(this.$d.minutes,2,"0"),s:this.$d.seconds,ss:r.s(this.$d.seconds,2,"0"),SSS:r.s(this.$d.milliseconds,3,"0")};return L.replace(P,(function(C,M){return M||String(x[C])}))},k.as=function(p){return this.$ms/_[B(p)]},k.get=function(p){var L=this.$ms,x=B(p);return x==="milliseconds"?L%=1e3:L=x==="weeks"?U(L/_[x]):this.$d[x],L||0},k.add=function(p,L,x){var C;return C=L?p*_[B(L)]:Y(p)?p.$ms:X(p,this).$ms,X(this.$ms+C*(x?-1:1),this)},k.subtract=function(p,L){return this.add(p,L,!0)},k.locale=function(p){var L=this.clone();return L.$l=p,L},k.clone=function(){return X(this.$ms,this)},k.humanize=function(p){return n().add(this.$ms,"ms").locale(this.$l).fromNow(!p)},k.valueOf=function(){return this.asMilliseconds()},k.milliseconds=function(){return this.get("milliseconds")},k.asMilliseconds=function(){return this.as("milliseconds")},k.seconds=function(){return this.get("seconds")},k.asSeconds=function(){return this.as("seconds")},k.minutes=function(){return this.get("minutes")},k.asMinutes=function(){return this.as("minutes")},k.hours=function(){return this.get("hours")},k.asHours=function(){return this.as("hours")},k.days=function(){return this.get("days")},k.asDays=function(){return this.as("days")},k.weeks=function(){return this.get("weeks")},k.asWeeks=function(){return this.as("weeks")},k.months=function(){return this.get("months")},k.asMonths=function(){return this.as("months")},k.years=function(){return this.get("years")},k.asYears=function(){return this.as("years")},T})(),G=function(T,k,p){return T.add(k.years()*p,"y").add(k.months()*p,"M").add(k.days()*p,"d").add(k.hours()*p,"h").add(k.minutes()*p,"m").add(k.seconds()*p,"s").add(k.milliseconds()*p,"ms")};return function(T,k,p){n=p,r=p().$utils(),p.duration=function(C,M){var D=p.locale();return X(C,{$l:D},M)},p.isDuration=Y;var L=k.prototype.add,x=k.prototype.subtract;k.prototype.add=function(C,M){return Y(C)?G(this,C,1):L.bind(this)(C,M)},k.prototype.subtract=function(C,M){return Y(C)?G(this,C,-1):x.bind(this)(C,M)}}}))})(Kt)),Kt.exports}var Gi=Xi(),ji=oe(Gi),we=(function(){var t=d(function(D,c,g,b){for(g=g||{},b=D.length;b--;g[D[b]]=c);return g},"o"),e=[6,8,10,12,13,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,31,33,35,36,38,40],n=[1,26],r=[1,27],i=[1,28],s=[1,29],a=[1,30],y=[1,31],F=[1,32],S=[1,33],w=[1,34],P=[1,9],_=[1,10],Y=[1,11],X=[1,12],B=[1,13],v=[1,14],U=[1,15],R=[1,16],E=[1,19],z=[1,20],G=[1,21],T=[1,22],k=[1,23],p=[1,25],L=[1,35],x={trace:d(function(){},"trace"),yy:{},symbols_:{error:2,start:3,gantt:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NL:10,weekday:11,weekday_monday:12,weekday_tuesday:13,weekday_wednesday:14,weekday_thursday:15,weekday_friday:16,weekday_saturday:17,weekday_sunday:18,weekend:19,weekend_friday:20,weekend_saturday:21,dateFormat:22,inclusiveEndDates:23,topAxis:24,axisFormat:25,tickInterval:26,excludes:27,includes:28,todayMarker:29,title:30,acc_title:31,acc_title_value:32,acc_descr:33,acc_descr_value:34,acc_descr_multiline_value:35,section:36,clickStatement:37,taskTxt:38,taskData:39,click:40,callbackname:41,callbackargs:42,href:43,clickStatementDebug:44,$accept:0,$end:1},terminals_:{2:"error",4:"gantt",6:"EOF",8:"SPACE",10:"NL",12:"weekday_monday",13:"weekday_tuesday",14:"weekday_wednesday",15:"weekday_thursday",16:"weekday_friday",17:"weekday_saturday",18:"weekday_sunday",20:"weekend_friday",21:"weekend_saturday",22:"dateFormat",23:"inclusiveEndDates",24:"topAxis",25:"axisFormat",26:"tickInterval",27:"excludes",28:"includes",29:"todayMarker",30:"title",31:"acc_title",32:"acc_title_value",33:"acc_descr",34:"acc_descr_value",35:"acc_descr_multiline_value",36:"section",38:"taskTxt",39:"taskData",40:"click",41:"callbackname",42:"callbackargs",43:"href"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[11,1],[19,1],[19,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,1],[9,2],[37,2],[37,3],[37,3],[37,4],[37,3],[37,4],[37,2],[44,2],[44,3],[44,3],[44,4],[44,3],[44,4],[44,2]],performAction:d(function(c,g,b,m,I,o,W){var u=o.length-1;switch(I){case 1:return o[u-1];case 2:this.$=[];break;case 3:o[u-1].push(o[u]),this.$=o[u-1];break;case 4:case 5:this.$=o[u];break;case 6:case 7:this.$=[];break;case 8:m.setWeekday("monday");break;case 9:m.setWeekday("tuesday");break;case 10:m.setWeekday("wednesday");break;case 11:m.setWeekday("thursday");break;case 12:m.setWeekday("friday");break;case 13:m.setWeekday("saturday");break;case 14:m.setWeekday("sunday");break;case 15:m.setWeekend("friday");break;case 16:m.setWeekend("saturday");break;case 17:m.setDateFormat(o[u].substr(11)),this.$=o[u].substr(11);break;case 18:m.enableInclusiveEndDates(),this.$=o[u].substr(18);break;case 19:m.TopAxis(),this.$=o[u].substr(8);break;case 20:m.setAxisFormat(o[u].substr(11)),this.$=o[u].substr(11);break;case 21:m.setTickInterval(o[u].substr(13)),this.$=o[u].substr(13);break;case 22:m.setExcludes(o[u].substr(9)),this.$=o[u].substr(9);break;case 23:m.setIncludes(o[u].substr(9)),this.$=o[u].substr(9);break;case 24:m.setTodayMarker(o[u].substr(12)),this.$=o[u].substr(12);break;case 27:m.setDiagramTitle(o[u].substr(6)),this.$=o[u].substr(6);break;case 28:this.$=o[u].trim(),m.setAccTitle(this.$);break;case 29:case 30:this.$=o[u].trim(),m.setAccDescription(this.$);break;case 31:m.addSection(o[u].substr(8)),this.$=o[u].substr(8);break;case 33:m.addTask(o[u-1],o[u]),this.$="task";break;case 34:this.$=o[u-1],m.setClickEvent(o[u-1],o[u],null);break;case 35:this.$=o[u-2],m.setClickEvent(o[u-2],o[u-1],o[u]);break;case 36:this.$=o[u-2],m.setClickEvent(o[u-2],o[u-1],null),m.setLink(o[u-2],o[u]);break;case 37:this.$=o[u-3],m.setClickEvent(o[u-3],o[u-2],o[u-1]),m.setLink(o[u-3],o[u]);break;case 38:this.$=o[u-2],m.setClickEvent(o[u-2],o[u],null),m.setLink(o[u-2],o[u-1]);break;case 39:this.$=o[u-3],m.setClickEvent(o[u-3],o[u-1],o[u]),m.setLink(o[u-3],o[u-2]);break;case 40:this.$=o[u-1],m.setLink(o[u-1],o[u]);break;case 41:case 47:this.$=o[u-1]+" "+o[u];break;case 42:case 43:case 45:this.$=o[u-2]+" "+o[u-1]+" "+o[u];break;case 44:case 46:this.$=o[u-3]+" "+o[u-2]+" "+o[u-1]+" "+o[u];break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:17,12:n,13:r,14:i,15:s,16:a,17:y,18:F,19:18,20:S,21:w,22:P,23:_,24:Y,25:X,26:B,27:v,28:U,29:R,30:E,31:z,33:G,35:T,36:k,37:24,38:p,40:L},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:36,11:17,12:n,13:r,14:i,15:s,16:a,17:y,18:F,19:18,20:S,21:w,22:P,23:_,24:Y,25:X,26:B,27:v,28:U,29:R,30:E,31:z,33:G,35:T,36:k,37:24,38:p,40:L},t(e,[2,5]),t(e,[2,6]),t(e,[2,17]),t(e,[2,18]),t(e,[2,19]),t(e,[2,20]),t(e,[2,21]),t(e,[2,22]),t(e,[2,23]),t(e,[2,24]),t(e,[2,25]),t(e,[2,26]),t(e,[2,27]),{32:[1,37]},{34:[1,38]},t(e,[2,30]),t(e,[2,31]),t(e,[2,32]),{39:[1,39]},t(e,[2,8]),t(e,[2,9]),t(e,[2,10]),t(e,[2,11]),t(e,[2,12]),t(e,[2,13]),t(e,[2,14]),t(e,[2,15]),t(e,[2,16]),{41:[1,40],43:[1,41]},t(e,[2,4]),t(e,[2,28]),t(e,[2,29]),t(e,[2,33]),t(e,[2,34],{42:[1,42],43:[1,43]}),t(e,[2,40],{41:[1,44]}),t(e,[2,35],{43:[1,45]}),t(e,[2,36]),t(e,[2,38],{42:[1,46]}),t(e,[2,37]),t(e,[2,39])],defaultActions:{},parseError:d(function(c,g){if(g.recoverable)this.trace(c);else{var b=new Error(c);throw b.hash=g,b}},"parseError"),parse:d(function(c){var g=this,b=[0],m=[],I=[null],o=[],W=this.table,u="",K=0,l=0,$=2,O=1,j=o.slice.call(arguments,1),H=Object.create(this.lexer),J={yy:{}};for(var h in this.yy)Object.prototype.hasOwnProperty.call(this.yy,h)&&(J.yy[h]=this.yy[h]);H.setInput(c,J.yy),J.yy.lexer=H,J.yy.parser=this,typeof H.yylloc>"u"&&(H.yylloc={});var N=H.yylloc;o.push(N);var V=H.options&&H.options.ranges;typeof J.yy.parseError=="function"?this.parseError=J.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function f(ot){b.length=b.length-2*ot,I.length=I.length-ot,o.length=o.length-ot}d(f,"popStack");function tt(){var ot;return ot=m.pop()||H.lex()||O,typeof ot!="number"&&(ot instanceof Array&&(m=ot,ot=m.pop()),ot=g.symbols_[ot]||ot),ot}d(tt,"lex");for(var A,Q,Z,st,at={},pt,ut,He,Bt;;){if(Q=b[b.length-1],this.defaultActions[Q]?Z=this.defaultActions[Q]:((A===null||typeof A>"u")&&(A=tt()),Z=W[Q]&&W[Q][A]),typeof Z>"u"||!Z.length||!Z[0]){var ce="";Bt=[];for(pt in W[Q])this.terminals_[pt]&&pt>$&&Bt.push("'"+this.terminals_[pt]+"'");H.showPosition?ce="Parse error on line "+(K+1)+`: +`+H.showPosition()+` +Expecting `+Bt.join(", ")+", got '"+(this.terminals_[A]||A)+"'":ce="Parse error on line "+(K+1)+": Unexpected "+(A==O?"end of input":"'"+(this.terminals_[A]||A)+"'"),this.parseError(ce,{text:H.match,token:this.terminals_[A]||A,line:H.yylineno,loc:N,expected:Bt})}if(Z[0]instanceof Array&&Z.length>1)throw new Error("Parse Error: multiple actions possible at state: "+Q+", token: "+A);switch(Z[0]){case 1:b.push(A),I.push(H.yytext),o.push(H.yylloc),b.push(Z[1]),A=null,l=H.yyleng,u=H.yytext,K=H.yylineno,N=H.yylloc;break;case 2:if(ut=this.productions_[Z[1]][1],at.$=I[I.length-ut],at._$={first_line:o[o.length-(ut||1)].first_line,last_line:o[o.length-1].last_line,first_column:o[o.length-(ut||1)].first_column,last_column:o[o.length-1].last_column},V&&(at._$.range=[o[o.length-(ut||1)].range[0],o[o.length-1].range[1]]),st=this.performAction.apply(at,[u,l,K,J.yy,Z[1],I,o].concat(j)),typeof st<"u")return st;ut&&(b=b.slice(0,-1*ut*2),I=I.slice(0,-1*ut),o=o.slice(0,-1*ut)),b.push(this.productions_[Z[1]][0]),I.push(at.$),o.push(at._$),He=W[b[b.length-2]][b[b.length-1]],b.push(He);break;case 3:return!0}}return!0},"parse")},C=(function(){var D={EOF:1,parseError:d(function(g,b){if(this.yy.parser)this.yy.parser.parseError(g,b);else throw new Error(g)},"parseError"),setInput:d(function(c,g){return this.yy=g||this.yy||{},this._input=c,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 c=this._input[0];this.yytext+=c,this.yyleng++,this.offset++,this.match+=c,this.matched+=c;var g=c.match(/(?:\r\n?|\n).*/g);return g?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),c},"input"),unput:d(function(c){var g=c.length,b=c.split(/(?:\r\n?|\n)/g);this._input=c+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-g),this.offset-=g;var m=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),b.length-1&&(this.yylineno-=b.length-1);var I=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:b?(b.length===m.length?this.yylloc.first_column:0)+m[m.length-b.length].length-b[0].length:this.yylloc.first_column-g},this.options.ranges&&(this.yylloc.range=[I[0],I[0]+this.yyleng-g]),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(c){this.unput(this.match.slice(c))},"less"),pastInput:d(function(){var c=this.matched.substr(0,this.matched.length-this.match.length);return(c.length>20?"...":"")+c.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:d(function(){var c=this.match;return c.length<20&&(c+=this._input.substr(0,20-c.length)),(c.substr(0,20)+(c.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:d(function(){var c=this.pastInput(),g=new Array(c.length+1).join("-");return c+this.upcomingInput()+` +`+g+"^"},"showPosition"),test_match:d(function(c,g){var b,m,I;if(this.options.backtrack_lexer&&(I={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&&(I.yylloc.range=this.yylloc.range.slice(0))),m=c[0].match(/(?:\r\n?|\n).*/g),m&&(this.yylineno+=m.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:m?m[m.length-1].length-m[m.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+c[0].length},this.yytext+=c[0],this.match+=c[0],this.matches=c,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(c[0].length),this.matched+=c[0],b=this.performAction.call(this,this.yy,this,g,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),b)return b;if(this._backtrack){for(var o in I)this[o]=I[o];return!1}return!1},"test_match"),next:d(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var c,g,b,m;this._more||(this.yytext="",this.match="");for(var I=this._currentRules(),o=0;og[0].length)){if(g=b,m=o,this.options.backtrack_lexer){if(c=this.test_match(b,I[o]),c!==!1)return c;if(this._backtrack){g=!1;continue}else return!1}else if(!this.options.flex)break}return g?(c=this.test_match(g,I[m]),c!==!1?c:!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 g=this.next();return g||this.lex()},"lex"),begin:d(function(g){this.conditionStack.push(g)},"begin"),popState:d(function(){var g=this.conditionStack.length-1;return g>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(g){return g=this.conditionStack.length-1-Math.abs(g||0),g>=0?this.conditionStack[g]:"INITIAL"},"topState"),pushState:d(function(g){this.begin(g)},"pushState"),stateStackSize:d(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:d(function(g,b,m,I){switch(m){case 0:return this.begin("open_directive"),"open_directive";case 1:return this.begin("acc_title"),31;case 2:return this.popState(),"acc_title_value";case 3:return this.begin("acc_descr"),33;case 4:return this.popState(),"acc_descr_value";case 5:this.begin("acc_descr_multiline");break;case 6:this.popState();break;case 7:return"acc_descr_multiline_value";case 8:break;case 9:break;case 10:break;case 11:return 10;case 12:break;case 13:break;case 14:this.begin("href");break;case 15:this.popState();break;case 16:return 43;case 17:this.begin("callbackname");break;case 18:this.popState();break;case 19:this.popState(),this.begin("callbackargs");break;case 20:return 41;case 21:this.popState();break;case 22:return 42;case 23:this.begin("click");break;case 24:this.popState();break;case 25:return 40;case 26:return 4;case 27:return 22;case 28:return 23;case 29:return 24;case 30:return 25;case 31:return 26;case 32:return 28;case 33:return 27;case 34:return 29;case 35:return 12;case 36:return 13;case 37:return 14;case 38:return 15;case 39:return 16;case 40:return 17;case 41:return 18;case 42:return 20;case 43:return 21;case 44:return"date";case 45:return 30;case 46:return"accDescription";case 47:return 36;case 48:return 38;case 49:return 39;case 50:return":";case 51:return 6;case 52:return"INVALID"}},"anonymous"),rules:[/^(?:%%\{)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:%%(?!\{)*[^\n]*)/i,/^(?:[^\}]%%*[^\n]*)/i,/^(?:%%*[^\n]*[\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:%[^\n]*)/i,/^(?:href[\s]+["])/i,/^(?:["])/i,/^(?:[^"]*)/i,/^(?:call[\s]+)/i,/^(?:\([\s]*\))/i,/^(?:\()/i,/^(?:[^(]*)/i,/^(?:\))/i,/^(?:[^)]*)/i,/^(?:click[\s]+)/i,/^(?:[\s\n])/i,/^(?:[^\s\n]*)/i,/^(?:gantt\b)/i,/^(?:dateFormat\s[^#\n;]+)/i,/^(?:inclusiveEndDates\b)/i,/^(?:topAxis\b)/i,/^(?:axisFormat\s[^#\n;]+)/i,/^(?:tickInterval\s[^#\n;]+)/i,/^(?:includes\s[^#\n;]+)/i,/^(?:excludes\s[^#\n;]+)/i,/^(?:todayMarker\s[^\n;]+)/i,/^(?:weekday\s+monday\b)/i,/^(?:weekday\s+tuesday\b)/i,/^(?:weekday\s+wednesday\b)/i,/^(?:weekday\s+thursday\b)/i,/^(?:weekday\s+friday\b)/i,/^(?:weekday\s+saturday\b)/i,/^(?:weekday\s+sunday\b)/i,/^(?:weekend\s+friday\b)/i,/^(?:weekend\s+saturday\b)/i,/^(?:\d\d\d\d-\d\d-\d\d\b)/i,/^(?:title\s[^\n]+)/i,/^(?:accDescription\s[^#\n;]+)/i,/^(?:section\s[^\n]+)/i,/^(?:[^:\n]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[6,7],inclusive:!1},acc_descr:{rules:[4],inclusive:!1},acc_title:{rules:[2],inclusive:!1},callbackargs:{rules:[21,22],inclusive:!1},callbackname:{rules:[18,19,20],inclusive:!1},href:{rules:[15,16],inclusive:!1},click:{rules:[24,25],inclusive:!1},INITIAL:{rules:[0,1,3,5,8,9,10,11,12,13,14,17,23,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52],inclusive:!0}}};return D})();x.lexer=C;function M(){this.yy={}}return d(M,"Parser"),M.prototype=x,x.Parser=M,new M})();we.parser=we;var Qi=we;it.extend(Oi);it.extend(Vi);it.extend(Bi);var rn={friday:5,saturday:6},lt="",Ye="",Fe=void 0,Ue="",Lt=[],At=[],Ee=new Map,Ie=[],se=[],Wt="",Le="",Yn=["active","done","crit","milestone","vert"],Ae=[],_t="",qt=!1,We=!1,$e="sunday",ae="saturday",De=0,Ji=d(function(){Ie=[],se=[],Wt="",Ae=[],te=0,Ce=void 0,ee=void 0,et=[],lt="",Ye="",Le="",Fe=void 0,Ue="",Lt=[],At=[],qt=!1,We=!1,De=0,Ee=new Map,_t="",Gn(),$e="sunday",ae="saturday"},"clear"),Ki=d(function(t){_t=t},"setDiagramId"),ts=d(function(t){Ye=t},"setAxisFormat"),es=d(function(){return Ye},"getAxisFormat"),ns=d(function(t){Fe=t},"setTickInterval"),rs=d(function(){return Fe},"getTickInterval"),is=d(function(t){Ue=t},"setTodayMarker"),ss=d(function(){return Ue},"getTodayMarker"),as=d(function(t){lt=t},"setDateFormat"),os=d(function(){qt=!0},"enableInclusiveEndDates"),cs=d(function(){return qt},"endDatesAreInclusive"),us=d(function(){We=!0},"enableTopAxis"),ls=d(function(){return We},"topAxisEnabled"),fs=d(function(t){Le=t},"setDisplayMode"),ds=d(function(){return Le},"getDisplayMode"),hs=d(function(){return lt},"getDateFormat"),Fn=d((t,e)=>{const n=e.toLowerCase().split(/[\s,]+/).filter(r=>r!=="");return[...new Set([...t,...n])]},"mergeTokens"),ms=d(function(t){Lt=Fn(Lt,t)},"setIncludes"),gs=d(function(){return Lt},"getIncludes"),ys=d(function(t){At=Fn(At,t)},"setExcludes"),ks=d(function(){return At},"getExcludes"),ps=d(function(){return Ee},"getLinks"),vs=d(function(t){Wt=t,Ie.push(t)},"addSection"),Ts=d(function(){return Ie},"getSections"),xs=d(function(){let t=sn();const e=10;let n=0;for(;!t&&ny))throw new Error("Failed to find a valid date that was not excluded by `excludes` after 10,000 iterations.");t=t.add(1,"d")}return[e,a]},"fixTaskDates"),Me=d(function(t,e,n){if(n=n.trim(),d(y=>{const F=y.trim();return F==="x"||F==="X"},"isTimestampFormat")(e)&&/^\d+$/.test(n))return new Date(Number(n));const s=/^after\s+(?[\d\w- ]+)/.exec(n);if(s!==null){let y=null;for(const S of s.groups.ids.split(" ")){let w=Ct(S);w!==void 0&&(!y||w.endTime>y.endTime)&&(y=w)}if(y)return y.endTime;const F=new Date;return F.setHours(0,0,0,0),F}let a=it(n,e.trim(),!0);if(a.isValid())return a.toDate();{Tt.debug("Invalid date:"+n),Tt.debug("With date format:"+e.trim());const y=new Date(n);if(y===void 0||isNaN(y.getTime())||y.getFullYear()<-1e4||y.getFullYear()>1e4)throw new Error("Invalid date:"+n);return y}},"getStartDate"),In=d(function(t){const e=/^(\d+(?:\.\d+)?)([Mdhmswy]|ms)$/.exec(t.trim());return e!==null?[Number.parseFloat(e[1]),e[2]]:[NaN,"ms"]},"parseDuration"),Ln=d(function(t,e,n,r=!1){n=n.trim();const s=/^until\s+(?[\d\w- ]+)/.exec(n);if(s!==null){let w=null;for(const _ of s.groups.ids.split(" ")){let Y=Ct(_);Y!==void 0&&(!w||Y.startTime{window.open(n,"_self")}),Ee.set(r,n))}),Wn(t,"clickable")},"setLink"),Wn=d(function(t,e){t.split(",").forEach(function(n){let r=Ct(n);r!==void 0&&r.classes.push(e)})},"setClass"),Us=d(function(t,e,n){if(Yt().securityLevel!=="loose"||e===void 0)return;let r=[];if(typeof n=="string"){r=n.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);for(let s=0;s{jn.runFunc(e,...r)})},"setClickFun"),$n=d(function(t,e){Ae.push(function(){const n=_t?`${_t}-${t}`:t,r=document.querySelector(`[id="${n}"]`);r!==null&&r.addEventListener("click",function(){e()})},function(){const n=_t?`${_t}-${t}`:t,r=document.querySelector(`[id="${n}-text"]`);r!==null&&r.addEventListener("click",function(){e()})})},"pushFun"),Es=d(function(t,e,n){t.split(",").forEach(function(r){Us(r,e,n)}),Wn(t,"clickable")},"setClickEvent"),Is=d(function(t){Ae.forEach(function(e){e(t)})},"bindFunctions"),Ls={getConfig:d(()=>Yt().gantt,"getConfig"),clear:Ji,setDateFormat:as,getDateFormat:hs,enableInclusiveEndDates:os,endDatesAreInclusive:cs,enableTopAxis:us,topAxisEnabled:ls,setAxisFormat:ts,getAxisFormat:es,setTickInterval:ns,getTickInterval:rs,setTodayMarker:is,getTodayMarker:ss,setAccTitle:qn,getAccTitle:zn,setDiagramTitle:Rn,getDiagramTitle:Vn,setDiagramId:Ki,setDisplayMode:fs,getDisplayMode:ds,setAccDescription:Pn,getAccDescription:Nn,addSection:vs,getSections:Ts,getTasks:xs,addTask:_s,findTaskById:Ct,addTaskOrg:Ys,setIncludes:ms,getIncludes:gs,setExcludes:ys,getExcludes:ks,setClickEvent:Es,setLink:Fs,getLinks:ps,bindFunctions:Is,parseDuration:In,isInvalidDate:Un,setWeekday:bs,getWeekday:ws,setWeekend:Ds};function Oe(t,e,n){let r=!0;for(;r;)r=!1,n.forEach(function(i){const s="^\\s*"+i+"\\s*$",a=new RegExp(s);t[0].match(a)&&(e[i]=!0,t.shift(1),r=!0)})}d(Oe,"getTaskTags");it.extend(ji);var As=d(function(){Tt.debug("Something is calling, setConf, remove the call")},"setConf"),an={monday:Vt,tuesday:vn,wednesday:Tn,thursday:bt,friday:xn,saturday:bn,sunday:zt},Ws=d((t,e)=>{let n=[...t].map(()=>-1/0),r=[...t].sort((s,a)=>s.startTime-a.startTime||s.order-a.order),i=0;for(const s of r)for(let a=0;a=n[a]){n[a]=s.endTime,s.order=a+e,a>i&&(i=a);break}return i},"getMaxIntersections"),dt,Te=1e4,$s=d(function(t,e,n,r){const i=Yt().gantt;r.db.setDiagramId(e);const s=Yt().securityLevel;let a;s==="sandbox"&&(a=Zt("#i"+e));const y=s==="sandbox"?Zt(a.nodes()[0].contentDocument.body):Zt("body"),F=s==="sandbox"?a.nodes()[0].contentDocument:document,S=F.getElementById(e);dt=S.parentElement.offsetWidth,dt===void 0&&(dt=1200),i.useWidth!==void 0&&(dt=i.useWidth);const w=r.db.getTasks(),P=w.filter(x=>!x.vert);let _=[];for(const x of P)_.push(x.type);_=L(_);const Y={};let X=2*i.topPadding;if(r.db.getDisplayMode()==="compact"||i.displayMode==="compact"){const x={};for(const M of P)x[M.section]===void 0?x[M.section]=[M]:x[M.section].push(M);let C=0;for(const M of Object.keys(x)){const D=Ws(x[M],C)+1;C+=D,X+=D*(i.barHeight+i.barGap),Y[M]=D}}else{X+=P.length*(i.barHeight+i.barGap);for(const x of _)Y[x]=P.filter(C=>C.type===x).length}S.setAttribute("viewBox","0 0 "+dt+" "+X);const B=y.select(`[id="${e}"]`),v=Li().domain([rr(w,function(x){return x.startTime}),nr(w,function(x){return x.endTime})]).rangeRound([0,dt-i.leftPadding-i.rightPadding]);function U(x,C){const M=x.startTime,D=C.startTime;let c=0;return M>D?c=1:Ml.vert===$.vert?0:l.vert?1:-1);const m=x.filter(l=>!l.vert),o=[...new Set(m.map(l=>l.order))].map(l=>m.find($=>$.order===l));B.append("g").selectAll("rect").data(o).enter().append("rect").attr("x",0).attr("y",function(l,$){return $=l.order,$*C+M-2}).attr("width",function(){return b-i.rightPadding/2}).attr("height",C).attr("class",function(l){for(const[$,O]of _.entries())if(l.type===O)return"section section"+$%i.numberSectionStyles;return"section section0"}).enter();const W=B.append("g").selectAll("rect").data(x).enter(),u=r.db.getLinks();if(W.append("rect").attr("id",function(l){return e+"-"+l.id}).attr("rx",3).attr("ry",3).attr("x",function(l){return l.milestone?v(l.startTime)+D+.5*(v(l.endTime)-v(l.startTime))-.5*c:v(l.startTime)+D}).attr("y",function(l,$){return $=l.order,l.vert?i.gridLineStartPadding:$*C+M}).attr("width",function(l){return l.milestone?c:l.vert?.08*c:v(l.renderEndTime||l.endTime)-v(l.startTime)}).attr("height",function(l){return l.vert?m.length*(i.barHeight+i.barGap)+i.barHeight*2:c}).attr("transform-origin",function(l,$){return $=l.order,(v(l.startTime)+D+.5*(v(l.endTime)-v(l.startTime))).toString()+"px "+($*C+M+.5*c).toString()+"px"}).attr("class",function(l){const $="task";let O="";l.classes.length>0&&(O=l.classes.join(" "));let j=0;for(const[J,h]of _.entries())l.type===h&&(j=J%i.numberSectionStyles);let H="";return l.active?l.crit?H+=" activeCrit":H=" active":l.done?l.crit?H=" doneCrit":H=" done":l.crit&&(H+=" crit"),H.length===0&&(H=" task"),l.milestone&&(H=" milestone "+H),l.vert&&(H=" vert "+H),H+=j,H+=" "+O,$+H}),W.append("text").attr("id",function(l){return e+"-"+l.id+"-text"}).text(function(l){return l.task}).attr("font-size",i.fontSize).attr("x",function(l){let $=v(l.startTime),O=v(l.renderEndTime||l.endTime);if(l.milestone&&($+=.5*(v(l.endTime)-v(l.startTime))-.5*c,O=$+c),l.vert)return v(l.startTime)+D;const j=this.getBBox().width;return j>O-$?O+j+1.5*i.leftPadding>b?$+D-5:O+D+5:(O-$)/2+$+D}).attr("y",function(l,$){return l.vert?i.gridLineStartPadding+m.length*(i.barHeight+i.barGap)+60:($=l.order,$*C+i.barHeight/2+(i.fontSize/2-2)+M)}).attr("text-height",c).attr("class",function(l){const $=v(l.startTime);let O=v(l.endTime);l.milestone&&(O=$+c);const j=this.getBBox().width;let H="";l.classes.length>0&&(H=l.classes.join(" "));let J=0;for(const[N,V]of _.entries())l.type===V&&(J=N%i.numberSectionStyles);let h="";return l.active&&(l.crit?h="activeCritText"+J:h="activeText"+J),l.done?l.crit?h=h+" doneCritText"+J:h=h+" doneText"+J:l.crit&&(h=h+" critText"+J),l.milestone&&(h+=" milestoneText"),l.vert&&(h+=" vertText"),j>O-$?O+j+1.5*i.leftPadding>b?H+" taskTextOutsideLeft taskTextOutside"+J+" "+h:H+" taskTextOutsideRight taskTextOutside"+J+" "+h+" width-"+j:H+" taskText taskText"+J+" "+h+" width-"+j}),Yt().securityLevel==="sandbox"){let l;l=Zt("#i"+e);const $=l.nodes()[0].contentDocument;W.filter(function(O){return u.has(O.id)}).each(function(O){var j=$.querySelector("#"+CSS.escape(e+"-"+O.id)),H=$.querySelector("#"+CSS.escape(e+"-"+O.id+"-text"));const J=j.parentNode;var h=$.createElement("a");h.setAttribute("xlink:href",u.get(O.id)),h.setAttribute("target","_top"),J.appendChild(h),h.appendChild(j),h.appendChild(H)})}}d(E,"drawRects");function z(x,C,M,D,c,g,b,m){if(b.length===0&&m.length===0)return;let I,o;for(const{startTime:O,endTime:j}of g)(I===void 0||Oo)&&(o=j);if(!I||!o)return;if(it(o).diff(it(I),"year")>5){Tt.warn("The difference between the min and max time is more than 5 years. This will cause performance issues. Skipping drawing exclude days.");return}const W=r.db.getDateFormat(),u=[];let K=null,l=it(I);for(;l.valueOf()<=o;)r.db.isInvalidDate(l,W,b,m)?K?K.end=l:K={start:l,end:l}:K&&(u.push(K),K=null),l=l.add(1,"d");B.append("g").selectAll("rect").data(u).enter().append("rect").attr("id",O=>e+"-exclude-"+O.start.format("YYYY-MM-DD")).attr("x",O=>v(O.start.startOf("day"))+M).attr("y",i.gridLineStartPadding).attr("width",O=>v(O.end.endOf("day"))-v(O.start.startOf("day"))).attr("height",c-C-i.gridLineStartPadding).attr("transform-origin",function(O,j){return(v(O.start)+M+.5*(v(O.end)-v(O.start))).toString()+"px "+(j*x+.5*c).toString()+"px"}).attr("class","exclude-range")}d(z,"drawExcludeDays");function G(x,C,M,D){if(M<=0||x>C)return 1/0;const c=C-x,g=it.duration({[D??"day"]:M}).asMilliseconds();return g<=0?1/0:Math.ceil(c/g)}d(G,"getEstimatedTickCount");function T(x,C,M,D){const c=r.db.getDateFormat(),g=r.db.getAxisFormat();let b;g?b=g:c==="D"?b="%d":b=i.axisFormat??"%Y-%m-%d";let m=fr(v).tickSize(-D+C+i.gridLineStartPadding).tickFormat(ie(b));const o=/^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/.exec(r.db.getTickInterval()||i.tickInterval);if(o!==null){const W=parseInt(o[1],10);if(isNaN(W)||W<=0)Tt.warn(`Invalid tick interval value: "${o[1]}". Skipping custom tick interval.`);else{const u=o[2],K=r.db.getWeekday()||i.weekday,l=v.domain(),$=l[0],O=l[1],j=G($,O,W,u);if(j>Te)Tt.warn(`The tick interval "${W}${u}" would generate ${j} ticks, which exceeds the maximum allowed (${Te}). This may indicate an invalid date or time range. Skipping custom tick interval.`);else switch(u){case"millisecond":m.ticks(Et.every(W));break;case"second":m.ticks(vt.every(W));break;case"minute":m.ticks(Nt.every(W));break;case"hour":m.ticks(Pt.every(W));break;case"day":m.ticks(xt.every(W));break;case"week":m.ticks(an[K].every(W));break;case"month":m.ticks(Rt.every(W));break}}}if(B.append("g").attr("class","grid").attr("transform","translate("+x+", "+(D-50)+")").call(m).selectAll("text").style("text-anchor","middle").attr("fill","#000").attr("stroke","none").attr("font-size",10).attr("dy","1em"),r.db.topAxisEnabled()||i.topAxis){let W=lr(v).tickSize(-D+C+i.gridLineStartPadding).tickFormat(ie(b));if(o!==null){const u=parseInt(o[1],10);if(isNaN(u)||u<=0)Tt.warn(`Invalid tick interval value: "${o[1]}". Skipping custom tick interval.`);else{const K=o[2],l=r.db.getWeekday()||i.weekday,$=v.domain(),O=$[0],j=$[1];if(G(O,j,u,K)<=Te)switch(K){case"millisecond":W.ticks(Et.every(u));break;case"second":W.ticks(vt.every(u));break;case"minute":W.ticks(Nt.every(u));break;case"hour":W.ticks(Pt.every(u));break;case"day":W.ticks(xt.every(u));break;case"week":W.ticks(an[l].every(u));break;case"month":W.ticks(Rt.every(u));break}}}B.append("g").attr("class","grid").attr("transform","translate("+x+", "+C+")").call(W).selectAll("text").style("text-anchor","middle").attr("fill","#000").attr("stroke","none").attr("font-size",10)}}d(T,"makeGrid");function k(x,C){let M=0;const D=Object.keys(Y).map(c=>[c,Y[c]]);B.append("g").selectAll("text").data(D).enter().append(function(c){const g=c[0].split(Zn.lineBreakRegex),b=-(g.length-1)/2,m=F.createElementNS("http://www.w3.org/2000/svg","text");m.setAttribute("dy",b+"em");for(const[I,o]of g.entries()){const W=F.createElementNS("http://www.w3.org/2000/svg","tspan");W.setAttribute("alignment-baseline","central"),W.setAttribute("x","10"),I>0&&W.setAttribute("dy","1em"),W.textContent=o,m.appendChild(W)}return m}).attr("x",10).attr("y",function(c,g){if(g>0)for(let b=0;b` + .mermaid-main-font { + font-family: ${t.fontFamily}; + } + + .exclude-range { + fill: ${t.excludeBkgColor}; + } + + .section { + stroke: none; + opacity: 0.2; + } + + .section0 { + fill: ${t.sectionBkgColor}; + } + + .section2 { + fill: ${t.sectionBkgColor2}; + } + + .section1, + .section3 { + fill: ${t.altSectionBkgColor}; + opacity: 0.2; + } + + .sectionTitle0 { + fill: ${t.titleColor}; + } + + .sectionTitle1 { + fill: ${t.titleColor}; + } + + .sectionTitle2 { + fill: ${t.titleColor}; + } + + .sectionTitle3 { + fill: ${t.titleColor}; + } + + .sectionTitle { + text-anchor: start; + font-family: ${t.fontFamily}; + } + + + /* Grid and axis */ + + .grid .tick { + stroke: ${t.gridColor}; + opacity: 0.8; + shape-rendering: crispEdges; + } + + .grid .tick text { + font-family: ${t.fontFamily}; + fill: ${t.textColor}; + } + + .grid path { + stroke-width: 0; + } + + + /* Today line */ + + .today { + fill: none; + stroke: ${t.todayLineColor}; + stroke-width: 2px; + } + + + /* Task styling */ + + /* Default task */ + + .task { + stroke-width: 2; + } + + .taskText { + text-anchor: middle; + font-family: ${t.fontFamily}; + } + + .taskTextOutsideRight { + fill: ${t.taskTextDarkColor}; + text-anchor: start; + font-family: ${t.fontFamily}; + } + + .taskTextOutsideLeft { + fill: ${t.taskTextDarkColor}; + text-anchor: end; + } + + + /* Special case clickable */ + + .task.clickable { + cursor: pointer; + } + + .taskText.clickable { + cursor: pointer; + fill: ${t.taskTextClickableColor} !important; + font-weight: bold; + } + + .taskTextOutsideLeft.clickable { + cursor: pointer; + fill: ${t.taskTextClickableColor} !important; + font-weight: bold; + } + + .taskTextOutsideRight.clickable { + cursor: pointer; + fill: ${t.taskTextClickableColor} !important; + font-weight: bold; + } + + + /* Specific task settings for the sections*/ + + .taskText0, + .taskText1, + .taskText2, + .taskText3 { + fill: ${t.taskTextColor}; + } + + .task0, + .task1, + .task2, + .task3 { + fill: ${t.taskBkgColor}; + stroke: ${t.taskBorderColor}; + } + + .taskTextOutside0, + .taskTextOutside2 + { + fill: ${t.taskTextOutsideColor}; + } + + .taskTextOutside1, + .taskTextOutside3 { + fill: ${t.taskTextOutsideColor}; + } + + + /* Active task */ + + .active0, + .active1, + .active2, + .active3 { + fill: ${t.activeTaskBkgColor}; + stroke: ${t.activeTaskBorderColor}; + } + + .activeText0, + .activeText1, + .activeText2, + .activeText3 { + fill: ${t.taskTextDarkColor} !important; + } + + + /* Completed task */ + + .done0, + .done1, + .done2, + .done3 { + stroke: ${t.doneTaskBorderColor}; + fill: ${t.doneTaskBkgColor}; + stroke-width: 2; + } + + .doneText0, + .doneText1, + .doneText2, + .doneText3 { + fill: ${t.taskTextDarkColor} !important; + } + + /* Done task text displayed outside the bar sits against the diagram background, + not against the done-task bar, so it must use the outside/contrast color. */ + .doneText0.taskTextOutsideLeft, + .doneText0.taskTextOutsideRight, + .doneText1.taskTextOutsideLeft, + .doneText1.taskTextOutsideRight, + .doneText2.taskTextOutsideLeft, + .doneText2.taskTextOutsideRight, + .doneText3.taskTextOutsideLeft, + .doneText3.taskTextOutsideRight { + fill: ${t.taskTextOutsideColor} !important; + } + + + /* Tasks on the critical line */ + + .crit0, + .crit1, + .crit2, + .crit3 { + stroke: ${t.critBorderColor}; + fill: ${t.critBkgColor}; + stroke-width: 2; + } + + .activeCrit0, + .activeCrit1, + .activeCrit2, + .activeCrit3 { + stroke: ${t.critBorderColor}; + fill: ${t.activeTaskBkgColor}; + stroke-width: 2; + } + + .doneCrit0, + .doneCrit1, + .doneCrit2, + .doneCrit3 { + stroke: ${t.critBorderColor}; + fill: ${t.doneTaskBkgColor}; + stroke-width: 2; + cursor: pointer; + shape-rendering: crispEdges; + } + + .milestone { + transform: rotate(45deg) scale(0.8,0.8); + } + + .milestoneText { + font-style: italic; + } + .doneCritText0, + .doneCritText1, + .doneCritText2, + .doneCritText3 { + fill: ${t.taskTextDarkColor} !important; + } + + /* Done-crit task text outside the bar — same reasoning as doneText above. */ + .doneCritText0.taskTextOutsideLeft, + .doneCritText0.taskTextOutsideRight, + .doneCritText1.taskTextOutsideLeft, + .doneCritText1.taskTextOutsideRight, + .doneCritText2.taskTextOutsideLeft, + .doneCritText2.taskTextOutsideRight, + .doneCritText3.taskTextOutsideLeft, + .doneCritText3.taskTextOutsideRight { + fill: ${t.taskTextOutsideColor} !important; + } + + .vert { + stroke: ${t.vertLineColor}; + } + + .vertText { + font-size: 15px; + text-anchor: middle; + fill: ${t.vertLineColor} !important; + } + + .activeCritText0, + .activeCritText1, + .activeCritText2, + .activeCritText3 { + fill: ${t.taskTextDarkColor} !important; + } + + .titleText { + text-anchor: middle; + font-size: 18px; + fill: ${t.titleColor||t.textColor}; + font-family: ${t.fontFamily}; + } +`,"getStyles"),Ns=Hs,qs={parser:Qi,db:Ls,renderer:Os,styles:Ns};export{qs as diagram}; diff --git a/apps/kimi-code/dist-web/assets/gdshader-DkwncUOv.js b/apps/kimi-code/dist-web/assets/gdshader-DkwncUOv.js new file mode 100644 index 0000000000000000000000000000000000000000..87c5bb474148e56ebd953407ea35d0641763166b --- /dev/null +++ b/apps/kimi-code/dist-web/assets/gdshader-DkwncUOv.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"displayName":"GDShader","fileTypes":["gdshader"],"name":"gdshader","patterns":[{"include":"#any"}],"repository":{"any":{"patterns":[{"include":"#comment"},{"include":"#enclosed"},{"include":"#classifier"},{"include":"#definition"},{"include":"#keyword"},{"include":"#element"},{"include":"#separator"},{"include":"#operator"}]},"arraySize":{"begin":"\\\\[","captures":{"0":{"name":"punctuation.bracket.gdshader"}},"end":"]","name":"meta.array-size.gdshader","patterns":[{"include":"#comment"},{"include":"#keyword"},{"include":"#element"},{"include":"#separator"}]},"classifier":{"begin":"(?=\\\\b(?:shader_type|render_mode)\\\\b)","end":"(?<=;)","name":"meta.classifier.gdshader","patterns":[{"include":"#comment"},{"include":"#keyword"},{"include":"#identifierClassification"},{"include":"#separator"}]},"classifierKeyword":{"match":"\\\\b(?:shader_type|render_mode)\\\\b","name":"keyword.language.classifier.gdshader"},"comment":{"patterns":[{"include":"#commentLine"},{"include":"#commentBlock"}]},"commentBlock":{"begin":"/\\\\*","end":"\\\\*/","name":"comment.block.gdshader"},"commentLine":{"begin":"//","end":"$","name":"comment.line.double-slash.gdshader"},"constantFloat":{"match":"\\\\b(?:E|PI|TAU)\\\\b","name":"constant.language.float.gdshader"},"constructor":{"match":"\\\\b(?:[A-Z_a-z]\\\\w*(?=\\\\s*\\\\[\\\\s*\\\\w*\\\\s*]\\\\s*\\\\()|[A-Z]\\\\w*(?=\\\\s*\\\\())","name":"entity.name.type.constructor.gdshader"},"controlKeyword":{"match":"\\\\b(?:if|else|do|while|for|continue|break|switch|case|default|return|discard)\\\\b","name":"keyword.control.gdshader"},"definition":{"patterns":[{"include":"#structDefinition"}]},"element":{"patterns":[{"include":"#literalFloat"},{"include":"#literalInt"},{"include":"#literalBool"},{"include":"#identifierType"},{"include":"#constructor"},{"include":"#processorFunction"},{"include":"#identifierFunction"},{"include":"#swizzling"},{"include":"#identifierField"},{"include":"#constantFloat"},{"include":"#languageVariable"},{"include":"#identifierVariable"}]},"enclosed":{"begin":"\\\\(","captures":{"0":{"name":"punctuation.parenthesis.gdshader"}},"end":"\\\\)","name":"meta.parenthesis.gdshader","patterns":[{"include":"#any"}]},"fieldDefinition":{"begin":"\\\\b[A-Z_a-z]\\\\w*\\\\b","beginCaptures":{"0":{"patterns":[{"include":"#typeKeyword"},{"match":".+","name":"entity.name.type.gdshader"}]}},"end":"(?<=;)","name":"meta.definition.field.gdshader","patterns":[{"include":"#comment"},{"include":"#keyword"},{"include":"#arraySize"},{"include":"#fieldName"},{"include":"#any"}]},"fieldName":{"match":"\\\\b[A-Z_a-z]\\\\w*\\\\b","name":"entity.name.variable.field.gdshader"},"hintKeyword":{"match":"\\\\b(?:source_color|hint_(?:color|range|(?:black_)?albedo|normal|(?:default_)?(?:white|black)|aniso|anisotropy|roughness_(?:[abgr]|normal|gray))|filter_(?:nearest|linear)(?:_mipmap(?:_anisotropic)?)?|repeat_(?:en|dis)able)\\\\b","name":"support.type.annotation.gdshader"},"identifierClassification":{"match":"\\\\b[_a-z]+\\\\b","name":"entity.other.inherited-class.gdshader"},"identifierField":{"captures":{"1":{"name":"punctuation.accessor.gdshader"},"2":{"name":"entity.name.variable.field.gdshader"}},"match":"(\\\\.)\\\\s*([A-Z_a-z]\\\\w*)\\\\b(?!\\\\s*\\\\()"},"identifierFunction":{"match":"\\\\b[A-Z_a-z]\\\\w*(?=(?:\\\\s|/\\\\*(?:\\\\*(?!/)|[^*])*\\\\*/)*\\\\()","name":"entity.name.function.gdshader"},"identifierType":{"match":"\\\\b[A-Z_a-z]\\\\w*(?=(?:\\\\s*\\\\[\\\\s*\\\\w*\\\\s*])?\\\\s+[A-Z_a-z]\\\\w*\\\\b)","name":"entity.name.type.gdshader"},"identifierVariable":{"match":"\\\\b[A-Z_a-z]\\\\w*\\\\b","name":"variable.name.gdshader"},"keyword":{"patterns":[{"include":"#classifierKeyword"},{"include":"#structKeyword"},{"include":"#controlKeyword"},{"include":"#modifierKeyword"},{"include":"#precisionKeyword"},{"include":"#typeKeyword"},{"include":"#hintKeyword"}]},"languageVariable":{"match":"\\\\b[A-Z][0-9A-Z_]*\\\\b","name":"variable.language.gdshader"},"literalBool":{"match":"\\\\b(?:false|true)\\\\b","name":"constant.language.boolean.gdshader"},"literalFloat":{"match":"\\\\b(?:\\\\d+[Ee][-+]?\\\\d+|(?:\\\\d*\\\\.\\\\d+|\\\\d+\\\\.)(?:[Ee][-+]?\\\\d+)?)[Ff]?","name":"constant.numeric.float.gdshader"},"literalInt":{"match":"\\\\b(?:0[Xx]\\\\h+|\\\\d+[Uu]?)\\\\b","name":"constant.numeric.integer.gdshader"},"modifierKeyword":{"match":"\\\\b(?:const|global|instance|uniform|varying|in|out|inout|flat|smooth)\\\\b","name":"storage.modifier.gdshader"},"operator":{"match":"<<=?|>>=?|[-!\\\\&*+/<=>|]=|&&|\\\\|\\\\||[-!%\\\\&*+/<=>^|~]","name":"keyword.operator.gdshader"},"precisionKeyword":{"match":"\\\\b(?:low|medium|high)p\\\\b","name":"storage.type.built-in.primitive.precision.gdshader"},"processorFunction":{"match":"\\\\b(?:vertex|fragment|light|start|process|sky|fog)(?=(?:\\\\s|/\\\\*(?:\\\\*(?!/)|[^*])*\\\\*/)*\\\\()","name":"support.function.gdshader"},"separator":{"patterns":[{"match":"\\\\.","name":"punctuation.accessor.gdshader"},{"include":"#separatorComma"},{"match":";","name":"punctuation.terminator.statement.gdshader"},{"match":":","name":"keyword.operator.type.annotation.gdshader"}]},"separatorComma":{"match":",","name":"punctuation.separator.comma.gdshader"},"structDefinition":{"begin":"(?=\\\\bstruct\\\\b)","end":"(?<=;)","patterns":[{"include":"#comment"},{"include":"#keyword"},{"include":"#structName"},{"include":"#structDefinitionBlock"},{"include":"#separator"}]},"structDefinitionBlock":{"begin":"\\\\{","captures":{"0":{"name":"punctuation.definition.block.struct.gdshader"}},"end":"}","name":"meta.definition.block.struct.gdshader","patterns":[{"include":"#comment"},{"include":"#precisionKeyword"},{"include":"#fieldDefinition"},{"include":"#keyword"},{"include":"#any"}]},"structKeyword":{"match":"\\\\bstruct\\\\b","name":"keyword.other.struct.gdshader"},"structName":{"match":"\\\\b[A-Z_a-z]\\\\w*\\\\b","name":"entity.name.type.struct.gdshader"},"swizzling":{"captures":{"1":{"name":"punctuation.accessor.gdshader"},"2":{"name":"variable.other.property.gdshader"}},"match":"(\\\\.)\\\\s*([w-z]{2,4}|[abgr]{2,4}|[pqst]{2,4})\\\\b"},"typeKeyword":{"match":"\\\\b(?:void|bool|[biu]?vec[234]|u?int|float|mat[234]|[iu]?sampler(?:3D|2D(?:Array)?)|samplerCube)\\\\b","name":"support.type.gdshader"}},"scopeName":"source.gdshader"}')),a=[e];export{a as default}; diff --git a/apps/kimi-code/dist-web/assets/github-dark-high-contrast-E3gJ1_iC.js b/apps/kimi-code/dist-web/assets/github-dark-high-contrast-E3gJ1_iC.js new file mode 100644 index 0000000000000000000000000000000000000000..924234dfb030bb9ea784727e7457bd7b3ffcec6a --- /dev/null +++ b/apps/kimi-code/dist-web/assets/github-dark-high-contrast-E3gJ1_iC.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"colors":{"activityBar.activeBorder":"#ff967d","activityBar.background":"#0a0c10","activityBar.border":"#7a828e","activityBar.foreground":"#f0f3f6","activityBar.inactiveForeground":"#f0f3f6","activityBarBadge.background":"#409eff","activityBarBadge.foreground":"#0a0c10","badge.background":"#409eff","badge.foreground":"#0a0c10","breadcrumb.activeSelectionForeground":"#f0f3f6","breadcrumb.focusForeground":"#f0f3f6","breadcrumb.foreground":"#f0f3f6","breadcrumbPicker.background":"#272b33","button.background":"#09b43a","button.foreground":"#0a0c10","button.hoverBackground":"#26cd4d","button.secondaryBackground":"#4c525d","button.secondaryForeground":"#f0f3f6","button.secondaryHoverBackground":"#525964","checkbox.background":"#272b33","checkbox.border":"#7a828e","debugConsole.errorForeground":"#ffb1af","debugConsole.infoForeground":"#bdc4cc","debugConsole.sourceForeground":"#f7c843","debugConsole.warningForeground":"#f0b72f","debugConsoleInputIcon.foreground":"#cb9eff","debugIcon.breakpointForeground":"#ff6a69","debugTokenExpression.boolean":"#4ae168","debugTokenExpression.error":"#ffb1af","debugTokenExpression.name":"#91cbff","debugTokenExpression.number":"#4ae168","debugTokenExpression.string":"#addcff","debugTokenExpression.value":"#addcff","debugToolBar.background":"#272b33","descriptionForeground":"#f0f3f6","diffEditor.insertedLineBackground":"#09b43a26","diffEditor.insertedTextBackground":"#26cd4d4d","diffEditor.removedLineBackground":"#ff6a6926","diffEditor.removedTextBackground":"#ff94924d","dropdown.background":"#272b33","dropdown.border":"#7a828e","dropdown.foreground":"#f0f3f6","dropdown.listBackground":"#272b33","editor.background":"#0a0c10","editor.findMatchBackground":"#e09b13","editor.findMatchHighlightBackground":"#fbd66980","editor.focusedStackFrameHighlightBackground":"#09b43a","editor.foldBackground":"#9ea7b31a","editor.foreground":"#f0f3f6","editor.inactiveSelectionBackground":"#9ea7b3","editor.lineHighlightBackground":"#9ea7b31a","editor.lineHighlightBorder":"#71b7ff","editor.linkedEditingBackground":"#71b7ff12","editor.selectionBackground":"#ffffff","editor.selectionForeground":"#0a0c10","editor.selectionHighlightBackground":"#26cd4d40","editor.stackFrameHighlightBackground":"#e09b13","editor.wordHighlightBackground":"#9ea7b380","editor.wordHighlightBorder":"#9ea7b399","editor.wordHighlightStrongBackground":"#9ea7b34d","editor.wordHighlightStrongBorder":"#9ea7b399","editorBracketHighlight.foreground1":"#91cbff","editorBracketHighlight.foreground2":"#4ae168","editorBracketHighlight.foreground3":"#f7c843","editorBracketHighlight.foreground4":"#ffb1af","editorBracketHighlight.foreground5":"#ffadd4","editorBracketHighlight.foreground6":"#dbb7ff","editorBracketHighlight.unexpectedBracket.foreground":"#f0f3f6","editorBracketMatch.background":"#26cd4d40","editorBracketMatch.border":"#26cd4d99","editorCursor.foreground":"#71b7ff","editorGroup.border":"#7a828e","editorGroupHeader.tabsBackground":"#010409","editorGroupHeader.tabsBorder":"#7a828e","editorGutter.addedBackground":"#09b43a","editorGutter.deletedBackground":"#ff6a69","editorGutter.modifiedBackground":"#e09b13","editorIndentGuide.activeBackground":"#f0f3f63d","editorIndentGuide.background":"#f0f3f61f","editorInlayHint.background":"#bdc4cc33","editorInlayHint.foreground":"#f0f3f6","editorInlayHint.paramBackground":"#bdc4cc33","editorInlayHint.paramForeground":"#f0f3f6","editorInlayHint.typeBackground":"#bdc4cc33","editorInlayHint.typeForeground":"#f0f3f6","editorLineNumber.activeForeground":"#f0f3f6","editorLineNumber.foreground":"#9ea7b3","editorOverviewRuler.border":"#010409","editorWhitespace.foreground":"#7a828e","editorWidget.background":"#272b33","errorForeground":"#ff6a69","focusBorder":"#409eff","foreground":"#f0f3f6","gitDecoration.addedResourceForeground":"#26cd4d","gitDecoration.conflictingResourceForeground":"#e7811d","gitDecoration.deletedResourceForeground":"#ff6a69","gitDecoration.ignoredResourceForeground":"#9ea7b3","gitDecoration.modifiedResourceForeground":"#f0b72f","gitDecoration.submoduleResourceForeground":"#f0f3f6","gitDecoration.untrackedResourceForeground":"#26cd4d","icon.foreground":"#f0f3f6","input.background":"#0a0c10","input.border":"#7a828e","input.foreground":"#f0f3f6","input.placeholderForeground":"#9ea7b3","keybindingLabel.foreground":"#f0f3f6","list.activeSelectionBackground":"#9ea7b366","list.activeSelectionForeground":"#f0f3f6","list.focusBackground":"#409eff26","list.focusForeground":"#f0f3f6","list.highlightForeground":"#71b7ff","list.hoverBackground":"#9ea7b31a","list.hoverForeground":"#f0f3f6","list.inactiveFocusBackground":"#409eff26","list.inactiveSelectionBackground":"#9ea7b366","list.inactiveSelectionForeground":"#f0f3f6","minimapSlider.activeBackground":"#bdc4cc47","minimapSlider.background":"#bdc4cc33","minimapSlider.hoverBackground":"#bdc4cc3d","notificationCenterHeader.background":"#272b33","notificationCenterHeader.foreground":"#f0f3f6","notifications.background":"#272b33","notifications.border":"#7a828e","notifications.foreground":"#f0f3f6","notificationsErrorIcon.foreground":"#ff6a69","notificationsInfoIcon.foreground":"#71b7ff","notificationsWarningIcon.foreground":"#f0b72f","panel.background":"#010409","panel.border":"#7a828e","panelInput.border":"#7a828e","panelTitle.activeBorder":"#ff967d","panelTitle.activeForeground":"#f0f3f6","panelTitle.inactiveForeground":"#f0f3f6","peekViewEditor.background":"#9ea7b31a","peekViewEditor.matchHighlightBackground":"#e09b13","peekViewResult.background":"#0a0c10","peekViewResult.matchHighlightBackground":"#e09b13","pickerGroup.border":"#7a828e","pickerGroup.foreground":"#f0f3f6","progressBar.background":"#409eff","quickInput.background":"#272b33","quickInput.foreground":"#f0f3f6","scrollbar.shadow":"#7a828e33","scrollbarSlider.activeBackground":"#bdc4cc47","scrollbarSlider.background":"#bdc4cc33","scrollbarSlider.hoverBackground":"#bdc4cc3d","settings.headerForeground":"#f0f3f6","settings.modifiedItemIndicator":"#e09b13","sideBar.background":"#010409","sideBar.border":"#7a828e","sideBar.foreground":"#f0f3f6","sideBarSectionHeader.background":"#010409","sideBarSectionHeader.border":"#7a828e","sideBarSectionHeader.foreground":"#f0f3f6","sideBarTitle.foreground":"#f0f3f6","statusBar.background":"#0a0c10","statusBar.border":"#7a828e","statusBar.debuggingBackground":"#ff6a69","statusBar.debuggingForeground":"#0a0c10","statusBar.focusBorder":"#409eff80","statusBar.foreground":"#f0f3f6","statusBar.noFolderBackground":"#0a0c10","statusBarItem.activeBackground":"#f0f3f61f","statusBarItem.focusBorder":"#409eff","statusBarItem.hoverBackground":"#f0f3f614","statusBarItem.prominentBackground":"#9ea7b366","statusBarItem.remoteBackground":"#525964","statusBarItem.remoteForeground":"#f0f3f6","symbolIcon.arrayForeground":"#fe9a2d","symbolIcon.booleanForeground":"#71b7ff","symbolIcon.classForeground":"#fe9a2d","symbolIcon.colorForeground":"#91cbff","symbolIcon.constantForeground":["#acf7b6","#72f088","#4ae168","#26cd4d","#09b43a","#09b43a","#02a232","#008c2c","#007728","#006222"],"symbolIcon.constructorForeground":"#dbb7ff","symbolIcon.enumeratorForeground":"#fe9a2d","symbolIcon.enumeratorMemberForeground":"#71b7ff","symbolIcon.eventForeground":"#9ea7b3","symbolIcon.fieldForeground":"#fe9a2d","symbolIcon.fileForeground":"#f0b72f","symbolIcon.folderForeground":"#f0b72f","symbolIcon.functionForeground":"#cb9eff","symbolIcon.interfaceForeground":"#fe9a2d","symbolIcon.keyForeground":"#71b7ff","symbolIcon.keywordForeground":"#ff9492","symbolIcon.methodForeground":"#cb9eff","symbolIcon.moduleForeground":"#ff9492","symbolIcon.namespaceForeground":"#ff9492","symbolIcon.nullForeground":"#71b7ff","symbolIcon.numberForeground":"#26cd4d","symbolIcon.objectForeground":"#fe9a2d","symbolIcon.operatorForeground":"#91cbff","symbolIcon.packageForeground":"#fe9a2d","symbolIcon.propertyForeground":"#fe9a2d","symbolIcon.referenceForeground":"#71b7ff","symbolIcon.snippetForeground":"#71b7ff","symbolIcon.stringForeground":"#91cbff","symbolIcon.structForeground":"#fe9a2d","symbolIcon.textForeground":"#91cbff","symbolIcon.typeParameterForeground":"#91cbff","symbolIcon.unitForeground":"#71b7ff","symbolIcon.variableForeground":"#fe9a2d","tab.activeBackground":"#0a0c10","tab.activeBorder":"#0a0c10","tab.activeBorderTop":"#ff967d","tab.activeForeground":"#f0f3f6","tab.border":"#7a828e","tab.hoverBackground":"#0a0c10","tab.inactiveBackground":"#010409","tab.inactiveForeground":"#f0f3f6","tab.unfocusedActiveBorder":"#0a0c10","tab.unfocusedActiveBorderTop":"#7a828e","tab.unfocusedHoverBackground":"#9ea7b31a","terminal.ansiBlack":"#7a828e","terminal.ansiBlue":"#71b7ff","terminal.ansiBrightBlack":"#9ea7b3","terminal.ansiBrightBlue":"#91cbff","terminal.ansiBrightCyan":"#56d4dd","terminal.ansiBrightGreen":"#4ae168","terminal.ansiBrightMagenta":"#dbb7ff","terminal.ansiBrightRed":"#ffb1af","terminal.ansiBrightWhite":"#ffffff","terminal.ansiBrightYellow":"#f7c843","terminal.ansiCyan":"#39c5cf","terminal.ansiGreen":"#26cd4d","terminal.ansiMagenta":"#cb9eff","terminal.ansiRed":"#ff9492","terminal.ansiWhite":"#d9dee3","terminal.ansiYellow":"#f0b72f","terminal.foreground":"#f0f3f6","textBlockQuote.background":"#010409","textBlockQuote.border":"#7a828e","textCodeBlock.background":"#9ea7b366","textLink.activeForeground":"#71b7ff","textLink.foreground":"#71b7ff","textPreformat.background":"#9ea7b366","textPreformat.foreground":"#f0f3f6","textSeparator.foreground":"#7a828e","titleBar.activeBackground":"#0a0c10","titleBar.activeForeground":"#f0f3f6","titleBar.border":"#7a828e","titleBar.inactiveBackground":"#010409","titleBar.inactiveForeground":"#f0f3f6","tree.indentGuidesStroke":"#7a828e","welcomePage.buttonBackground":"#272b33","welcomePage.buttonHoverBackground":"#525964"},"displayName":"GitHub Dark High Contrast","name":"github-dark-high-contrast","semanticHighlighting":true,"tokenColors":[{"scope":["comment","punctuation.definition.comment","string.comment"],"settings":{"foreground":"#bdc4cc"}},{"scope":["constant.other.placeholder","constant.character"],"settings":{"foreground":"#ff9492"}},{"scope":["constant","entity.name.constant","variable.other.constant","variable.other.enummember","variable.language","entity"],"settings":{"foreground":"#91cbff"}},{"scope":["entity.name","meta.export.default","meta.definition.variable"],"settings":{"foreground":"#ffb757"}},{"scope":["variable.parameter.function","meta.jsx.children","meta.block","meta.tag.attributes","entity.name.constant","meta.object.member","meta.embedded.expression"],"settings":{"foreground":"#f0f3f6"}},{"scope":"entity.name.function","settings":{"foreground":"#dbb7ff"}},{"scope":["entity.name.tag","support.class.component"],"settings":{"foreground":"#72f088"}},{"scope":"keyword","settings":{"foreground":"#ff9492"}},{"scope":["storage","storage.type"],"settings":{"foreground":"#ff9492"}},{"scope":["storage.modifier.package","storage.modifier.import","storage.type.java"],"settings":{"foreground":"#f0f3f6"}},{"scope":["string","string punctuation.section.embedded source"],"settings":{"foreground":"#addcff"}},{"scope":"support","settings":{"foreground":"#91cbff"}},{"scope":"meta.property-name","settings":{"foreground":"#91cbff"}},{"scope":"variable","settings":{"foreground":"#ffb757"}},{"scope":"variable.other","settings":{"foreground":"#f0f3f6"}},{"scope":"invalid.broken","settings":{"fontStyle":"italic","foreground":"#ffb1af"}},{"scope":"invalid.deprecated","settings":{"fontStyle":"italic","foreground":"#ffb1af"}},{"scope":"invalid.illegal","settings":{"fontStyle":"italic","foreground":"#ffb1af"}},{"scope":"invalid.unimplemented","settings":{"fontStyle":"italic","foreground":"#ffb1af"}},{"scope":"carriage-return","settings":{"background":"#ff9492","content":"^M","fontStyle":"italic underline","foreground":"#ffffff"}},{"scope":"message.error","settings":{"foreground":"#ffb1af"}},{"scope":"string variable","settings":{"foreground":"#91cbff"}},{"scope":["source.regexp","string.regexp"],"settings":{"foreground":"#addcff"}},{"scope":["string.regexp.character-class","string.regexp constant.character.escape","string.regexp source.ruby.embedded","string.regexp string.regexp.arbitrary-repitition"],"settings":{"foreground":"#addcff"}},{"scope":"string.regexp constant.character.escape","settings":{"fontStyle":"bold","foreground":"#72f088"}},{"scope":"support.constant","settings":{"foreground":"#91cbff"}},{"scope":"support.variable","settings":{"foreground":"#91cbff"}},{"scope":"support.type.property-name.json","settings":{"foreground":"#72f088"}},{"scope":"meta.module-reference","settings":{"foreground":"#91cbff"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#ffb757"}},{"scope":["markup.heading","markup.heading entity.name"],"settings":{"fontStyle":"bold","foreground":"#91cbff"}},{"scope":"markup.quote","settings":{"foreground":"#72f088"}},{"scope":"markup.italic","settings":{"fontStyle":"italic","foreground":"#f0f3f6"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#f0f3f6"}},{"scope":["markup.underline"],"settings":{"fontStyle":"underline"}},{"scope":["markup.strikethrough"],"settings":{"fontStyle":"strikethrough"}},{"scope":"markup.inline.raw","settings":{"foreground":"#91cbff"}},{"scope":["markup.deleted","meta.diff.header.from-file","punctuation.definition.deleted"],"settings":{"background":"#ad0116","foreground":"#ffb1af"}},{"scope":["punctuation.section.embedded"],"settings":{"foreground":"#ff9492"}},{"scope":["markup.inserted","meta.diff.header.to-file","punctuation.definition.inserted"],"settings":{"background":"#006222","foreground":"#72f088"}},{"scope":["markup.changed","punctuation.definition.changed"],"settings":{"background":"#a74c00","foreground":"#ffb757"}},{"scope":["markup.ignored","markup.untracked"],"settings":{"background":"#91cbff","foreground":"#272b33"}},{"scope":"meta.diff.range","settings":{"fontStyle":"bold","foreground":"#dbb7ff"}},{"scope":"meta.diff.header","settings":{"foreground":"#91cbff"}},{"scope":"meta.separator","settings":{"fontStyle":"bold","foreground":"#91cbff"}},{"scope":"meta.output","settings":{"foreground":"#91cbff"}},{"scope":["brackethighlighter.tag","brackethighlighter.curly","brackethighlighter.round","brackethighlighter.square","brackethighlighter.angle","brackethighlighter.quote"],"settings":{"foreground":"#bdc4cc"}},{"scope":"brackethighlighter.unmatched","settings":{"foreground":"#ffb1af"}},{"scope":["constant.other.reference.link","string.other.link"],"settings":{"foreground":"#addcff"}}],"type":"dark"}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/github-light-DAi9KRSo.js b/apps/kimi-code/dist-web/assets/github-light-DAi9KRSo.js new file mode 100644 index 0000000000000000000000000000000000000000..28362e1b674a8d6d949cc748165da1ff0f60e85e --- /dev/null +++ b/apps/kimi-code/dist-web/assets/github-light-DAi9KRSo.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"colors":{"activityBar.activeBorder":"#f9826c","activityBar.background":"#fff","activityBar.border":"#e1e4e8","activityBar.foreground":"#2f363d","activityBar.inactiveForeground":"#959da5","activityBarBadge.background":"#2188ff","activityBarBadge.foreground":"#fff","badge.background":"#dbedff","badge.foreground":"#005cc5","breadcrumb.activeSelectionForeground":"#586069","breadcrumb.focusForeground":"#2f363d","breadcrumb.foreground":"#6a737d","breadcrumbPicker.background":"#fafbfc","button.background":"#159739","button.foreground":"#fff","button.hoverBackground":"#138934","button.secondaryBackground":"#e1e4e8","button.secondaryForeground":"#1b1f23","button.secondaryHoverBackground":"#d1d5da","checkbox.background":"#fafbfc","checkbox.border":"#d1d5da","debugToolBar.background":"#fff","descriptionForeground":"#6a737d","diffEditor.insertedTextBackground":"#34d05822","diffEditor.removedTextBackground":"#d73a4922","dropdown.background":"#fafbfc","dropdown.border":"#e1e4e8","dropdown.foreground":"#2f363d","dropdown.listBackground":"#fff","editor.background":"#fff","editor.findMatchBackground":"#ffdf5d","editor.findMatchHighlightBackground":"#ffdf5d66","editor.focusedStackFrameHighlightBackground":"#28a74525","editor.foldBackground":"#d1d5da11","editor.foreground":"#24292e","editor.inactiveSelectionBackground":"#0366d611","editor.lineHighlightBackground":"#f6f8fa","editor.linkedEditingBackground":"#0366d611","editor.selectionBackground":"#0366d625","editor.selectionHighlightBackground":"#34d05840","editor.selectionHighlightBorder":"#34d05800","editor.stackFrameHighlightBackground":"#ffd33d33","editor.wordHighlightBackground":"#34d05800","editor.wordHighlightBorder":"#24943e99","editor.wordHighlightStrongBackground":"#34d05800","editor.wordHighlightStrongBorder":"#24943e50","editorBracketHighlight.foreground1":"#005cc5","editorBracketHighlight.foreground2":"#e36209","editorBracketHighlight.foreground3":"#5a32a3","editorBracketHighlight.foreground4":"#005cc5","editorBracketHighlight.foreground5":"#e36209","editorBracketHighlight.foreground6":"#5a32a3","editorBracketMatch.background":"#34d05840","editorBracketMatch.border":"#34d05800","editorCursor.foreground":"#044289","editorError.foreground":"#cb2431","editorGroup.border":"#e1e4e8","editorGroupHeader.tabsBackground":"#f6f8fa","editorGroupHeader.tabsBorder":"#e1e4e8","editorGutter.addedBackground":"#28a745","editorGutter.deletedBackground":"#d73a49","editorGutter.modifiedBackground":"#2188ff","editorIndentGuide.activeBackground":"#d7dbe0","editorIndentGuide.background":"#eff2f6","editorLineNumber.activeForeground":"#24292e","editorLineNumber.foreground":"#1b1f234d","editorOverviewRuler.border":"#fff","editorWarning.foreground":"#f9c513","editorWhitespace.foreground":"#d1d5da","editorWidget.background":"#f6f8fa","errorForeground":"#cb2431","focusBorder":"#2188ff","foreground":"#444d56","gitDecoration.addedResourceForeground":"#28a745","gitDecoration.conflictingResourceForeground":"#e36209","gitDecoration.deletedResourceForeground":"#d73a49","gitDecoration.ignoredResourceForeground":"#959da5","gitDecoration.modifiedResourceForeground":"#005cc5","gitDecoration.submoduleResourceForeground":"#959da5","gitDecoration.untrackedResourceForeground":"#28a745","input.background":"#fafbfc","input.border":"#e1e4e8","input.foreground":"#2f363d","input.placeholderForeground":"#959da5","list.activeSelectionBackground":"#e2e5e9","list.activeSelectionForeground":"#2f363d","list.focusBackground":"#cce5ff","list.hoverBackground":"#ebf0f4","list.hoverForeground":"#2f363d","list.inactiveFocusBackground":"#dbedff","list.inactiveSelectionBackground":"#e8eaed","list.inactiveSelectionForeground":"#2f363d","notificationCenterHeader.background":"#e1e4e8","notificationCenterHeader.foreground":"#6a737d","notifications.background":"#fafbfc","notifications.border":"#e1e4e8","notifications.foreground":"#2f363d","notificationsErrorIcon.foreground":"#d73a49","notificationsInfoIcon.foreground":"#005cc5","notificationsWarningIcon.foreground":"#e36209","panel.background":"#f6f8fa","panel.border":"#e1e4e8","panelInput.border":"#e1e4e8","panelTitle.activeBorder":"#f9826c","panelTitle.activeForeground":"#2f363d","panelTitle.inactiveForeground":"#6a737d","pickerGroup.border":"#e1e4e8","pickerGroup.foreground":"#2f363d","progressBar.background":"#2188ff","quickInput.background":"#fafbfc","quickInput.foreground":"#2f363d","scrollbar.shadow":"#6a737d33","scrollbarSlider.activeBackground":"#959da588","scrollbarSlider.background":"#959da533","scrollbarSlider.hoverBackground":"#959da544","settings.headerForeground":"#2f363d","settings.modifiedItemIndicator":"#2188ff","sideBar.background":"#f6f8fa","sideBar.border":"#e1e4e8","sideBar.foreground":"#586069","sideBarSectionHeader.background":"#f6f8fa","sideBarSectionHeader.border":"#e1e4e8","sideBarSectionHeader.foreground":"#2f363d","sideBarTitle.foreground":"#2f363d","statusBar.background":"#fff","statusBar.border":"#e1e4e8","statusBar.debuggingBackground":"#f9826c","statusBar.debuggingForeground":"#fff","statusBar.foreground":"#586069","statusBar.noFolderBackground":"#fff","statusBarItem.prominentBackground":"#e8eaed","statusBarItem.remoteBackground":"#fff","statusBarItem.remoteForeground":"#586069","tab.activeBackground":"#fff","tab.activeBorder":"#fff","tab.activeBorderTop":"#f9826c","tab.activeForeground":"#2f363d","tab.border":"#e1e4e8","tab.hoverBackground":"#fff","tab.inactiveBackground":"#f6f8fa","tab.inactiveForeground":"#6a737d","tab.unfocusedActiveBorder":"#fff","tab.unfocusedActiveBorderTop":"#e1e4e8","tab.unfocusedHoverBackground":"#fff","terminal.ansiBlack":"#24292e","terminal.ansiBlue":"#0366d6","terminal.ansiBrightBlack":"#959da5","terminal.ansiBrightBlue":"#005cc5","terminal.ansiBrightCyan":"#3192aa","terminal.ansiBrightGreen":"#22863a","terminal.ansiBrightMagenta":"#5a32a3","terminal.ansiBrightRed":"#cb2431","terminal.ansiBrightWhite":"#d1d5da","terminal.ansiBrightYellow":"#b08800","terminal.ansiCyan":"#1b7c83","terminal.ansiGreen":"#28a745","terminal.ansiMagenta":"#5a32a3","terminal.ansiRed":"#d73a49","terminal.ansiWhite":"#6a737d","terminal.ansiYellow":"#dbab09","terminal.foreground":"#586069","terminal.tab.activeBorder":"#f9826c","terminalCursor.background":"#d1d5da","terminalCursor.foreground":"#005cc5","textBlockQuote.background":"#fafbfc","textBlockQuote.border":"#e1e4e8","textCodeBlock.background":"#f6f8fa","textLink.activeForeground":"#005cc5","textLink.foreground":"#0366d6","textPreformat.foreground":"#586069","textSeparator.foreground":"#d1d5da","titleBar.activeBackground":"#fff","titleBar.activeForeground":"#2f363d","titleBar.border":"#e1e4e8","titleBar.inactiveBackground":"#f6f8fa","titleBar.inactiveForeground":"#6a737d","tree.indentGuidesStroke":"#e1e4e8","welcomePage.buttonBackground":"#f6f8fa","welcomePage.buttonHoverBackground":"#e1e4e8"},"displayName":"GitHub Light","name":"github-light","semanticHighlighting":true,"tokenColors":[{"scope":["comment","punctuation.definition.comment","string.comment"],"settings":{"foreground":"#6a737d"}},{"scope":["constant","entity.name.constant","variable.other.constant","variable.other.enummember","variable.language"],"settings":{"foreground":"#005cc5"}},{"scope":["entity","entity.name"],"settings":{"foreground":"#6f42c1"}},{"scope":"variable.parameter.function","settings":{"foreground":"#24292e"}},{"scope":"entity.name.tag","settings":{"foreground":"#22863a"}},{"scope":"keyword","settings":{"foreground":"#d73a49"}},{"scope":["storage","storage.type"],"settings":{"foreground":"#d73a49"}},{"scope":["storage.modifier.package","storage.modifier.import","storage.type.java"],"settings":{"foreground":"#24292e"}},{"scope":["string","punctuation.definition.string","string punctuation.section.embedded source"],"settings":{"foreground":"#032f62"}},{"scope":"support","settings":{"foreground":"#005cc5"}},{"scope":"meta.property-name","settings":{"foreground":"#005cc5"}},{"scope":"variable","settings":{"foreground":"#e36209"}},{"scope":"variable.other","settings":{"foreground":"#24292e"}},{"scope":"invalid.broken","settings":{"fontStyle":"italic","foreground":"#b31d28"}},{"scope":"invalid.deprecated","settings":{"fontStyle":"italic","foreground":"#b31d28"}},{"scope":"invalid.illegal","settings":{"fontStyle":"italic","foreground":"#b31d28"}},{"scope":"invalid.unimplemented","settings":{"fontStyle":"italic","foreground":"#b31d28"}},{"scope":"carriage-return","settings":{"background":"#d73a49","content":"^M","fontStyle":"italic underline","foreground":"#fafbfc"}},{"scope":"message.error","settings":{"foreground":"#b31d28"}},{"scope":"string variable","settings":{"foreground":"#005cc5"}},{"scope":["source.regexp","string.regexp"],"settings":{"foreground":"#032f62"}},{"scope":["string.regexp.character-class","string.regexp constant.character.escape","string.regexp source.ruby.embedded","string.regexp string.regexp.arbitrary-repitition"],"settings":{"foreground":"#032f62"}},{"scope":"string.regexp constant.character.escape","settings":{"fontStyle":"bold","foreground":"#22863a"}},{"scope":"support.constant","settings":{"foreground":"#005cc5"}},{"scope":"support.variable","settings":{"foreground":"#005cc5"}},{"scope":"meta.module-reference","settings":{"foreground":"#005cc5"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#e36209"}},{"scope":["markup.heading","markup.heading entity.name"],"settings":{"fontStyle":"bold","foreground":"#005cc5"}},{"scope":"markup.quote","settings":{"foreground":"#22863a"}},{"scope":"markup.italic","settings":{"fontStyle":"italic","foreground":"#24292e"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#24292e"}},{"scope":["markup.underline"],"settings":{"fontStyle":"underline"}},{"scope":["markup.strikethrough"],"settings":{"fontStyle":"strikethrough"}},{"scope":"markup.inline.raw","settings":{"foreground":"#005cc5"}},{"scope":["markup.deleted","meta.diff.header.from-file","punctuation.definition.deleted"],"settings":{"background":"#ffeef0","foreground":"#b31d28"}},{"scope":["markup.inserted","meta.diff.header.to-file","punctuation.definition.inserted"],"settings":{"background":"#f0fff4","foreground":"#22863a"}},{"scope":["markup.changed","punctuation.definition.changed"],"settings":{"background":"#ffebda","foreground":"#e36209"}},{"scope":["markup.ignored","markup.untracked"],"settings":{"background":"#005cc5","foreground":"#f6f8fa"}},{"scope":"meta.diff.range","settings":{"fontStyle":"bold","foreground":"#6f42c1"}},{"scope":"meta.diff.header","settings":{"foreground":"#005cc5"}},{"scope":"meta.separator","settings":{"fontStyle":"bold","foreground":"#005cc5"}},{"scope":"meta.output","settings":{"foreground":"#005cc5"}},{"scope":["brackethighlighter.tag","brackethighlighter.curly","brackethighlighter.round","brackethighlighter.square","brackethighlighter.angle","brackethighlighter.quote"],"settings":{"foreground":"#586069"}},{"scope":"brackethighlighter.unmatched","settings":{"foreground":"#b31d28"}},{"scope":["constant.other.reference.link","string.other.link"],"settings":{"fontStyle":"underline","foreground":"#032f62"}}],"type":"light"}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/glimmer-js-ByusRIyA.js b/apps/kimi-code/dist-web/assets/glimmer-js-ByusRIyA.js new file mode 100644 index 0000000000000000000000000000000000000000..12f63a9f2801a2cce7b5c4acba967f19b9174d39 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/glimmer-js-ByusRIyA.js @@ -0,0 +1 @@ +import e from"./javascript-wDzz0qaB.js";import n from"./typescript-BPQ3VLAy.js";import t from"./css-CLj8gQPS.js";import a from"./html-pp8916En.js";const i=Object.freeze(JSON.parse(`{"displayName":"Glimmer JS","injections":{"L:source.gjs -comment -(string -meta.embedded)":{"patterns":[{"include":"#main"}]}},"name":"glimmer-js","patterns":[{"include":"#main"},{"include":"source.js"}],"repository":{"as-keyword":{"match":"\\\\s\\\\b(as)\\\\b(?=\\\\s\\\\|)","name":"keyword.control","patterns":[]},"as-params":{"begin":"(?)","endCaptures":{"1":{"name":"punctuation.definition.tag"},"2":{"name":"punctuation.definition.tag"}},"name":"meta.tag.any.ember-handlebars","patterns":[{"include":"#tag-like-content"}]},"digit":{"captures":{"0":{"name":"constant.numeric"},"1":{"name":"constant.numeric"},"2":{"name":"constant.numeric"}},"match":"\\\\d*(\\\\.)?\\\\d+","patterns":[]},"entities":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.entity.html.ember-handlebars"},"3":{"name":"punctuation.definition.entity.html.ember-handlebars"}},"match":"(&)([0-9A-Za-z]+|#[0-9]+|#x\\\\h+)(;)","name":"constant.character.entity.html.ember-handlebars"},{"match":"&","name":"invalid.illegal.bad-ampersand.html.ember-handlebars"}]},"glimmer-argument":{"captures":{"1":{"name":"entity.other.attribute-name.ember-handlebars.argument","patterns":[{"match":"(@)","name":"markup.italic"}]},"2":{"name":"punctuation.separator.key-value.html.ember-handlebars"}},"match":"\\\\s(@[-.0-:A-Z_a-z]+)(=)?"},"glimmer-as-stuff":{"patterns":[{"include":"#as-keyword"},{"include":"#as-params"}]},"glimmer-block":{"begin":"(\\\\{\\\\{~?)([#/])(([$\\\\--9@-Z_a-z]+))","captures":{"1":{"name":"punctuation.definition.tag"},"2":{"name":"punctuation.definition.tag"},"3":{"name":"keyword.control","patterns":[{"include":"#glimmer-component-path"},{"match":"(/)+","name":"punctuation.definition.tag"},{"match":"(\\\\.)+","name":"punctuation.definition.tag"}]}},"end":"(~?}})","name":"entity.expression.ember-handlebars","patterns":[{"include":"#glimmer-as-stuff"},{"include":"#glimmer-supexp-content"}]},"glimmer-bools":{"captures":{"0":{"name":"keyword.operator"},"1":{"name":"keyword.operator"},"2":{"name":"string.regexp"},"3":{"name":"string.regexp"},"4":{"name":"keyword.operator"}},"match":"(\\\\{\\\\{~?)(true|false|null|undefined|\\\\d*(\\\\.)?\\\\d+)(~?}})","name":"entity.expression.ember-handlebars"},"glimmer-comment-block":{"begin":"\\\\{\\\\{!--","captures":{"0":{"name":"punctuation.definition.block.comment.glimmer"}},"end":"--}}","name":"comment.block.glimmer","patterns":[{"include":"#script"},{"include":"#attention"}]},"glimmer-comment-inline":{"begin":"\\\\{\\\\{!","captures":{"0":{"name":"punctuation.definition.block.comment.glimmer"}},"end":"}}","name":"comment.inline.glimmer","patterns":[{"include":"#script"},{"include":"#attention"}]},"glimmer-component-path":{"captures":{"1":{"name":"punctuation.definition.tag"}},"match":"(::|[$._])"},"glimmer-control-expression":{"begin":"(\\\\{\\\\{~?)(([-/-9A-Z_a-z]+)\\\\s)","captures":{"1":{"name":"keyword.operator"},"2":{"name":"keyword.operator"},"3":{"name":"keyword.control"}},"end":"(~?}})","name":"entity.expression.ember-handlebars","patterns":[{"include":"#glimmer-supexp-content"}]},"glimmer-else-block":{"captures":{"0":{"name":"punctuation.definition.tag"},"1":{"name":"punctuation.definition.tag"},"2":{"name":"keyword.control"},"3":{"name":"keyword.control","patterns":[{"include":"#glimmer-subexp"},{"include":"#string-single-quoted-handlebars"},{"include":"#string-double-quoted-handlebars"},{"include":"#boolean"},{"include":"#digit"},{"include":"#param"},{"include":"#glimmer-parameter-name"},{"include":"#glimmer-parameter-value"}]},"4":{"name":"punctuation.definition.tag"}},"match":"(\\\\{\\\\{~?)(else(?:\\\\s[a-z]+\\\\s|))([\\\\x08().0-9@-Za-z\\\\s]+)?(~?}})","name":"entity.expression.ember-handlebars"},"glimmer-expression":{"begin":"(\\\\{\\\\{~?)(([-().0-9@-Z_a-z\\\\s]+))","captures":{"1":{"name":"keyword.operator"},"2":{"name":"keyword.operator"},"3":{"name":"support.function","patterns":[{"match":"\\\\(+","name":"string.regexp"},{"match":"\\\\)+","name":"string.regexp"},{"match":"(\\\\.)+","name":"punctuation.definition.tag"},{"include":"#glimmer-supexp-content"}]}},"end":"(~?}})","name":"entity.expression.ember-handlebars","patterns":[{"include":"#glimmer-supexp-content"}]},"glimmer-expression-property":{"begin":"(\\\\{\\\\{~?)((@|this.)([-.0-9A-Z_a-z]+))","captures":{"1":{"name":"keyword.operator"},"2":{"name":"keyword.operator"},"3":{"name":"support.function","patterns":[{"match":"(@|this)","name":"variable.language"},{"match":"(\\\\.)+","name":"punctuation.definition.tag"}]},"4":{"name":"support.function","patterns":[{"match":"(\\\\.)+","name":"punctuation.definition.tag"}]}},"end":"(~?}})","name":"entity.expression.ember-handlebars","patterns":[{"include":"#glimmer-supexp-content"}]},"glimmer-parameter-name":{"captures":{"1":{"name":"variable.parameter.name.ember-handlebars"},"2":{"name":"punctuation.definition.expression.ember-handlebars"}},"match":"\\\\b([-0-9A-Z_a-z]+)(\\\\s?=)","patterns":[]},"glimmer-parameter-value":{"captures":{"1":{"name":"support.function","patterns":[{"match":"(\\\\.)+","name":"punctuation.definition.tag"}]}},"match":"\\\\b([-.0-:A-Z_a-z]+)\\\\b(?!=)","patterns":[]},"glimmer-special-block":{"captures":{"0":{"name":"keyword.operator"},"1":{"name":"keyword.operator"},"2":{"name":"keyword.control"},"3":{"name":"keyword.operator"}},"match":"(\\\\{\\\\{~?)(yield|outlet)(~?}})","name":"entity.expression.ember-handlebars"},"glimmer-subexp":{"begin":"(\\\\()([-.0-9@-Za-z]+)","captures":{"1":{"name":"keyword.other"},"2":{"name":"keyword.control"}},"end":"(\\\\))","name":"entity.subexpression.ember-handlebars","patterns":[{"include":"#glimmer-supexp-content"}]},"glimmer-supexp-content":{"patterns":[{"include":"#glimmer-subexp"},{"include":"#string-single-quoted-handlebars"},{"include":"#string-double-quoted-handlebars"},{"include":"#boolean"},{"include":"#digit"},{"include":"#param"},{"include":"#glimmer-parameter-name"},{"include":"#glimmer-parameter-value"}]},"glimmer-unescaped-expression":{"begin":"\\\\{\\\\{\\\\{","captures":{"0":{"name":"keyword.operator"}},"end":"}}}","name":"entity.unescaped.expression.ember-handlebars","patterns":[{"include":"#string-single-quoted-handlebars"},{"include":"#string-double-quoted-handlebars"},{"include":"#glimmer-subexp"},{"include":"#param"}]},"html-attribute":{"captures":{"1":{"name":"entity.other.attribute-name.ember-handlebars","patterns":[{"match":"(\\\\.\\\\.\\\\.attributes)","name":"markup.bold"}]},"2":{"name":"punctuation.separator.key-value.html.ember-handlebars"}},"match":"\\\\s([-.0-:A-Z_a-z]+)(=)?"},"html-comment":{"begin":"","name":"comment.block.html","patterns":[{"match":"\\\\G-?>","name":"invalid.illegal.characters-not-allowed-here.html"},{"match":")|(?=-->))","name":"invalid.illegal.characters-not-allowed-here.html"},{"match":"--!>","name":"invalid.illegal.characters-not-allowed-here.html"}]},"core-minus-invalid":{"patterns":[{"include":"#xml-processing"},{"include":"#comment"},{"include":"#doctype"},{"include":"#cdata"},{"include":"#tags-valid"},{"include":"#entities"}]},"doctype":{"begin":"","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.doctype.html","patterns":[{"match":"\\\\G(?i:DOCTYPE)","name":"entity.name.tag.html"},{"begin":"\\"","end":"\\"","name":"string.quoted.double.html"},{"match":"[^>\\\\s]+","name":"entity.other.attribute-name.html"}]},"entities":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.entity.html"},"912":{"name":"punctuation.definition.entity.html"}},"match":"(&)(?=[A-Za-z])((a(s(ymp(eq)?|cr|t)|n(d(slope|[dv]|and)?|g(s(t|ph)|zarr|e|le|rt(vb(d)?)?|msd(a([a-h]))?)?)|c(y|irc|d|ute|E)?|tilde|o(pf|gon)|uml|p(id|os|prox(eq)?|[Ee]|acir)?|elig|f(r)?|w((?:con|)int)|l(pha|e(ph|fsym))|acute|ring|grave|m(p|a(cr|lg))|breve)|A(s(sign|cr)|nd|MP|c(y|irc)|tilde|o(pf|gon)|uml|pplyFunction|fr|Elig|lpha|acute|ring|grave|macr|breve))|(B(scr|cy|opf|umpeq|e(cause|ta|rnoullis)|fr|a(ckslash|r(v|wed))|reve)|b(s(cr|im(e)?|ol(hsub|b)?|emi)|n(ot|e(quiv)?)|c(y|ong)|ig(s(tar|qcup)|c(irc|up|ap)|triangle(down|up)|o(times|dot|plus)|uplus|vee|wedge)|o(t(tom)?|pf|wtie|x(h([DUdu])?|times|H([DUdu])?|d([LRlr])|u([LRlr])|plus|D([LRlr])|v([HLRhlr])?|U([LRlr])|V([HLRhlr])?|minus|box))|Not|dquo|u(ll(et)?|mp(e(q)?|E)?)|prime|e(caus(e)?|t(h|ween|a)|psi|rnou|mptyv)|karow|fr|l(ock|k(1([24])|34)|a(nk|ck(square|triangle(down|left|right)?|lozenge)))|a(ck(sim(eq)?|cong|prime|epsilon)|r(vee|wed(ge)?))|r(eve|vbar)|brk(tbrk)?))|(c(s(cr|u(p(e)?|b(e)?))|h(cy|i|eck(mark)?)|ylcty|c(irc|ups(sm)?|edil|a(ps|ron))|tdot|ir(scir|c(eq|le(d(R|circ|S|dash|ast)|arrow(left|right)))?|e|fnint|E|mid)?|o(n(int|g(dot)?)|p(y(sr)?|f|rod)|lon(e(q)?)?|m(p(fn|le(xes|ment))?|ma(t)?))|dot|u(darr([lr])|p(s|c([au]p)|or|dot|brcap)?|e(sc|pr)|vee|wed|larr(p)?|r(vearrow(left|right)|ly(eq(succ|prec)|vee|wedge)|arr(m)?|ren))|e(nt(erdot)?|dil|mptyv)|fr|w((?:con|)int)|lubs(uit)?|a(cute|p(s|c([au]p)|dot|and|brcup)?|r(on|et))|r(oss|arr))|C(scr|hi|c(irc|onint|edil|aron)|ircle(Minus|Times|Dot|Plus)|Hcy|o(n(tourIntegral|int|gruent)|unterClockwiseContourIntegral|p(f|roduct)|lon(e)?)|dot|up(Cap)?|OPY|e(nterDot|dilla)|fr|lo(seCurly((?:Double|)Quote)|ckwiseContourIntegral)|a(yleys|cute|p(italDifferentialD)?)|ross))|(d(s(c([ry])|trok|ol)|har([lr])|c(y|aron)|t(dot|ri(f)?)|i(sin|e|v(ide(ontimes)?|onx)?|am(s|ond(suit)?)?|gamma)|Har|z(cy|igrarr)|o(t(square|plus|eq(dot)?|minus)?|ublebarwedge|pf|wn(harpoon(left|right)|downarrows|arrow)|llar)|d(otseq|a(rr|gger))?|u(har|arr)|jcy|e(lta|g|mptyv)|f(isht|r)|wangle|lc(orn|rop)|a(sh(v)?|leth|rr|gger)|r(c(orn|rop)|bkarow)|b(karow|lac)|Arr)|D(s(cr|trok)|c(y|aron)|Scy|i(fferentialD|a(critical(Grave|Tilde|Do(t|ubleAcute)|Acute)|mond))|o(t(Dot|Equal)?|uble(Right(Tee|Arrow)|ContourIntegral|Do(t|wnArrow)|Up((?:Down|)Arrow)|VerticalBar|L(ong(RightArrow|Left((?:Right|)Arrow))|eft(RightArrow|Tee|Arrow)))|pf|wn(Right(TeeVector|Vector(Bar)?)|Breve|Tee(Arrow)?|arrow|Left(RightVector|TeeVector|Vector(Bar)?)|Arrow(Bar|UpArrow)?))|Zcy|el(ta)?|D(otrahd)?|Jcy|fr|a(shv|rr|gger)))|(e(s(cr|im|dot)|n(sp|g)|c(y|ir(c)?|olon|aron)|t([ah])|o(pf|gon)|dot|u(ro|ml)|p(si(v|lon)?|lus|ar(sl)?)|e|D(D??ot)|q(s(im|lant(less|gtr))|c(irc|olon)|u(iv(DD)?|est|als)|vparsl)|f(Dot|r)|l(s(dot)?|inters|l)?|a(ster|cute)|r(Dot|arr)|g(s(dot)?|rave)?|x(cl|ist|p(onentiale|ectation))|m(sp(1([34]))?|pty(set|v)?|acr))|E(s(cr|im)|c(y|irc|aron)|ta|o(pf|gon)|NG|dot|uml|TH|psilon|qu(ilibrium|al(Tilde)?)|fr|lement|acute|grave|x(ists|ponentialE)|m(pty((?:|Very)SmallSquare)|acr)))|(f(scr|nof|cy|ilig|o(pf|r(k(v)?|all))|jlig|partint|emale|f(ilig|l(l??ig)|r)|l(tns|lig|at)|allingdotseq|r(own|a(sl|c(1([2-68])|78|2([35])|3([458])|45|5([68])))))|F(scr|cy|illed((?:|Very)SmallSquare)|o(uriertrf|pf|rAll)|fr))|(G(scr|c(y|irc|edil)|t|opf|dot|T|Jcy|fr|amma(d)?|reater(Greater|SlantEqual|Tilde|Equal(Less)?|FullEqual|Less)|g|breve)|g(s(cr|im([el])?)|n(sim|e(q(q)?)?|E|ap(prox)?)|c(y|irc)|t(c(c|ir)|dot|quest|lPar|r(sim|dot|eq(q?less)|less|a(pprox|rr)))?|imel|opf|dot|jcy|e(s(cc|dot(o(l)?)?|l(es)?)?|q(slant|q)?|l)?|v(nE|ertneqq)|fr|E(l)?|l([Eaj])?|a(cute|p|mma(d)?)|rave|g(g)?|breve))|(h(s(cr|trok|lash)|y(phen|bull)|circ|o(ok((?:lef|righ)tarrow)|pf|arr|rbar|mtht)|e(llip|arts(uit)?|rcon)|ks([ew]arow)|fr|a(irsp|lf|r(dcy|r(cir|w)?)|milt)|bar|Arr)|H(s(cr|trok)|circ|ilbertSpace|o(pf|rizontalLine)|ump(DownHump|Equal)|fr|a(cek|t)|ARDcy))|(i(s(cr|in(s(v)?|dot|[Ev])?)|n(care|t(cal|prod|e(rcal|gers)|larhk)?|odot|fin(tie)?)?|c(y|irc)?|t(ilde)?|i(nfin|i(i??nt)|ota)?|o(cy|ta|pf|gon)|u(kcy|ml)|jlig|prod|e(cy|xcl)|quest|f([fr])|acute|grave|m(of|ped|a(cr|th|g(part|e|line))))|I(scr|n(t(e(rsection|gral))?|visible(Comma|Times))|c(y|irc)|tilde|o(ta|pf|gon)|dot|u(kcy|ml)|Ocy|Jlig|fr|Ecy|acute|grave|m(plies|a(cr|ginaryI))?))|(j(s(cr|ercy)|c(y|irc)|opf|ukcy|fr|math)|J(s(cr|ercy)|c(y|irc)|opf|ukcy|fr))|(k(scr|hcy|c(y|edil)|opf|jcy|fr|appa(v)?|green)|K(scr|c(y|edil)|Hcy|opf|Jcy|fr|appa))|(l(s(h|cr|trok|im([eg])?|q(uo(r)?|b)|aquo)|h(ar(d|u(l)?)|blk)|n(sim|e(q(q)?)?|E|ap(prox)?)|c(y|ub|e(d??il)|aron)|Barr|t(hree|c(c|ir)|imes|dot|quest|larr|r(i([ef])?|Par))?|Har|o(ng(left((?:|right)arrow)|rightarrow|mapsto)|times|z(enge|f)?|oparrow(left|right)|p(f|lus|ar)|w(ast|bar)|a(ng|rr)|brk)|d(sh|ca|quo(r)?|r((?:d|us)har))|ur((?:ds|u)har)|jcy|par(lt)?|e(s(s(sim|dot|eq(q?gtr)|approx|gtr)|cc|dot(o(r)?)?|g(es)?)?|q(slant|q)?|ft(harpoon(down|up)|threetimes|leftarrows|arrow(tail)?|right(squigarrow|harpoons|arrow(s)?))|g)?|v(nE|ertneqq)|f(isht|loor|r)|E(g)?|l(hard|corner|tri|arr)?|a(ng(d|le)?|cute|t(e(s)?|ail)?|p|emptyv|quo|rr(sim|hk|tl|pl|fs|lp|b(fs)?)?|gran|mbda)|r(har(d)?|corner|tri|arr|m)|g(E)?|m(idot|oust(ache)?)|b(arr|r(k(sl([du])|e)|ac([ek]))|brk)|A(tail|arr|rr))|L(s(h|cr|trok)|c(y|edil|aron)|t|o(ng(RightArrow|left((?:|right)arrow)|rightarrow|Left((?:Right|)Arrow))|pf|wer((?:Righ|Lef)tArrow))|T|e(ss(Greater|SlantEqual|Tilde|EqualGreater|FullEqual|Less)|ft(Right(Vector|Arrow)|Ceiling|T(ee(Vector|Arrow)?|riangle(Bar|Equal)?)|Do(ubleBracket|wn(TeeVector|Vector(Bar)?))|Up(TeeVector|DownVector|Vector(Bar)?)|Vector(Bar)?|arrow|rightarrow|Floor|A(ngleBracket|rrow(RightArrow|Bar)?)))|Jcy|fr|l(eftarrow)?|a(ng|cute|placetrf|rr|mbda)|midot))|(M(scr|cy|inusPlus|opf|u|e(diumSpace|llintrf)|fr|ap)|m(s(cr|tpos)|ho|nplus|c(y|omma)|i(nus(d(u)?|b)?|cro|d(cir|dot|ast)?)|o(dels|pf)|dash|u((?:lti|)map)?|p|easuredangle|DDot|fr|l(cp|dr)|a(cr|p(sto(down|up|left)?)?|l(t(ese)?|e)|rker)))|(n(s(hort(parallel|mid)|c(cue|[er])?|im(e(q)?)?|u(cc(eq)?|p(set(eq(q)?)?|[Ee])?|b(set(eq(q)?)?|[Ee])?)|par|qsu([bp]e)|mid)|Rightarrow|h(par|arr|Arr)|G(t(v)?|g)|c(y|ong(dot)?|up|edil|a(p|ron))|t(ilde|lg|riangle(left(eq)?|right(eq)?)|gl)|i(s(d)?|v)?|o(t(ni(v([abc]))?|in(dot|v([abc])|E)?)?|pf)|dash|u(m(sp|ero)?)?|jcy|p(olint|ar(sl|t|allel)?|r(cue|e(c(eq)?)?)?)|e(s(im|ear)|dot|quiv|ar(hk|r(ow)?)|xist(s)?|Arr)?|v(sim|infin|Harr|dash|Dash|l(t(rie)?|e|Arr)|ap|r(trie|Arr)|g([et]))|fr|w(near|ar(hk|r(ow)?)|Arr)|V([Dd]ash)|l(sim|t(ri(e)?)?|dr|e(s(s)?|q(slant|q)?|ft((?:|right)arrow))?|E|arr|Arr)|a(ng|cute|tur(al(s)?)?|p(id|os|prox|E)?|bla)|r(tri(e)?|ightarrow|arr([cw])?|Arr)|g(sim|t(r)?|e(s|q(slant|q)?)?|E)|mid|L(t(v)?|eft((?:|right)arrow)|l)|b(sp|ump(e)?))|N(scr|c(y|edil|aron)|tilde|o(nBreakingSpace|Break|t(R(ightTriangle(Bar|Equal)?|everseElement)|Greater(Greater|SlantEqual|Tilde|Equal|FullEqual|Less)?|S(u(cceeds(SlantEqual|Tilde|Equal)?|perset(Equal)?|bset(Equal)?)|quareSu(perset(Equal)?|bset(Equal)?))|Hump(DownHump|Equal)|Nested(GreaterGreater|LessLess)|C(ongruent|upCap)|Tilde(Tilde|Equal|FullEqual)?|DoubleVerticalBar|Precedes((?:Slant|)Equal)?|E(qual(Tilde)?|lement|xists)|VerticalBar|Le(ss(Greater|SlantEqual|Tilde|Equal|Less)?|ftTriangle(Bar|Equal)?))?|pf)|u|e(sted(GreaterGreater|LessLess)|wLine|gative(MediumSpace|Thi((?:n|ck)Space)|VeryThinSpace))|Jcy|fr|acute))|(o(s(cr|ol|lash)|h(m|bar)|c(y|ir(c)?)|ti(lde|mes(as)?)|S|int|opf|d(sold|iv|ot|ash|blac)|uml|p(erp|lus|ar)|elig|vbar|f(cir|r)|l(c(ir|ross)|t|ine|arr)|a(st|cute)|r(slope|igof|or|d(er(of)?|[fm])?|v|arr)?|g(t|on|rave)|m(i(nus|cron|d)|ega|acr))|O(s(cr|lash)|c(y|irc)|ti(lde|mes)|opf|dblac|uml|penCurly((?:Double|)Quote)|ver(B(ar|rac(e|ket))|Parenthesis)|fr|Elig|acute|r|grave|m(icron|ega|acr)))|(p(s(cr|i)|h(i(v)?|one|mmat)|cy|i(tchfork|v)?|o(intint|und|pf)|uncsp|er(cnt|tenk|iod|p|mil)|fr|l(us(sim|cir|two|d([ou])|e|acir|mn|b)?|an(ck(h)?|kv))|ar(s(im|l)|t|a(llel)?)?|r(sim|n(sim|E|ap)|cue|ime(s)?|o(d|p(to)?|f(surf|line|alar))|urel|e(c(sim|n(sim|eqq|approx)|curlyeq|eq|approx)?)?|E|ap)?|m)|P(s(cr|i)|hi|cy|i|o(incareplane|pf)|fr|lusMinus|artialD|r(ime|o(duct|portion(al)?)|ecedes(SlantEqual|Tilde|Equal)?)?))|(q(scr|int|opf|u(ot|est(eq)?|at(int|ernions))|prime|fr)|Q(scr|opf|UOT|fr))|(R(s(h|cr)|ho|c(y|edil|aron)|Barr|ight(Ceiling|T(ee(Vector|Arrow)?|riangle(Bar|Equal)?)|Do(ubleBracket|wn(TeeVector|Vector(Bar)?))|Up(TeeVector|DownVector|Vector(Bar)?)|Vector(Bar)?|arrow|Floor|A(ngleBracket|rrow(Bar|LeftArrow)?))|o(undImplies|pf)|uleDelayed|e(verse(UpEquilibrium|E(quilibrium|lement)))?|fr|EG|a(ng|cute|rr(tl)?)|rightarrow)|r(s(h|cr|q(uo(r)?|b)|aquo)|h(o(v)?|ar(d|u(l)?))|nmid|c(y|ub|e(d??il)|aron)|Barr|t(hree|imes|ri([ef]|ltri)?)|i(singdotseq|ng|ght(squigarrow|harpoon(down|up)|threetimes|left(harpoons|arrows)|arrow(tail)?|rightarrows))|Har|o(times|p(f|lus|ar)|a(ng|rr)|brk)|d(sh|ca|quo(r)?|ldhar)|uluhar|p(polint|ar(gt)?)|e(ct|al(s|ine|part)?|g)|f(isht|loor|r)|l(har|arr|m)|a(ng([de]|le)?|c(ute|e)|t(io(nals)?|ail)|dic|emptyv|quo|rr(sim|hk|c|tl|pl|fs|w|lp|ap|b(fs)?)?)|rarr|x|moust(ache)?|b(arr|r(k(sl([du])|e)|ac([ek]))|brk)|A(tail|arr|rr)))|(s(s(cr|tarf|etmn|mile)|h(y|c(hcy|y)|ort(parallel|mid)|arp)|c(sim|y|n(sim|E|ap)|cue|irc|polint|e(dil)?|E|a(p|ron))?|t(ar(f)?|r(ns|aight(phi|epsilon)))|i(gma([fv])?|m(ne|dot|plus|e(q)?|l(E)?|rarr|g(E)?)?)|zlig|o(pf|ftcy|l(b(ar)?)?)|dot([be])?|u(ng|cc(sim|n(sim|eqq|approx)|curlyeq|eq|approx)?|p(s(im|u([bp])|et(neq(q)?|eq(q)?)?)|hs(ol|ub)|1|n([Ee])|2|d(sub|ot)|3|plus|e(dot)?|E|larr|mult)?|m|b(s(im|u([bp])|et(neq(q)?|eq(q)?)?)|n([Ee])|dot|plus|e(dot)?|E|rarr|mult)?)|pa(des(uit)?|r)|e(swar|ct|tm(n|inus)|ar(hk|r(ow)?)|xt|mi|Arr)|q(su(p(set(eq)?|e)?|b(set(eq)?|e)?)|c(up(s)?|ap(s)?)|u(f|ar([ef]))?)|fr(own)?|w(nwar|ar(hk|r(ow)?)|Arr)|larr|acute|rarr|m(t(e(s)?)?|i(d|le)|eparsl|a(shp|llsetminus))|bquo)|S(scr|hort((?:Right|Down|Up|Left)Arrow)|c(y|irc|edil|aron)?|tar|igma|H(cy|CHcy)|opf|u(c(hThat|ceeds(SlantEqual|Tilde|Equal)?)|p(set|erset(Equal)?)?|m|b(set(Equal)?)?)|OFTcy|q(uare(Su(perset(Equal)?|bset(Equal)?)|Intersection|Union)?|rt)|fr|acute|mallCircle))|(t(s(hcy|c([ry])|trok)|h(i(nsp|ck(sim|approx))|orn|e(ta(sym|v)?|re(4|fore))|k(sim|ap))|c(y|edil|aron)|i(nt|lde|mes(d|b(ar)?)?)|o(sa|p(cir|f(ork)?|bot)?|ea)|dot|prime|elrec|fr|w(ixt|ohead((?:lef|righ)tarrow))|a(u|rget)|r(i(sb|time|dot|plus|e|angle(down|q|left(eq)?|right(eq)?)?|minus)|pezium|ade)|brk)|T(s(cr|trok)|RADE|h(i((?:n|ck)Space)|e(ta|refore))|c(y|edil|aron)|S(H??cy)|ilde(Tilde|Equal|FullEqual)?|HORN|opf|fr|a([bu])|ripleDot))|(u(scr|h(ar([lr])|blk)|c(y|irc)|t(ilde|dot|ri(f)?)|Har|o(pf|gon)|d(har|arr|blac)|u(arr|ml)|p(si(h|lon)?|harpoon(left|right)|downarrow|uparrows|lus|arrow)|f(isht|r)|wangle|l(c(orn(er)?|rop)|tri)|a(cute|rr)|r(c(orn(er)?|rop)|tri|ing)|grave|m(l|acr)|br(cy|eve)|Arr)|U(scr|n(ion(Plus)?|der(B(ar|rac(e|ket))|Parenthesis))|c(y|irc)|tilde|o(pf|gon)|dblac|uml|p(si(lon)?|downarrow|Tee(Arrow)?|per((?:Righ|Lef)tArrow)|DownArrow|Equilibrium|arrow|Arrow(Bar|DownArrow)?)|fr|a(cute|rr(ocir)?)|ring|grave|macr|br(cy|eve)))|(v(s(cr|u(pn([Ee])|bn([Ee])))|nsu([bp])|cy|Bar(v)?|zigzag|opf|dash|prop|e(e(eq|bar)?|llip|r(t|bar))|Dash|fr|ltri|a(ngrt|r(s(igma|u(psetneq(q)?|bsetneq(q)?))|nothing|t(heta|riangle(left|right))|p(hi|i|ropto)|epsilon|kappa|r(ho)?))|rtri|Arr)|V(scr|cy|opf|dash(l)?|e(e|r(yThinSpace|t(ical(Bar|Separator|Tilde|Line))?|bar))|Dash|vdash|fr|bar))|(w(scr|circ|opf|p|e(ierp|d(ge(q)?|bar))|fr|r(eath)?)|W(scr|circ|opf|edge|fr))|(X(scr|i|opf|fr)|x(s(cr|qcup)|h([Aa]rr)|nis|c(irc|up|ap)|i|o(time|dot|p(f|lus))|dtri|u(tri|plus)|vee|fr|wedge|l([Aa]rr)|r([Aa]rr)|map))|(y(scr|c(y|irc)|icy|opf|u(cy|ml)|en|fr|ac(y|ute))|Y(scr|c(y|irc)|opf|uml|Icy|Ucy|fr|acute|Acy))|(z(scr|hcy|c(y|aron)|igrarr|opf|dot|e(ta|etrf)|fr|w(n?j)|acute)|Z(scr|c(y|aron)|Hcy|opf|dot|e(ta|roWidthSpace)|fr|acute)))(;)","name":"constant.character.entity.named.$2.html"},{"captures":{"1":{"name":"punctuation.definition.entity.html"},"3":{"name":"punctuation.definition.entity.html"}},"match":"(&)#[0-9]+(;)","name":"constant.character.entity.numeric.decimal.html"},{"captures":{"1":{"name":"punctuation.definition.entity.html"},"3":{"name":"punctuation.definition.entity.html"}},"match":"(&)#[Xx]\\\\h+(;)","name":"constant.character.entity.numeric.hexadecimal.html"},{"match":"&(?=[0-9A-Za-z]+;)","name":"invalid.illegal.ambiguous-ampersand.html"}]},"math":{"patterns":[{"begin":"(?i)(<)(math)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.structure.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()","endCaptures":{"0":{"name":"meta.tag.structure.$2.end.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.element.structure.$2.html","patterns":[{"begin":"(?)\\\\G","end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]}],"repository":{"attribute":{"patterns":[{"begin":"(s(hift|ymmetric|cript(sizemultiplier|level|minsize)|t(ackalign|retchy)|ide|u([bp]scriptshift)|e(parator(s)?|lection)|rc)|h(eight|ref)|n(otation|umalign)|c(haralign|olumn(spa(n|cing)|width|lines|align)|lose|rossout)|i(n(dent(shift(first|last)?|target|align(first|last)?)|fixlinebreakstyle)|d)|o(pen|verflow)|d(i(splay(style)?|r)|e(nomalign|cimalpoint|pth))|position|e(dge|qual(columns|rows))|voffset|f(orm|ence|rame(spacing)?)|width|l(space|ine(thickness|leading|break(style|multchar)?)|o(ngdivstyle|cation)|ength|quote|argeop)|a(c(cent(under)?|tiontype)|l(t(text|img(-(height|valign|width))?)|ign(mentscope)?))|r(space|ow(spa(n|cing)|lines|align)|quote)|groupalign|x(link:href|mlns)|m(in(size|labelspacing)|ovablelimits|a(th(size|color|variant|background)|xsize))|bevelled)(?![-:\\\\w])","beginCaptures":{"0":{"name":"entity.other.attribute-name.html"}},"end":"(?=\\\\s*+[^=\\\\s])","name":"meta.attribute.$1.html","patterns":[{"include":"#attribute-interior"}]},{"begin":"([^\\\\x00- \\"'/<=>\\\\x7F-\\\\x{9F}﷐-﷯￾￿🿾🿿𯿾𯿿𿿾𿿿\\\\x{4FFFE}\\\\x{4FFFF}\\\\x{5FFFE}\\\\x{5FFFF}\\\\x{6FFFE}\\\\x{6FFFF}\\\\x{7FFFE}\\\\x{7FFFF}\\\\x{8FFFE}\\\\x{8FFFF}\\\\x{9FFFE}\\\\x{9FFFF}\\\\x{AFFFE}\\\\x{AFFFF}\\\\x{BFFFE}\\\\x{BFFFF}\\\\x{CFFFE}\\\\x{CFFFF}\\\\x{DFFFE}\\\\x{DFFFF}\\\\x{EFFFE}\\\\x{EFFFF}\\\\x{FFFFE}\\\\x{FFFFF}\\\\x{10FFFE}\\\\x{10FFFF}]+)","beginCaptures":{"0":{"name":"entity.other.attribute-name.html"}},"end":"(?=\\\\s*+[^=\\\\s])","name":"meta.attribute.unrecognized.$1.html","patterns":[{"include":"#attribute-interior"}]},{"match":"[^>\\\\s]+","name":"invalid.illegal.character-not-allowed-here.html"}]},"tags":{"patterns":[{"include":"#comment"},{"include":"#cdata"},{"captures":{"0":{"name":"meta.tag.structure.math.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(annotation|annotation-xml|semantics|menclose|merror|mfenced|mfrac|mpadded|mphantom|mroot|mrow|msqrt|mstyle|mmultiscripts|mover|mprescripts|msub|msubsup|msup|munder|munderover|none|mlabeledtr|mtable|mtd|mtr|mlongdiv|mscarries|mscarry|msgroup|msline|msrow|mstack|maction)(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.structure.math.$2.html"},{"begin":"(?i)(<)(annotation|annotation-xml|semantics|menclose|merror|mfenced|mfrac|mpadded|mphantom|mroot|mrow|msqrt|mstyle|mmultiscripts|mover|mprescripts|msub|msubsup|msup|munder|munderover|none|mlabeledtr|mtable|mtd|mtr|mlongdiv|mscarries|mscarry|msgroup|msline|msrow|mstack|maction)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.structure.math.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.inline.math.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(m(?:[inos]|space|text|aligngroup|alignmark))(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.inline.math.$2.html"},{"begin":"(?i)(<)(m(?:[inos]|space|text|aligngroup|alignmark))(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.inline.math.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.object.math.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(mglyph)(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.object.math.$2.html"},{"begin":"(?i)(<)(mglyph)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.object.math.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.other.invalid.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.illegal.unrecognized-tag.html"},"4":{"patterns":[{"include":"#attribute"}]},"6":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(([:\\\\w]+))(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.other.invalid.html"},{"begin":"(?i)(<)((\\\\w[^>\\\\s]*))(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.other.invalid.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.illegal.unrecognized-tag.html"},"4":{"patterns":[{"include":"#attribute"}]},"6":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.invalid.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"include":"#tags-invalid"}]}}},"svg":{"patterns":[{"begin":"(?i)(<)(svg)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.structure.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()","endCaptures":{"0":{"name":"meta.tag.structure.$2.end.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.element.structure.$2.html","patterns":[{"begin":"(?)\\\\G","end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]}],"repository":{"attribute":{"patterns":[{"begin":"(s(hape-rendering|ystemLanguage|cale|t(yle|itchTiles|op-(color|opacity)|dDeviation|em([hv])|artOffset|r(i(ng|kethrough-(thickness|position))|oke(-(opacity|dash(offset|array)|width|line(cap|join)|miterlimit))?))|urfaceScale|p(e(cular(Constant|Exponent)|ed)|acing|readMethod)|eed|lope)|h(oriz-(origin-x|adv-x)|eight|anging|ref(lang)?)|y([12]|ChannelSelector)?|n(umOctaves|ame)|c(y|o(ntentS((?:cript|tyle)Type)|lor(-(interpolation(-filters)?|profile|rendering))?)|ursor|l(ip(-(path|rule)|PathUnits)?|ass)|a(p-height|lcMode)|x)|t(ype|o|ext(-(decoration|anchor|rendering)|Length)|a(rget([XY])?|b(index|leValues))|ransform)|i(n(tercept|2)?|d(eographic)?|mage-rendering)|z(oomAndPan)?|o(p(erator|acity)|ver(flow|line-(thickness|position))|ffset|r(i(ent(ation)?|gin)|der))|d(y|i(splay|visor|ffuseConstant|rection)|ominant-baseline|ur|e(scent|celerate)|x)?|u(1|n(i(code(-(range|bidi))?|ts-per-em)|derline-(thickness|position))|2)|p(ing|oint(s(At([XYZ]))?|er-events)|a(nose-1|t(h(Length)?|tern(ContentUnits|Transform|Units))|int-order)|r(imitiveUnits|eserveA(spectRatio|lpha)))|e(n(d|able-background)|dgeMode|levation|x(ternalResourcesRequired|ponent))|v(i(sibility|ew(Box|Target))|-(hanging|ideographic|alphabetic|mathematical)|e(ctor-effect|r(sion|t-(origin-([xy])|adv-y)))|alues)|k([123]|e(y(Splines|Times|Points)|rn(ing|el(Matrix|UnitLength)))|4)?|f(y|il(ter(Res|Units)?|l(-(opacity|rule))?)|o(nt-(s(t(yle|retch)|ize(-adjust)?)|variant|family|weight)|rmat)|lood-(color|opacity)|r(om)?|x)|w(idth(s)?|ord-spacing|riting-mode)|l(i(ghting-color|mitingConeAngle)|ocal|e(ngthAdjust|tter-spacing)|ang)|a(scent|cc(umulate|ent-height)|ttribute(Name|Type)|zimuth|dditive|utoReverse|l(ignment-baseline|phabetic|lowReorder)|rabic-form|mplitude)|r(y|otate|e(s(tart|ult)|ndering-intent|peat(Count|Dur)|quired(Extensions|Features)|f([XY]|errerPolicy)|l)|adius|x)?|g([12]|lyph(Ref|-(name|orientation-(horizontal|vertical)))|radient(Transform|Units))|x([12]|ChannelSelector|-height|link:(show|href|t(ype|itle)|a(ctuate|rcrole)|role)|ml:(space|lang|base))?|m(in|ode|e(thod|dia)|a(sk((?:Content|)Units)?|thematical|rker(Height|-(start|end|mid)|Units|Width)|x))|b(y|ias|egin|ase(Profile|line-shift|Frequency)|box))(?![-:\\\\w])","beginCaptures":{"0":{"name":"entity.other.attribute-name.html"}},"end":"(?=\\\\s*+[^=\\\\s])","name":"meta.attribute.$1.html","patterns":[{"include":"#attribute-interior"}]},{"begin":"([^\\\\x00- \\"'/<=>\\\\x7F-\\\\x{9F}﷐-﷯￾￿🿾🿿𯿾𯿿𿿾𿿿\\\\x{4FFFE}\\\\x{4FFFF}\\\\x{5FFFE}\\\\x{5FFFF}\\\\x{6FFFE}\\\\x{6FFFF}\\\\x{7FFFE}\\\\x{7FFFF}\\\\x{8FFFE}\\\\x{8FFFF}\\\\x{9FFFE}\\\\x{9FFFF}\\\\x{AFFFE}\\\\x{AFFFF}\\\\x{BFFFE}\\\\x{BFFFF}\\\\x{CFFFE}\\\\x{CFFFF}\\\\x{DFFFE}\\\\x{DFFFF}\\\\x{EFFFE}\\\\x{EFFFF}\\\\x{FFFFE}\\\\x{FFFFF}\\\\x{10FFFE}\\\\x{10FFFF}]+)","beginCaptures":{"0":{"name":"entity.other.attribute-name.html"}},"end":"(?=\\\\s*+[^=\\\\s])","name":"meta.attribute.unrecognized.$1.html","patterns":[{"include":"#attribute-interior"}]},{"match":"[^>\\\\s]+","name":"invalid.illegal.character-not-allowed-here.html"}]},"tags":{"patterns":[{"include":"#comment"},{"include":"#cdata"},{"captures":{"0":{"name":"meta.tag.metadata.svg.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(color-profile|desc|metadata|script|style|title)(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.metadata.svg.$2.html"},{"begin":"(?i)(<)(color-profile|desc|metadata|script|style|title)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.metadata.svg.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.structure.svg.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(animateMotion|clipPath|defs|feComponentTransfer|feDiffuseLighting|feMerge|feSpecularLighting|filter|g|hatch|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|pattern|radialGradient|switch|text|textPath)(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.structure.svg.$2.html"},{"begin":"(?i)(<)(animateMotion|clipPath|defs|feComponentTransfer|feDiffuseLighting|feMerge|feSpecularLighting|filter|g|hatch|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|pattern|radialGradient|switch|text|textPath)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.structure.svg.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.inline.svg.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(a|animate|discard|feBlend|feColorMatrix|feComposite|feConvolveMatrix|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feMergeNode|feMorphology|feOffset|fePointLight|feSpotLight|feTile|feTurbulence|hatchPath|mpath|set|solidcolor|stop|tspan)(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.inline.svg.$2.html"},{"begin":"(?i)(<)(a|animate|discard|feBlend|feColorMatrix|feComposite|feConvolveMatrix|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feMergeNode|feMorphology|feOffset|fePointLight|feSpotLight|feTile|feTurbulence|hatchPath|mpath|set|solidcolor|stop|tspan)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.inline.svg.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.object.svg.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(circle|ellipse|feImage|foreignObject|image|line|path|polygon|polyline|rect|symbol|use|view)(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.object.svg.$2.html"},{"begin":"(?i)(<)(a|circle|ellipse|feImage|foreignObject|image|line|path|polygon|polyline|rect|symbol|use|view)(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.object.svg.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#attribute"}]},"5":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.other.svg.$2.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"},"4":{"patterns":[{"include":"#attribute"}]},"6":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)((altGlyph|altGlyphDef|altGlyphItem|animateColor|animateTransform|cursor|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|glyph|glyphRef|hkern|missing-glyph|tref|vkern))(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.other.svg.$2.html"},{"begin":"(?i)(<)((altGlyph|altGlyphDef|altGlyphItem|animateColor|animateTransform|cursor|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|glyph|glyphRef|hkern|missing-glyph|tref|vkern))(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.other.svg.$2.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"},"4":{"patterns":[{"include":"#attribute"}]},"6":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"captures":{"0":{"name":"meta.tag.other.invalid.void.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.illegal.unrecognized-tag.html"},"4":{"patterns":[{"include":"#attribute"}]},"6":{"name":"punctuation.definition.tag.end.html"}},"match":"(?i)(<)(([:\\\\w]+))(?=\\\\s|/?>)(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(/>)","name":"meta.element.other.invalid.html"},{"begin":"(?i)(<)((\\\\w[^>\\\\s]*))(?=\\\\s|/?>)(?:(([^\\"'>]|\\"[^\\"]*\\"|'[^']*')*)(>))?","beginCaptures":{"0":{"name":"meta.tag.other.invalid.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.illegal.unrecognized-tag.html"},"4":{"patterns":[{"include":"#attribute"}]},"6":{"name":"punctuation.definition.tag.end.html"}},"end":"(?i)()|(/>)|(?=)\\\\G","end":"(?=/>)|>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.invalid.start.html","patterns":[{"include":"#attribute"}]},{"include":"#tags"}]},{"include":"#tags-invalid"}]}}},"tags-invalid":{"patterns":[{"begin":"(\\\\s]*))(?)","endCaptures":{"1":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.$2.html","patterns":[{"include":"#attribute"}]}]},"tags-valid":{"patterns":[{"begin":"(^[\\\\t ]+)?(?=<(?i:style)\\\\b(?!-))","beginCaptures":{"1":{"name":"punctuation.whitespace.embedded.leading.html"}},"end":"(?!\\\\G)([\\\\t ]*$\\\\n?)?","endCaptures":{"1":{"name":"punctuation.whitespace.embedded.trailing.html"}},"patterns":[{"begin":"(?i)(<)(style)(?=\\\\s|/?>)","beginCaptures":{"0":{"name":"meta.tag.metadata.style.start.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"(?i)((<)/)(style)\\\\s*(>)","endCaptures":{"0":{"name":"meta.tag.metadata.style.end.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"source.css-ignored-vscode"},"3":{"name":"entity.name.tag.html"},"4":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.embedded.block.html","patterns":[{"begin":"\\\\G","captures":{"1":{"name":"punctuation.definition.tag.end.html"}},"end":"(>)","name":"meta.tag.metadata.style.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?!\\\\G)","end":"(?=)","endCaptures":{"0":{"name":"meta.tag.metadata.script.end.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.embedded.block.html","patterns":[{"begin":"\\\\G","end":"(?=/)","patterns":[{"begin":"(>)","beginCaptures":{"0":{"name":"meta.tag.metadata.script.start.html"},"1":{"name":"punctuation.definition.tag.end.html"}},"end":"((<))(?=/(?i:script))","endCaptures":{"0":{"name":"meta.tag.metadata.script.end.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"source.js-ignored-vscode"}},"patterns":[{"begin":"\\\\G","end":"(?=|type(?=[=\\\\s])(?!\\\\s*=\\\\s*(''|\\"\\"|([\\"']?)(text/(javascript(1\\\\.[0-5])?|x-javascript|jscript|livescript|(x-)?ecmascript|babel)|application/((?:(x-)?jav|(x-)?ecm)ascript)|module)[\\"'>\\\\s]))))","name":"meta.tag.metadata.script.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i:(?=type\\\\s*=\\\\s*([\\"']?)text/(x-handlebars|(x-(handlebars-)?|ng-)?template|html)[\\"'>\\\\s]))","end":"((<))(?=/(?i:script))","endCaptures":{"0":{"name":"meta.tag.metadata.script.end.html"},"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"text.html.basic"}},"patterns":[{"begin":"\\\\G","end":"(>)","endCaptures":{"1":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.script.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?!\\\\G)","end":"(?=)","endCaptures":{"1":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.script.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?!\\\\G)","end":"(?=)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.$2.void.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(noscript|title)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(col|hr|input)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.$2.void.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(address|article|aside|blockquote|body|button|caption|colgroup|datalist|dd|details|dialog|div|dl|dt|fieldset|figcaption|figure|footer|form|head|header|hgroup|html|h[1-6]|label|legend|li|main|map|menu|meter|nav|ol|optgroup|option|output|p|pre|progress|section|select|slot|summary|table|tbody|td|template|textarea|tfoot|th|thead|tr|ul)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(area|br|wbr)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.$2.void.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(a|abbr|b|bdi|bdo|cite|code|data|del|dfn|em|i|ins|kbd|mark|q|rp|rt|ruby|s|samp|small|span|strong|sub|sup|time|u|var)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(embed|img|param|source|track)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.$2.void.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)(audio|canvas|iframe|object|picture|video)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)((basefont|isindex))(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.metadata.$2.void.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)((center|frameset|noembed|noframes))(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.structure.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)((acronym|big|blink|font|strike|tt|xmp))(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)((frame))(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.$2.void.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)((applet))(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.deprecated.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.object.$2.end.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)(<)((dir|keygen|listing|menuitem|plaintext|spacer))(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.illegal.no-longer-supported.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.$2.start.html","patterns":[{"include":"#attribute"}]},{"begin":"(?i)()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"},"3":{"name":"invalid.illegal.no-longer-supported.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.$2.end.html","patterns":[{"include":"#attribute"}]},{"include":"#math"},{"include":"#svg"},{"begin":"(<)([A-Za-z][.0-9A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]*-[-.0-9A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]*)(?=\\\\s|/?>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.custom.start.html","patterns":[{"include":"#attribute"}]},{"begin":"()","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.custom.end.html","patterns":[{"include":"#attribute"}]}]},"xml-processing":{"begin":"(<\\\\?)(xml)","captures":{"1":{"name":"punctuation.definition.tag.html"},"2":{"name":"entity.name.tag.html"}},"end":"(\\\\?>)","name":"meta.tag.metadata.processing.xml.html","patterns":[{"include":"#attribute"}]}},"scopeName":"text.html.basic","embeddedLangs":["javascript","css"]}`)),r=[...t,...e,n];export{r as default}; diff --git a/apps/kimi-code/dist-web/assets/hurl-irOxFIW8.js b/apps/kimi-code/dist-web/assets/hurl-irOxFIW8.js new file mode 100644 index 0000000000000000000000000000000000000000..7ae407772406b08e4613de97315d1be261368394 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/hurl-irOxFIW8.js @@ -0,0 +1 @@ +import e from"./graphql-ChdNCCLP.js";import t from"./xml-sdJ4AIDG.js";import n from"./csv-fuZLfV_i.js";import"./javascript-wDzz0qaB.js";import"./typescript-BPQ3VLAy.js";import"./jsx-g9-lgVsj.js";import"./tsx-COt5Ahok.js";import"./java-CylS5w8V.js";const a=Object.freeze(JSON.parse('{"displayName":"Hurl","name":"hurl","patterns":[{"include":"#comments"},{"include":"#sections"},{"include":"#http"},{"include":"#strings"},{"include":"#body"},{"include":"#request"}],"repository":{"body":{"patterns":[{"begin":"```graphql(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"}},"end":"```$","name":"meta.embedded.block.graphql.hurl","patterns":[{"include":"source.graphql"}]},{"begin":"```xml(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"}},"end":"```$","name":"meta.embedded.block.xml.hurl","patterns":[{"include":"text.xml"}]},{"begin":"```json(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"}},"end":"```$","name":"meta.embedded.block.json.hurl","patterns":[{"include":"text.json"}]},{"begin":"```csv(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"}},"end":"```$","name":"meta.embedded.block.csv.hurl","patterns":[{"include":"text.csv"}]},{"begin":"```hex(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"}},"contentName":"text.plain","end":"```$","name":"string.quoted.multiline.hurl"},{"begin":"```base64(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"}},"contentName":"text.plain","end":"```$","name":"string.quoted.multiline.hurl"},{"begin":"```([^,]*)(,\\\\w+)*$","beginCaptures":{"1":{"name":"support.type"},"2":{"name":"support.type"}},"end":"```$","name":"string.quoted.multiline.hurl"},{"match":"`(\\\\\\\\.|[^\\\\\\\\`])*`","name":"string.quoted.backtick.hurl","patterns":[{"include":"#escapes"}]},{"begin":"\\\\b(base64|hex),","beginCaptures":{"1":{"name":"support.function.name"}},"contentName":"text.plain","end":";","endCaptures":{"0":{"name":"support.function"}},"name":"support.function","patterns":[{"include":"#placeholders"}]}]},"comments":{"patterns":[{"match":"#.*$","name":"comment.line.number-sign.hurl"}]},"escapes":{"patterns":[{"match":"\\\\\\\\[\\"#\\\\\\\\`bnrtu]","name":"constant.character.escape.hurl"}]},"http":{"patterns":[{"captures":{"1":{"name":"constant.language.version.hurl"},"3":{"name":"constant.numeric.status.hurl"}},"match":"\\\\b(HTTP(/(?:1\\\\.0|1\\\\.1|2))?)([\\\\t ]+([0-9]{3}))?\\\\b"}]},"placeholders":{"patterns":[{"begin":"(\\\\{\\\\{)\\\\s*","beginCaptures":{"1":{"name":"string.interpolated.hurl"}},"contentName":"variable.other.hurl","end":"\\\\s*(}})","endCaptures":{"1":{"name":"string.interpolated.hurl"}}}]},"request":{"patterns":[{"match":"\\\\b(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|TRACE|CONNECT)\\\\b","name":"keyword.control.method.hurl"},{"captures":{"1":{"name":"string.unquoted.url.hurl","patterns":[{"include":"#placeholders"}]}},"match":"(https?://[^\\\\t\\\\n]+)\\\\s*$","name":"string.unquoted.url.hurl"},{"begin":"^([-0-9A-Za-z]+)(:)\\\\s*","beginCaptures":{"1":{"name":"entity.name.tag.header.hurl"},"2":{"name":"punctuation.separator.key-value.hurl"}},"contentName":"string.unquoted.hurl","end":"$","name":"entity.name.tag.header.hurl","patterns":[{"include":"#placeholders"}]}]},"sections":{"patterns":[{"match":"^\\\\s*\\\\[(QueryStringParams|Query|FormParams|Form|MultipartFormData|Multipart|Cookies|Captures|Asserts|BasicAuth|Options)]","name":"entity.name.section.hurl"}]},"strings":{"patterns":[{"match":"\\"(\\\\\\\\.|[^\\"\\\\\\\\])*\\"","name":"string.quoted.double.hurl","patterns":[{"include":"#escapes"}]}]}},"scopeName":"source.hurl","embeddedLangs":["graphql","xml","csv"]}')),c=[...e,...t,...n,a];export{c as default}; diff --git a/apps/kimi-code/dist-web/assets/index-Dc9ox5VC.js b/apps/kimi-code/dist-web/assets/index-Dc9ox5VC.js new file mode 100644 index 0000000000000000000000000000000000000000..d3d90bbfc0084cdfdb47b2dd3f23512961393568 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/index-Dc9ox5VC.js @@ -0,0 +1,7 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-CSaMMAzR.js","assets/index-DGpUsOcn.js","assets/index-Baap3_X9.js","assets/index-dAouBbjn.css"])))=>i.map(i=>d[i]); +import{bR as Q}from"./index-Baap3_X9.js";var Y=class{chunks=[];cached="";dirty=!1;length=0;append(e){e&&(this.chunks.push(e),this.length+=e.length,this.dirty=!0,this.chunks.length>256&&this.compact())}clear(e=""){this.chunks=e?[e]:[],this.cached=e,this.dirty=!1,this.length=e.length}toString(){return this.dirty&&(this.cached=this.chunks.join(""),this.dirty=!1),this.cached}compact(){this.chunks=[this.chunks.join("")]}};function $(e,i){e.replaceChildren();const t=document.createElement("div");t.className="stream-diffs-shell",t.style.overflow="auto",t.style.maxHeight=typeof i=="number"?`${i}px`:i??"none";const n=document.createElement("div");return n.className="stream-diffs-surface",t.appendChild(n),e.appendChild(t),{shell:t,surface:n}}function E(e,i,t){return{name:e,contents:i,lang:t}}var Z=class{input;container;surface;instance;diff;selectedLines=null;disposed=!1;renderListeners=new Set;visualRevision=0;visualReadyPromise=Promise.resolve(!1);resolveVisualReady;constructor(e){this.input=e}async mount(e){this.disposed=!1,this.container=e,this.surface=$(e).surface,await this.render()}async update(e){this.input=e,this.surface&&await this.render(!0)}updateFile(e,i){return this.update({kind:"file",file:e,annotations:i,options:this.input.kind==="file"?this.input.options:void 0,workerManager:this.input.kind==="file"?this.input.workerManager:void 0})}updateDiff(e,i,t){return this.update({kind:"diff",oldFile:e,newFile:i,annotations:t,options:z(this.input)?this.input.options:void 0,workerManager:z(this.input)?this.input.workerManager:void 0})}updateParsedDiff(e,i){return this.update({kind:"diff",fileDiff:e,annotations:i,options:z(this.input)?this.input.options:void 0,workerManager:z(this.input)?this.input.workerManager:void 0})}updatePatch(e,i=0,t,n=0){return this.update({kind:"patch",patch:e,patchIndex:n,fileIndex:i,annotations:t,options:this.input.kind==="patch"?this.input.options:void 0,workerManager:this.input.kind==="patch"?this.input.workerManager:void 0})}updateMergeConflict(e,i){return this.update({kind:"merge-conflict",file:e,annotations:i,options:this.input.kind==="merge-conflict"?this.input.options:void 0,workerManager:this.input.kind==="merge-conflict"?this.input.workerManager:void 0})}setSelectedLines(e){this.selectedLines=e,this.instance?.setSelectedLines(e)}setAnnotations(e){this.instance&&(this.input.kind==="file"?(this.input.annotations=e,this.instance.setLineAnnotations(this.input.annotations)):(this.input.annotations=e,this.instance.setLineAnnotations(this.input.annotations)),this.emitRender())}setThemeType(e){this.input.options?this.input.options={...this.input.options,themeType:e}:this.input.options={themeType:e},this.instance?.setThemeType(e)}async setTheme(e){this.input.options?this.input.options={...this.input.options,theme:e}:this.input.options={theme:e},this.surface&&await this.render(!1)}async setOptions(e){this.input.options=e,this.surface&&await this.render(!1)}acceptReject(e,i){if(!z(this.input)||!this.diff)throw new Error("acceptReject() requires a diff view");const{diffAcceptRejectHunk:t}=this.module;return this.diff=t(this.diff,e,i),this.instance.render({fileDiff:this.diff,containerWrapper:this.surface,lineAnnotations:this.input.annotations}),this.diff}resolveConflict(e,i){if(this.input.kind!=="merge-conflict")throw new Error("resolveConflict() requires a merge-conflict view");const t=this.instance.resolveConflict(e,i);return t&&(this.input.file=t.file,this.diff=t.fileDiff),t?.file}getResolvedFile(){if(!z(this.input)||!this.diff||this.diff.isPartial)return;const e="newFile"in this.input?this.input.newFile:void 0;return{name:e?.name??this.diff.name,contents:this.diff.additionLines.join(""),lang:e?.lang??this.diff.lang}}getDiff(){return this.diff}getInput(){return this.input}getNativeInstance(){return this.instance}onDidRender(e){return this.renderListeners.add(e),{dispose:()=>this.renderListeners.delete(e)}}async whenVisualReady(){let e=this.visualReadyPromise;for(;;){const i=await e;if(e===this.visualReadyPromise)return i;e=this.visualReadyPromise}}dispose(){this.disposed=!0,this.invalidateVisualReady(),this.instance?.cleanUp(),this.instance=void 0,this.surface=void 0,this.container?.replaceChildren(),this.container=void 0,this.renderListeners.clear()}module;async render(e=!0){const i=this.surface;if(!i||this.disposed)return;const t=this.beginVisualRender(),n=this.module??=await Q(()=>import("./index-CSaMMAzR.js"),__vite__mapDeps([0,1,2,3]));if(this.disposed||i!==this.surface)return;if(this.instance?.cleanUp(),i.replaceChildren(),this.input.kind==="file"){const o=new n.File(b(this.input.options,()=>this.markVisualReady(t)),this.input.workerManager);o.render({file:this.input.file,containerWrapper:i,lineAnnotations:this.input.annotations}),this.instance=o,o.setSelectedLines(this.selectedLines),this.diff=void 0;return}if(z(this.input)){if(e||!this.diff)if(this.input.kind==="patch"){const a=n.parsePatchFiles(this.input.patch)[this.input.patchIndex??0];if(!a)throw new Error(`Patch does not contain patch index ${this.input.patchIndex??0}`);const d=a.files[this.input.fileIndex??0];if(!d)throw new Error(`Patch does not contain file index ${this.input.fileIndex??0}`);this.diff=d}else"fileDiff"in this.input?this.diff=this.input.fileDiff:this.diff=n.parseDiffFromFile(this.input.oldFile,this.input.newFile,this.input.options?.parseDiffOptions);const o=new n.FileDiff(b(this.input.options,()=>this.markVisualReady(t)),this.input.workerManager);o.render({fileDiff:this.diff,containerWrapper:i,lineAnnotations:this.input.annotations}),this.instance=o,o.setSelectedLines(this.selectedLines);return}const r=new n.UnresolvedFile(b(this.input.options,()=>this.markVisualReady(t)),this.input.workerManager);r.render({file:this.input.file,containerWrapper:i,lineAnnotations:this.input.annotations}),this.instance=r,r.setSelectedLines(this.selectedLines),this.diff=r.fileDiff}emitRender(){for(const e of this.renderListeners)e()}beginVisualRender(){this.resolveVisualReady?.(!1);const e=++this.visualRevision;return this.visualReadyPromise=new Promise(i=>{this.resolveVisualReady=i}),e}markVisualReady(e){this.disposed||e!==this.visualRevision||(this.resolveVisualReady?.(!0),this.resolveVisualReady=void 0,this.emitRender())}invalidateVisualReady(){this.visualRevision++,this.resolveVisualReady?.(!1),this.resolveVisualReady=void 0}};function x(e){return new Z(e)}function ee(e){return!e||e.useTokenTransformer===!0||!e.onTokenClick&&!e.onTokenEnter&&!e.onTokenLeave?e:{...e,useTokenTransformer:!0}}function b(e,i){const t=ee(e),n=t?.onPostRender;return{...t,onPostRender(...r){n?.(...r),i()}}}function z(e){return e.kind==="diff"||e.kind==="patch"}var K=class{options;state="idle";stats={characters:0,lines:0,writes:0,resets:0,renderMode:"plain-text",overflowed:!1};text=new Y;pending=[];scheduled;generation=0;container;shell;surface;finalizedSurface;plainText;finalizePromise;renderListeners=new Set;finalizedRenderSubscription;constructor(e={}){this.options=e}async mount(e){if(this.state==="disposed")throw new Error("Cannot mount a disposed code stream. Create a new controller instead.");++this.generation,this.cancelScheduledFlush(),this.finalizedSurface?.dispose(),this.finalizedRenderSubscription?.dispose(),this.container?.replaceChildren(),this.finalizedSurface=void 0,this.finalizedRenderSubscription=void 0,this.plainText=void 0,this.pending=[],this.setState("mounting"),this.container=e;const{shell:i,surface:t}=$(e,this.options.maxHeight);this.shell=i,this.surface=t,this.mountPlainText(t),this.stats.startedAt??=performance.now(),this.setState("streaming")}append(e){if(e){if(this.state==="finalized"||this.state==="finalizing"||this.state==="disposed")throw new Error(`Cannot append while stream is ${this.state}`);this.text.append(e),this.stats.characters=this.text.length,this.stats.lines+=ie(e)+(this.stats.lines===0?1:0),this.pending.push(e),this.scheduleFlush()}}updateSnapshot(e){const i=this.text.toString();if(e.startsWith(i)){this.append(e.slice(i.length));return}const t=this.options.nonAppendBehavior??"reset";if(t!=="ignore"){if(t==="throw")throw new Error("Snapshot violates the append-only stream contract");return this.reset(e)}}async consume(e){try{if(Symbol.asyncIterator in e)for await(const i of e)this.append(i);else{const i=e.getReader();try{for(;;){const{done:t,value:n}=await i.read();if(t)break;this.append(n)}}finally{i.releaseLock()}}}catch(i){throw this.fail(i),i}}async flush(){if(this.cancelScheduledFlush(),!this.pending.length)return;const e=this.shouldFollowViewport(),i=this.pending.join("");this.pending.length=0,this.plainText?.append(i),this.stats.writes++,this.followViewport(e),this.emitRender()}finalize(e={view:"stream"}){if(this.state==="finalized")return Promise.resolve();if(this.finalizePromise)return this.finalizePromise;const i=this.performFinalize(e).finally(()=>{this.finalizePromise===i&&(this.finalizePromise=void 0)});return this.finalizePromise=i,i}async performFinalize(e){if(this.state==="disposed")throw new Error("Cannot finalize a disposed code stream");const i=this.generation;if(this.setState("finalizing"),await this.flush(),i!==this.generation)return;if(this.stats.finalizedAt=performance.now(),!e.view||e.view==="stream"){this.setState("finalized");return}const t=this.surface;if(!t)throw new Error("Mount the stream before finalizing to a file or diff view");const n=this.options.fileName??`code.${this.options.language??"txt"}`,r=E(n,this.getText(),this.options.language);let o;if(e.view==="file"){const{annotations:c,workerManager:g,view:S,...T}=e;o=x({kind:"file",file:r,annotations:c,options:{theme:this.options.theme,themeType:this.options.themeType,...T},workerManager:g??this.options.workerManager})}else{const{annotations:c,original:g,workerManager:S,view:T,...L}=e;o=x({kind:"diff",oldFile:E(n,g,this.options.language),newFile:r,annotations:c,options:{theme:this.options.theme,themeType:this.options.themeType,...L},workerManager:S??this.options.workerManager})}const a=document.createElement("div");if(a.className="stream-diffs-finalized",await o.mount(a),i!==this.generation){o.dispose();return}const d=this.shell,p=d?.scrollTop??0,h=d?d.scrollHeight-d.scrollTop-d.clientHeight:0;t.replaceWith(a),this.surface=a,this.plainText=void 0,this.finalizedSurface=o,this.finalizedRenderSubscription=o.onDidRender(()=>this.emitRender()),d&&(this.options.autoScroll==="always"||this.options.autoScroll!=="never"&&h<=(this.options.autoScrollThresholdPx??32)?d.scrollTop=d.scrollHeight:d.scrollTop=p),this.setState("finalized"),this.emitRender()}async reset(e=""){const i=this.container;++this.generation,this.cancelScheduledFlush(),this.finalizedSurface?.dispose(),this.finalizedRenderSubscription?.dispose(),this.finalizedSurface=void 0,this.finalizedRenderSubscription=void 0,this.plainText=void 0,this.pending=[],this.finalizePromise=void 0,this.text.clear(),this.stats.resets++,this.stats.characters=0,this.stats.lines=0,this.stats.renderMode="plain-text",this.stats.overflowed=!1,this.setState("idle"),e&&this.append(e),i&&await this.mount(i)}setThemeType(e){this.options.themeType=e,this.finalizedSurface?.setThemeType(e)}async setTheme(e){this.options.theme=e,this.finalizedSurface&&await this.finalizedSurface.setTheme(e)}async setLanguage(e){if(e===this.options.language||(this.options.language=e,!this.finalizedSurface))return;const i=this.finalizedSurface.getInput();i.kind==="file"?await this.finalizedSurface.updateFile({...i.file,lang:e},i.annotations):i.kind==="diff"&&"oldFile"in i&&await this.finalizedSurface.updateDiff({...i.oldFile,lang:e},{...i.newFile,lang:e},i.annotations)}getText(){return this.text.toString()}getState(){return this.state}getStats(){return{...this.stats}}getElement(){return this.shell}getFinalizedSurface(){return this.finalizedSurface}onDidRender(e){return this.renderListeners.add(e),{dispose:()=>this.renderListeners.delete(e)}}dispose(){++this.generation,this.cancelScheduledFlush(),this.finalizedSurface?.dispose(),this.finalizedRenderSubscription?.dispose(),this.container?.replaceChildren(),this.plainText=void 0,this.container=void 0,this.surface=void 0,this.shell=void 0,this.finalizedSurface=void 0,this.finalizedRenderSubscription=void 0,this.finalizePromise=void 0,this.renderListeners.clear(),this.setState("disposed")}scheduleFlush(){if(this.scheduled!=null||!this.plainText)return;const e=this.options.flushStrategy??"raf";e==="raf"&&typeof requestAnimationFrame=="function"?this.scheduled=requestAnimationFrame(()=>void this.flush()):this.scheduled=globalThis.setTimeout(()=>void this.flush(),e==="raf"?0:e.intervalMs)}cancelScheduledFlush(){this.scheduled!=null&&(typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(this.scheduled),clearTimeout(this.scheduled),this.scheduled=void 0)}shouldFollowViewport(){const e=this.shell;return!e||this.options.autoScroll==="never"?!1:this.options.autoScroll==="always"?!0:e.scrollHeight-e.scrollTop-e.clientHeight<=(this.options.autoScrollThresholdPx??32)}followViewport(e=this.shouldFollowViewport()){this.shell&&e&&(this.shell.scrollTop=this.shell.scrollHeight)}mountPlainText(e){const i=document.createElement("pre");i.className="stream-diffs-plain-text",i.dataset.streamDiffsState="streaming",i.style.margin="0",i.style.whiteSpace=this.options.wrap?"pre-wrap":"pre",i.style.overflowWrap=this.options.wrap?"anywhere":"normal",i.textContent=this.getText(),e.replaceChildren(i),this.plainText=i}setState(e){this.state=e,this.options.onStateChange?.(e)}emitRender(){for(const e of this.renderListeners)e()}fail(e){this.state!=="disposed"&&(this.setState("error"),this.options.onError?.(e))}};function ie(e){let i=0;for(let t=0;t{this.finalizePromise===i&&(this.finalizePromise=void 0)});return this.finalizePromise=i,i}async performFinalize(e){if(this.state==="disposed")throw new Error("Cannot finalize a disposed diff stream");const i=this.surface;if(!i)throw new Error("Mount the diff stream before finalizing it");const t=this.generation;this.setState("finalizing");const n=x({kind:"diff",oldFile:this.asFile(this.original),newFile:this.asFile(this.modified),annotations:e,options:{...this.options,diffStyle:this.options.diffStyle??"unified"},workerManager:this.options.workerManager}),r=document.createElement("div");if(r.className="stream-diffs-finalized",await n.mount(r),t!==this.generation){n.dispose();return}const o=this.shell,a=o?.scrollTop??0;return i.replaceWith(r),this.surface=r,this.finalizedSurface=n,this.finalizedRenderSubscription=n.onDidRender(()=>this.emitRender()),o&&(o.scrollTop=a),this.setState("finalized"),this.emitRender(),n}setThemeType(e){this.options.themeType=e,this.finalizedSurface?.setThemeType(e)}async setTheme(e){this.options.theme=e,this.finalizedSurface&&await this.finalizedSurface.setTheme(e)}async setLanguage(e){if(e!==this.options.language){if(this.options.language=e,this.finalizedSurface){const i=this.finalizedSurface.getInput();i.kind==="diff"&&"oldFile"in i&&await this.finalizedSurface.updateDiff({...i.oldFile,lang:e},{...i.newFile,lang:e},i.annotations);return}this.renderPre()}}getOriginal(){return this.original}getModified(){return this.modified}getState(){return this.state}getElement(){return this.shell}getFinalizedSurface(){return this.finalizedSurface}onDidRender(e){return this.renderListeners.add(e),{dispose:()=>this.renderListeners.delete(e)}}dispose(){++this.generation,this.finalizedSurface?.dispose(),this.finalizedRenderSubscription?.dispose(),this.container?.replaceChildren(),this.container=void 0,this.shell=void 0,this.surface=void 0,this.finalizedSurface=void 0,this.finalizedRenderSubscription=void 0,this.finalizePromise=void 0,this.renderListeners.clear(),this.setState("disposed")}renderPre(){const e=this.surface;if(!e||this.finalizedSurface)return;const i=document.createElement("div");i.className=`stream-diffs-diff-pre stream-diffs-diff-pre--${this.options.diffStyle??"unified"}`,i.dataset.streamDiffsState="streaming",i.style.minWidth="max-content",(this.options.diffStyle??"unified")==="split"?(i.style.display="grid",i.style.gridTemplateColumns="minmax(0, 1fr) minmax(0, 1fr)",i.append(this.createPre(this.original,"deletions"),this.createPre(this.modified,"additions"))):i.append(this.createPre(te(this.original,this.modified),"unified")),e.replaceChildren(i)}createPre(e,i){const t=document.createElement("pre");return t.className=`stream-diffs-diff-pre__pane stream-diffs-diff-pre__pane--${i}`,t.dataset.side=i,t.style.margin="0",t.style.whiteSpace=this.options.wrap?"pre-wrap":"pre",t.style.overflowWrap=this.options.wrap?"anywhere":"normal",t.textContent=e,t}asFile(e){return E(this.options.fileName??`code.${this.options.language??"txt"}`,e,this.options.language)}setState(e){this.state=e,this.options.onStateChange?.(e)}emitRender(){for(const e of this.renderListeners)e()}};function te(e,i){const t=e.split(` +`),n=i.split(` +`);let r=0;for(;r` ${a}`),...t.slice(r,t.length-o).map(a=>`- ${a}`),...n.slice(r,n.length-o).map(a=>`+ ${a}`),...t.slice(t.length-o).map(a=>` ${a}`)].join(` +`)}function he(e){return new G(e)}function ue(e={}){let i,t,n,r,o,a="text",d="",p="",h,c=0,g="system",S=U(e),T=q(e);const L={disableLineNumbers:e.lineNumbers===!1,overflow:e.wordWrap==="on"?"wrap":"scroll",enableLineSelection:e.enableLineSelection},M=()=>({...L,theme:S,themeType:g});async function H(s,l,u){k();const w=c;if(N(s,e),h=s,a=R(u),_(l))return V(s,l,a);if(e.stream===!1)return O(s,l,a);const f=new K({...M(),...F(e),fileName:`code.${a}`,language:a,maxHeight:e.MAX_HEIGHT,autoScroll:e.autoScrollOnUpdate===!1?"never":"near-bottom",autoScrollThresholdPx:e.autoScrollThresholdPx,workerManager:e.workerManager});if(i=f,f.append(l),await f.mount(s),w!==c||i!==f||h!==s)throw f.dispose(),new Error("Editor creation was cancelled");return e.onController?.(f),r=C(()=>f.getText(),s,()=>f.getFinalizedSurface(),m=>f.onDidRender(m)),r}async function I(s,l,u,w){k();const f=c;N(s,e),h=s,a=R(w),d=l,p=u;let m,v;if(e.stream===!1){if(m=x({kind:"diff",oldFile:y(l),newFile:y(u),annotations:e.lineAnnotations,workerManager:e.workerManager,options:{...M(),diffStyle:e.diffStyle??(e.renderSideBySide===!1?"unified":"split"),...F(e)}}),n=m,await m.mount(s),f!==c||n!==m||h!==s)throw m.dispose(),new Error("Editor creation was cancelled");e.onController?.(m)}else{if(v=new G({...M(),...F(e),fileName:`code.${a}`,language:a,diffStyle:e.diffStyle??(e.renderSideBySide===!1?"unified":"split"),maxHeight:e.MAX_HEIGHT,wrap:e.wordWrap==="on",workerManager:e.workerManager}),t=v,await v.mount(s,l,u),f!==c||t!==v||h!==s)throw v.dispose(),new Error("Editor creation was cancelled");e.onController?.(v)}return o=oe(()=>d,()=>p,s,()=>m??v?.getFinalizedSurface()),o}async function X(s,l=a){const u=R(l);if(_(s)){n?.getInput().kind==="merge-conflict"?(a=u,await n.updateMergeConflict(y(s),e.lineAnnotations)):h&&await V(h,s,u);return}if(e.stream===!1){n?.getInput().kind==="file"?(a=u,await n.updateFile(y(s),e.lineAnnotations)):h&&await O(h,s,u);return}if(!i){h&&await H(h,s,u);return}if(i.getState()==="finalized"){s!==i.getText()&&await i.reset(s);return}if(u!==a){a=u,await i.setLanguage(u),s!==i.getText()&&await i.reset(s);return}const w=i.getText();s.startsWith(w)?i.append(s.slice(w.length)):await i.reset(s)}async function P(s,l,u=a){if(d=s,p=l,a=R(u),t){await t.update(s,l);return}if(!n){h&&await I(h,s,l,u);return}await n.updateDiff(y(s),y(l))}function k(){c++,i?.dispose(),t?.dispose(),t||n?.dispose(),i=void 0,t=void 0,n=void 0,r=void 0,o=void 0,h=void 0}async function O(s,l,u){k();const w=c;h=s,a=u;const f=x({kind:"file",file:y(l),annotations:e.lineAnnotations,workerManager:e.workerManager,options:{...M(),...F(e)}});if(n=f,await f.mount(s),w!==c||n!==f||h!==s)throw f.dispose(),new Error("Editor creation was cancelled");return e.onController?.(f),r=C(()=>B(f)??l,s,()=>f,m=>f.onDidRender(m)),r}async function V(s,l,u){k();const w=c;h=s,a=u;const f=x({kind:"merge-conflict",file:y(l),annotations:e.lineAnnotations,workerManager:e.workerManager,options:{...M(),...F(e)}});if(n=f,await f.mount(s),w!==c||n!==f||h!==s)throw f.dispose(),new Error("Editor creation was cancelled");return e.onController?.(f),r=C(()=>B(f)??l,s,()=>f,m=>f.onDidRender(m)),r}function _(s){return e.mergeConflict===!1?!1:/^<<<<<<< .+$/m.test(s)&&/^=======$/m.test(s)&&/^>>>>>>> .+$/m.test(s)}async function J(s){if(s){if(typeof s=="string"){const l=e.themes;if(l?.[0]===s){await W(),g="dark",i?.setThemeType("dark"),t?.setThemeType("dark"),n?.setThemeType("dark");return}if(l?.[1]===s){await W(),g="light",i?.setThemeType("light"),t?.setThemeType("light"),n?.setThemeType("light");return}}T=void 0,S=s,await j(s)}}async function W(){const s=q(e);!s||s===T||(T=s,S=U(e),await j(S))}async function j(s){await i?.setTheme(s),await t?.setTheme(s),await n?.setTheme(s)}function y(s){return E(`code.${a||"txt"}`,s,a)}return{runtimeKind:"stream-diffs",createEditor:H,createDiffEditor:I,updateCode:X,appendCode(s){i?.append(s)},async finalizeCode(){if(!i||i.getState()==="finalized")return i?.getFinalizedSurface();const s=F(e);return delete s.lineAnnotations,await i.finalize({view:"file",...s,theme:S,themeType:g,annotations:e.lineAnnotations,workerManager:e.workerManager}),i.getFinalizedSurface()},async finalizeDiff(){return t&&(n=await t.finalize(e.lineAnnotations)),n},updateDiff:P,updateOriginal(s,l=a){return P(s,p,l)},updateModified(s,l=a){return P(d,s,l)},appendOriginal(s,l=a){return P(d+s,p,l)},appendModified(s,l=a){return P(d,p+s,l)},cleanupEditor:k,safeClean:k,setTheme:J,async setLanguage(s){if(a=R(s),await i?.setLanguage(a),await t?.setLanguage(a),n&&!t){const l=n.getInput();l.kind==="file"||l.kind==="merge-conflict"?await n.update({...l,file:{...l.file,lang:a}}):l.kind==="diff"&&"oldFile"in l&&await n.update({...l,oldFile:{...l.oldFile,lang:a},newFile:{...l.newFile,lang:a}})}},getCurrentTheme:()=>S,getEditor:()=>le,getEditorView:()=>r??null,getDiffEditorView:()=>o??null,getDiffModels:()=>({original:D(()=>d),modified:D(()=>n?.getResolvedFile()?.contents??t?.getModified()??p)}),getCode:()=>{const s=n?.getInput();return s?.kind==="diff"||s?.kind==="patch"?{original:d,modified:n?.getResolvedFile()?.contents??p}:s?.kind==="file"||s?.kind==="merge-conflict"?s.file.contents:t?{original:t.getOriginal(),modified:t.getModified()}:i?.getText()??null},refreshDiffPresentation:()=>n?.update(n.getInput()),whenVisualReady:async()=>{const s=h,l=c,u=n??i?.getFinalizedSurface()??t?.getFinalizedSurface();return!u||!await u.whenVisualReady()?!1:ne(s,()=>l===c&&s===h&&u===(n??i?.getFinalizedSurface()??t?.getFinalizedSurface()),()=>se(n??i?.getFinalizedSurface()??t?.getFinalizedSurface()))}}}async function ne(e,i,t){if(!e||typeof window>"u")return!1;let n="",r,o=0;for(let a=0;a<120;a+=1){if(!i())return!1;const d=e.querySelector(".stream-diffs-shell"),p=d?.querySelector("diffs-container")?.shadowRoot?.querySelector("pre"),h=d?.getBoundingClientRect(),c=p?.textContent??"";if(h&&h.width>0&&h.height>0&&p&&t()){const g=`${Math.round(h.width)}:${Math.round(h.height)}:${p.scrollWidth}:${p.scrollHeight}:${c.length}`;if(o=p===r&&g===n?o+1:1,r=p,n=g,o>=2)return!0}else n="",r=void 0,o=0;await ae()}return!1}function se(e){if(!e)return!0;const i=e.getNativeInstance(),t=i?.fileRenderer??i?.hunksRenderer;if(!t)return!0;const n=t.renderCache;if(!n?.result)return!1;if(n.highlighted===!0)return!0;const r=e.getInput();if(R(r.kind==="file"||r.kind==="merge-conflict"?r.file.lang:"oldFile"in r?r.oldFile.lang??r.newFile.lang:e.getDiff()?.lang)==="text")return!0;const o=Number(t.getTokenizeMaxLength?.()??1e5);if(r.kind==="file"||r.kind==="merge-conflict")return re(r.file.contents)>o;const a=e.getDiff();return!!a&&Math.max(a.additionLines.length,a.deletionLines.length)>o}function R(e){return!e||/^(?:text|txt|plain|plaintext)$/i.test(e)?"text":e}function re(e){if(!e)return 0;let i=1;for(let t=0;t{let i=!1;const t=()=>{i||(i=!0,window.clearTimeout(r),window.cancelAnimationFrame(n),e())},n=window.requestAnimationFrame(t),r=window.setTimeout(t,50)})}function U(e){return e.themes?.length&&typeof e.themes[0]=="string"&&typeof e.themes[1]=="string"?{dark:e.themes[0],light:e.themes[1]}:e.theme??void 0}function q(e){if(!(typeof e.themes?.[0]!="string"||typeof e.themes?.[1]!="string"))return`${e.themes[0]} +${e.themes[1]}`}function F(e){const i=new Set(["MAX_HEIGHT","theme","themes","readOnly","lineNumbers","wordWrap","renderSideBySide","autoScrollOnUpdate","autoScrollThresholdPx","stream","mergeConflict","lineAnnotations","onController","workerManager","languages","onThemeChange"]),t=Object.fromEntries(Object.entries(e).filter(([a])=>!i.has(a))),n=e.diffHideUnchangedRegions;delete t.diffHideUnchangedRegions;const r=typeof n=="object"&&n?n:void 0,o=r?.enabled!==!1;if(n===!1||r&&!o)t.expandUnchanged??=!0;else if((n===!0||r)&&(t.expandUnchanged??=!1,r)){const a=Number(r.contextLineCount);Number.isFinite(a)&&a>=0&&(t.parseDiffOptions={context:a,...t.parseDiffOptions});const d=Number(r.minimumLineCount);Number.isFinite(d)&&d>=1&&(t.collapsedContextThreshold??=Math.max(0,Math.floor(d)-1))}return t}function D(e){return{getValue:e,getLineCount:()=>e().split(` +`).length}}function B(e){const i=e?.getInput();return i?.kind==="file"||i?.kind==="merge-conflict"?i.file.contents:void 0}function C(e,i,t=()=>{},n){const r=()=>Number.parseFloat(i.style.fontSize)||14;return{getModel:()=>D(e),getContentHeight:()=>i.querySelector(".stream-diffs-shell")?.scrollHeight??i.scrollHeight,layout:()=>{},getOption(o){if(o===A.fontInfo)return{fontSize:r()};if(o===A.lineHeight)return Number.parseFloat(i.style.lineHeight)||Math.round(r()*1.5)},updateOptions(o){N(i,o)},onDidContentSizeChange:o=>n?.(o)??{dispose(){}},onDidLayoutChange:o=>n?.(o)??{dispose(){}},setSelectedLines:o=>t()?.setSelectedLines(o),setAnnotations:o=>t()?.setAnnotations(o),acceptReject:(o,a)=>t()?.acceptReject(o,a),resolveConflict:(o,a)=>t()?.resolveConflict(o,a)}}function oe(e,i,t,n){return{...C(i,t,n,r=>n()?.onDidRender(r)??{dispose(){}}),getOriginalEditor:()=>C(e,t,n,r=>n()?.onDidRender(r)??{dispose(){}}),getModifiedEditor:()=>C(i,t,n,r=>n()?.onDidRender(r)??{dispose(){}}),getLineChanges:()=>n()?.getDiff()?.hunks.map(r=>({originalStartLineNumber:r.deletionStart,originalEndLineNumber:r.deletionStart+r.deletionCount-1,modifiedStartLineNumber:r.additionStart,modifiedEndLineNumber:r.additionStart+r.additionCount-1}))??[],onDidUpdateDiff:r=>n()?.onDidRender(r)??{dispose(){}}}}const A={fontInfo:0,lineHeight:1},le={EditorOption:A};function N(e,i){const{style:t}=e;typeof i.fontSize=="number"&&(t.fontSize=`${i.fontSize}px`,t.setProperty("--diffs-font-size",`${i.fontSize}px`)),typeof i.lineHeight=="number"&&(t.lineHeight=`${i.lineHeight}px`,t.setProperty("--diffs-line-height",`${i.lineHeight}px`)),typeof i.fontFamily=="string"&&(t.fontFamily=i.fontFamily,t.setProperty("--diffs-font-family",i.fontFamily))}async function ce(){}function pe(e){return/^\s*new Promise((a,J)=>{var V=c=>{try{H(l.next(c))}catch($){J($)}},Q=c=>{try{H(l.throw(c))}catch($){J($)}},H=c=>c.done?a(c.value):Promise.resolve(c.value).then(V,Q);H((l=l.apply(R,xe)).next())});const p1=["data-markstream-mode"],f1={key:0,class:"infographic-block-header flex justify-between items-center border-b"},w1={key:0},g1={key:1,class:"flex items-center gap-x-2 overflow-hidden"},C1=["innerHTML"],k1={key:2},x1={key:3,class:"infographic-mode-toggle flex items-center gap-0.5"},y1=["disabled"],b1={class:"flex items-center gap-x-1"},M1={class:"flex items-center gap-x-1"},B1={key:4},F1={key:5,class:"infographic-header-actions flex items-center"},T1=["aria-pressed"],H1={key:0,xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},$1={key:1,xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},j1=["disabled"],L1=["disabled"],P1={key:0,xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},E1={key:1,xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},z1={key:0,class:"infographic-source"},S1={class:"infographic-source-code text-sm font-mono whitespace-pre-wrap"},Z1={key:1,class:"relative"},V1={key:0,class:"absolute top-2 right-2 z-10 rounded-lg"},D1={class:"flex items-center gap-2 backdrop-blur rounded-lg"},N1={key:0,class:"infographic-pending-source text-sm font-mono whitespace-pre-wrap"},Y1={class:"dialog-panel infographic-modal-panel relative w-full h-full max-w-full max-h-full rounded overflow-hidden"},_1={class:"absolute top-6 right-6 z-50 flex items-center gap-2"},se="infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",ke=Re(Ae({__name:"InfographicBlockNode",props:{node:{},maxHeight:{default:void 0},estimatedPreviewHeightPx:{},loading:{type:Boolean,default:!0},isDark:{type:Boolean},showHeader:{type:Boolean,default:!0},showModeToggle:{type:Boolean,default:!0},showCopyButton:{type:Boolean,default:!0},showCollapseButton:{type:Boolean,default:!0},showExportButton:{type:Boolean,default:!0},showFullscreenButton:{type:Boolean,default:!0},showZoomControls:{type:Boolean,default:!0}},emits:["copy","export","openModal"],setup(R,{emit:xe}){const l=R,{t:a}=qe(),J=Ge(),V=Je(),Q=Qe(),H=d(!1),c=d(!1),$=d(),p=d(),k=d(!0),ye=d(!1),j=d(!1),D=d(),K=d(null),L=d(!1),S=d(!1),A=d(null),P=d(typeof window>"u"||!Q.value),Ne=Ke(),x=We(e1,null);let E="";const be=T(()=>h1(l,Ne));typeof window<"u"&&B([()=>$.value,Q],([n,e])=>{var o,i,C;if((o=A.value)==null||o.destroy(),A.value=null,!e||P.value)return void(P.value=!0);if(!n)return void(P.value=!1);const f=(C=(i=V?.value.heavyBlockMargin)!=null?i:V?.value.rootMargin)!=null?C:"160px",w=J(n,{rootMargin:f,allowIdle:!1});A.value=w,P.value=w.isVisible.value,w.whenVisible.then(()=>{P.value=!0})},{immediate:!0});const z=T(()=>l.node.code),ue=T(()=>{var n;return(function(e){if(l.maxHeight==="none")return Ve(e,void 0,null);const o=ie(l.maxHeight);return Ve(e,void 0,o)})((n=ie(l.estimatedPreviewHeightPx))!=null?n:d1(z.value))}),ce=d(`${ue.value}px`),Ye=T(()=>ie(l.estimatedPreviewHeightPx)!=null);function Me(){var n;if(!p.value||Ye.value)return;const e=p.value.scrollHeight;if(e>0){const o=(n=ie((function(i){if(l.maxHeight==="none")return`${i}px`;if(l.maxHeight!=null){const f=Number.parseFloat(String(l.maxHeight));if(Number.isFinite(f))return`${Math.min(i,f)}px`}const C=p.value;if(C){const f=getComputedStyle(C).getPropertyValue("--ms-size-code-max-height").trim(),w=Number.parseFloat(f);if(Number.isFinite(w))return`${Math.min(i,w)}px`}return`${Math.min(i,500)}px`})(e)))!=null?n:e;ce.value=`${Math.max(o,ue.value)}px`}}const M=d(1),N=d(0),Y=d(0),_=d(!1),W=d({x:0,y:0}),Be=T(()=>z.value);function Fe(n){return!n||n.disabled}function h(n,e,o="top"){if(Fe(n.currentTarget))return;const i=n,C=i?.clientX!=null&&i?.clientY!=null?{x:i.clientX,y:i.clientY}:void 0;De(n.currentTarget,e,o,!1,C,l.isDark)}function v(){v1()}function Te(n){if(Fe(n.currentTarget))return;const e=H.value?a("common.copied")||"Copied":a("common.copy")||"Copy",o=n,i=o?.clientX!=null&&o?.clientY!=null?{x:o.clientX,y:o.clientY}:void 0;De(n.currentTarget,e,"top",!1,i,l.isDark)}function _e(){return re(this,null,function*(){try{const n=z.value;typeof navigator<"u"&&navigator.clipboard&&typeof navigator.clipboard.writeText=="function"&&(yield navigator.clipboard.writeText(n)),H.value=!0,setTimeout(()=>{H.value=!1},1e3)}catch(n){console.error("Failed to copy:",n)}})}function He(n){(n!=="preview"||Ze())&&(ye.value=!0,k.value=n==="source")}function Ie(){var n;const e=(n=p.value)==null?void 0:n.querySelector("svg");e?(function(o){re(this,null,function*(){try{const i=new XMLSerializer().serializeToString(o),C=new Blob([i],{type:"image/svg+xml;charset=utf-8"}),f=URL.createObjectURL(C);if(typeof document<"u"){const w=document.createElement("a");w.href=f,w.download=`infographic-${Date.now()}.svg`;try{document.body.appendChild(w),w.click(),document.body.removeChild(w)}catch{}URL.revokeObjectURL(f)}}catch(i){console.error("Failed to export SVG:",i)}})})(e):console.error("SVG element not found")}function de(n){n.key==="Escape"&&j.value&&ve()}function ve(){if(j.value=!1,D.value&&(D.value.innerHTML=""),K.value=null,typeof document<"u")try{document.body.style.overflow=""}catch{}if(typeof window<"u")try{window.removeEventListener("keydown",de)}catch{}}function Oe(){(function(){if(j.value=!0,typeof document<"u")try{document.body.style.overflow="hidden"}catch{}if(typeof window<"u")try{window.addEventListener("keydown",de)}catch{}U(()=>{if(p.value&&D.value){D.value.innerHTML="";const n=document.createElement("div");n.style.transition="transform 0.1s ease",n.style.transformOrigin="center center",n.style.width="100%",n.style.height="100%",n.style.display="flex",n.style.alignItems="center",n.style.justifyContent="center";const e=p.value.cloneNode(!0);e.classList.add("fullscreen"),e.style.height="auto",n.appendChild(e),D.value.appendChild(n),K.value=n,n.style.transform=`translate(${N.value}px, ${Y.value}px) scale(${M.value})`}})})()}function $e(){M.value<3&&(M.value+=.1)}function je(){M.value>.5&&(M.value-=.1)}function Le(){M.value=1,N.value=0,Y.value=0}function ee(n){_.value=!0,n instanceof MouseEvent?W.value={x:n.clientX-N.value,y:n.clientY-Y.value}:W.value={x:n.touches[0].clientX-N.value,y:n.touches[0].clientY-Y.value}}function ne(n){if(!_.value)return;let e,o;n instanceof MouseEvent?(e=n.clientX,o=n.clientY):(e=n.touches[0].clientX,o=n.touches[0].clientY),N.value=e-W.value.x,Y.value=o-W.value.y}function I(){_.value=!1}let g=null,me=!1,oe=!1,q=!1,te="",G=!1,he=0;function le(n){return!G&&n===he}function Pe(n=!1){return re(this,null,function*(){var e,o;if(G||!P.value||!p.value)return;if(me)return oe=!0,void(q=q||n);const i=Be.value;if(!n&&i===te&&L.value)return;const C=l.loading===!1,f=++he;me=!0,(function(){const m=be.value;m&&E!==m&&(E&&x?.markSettled(E),E=m,x?.markPending(m))})();const w=p.value.innerHTML,pe=L.value,Xe=S.value;S.value=!1;try{const m=yield m1();if(!le(f))return;if(!m)return void console.warn("Infographic library failed to load.");const Z=p.value;if(!Z)return;g&&((e=g.destroy)==null||e.call(g),g=null),Z.innerHTML="",g=new m({container:Z,width:"100%",height:"100%"});let fe="";if((o=g.on)==null||o.call(g,"error",we=>{fe=(Array.isArray(we)?we:[we]).map(y=>{var Se;return y instanceof Error?y.message:typeof y=="string"?y:String(y&&typeof y=="object"&&"message"in y?(Se=y.message)!=null?Se:"":y??"")}).filter(Boolean).join("; ")}),g.render(z.value),fe)throw new Error(fe);if(!Z.childNodes.length)throw new Error("Infographic render returned empty output.");L.value=!0,S.value=!1,te=i,U(()=>{le(f)&&Me()})}catch(m){if(!le(f))return;C&&l.loading===!1&&i===Be.value?(console.error("Failed to render infographic:",m),L.value=!1,S.value=!0,te="",p.value&&(p.value.innerHTML=`
Failed to render infographic: ${m instanceof Error?m.message:"Unknown error"}
`)):(L.value=pe,S.value=Xe,pe&&p.value&&(p.value.innerHTML=w))}finally{if(me=!1,le(f))if(oe){const m=q;oe=!1,q=!1,U(()=>{Pe(m)})}else(function(){re(this,null,function*(){const m=E;m&&(E="",yield U(),(function(Z=be.value){Z&&$.value&&x?.reportHeight(Z,$.value.offsetHeight)})(m),x?.markSettled(m))})})()}})}function O(n=!1){G||!P.value||k.value||c.value||U(()=>{G||Pe(n)})}B(()=>z.value,()=>{O(!0)}),B(()=>l.loading,(n,e)=>{e&&!n&&O(!0)}),B(()=>k.value,n=>{n||O(!0)}),B(()=>c.value,n=>{n||O()}),B(()=>l.maxHeight,()=>{U(()=>{Me()})}),B([()=>l.estimatedPreviewHeightPx,()=>z.value],()=>{L.value||k.value||(ce.value=`${ue.value}px`)}),B(()=>P.value,n=>{!n||k.value||c.value||O()}),n1(()=>{!ye.value&&Ze(),O()}),o1(()=>{var n,e;if(G=!0,he+=1,oe=!1,q=!1,(n=A.value)==null||n.destroy(),A.value=null,(function(){const o=E;o&&(E="",x?.markSettled(o))})(),g&&((e=g.destroy)==null||e.call(g),g=null),te="",typeof window<"u")try{window.removeEventListener("keydown",de)}catch{}});const Ee=T(()=>!0),ae=T(()=>k.value||c.value),Ue=T(()=>k.value?"fallback":S.value?"error":L.value?"preview":"pending"),ze=T(()=>({transform:`translate(${N.value}px, ${Y.value}px) scale(${M.value})`}));return B(ze,n=>{j.value&&K.value&&(K.value.style.transform=n.transform)}),(n,e)=>(r(),u("div",{ref_key:"viewportTarget",ref:$,class:b(["infographic-block-container rounded-lg border overflow-hidden",[{"is-rendering":l.loading,dark:l.isDark}]]),"data-markstream-infographic":"1","data-markstream-mode":Ue.value},[l.showHeader?(r(),u("div",f1,[n.$slots["header-left"]?(r(),u("div",w1,[ge(n.$slots,"header-left",{},void 0,!0)])):(r(),u("div",g1,[t("span",{class:"icon-slot action-icon shrink-0",innerHTML:s(` +`)},null,8,C1),e[21]||(e[21]=t("span",{class:"infographic-label font-medium font-mono truncate"},"Infographic",-1))])),n.$slots["header-center"]?(r(),u("div",k1,[ge(n.$slots,"header-center",{},void 0,!0)])):l.showModeToggle?(r(),u("div",x1,[t("button",{class:b(["infographic-mode-btn px-2 py-0.5 rounded transition-colors",[k.value?"":"is-active",Ee.value?"opacity-50 cursor-not-allowed":""]]),disabled:Ee.value,onClick:e[0]||(e[0]=()=>He("preview")),onMouseenter:e[1]||(e[1]=o=>h(o,s(a)("common.preview")||"Preview")),onFocus:e[2]||(e[2]=o=>h(o,s(a)("common.preview")||"Preview")),onMouseleave:v,onBlur:v},[t("div",b1,[e[22]||(e[22]=t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("path",{d:"M2.062 12.348a1 1 0 0 1 0-.696a10.75 10.75 0 0 1 19.876 0a1 1 0 0 1 0 .696a10.75 10.75 0 0 1-19.876 0"}),t("circle",{cx:"12",cy:"12",r:"3"})])],-1)),t("span",null,X(s(a)("common.preview")||"Preview"),1)])],42,y1),t("button",{class:b(["infographic-mode-btn px-2 py-0.5 rounded transition-colors",[k.value?"is-active":""]]),onClick:e[3]||(e[3]=()=>He("source")),onMouseenter:e[4]||(e[4]=o=>h(o,s(a)("common.source")||"Source")),onFocus:e[5]||(e[5]=o=>h(o,s(a)("common.source")||"Source")),onMouseleave:v,onBlur:v},[t("div",M1,[e[23]||(e[23]=t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"m16 18l6-6l-6-6M8 6l-6 6l6 6"})],-1)),t("span",null,X(s(a)("common.source")||"Source"),1)])],34)])):F("",!0),n.$slots["header-right"]?(r(),u("div",B1,[ge(n.$slots,"header-right",{},void 0,!0)])):(r(),u("div",F1,[l.showCollapseButton?(r(),u("button",{key:0,class:b(se),"aria-pressed":c.value,onClick:e[6]||(e[6]=o=>c.value=!c.value),onMouseenter:e[7]||(e[7]=o=>h(o,c.value?s(a)("common.expand")||"Expand":s(a)("common.collapse")||"Collapse")),onFocus:e[8]||(e[8]=o=>h(o,c.value?s(a)("common.expand")||"Expand":s(a)("common.collapse")||"Collapse")),onMouseleave:v,onBlur:v},[(r(),u("svg",{style:Ce({rotate:c.value?"0deg":"90deg"}),xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[...e[24]||(e[24]=[t("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"m9 18l6-6l-6-6"},null,-1)])],4))],40,T1)):F("",!0),l.showCopyButton?(r(),u("button",{key:1,class:b(se),onClick:_e,onMouseenter:e[9]||(e[9]=o=>Te(o)),onFocus:e[10]||(e[10]=o=>Te(o)),onMouseleave:v,onBlur:v},[H.value?(r(),u("svg",$1,[...e[26]||(e[26]=[t("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M20 6L9 17l-5-5"},null,-1)])])):(r(),u("svg",H1,[...e[25]||(e[25]=[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2"}),t("path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"})],-1)])]))],32)):F("",!0),l.showExportButton?(r(),u("button",{key:2,class:b(`${se} ${ae.value?"opacity-50 cursor-not-allowed":""}`),disabled:ae.value,onClick:Ie,onMouseenter:e[11]||(e[11]=o=>h(o,s(a)("common.export")||"Export")),onFocus:e[12]||(e[12]=o=>h(o,s(a)("common.export")||"Export")),onMouseleave:v,onBlur:v},[...e[27]||(e[27]=[t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("path",{d:"M12 15V3m9 12v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}),t("path",{d:"m7 10l5 5l5-5"})])],-1)])],42,j1)):F("",!0),l.showFullscreenButton?(r(),u("button",{key:3,class:b(`${se} ${ae.value?"opacity-50 cursor-not-allowed":""}`),disabled:ae.value,onClick:Oe,onMouseenter:e[13]||(e[13]=o=>h(o,j.value?s(a)("common.minimize")||"Minimize":s(a)("common.open")||"Open")),onFocus:e[14]||(e[14]=o=>h(o,j.value?s(a)("common.minimize")||"Minimize":s(a)("common.open")||"Open")),onMouseleave:v,onBlur:v},[j.value?(r(),u("svg",E1,[...e[29]||(e[29]=[t("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"m14 10l7-7m-1 7h-6V4M3 21l7-7m-6 0h6v6"},null,-1)])])):(r(),u("svg",P1,[...e[28]||(e[28]=[t("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M15 3h6v6m0-6l-7 7M3 21l7-7m-1 7H3v-6"},null,-1)])]))],42,L1)):F("",!0)]))])):F("",!0),t1(t("div",null,[k.value?(r(),u("div",z1,[t("pre",S1,X(z.value),1)])):(r(),u("div",Z1,[l.showZoomControls?(r(),u("div",V1,[t("div",D1,[t("button",{class:"infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",onClick:$e,onMouseenter:e[15]||(e[15]=o=>h(o,s(a)("common.zoomIn")||"Zoom in")),onFocus:e[16]||(e[16]=o=>h(o,s(a)("common.zoomIn")||"Zoom in")),onMouseleave:v,onBlur:v},[...e[30]||(e[30]=[t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("circle",{cx:"11",cy:"11",r:"8"}),t("path",{d:"m21 21l-4.35-4.35M11 8v6m-3-3h6"})])],-1)])],32),t("button",{class:"infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",onClick:je,onMouseenter:e[17]||(e[17]=o=>h(o,s(a)("common.zoomOut")||"Zoom out")),onFocus:e[18]||(e[18]=o=>h(o,s(a)("common.zoomOut")||"Zoom out")),onMouseleave:v,onBlur:v},[...e[31]||(e[31]=[t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("circle",{cx:"11",cy:"11",r:"8"}),t("path",{d:"m21 21l-4.35-4.35M8 11h6"})])],-1)])],32),t("button",{class:"infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",onClick:Le,onMouseenter:e[19]||(e[19]=o=>h(o,s(a)("common.resetZoom")||"Reset zoom")),onFocus:e[20]||(e[20]=o=>h(o,s(a)("common.resetZoom")||"Reset zoom")),onMouseleave:v,onBlur:v},X(Math.round(100*M.value))+"% ",33)])])):F("",!0),t("div",{class:"infographic-preview relative transition-all overflow-hidden block",style:Ce({height:ce.value}),onMousedown:ee,onMousemove:ne,onMouseup:I,onMouseleave:I,onTouchstartPassive:ee,onTouchmovePassive:ne,onTouchendPassive:I},[L.value||S.value?F("",!0):(r(),u("pre",N1,X(z.value),1)),t("div",{class:b(["absolute inset-0 cursor-grab",{"cursor-grabbing":_.value}]),style:Ce(ze.value)},[t("div",{ref_key:"infographicContainer",ref:p,class:"w-full text-center flex items-center justify-center min-h-full"},null,512)],6)],36)]))],512),[[l1,!c.value]]),(r(),a1(c1,{to:"body"},[t("div",{class:b(["markstream-vue",{dark:l.isDark}])},[i1(u1,{name:"infographic-dialog",appear:""},{default:r1(()=>[j.value?(r(),u("div",{key:0,class:"infographic-modal-overlay fixed inset-0 z-50 flex items-center justify-center p-4",onClick:s1(ve,["self"])},[t("div",Y1,[t("div",_1,[t("button",{class:"infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",onClick:$e},[...e[32]||(e[32]=[t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("circle",{cx:"11",cy:"11",r:"8"}),t("path",{d:"m21 21l-4.35-4.35M11 8v6m-3-3h6"})])],-1)])]),t("button",{class:"infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",onClick:je},[...e[33]||(e[33]=[t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[t("circle",{cx:"11",cy:"11",r:"8"}),t("path",{d:"m21 21l-4.35-4.35M8 11h6"})])],-1)])]),t("button",{class:"infographic-action-btn p-[var(--ms-action-btn-padding)] rounded",onClick:Le},X(Math.round(100*M.value))+"% ",1),t("button",{class:"infographic-action-btn inline-flex items-center justify-center p-[var(--ms-action-btn-padding)] rounded",onClick:ve},[...e[34]||(e[34]=[t("svg",{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink","aria-hidden":"true",role:"img",width:"1em",height:"1em",viewBox:"0 0 24 24",class:"action-icon"},[t("path",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2",d:"M18 6L6 18M6 6l12 12"})],-1)])])]),t("div",{ref_key:"modalContent",ref:D,class:b(["w-full h-full flex items-center justify-center p-4 overflow-hidden",{"cursor-grab":!_.value,"cursor-grabbing":_.value}]),onMousedown:ee,onMousemove:ne,onMouseup:I,onMouseleave:I,onTouchstartPassive:ee,onTouchmovePassive:ne,onTouchendPassive:I},null,34)])])):F("",!0)]),_:1})],2)]))],10,p1))}}),[["__scopeId","data-v-de34ec4b"]]);ke.install=R=>{R.component(ke.__name,ke)};export{ke as default}; diff --git a/apps/kimi-code/dist-web/assets/init-Gi6I4Gst.js b/apps/kimi-code/dist-web/assets/init-Gi6I4Gst.js new file mode 100644 index 0000000000000000000000000000000000000000..d44de94168e3af7f023afd933dae034f6a369d97 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/init-Gi6I4Gst.js @@ -0,0 +1 @@ +function t(e,a){switch(arguments.length){case 0:break;case 1:this.range(e);break;default:this.range(a).domain(e);break}return this}export{t as i}; diff --git a/apps/kimi-code/dist-web/assets/ishikawaDiagram-FXEZZL3T-CDU07xJY.js b/apps/kimi-code/dist-web/assets/ishikawaDiagram-FXEZZL3T-CDU07xJY.js new file mode 100644 index 0000000000000000000000000000000000000000..0008bad887d6077d103902b5a6f953d69a0a8405 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/ishikawaDiagram-FXEZZL3T-CDU07xJY.js @@ -0,0 +1,70 @@ +import{_ as l,c as lt,K as ct,D as ut,al as dt,p as yt,k as ft,n as et,a as pt,b as gt,g as kt,s as mt,o as wt,e as _t}from"./mermaidParser.worker-BFSlSHEW.js";var Q=(function(){var t=l(function(T,e,s,i){for(s=s||{},i=T.length;i--;s[T[i]]=e);return s},"o"),d=[1,4],n=[1,14],a=[1,12],o=[1,13],y=[6,7,8],p=[1,20],u=[1,18],m=[1,19],c=[6,7,11],k=[1,6,13,14],g=[1,23],_=[1,24],x=[1,6,7,11,13,14],D={trace:l(function(){},"trace"),yy:{},symbols_:{error:2,start:3,ishikawa:4,spaceLines:5,SPACELINE:6,NL:7,ISHIKAWA:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,TEXT:14,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"ISHIKAWA",11:"EOF",13:"SPACELIST",14:"TEXT"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,2],[12,1],[12,1],[12,1]],performAction:l(function(e,s,i,h,f,r,v){var w=r.length-1;switch(f){case 6:case 7:return h;case 15:h.addNode(r[w-1].length,r[w].trim());break;case 16:h.addNode(0,r[w].trim());break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:d},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:d},{6:n,7:[1,10],9:9,12:11,13:a,14:o},t(y,[2,3]),{1:[2,2]},t(y,[2,4]),t(y,[2,5]),{1:[2,6],6:n,12:15,13:a,14:o},{6:n,9:16,12:11,13:a,14:o},{6:p,7:u,10:17,11:m},t(c,[2,18],{14:[1,21]}),t(c,[2,16]),t(c,[2,17]),{6:p,7:u,10:22,11:m},{1:[2,7],6:n,12:15,13:a,14:o},t(k,[2,14],{7:g,11:_}),t(x,[2,8]),t(x,[2,9]),t(x,[2,10]),t(c,[2,15]),t(k,[2,13],{7:g,11:_}),t(x,[2,11]),t(x,[2,12])],defaultActions:{2:[2,1],6:[2,2]},parseError:l(function(e,s){if(s.recoverable)this.trace(e);else{var i=new Error(e);throw i.hash=s,i}},"parseError"),parse:l(function(e){var s=this,i=[0],h=[],f=[null],r=[],v=this.table,w="",I=0,$=0,L=2,A=1,C=r.slice.call(arguments,1),b=Object.create(this.lexer),S={yy:{}};for(var P in this.yy)Object.prototype.hasOwnProperty.call(this.yy,P)&&(S.yy[P]=this.yy[P]);b.setInput(e,S.yy),S.yy.lexer=b,S.yy.parser=this,typeof b.yylloc>"u"&&(b.yylloc={});var R=b.yylloc;r.push(R);var H=b.options&&b.options.ranges;typeof S.yy.parseError=="function"?this.parseError=S.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function K(B){i.length=i.length-2*B,f.length=f.length-B,r.length=r.length-B}l(K,"popStack");function J(){var B;return B=h.pop()||b.lex()||A,typeof B!="number"&&(B instanceof Array&&(h=B,B=h.pop()),B=s.symbols_[B]||B),B}l(J,"lex");for(var M,W,N,X,F={},G,V,tt,U;;){if(W=i[i.length-1],this.defaultActions[W]?N=this.defaultActions[W]:((M===null||typeof M>"u")&&(M=J()),N=v[W]&&v[W][M]),typeof N>"u"||!N.length||!N[0]){var Y="";U=[];for(G in v[W])this.terminals_[G]&&G>L&&U.push("'"+this.terminals_[G]+"'");b.showPosition?Y="Parse error on line "+(I+1)+`: +`+b.showPosition()+` +Expecting `+U.join(", ")+", got '"+(this.terminals_[M]||M)+"'":Y="Parse error on line "+(I+1)+": Unexpected "+(M==A?"end of input":"'"+(this.terminals_[M]||M)+"'"),this.parseError(Y,{text:b.match,token:this.terminals_[M]||M,line:b.yylineno,loc:R,expected:U})}if(N[0]instanceof Array&&N.length>1)throw new Error("Parse Error: multiple actions possible at state: "+W+", token: "+M);switch(N[0]){case 1:i.push(M),f.push(b.yytext),r.push(b.yylloc),i.push(N[1]),M=null,$=b.yyleng,w=b.yytext,I=b.yylineno,R=b.yylloc;break;case 2:if(V=this.productions_[N[1]][1],F.$=f[f.length-V],F._$={first_line:r[r.length-(V||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(V||1)].first_column,last_column:r[r.length-1].last_column},H&&(F._$.range=[r[r.length-(V||1)].range[0],r[r.length-1].range[1]]),X=this.performAction.apply(F,[w,$,I,S.yy,N[1],f,r].concat(C)),typeof X<"u")return X;V&&(i=i.slice(0,-1*V*2),f=f.slice(0,-1*V),r=r.slice(0,-1*V)),i.push(this.productions_[N[1]][0]),f.push(F.$),r.push(F._$),tt=v[i[i.length-2]][i[i.length-1]],i.push(tt);break;case 3:return!0}}return!0},"parse")},O=(function(){var T={EOF:1,parseError:l(function(s,i){if(this.yy.parser)this.yy.parser.parseError(s,i);else throw new Error(s)},"parseError"),setInput:l(function(e,s){return this.yy=s||this.yy||{},this._input=e,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:l(function(){var e=this._input[0];this.yytext+=e,this.yyleng++,this.offset++,this.match+=e,this.matched+=e;var s=e.match(/(?:\r\n?|\n).*/g);return s?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),e},"input"),unput:l(function(e){var s=e.length,i=e.split(/(?:\r\n?|\n)/g);this._input=e+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-s),this.offset-=s;var h=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),i.length-1&&(this.yylineno-=i.length-1);var f=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:i?(i.length===h.length?this.yylloc.first_column:0)+h[h.length-i.length].length-i[0].length:this.yylloc.first_column-s},this.options.ranges&&(this.yylloc.range=[f[0],f[0]+this.yyleng-s]),this.yyleng=this.yytext.length,this},"unput"),more:l(function(){return this._more=!0,this},"more"),reject:l(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:l(function(e){this.unput(this.match.slice(e))},"less"),pastInput:l(function(){var e=this.matched.substr(0,this.matched.length-this.match.length);return(e.length>20?"...":"")+e.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:l(function(){var e=this.match;return e.length<20&&(e+=this._input.substr(0,20-e.length)),(e.substr(0,20)+(e.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:l(function(){var e=this.pastInput(),s=new Array(e.length+1).join("-");return e+this.upcomingInput()+` +`+s+"^"},"showPosition"),test_match:l(function(e,s){var i,h,f;if(this.options.backtrack_lexer&&(f={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&&(f.yylloc.range=this.yylloc.range.slice(0))),h=e[0].match(/(?:\r\n?|\n).*/g),h&&(this.yylineno+=h.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:h?h[h.length-1].length-h[h.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+e[0].length},this.yytext+=e[0],this.match+=e[0],this.matches=e,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(e[0].length),this.matched+=e[0],i=this.performAction.call(this,this.yy,this,s,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var r in f)this[r]=f[r];return!1}return!1},"test_match"),next:l(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var e,s,i,h;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),r=0;rs[0].length)){if(s=i,h=r,this.options.backtrack_lexer){if(e=this.test_match(i,f[r]),e!==!1)return e;if(this._backtrack){s=!1;continue}else return!1}else if(!this.options.flex)break}return s?(e=this.test_match(s,f[h]),e!==!1?e:!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:l(function(){var s=this.next();return s||this.lex()},"lex"),begin:l(function(s){this.conditionStack.push(s)},"begin"),popState:l(function(){var s=this.conditionStack.length-1;return s>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:l(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:l(function(s){return s=this.conditionStack.length-1-Math.abs(s||0),s>=0?this.conditionStack[s]:"INITIAL"},"topState"),pushState:l(function(s){this.begin(s)},"pushState"),stateStackSize:l(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:l(function(s,i,h,f){switch(h){case 0:return 6;case 1:return 8;case 2:return 8;case 3:return 6;case 4:return 7;case 5:return 13;case 6:return 14;case 7:return 11}},"anonymous"),rules:[/^(?:\s*%%.*)/i,/^(?:ishikawa-beta\b)/i,/^(?:ishikawa\b)/i,/^(?:[\s]+[\n])/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:[^\n]+)/i,/^(?:$)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7],inclusive:!0}}};return T})();D.lexer=O;function E(){this.yy={}}return l(E,"Parser"),E.prototype=D,D.Parser=E,new E})();Q.parser=Q;var bt=Q,xt=class{constructor(){this.stack=[],this.clear=this.clear.bind(this),this.addNode=this.addNode.bind(this),this.getRoot=this.getRoot.bind(this)}static{l(this,"IshikawaDB")}clear(){this.root=void 0,this.stack=[],this.baseLevel=void 0,yt()}getRoot(){return this.root}addNode(t,d){const n=ft.sanitizeText(d,lt());if(!this.root){this.root={text:n,children:[]},this.stack=[{level:0,node:this.root}],et(n);return}this.baseLevel??=t;let a=t-this.baseLevel+1;for(a<=0&&(a=1);this.stack.length>1&&this.stack[this.stack.length-1].level>=a;)this.stack.pop();const o=this.stack[this.stack.length-1].node,y={text:n,children:[]};o.children.push(y),this.stack.push({level:a,node:y})}getAccTitle(){return pt()}setAccTitle(t){gt(t)}getAccDescription(){return kt()}setAccDescription(t){mt(t)}getDiagramTitle(){return wt()}setDiagramTitle(t){et(t)}},vt=14,j=250,St=30,$t=60,Et=5,ot=82*Math.PI/180,it=Math.cos(ot),st=Math.sin(ot),nt=l((t,d,n)=>{const a=t.node().getBBox(),o=a.width+d*2,y=a.height+d*2;_t(t,y,o,n),t.attr("viewBox",`${a.x-d} ${a.y-d} ${o} ${y}`)},"applyPaddedViewBox"),At=l((t,d,n,a)=>{const y=a.db.getRoot();if(!y)return;const p=lt(),{look:u,handDrawnSeed:m,themeVariables:c}=p,k=ct(p.fontSize)[0]??vt,g=u==="handDrawn",_=y.children??[],x=p.ishikawa?.diagramPadding??20,D=p.ishikawa?.useMaxWidth??!1,O=ut(d),E=O.append("g").attr("class","ishikawa"),T=g?dt.svg(O.node()):void 0,e=T?{roughSvg:T,seed:m??0,lineColor:c?.lineColor??"#333",fillColor:c?.mainBkg??"#fff"}:void 0,s=`ishikawa-arrow-${d}`;g||E.append("defs").append("marker").attr("id",s).attr("viewBox","0 0 10 10").attr("refX",0).attr("refY",5).attr("markerWidth",6).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 10 0 L 0 5 L 10 10 Z").attr("class","ishikawa-arrow");let i=0,h=j;const f=g?void 0:z(E,i,h,i,h,"ishikawa-spine");if(It(E,i,h,y.text,k,e),!_.length){g&&z(E,i,h,i,h,"ishikawa-spine",e),nt(O,x,D);return}i-=20;const r=_.filter((S,P)=>P%2===0),v=_.filter((S,P)=>P%2===1),w=at(r),I=at(v),$=w.total+I.total;let L=j,A=j;if($>0){const S=j*2,P=j*.3;L=Math.max(P,S*(w.total/$)),A=Math.max(P,S*(I.total/$))}const C=k*2;L=Math.max(L,w.max*C),A=Math.max(A,I.max*C),h=Math.max(L,j),f&&f.attr("y1",h).attr("y2",h),E.select(".ishikawa-head-group").attr("transform",`translate(0,${h})`);const b=Math.ceil(_.length/2);for(let S=0;SMath.min(R,H.getBBox().x),1/0)}if(g)z(E,i,h,0,h,"ishikawa-spine",e);else{f.attr("x1",i);const S=`url(#${s})`;E.selectAll("line.ishikawa-branch, line.ishikawa-sub-branch").attr("marker-start",S)}nt(O,x,D)},"draw"),at=l(t=>{const d=l(n=>n.children.reduce((a,o)=>a+1+d(o),0),"countDescendants");return t.reduce((n,a)=>{const o=d(a);return n.total+=o,n.max=Math.max(n.max,o),n},{total:0,max:0})},"sideStats"),It=l((t,d,n,a,o,y)=>{const p=Math.max(6,Math.floor(110/(o*.6))),u=t.append("g").attr("class","ishikawa-head-group").attr("transform",`translate(${d},${n})`),m=Z(u,ht(a,p),0,0,"ishikawa-head-label","start",o),c=m.node().getBBox(),k=Math.max(60,c.width+6),g=Math.max(40,c.height*2+40),_=`M 0 ${-g/2} L 0 ${g/2} Q ${k*2.4} 0 0 ${-g/2} Z`;if(y){const x=y.roughSvg.path(_,{roughness:1.5,seed:y.seed,fill:y.fillColor,fillStyle:"hachure",fillWeight:2.5,hachureGap:5,stroke:y.lineColor,strokeWidth:2});u.insert(()=>x,":first-child").attr("class","ishikawa-head")}else u.insert("path",":first-child").attr("class","ishikawa-head").attr("d",_);m.attr("transform",`translate(${(k-c.width)/2-c.x+3},${-c.y-c.height/2})`)},"drawHead"),Lt=l((t,d)=>{const n=[],a=[],o=l((y,p,u)=>{const m=d===-1?[...y].reverse():y;for(const c of m){const k=n.length,g=c.children??[];n.push({depth:u,text:ht(c.text,15),parentIndex:p,childCount:g.length}),u%2===0?(a.push(k),g.length&&o(g,k,u+1)):(g.length&&o(g,k,u+1),a.push(k))}},"walk");return o(t,-1,2),{entries:n,yOrder:a}},"flattenTree"),Tt=l((t,d,n,a,o,y,p)=>{const u=t.append("g").attr("class","ishikawa-label-group"),c=Z(u,d,n,a+11*o,"ishikawa-label cause","middle",y).node().getBBox();if(p){const k=p.roughSvg.rectangle(c.x-20,c.y-2,c.width+40,c.height+4,{roughness:1.5,seed:p.seed,fill:p.fillColor,fillStyle:"hachure",fillWeight:2.5,hachureGap:5,stroke:p.lineColor,strokeWidth:2});u.insert(()=>k,":first-child").attr("class","ishikawa-label-box")}else u.insert("rect",":first-child").attr("class","ishikawa-label-box").attr("x",c.x-20).attr("y",c.y-2).attr("width",c.width+40).attr("height",c.height+4)},"drawCauseLabel"),q=l((t,d,n,a,o,y)=>{const p=Math.sqrt(a*a+o*o);if(p===0)return;const u=a/p,m=o/p,c=6,k=-m*c,g=u*c,_=d,x=n,D=`M ${_} ${x} L ${_-u*c*2+k} ${x-m*c*2+g} L ${_-u*c*2-k} ${x-m*c*2-g} Z`,O=y.roughSvg.path(D,{roughness:1,seed:y.seed,fill:y.lineColor,fillStyle:"solid",stroke:y.lineColor,strokeWidth:1});t.append(()=>O)},"drawArrowMarker"),Mt=l((t,d,n,a,o,y,p,u)=>{const m=d.children??[],c=y*(m.length?1:.2),k=-it*c,g=st*c*o,_=n+k,x=a+g;if(z(t,n,a,_,x,"ishikawa-branch",u),u&&q(t,n,a,n-_,a-x,u),Tt(t,d.text,_,x,o,p,u),!m.length)return;const{entries:D,yOrder:O}=Lt(m,o),E=D.length,T=new Array(E);for(const[f,r]of O.entries())T[r]=a+g*((f+1)/(E+1));const e=new Map;e.set(-1,{x0:n,y0:a,x1:_,y1:x,childCount:m.length,childrenDrawn:0});const s=-it,i=st*o,h=o<0?"ishikawa-label up":"ishikawa-label down";for(const[f,r]of D.entries()){const v=T[f],w=e.get(r.parentIndex),I=t.append("g").attr("class","ishikawa-sub-group");let $=0,L=0,A=0;if(r.depth%2===0){const C=w.y1-w.y0;$=rt(w.x0,w.x1,C?(v-w.y0)/C:.5),L=v,A=$-(r.childCount>0?$t+r.childCount*Et:St),z(I,$,v,A,v,"ishikawa-sub-branch",u),u&&q(I,$,v,1,0,u),Z(I,r.text,A,v,"ishikawa-label align","end",p)}else{const C=w.childrenDrawn++;$=rt(w.x0,w.x1,(w.childCount-C)/(w.childCount+1)),L=w.y0,A=$+s*((v-L)/i),z(I,$,L,A,v,"ishikawa-sub-branch",u),u&&q(I,$,L,$-A,L-v,u),Z(I,r.text,A,v,h,"end",p)}r.childCount>0&&e.set(f,{x0:$,y0:L,x1:A,y1:v,childCount:r.childCount,childrenDrawn:0})}},"drawBranch"),Pt=l(t=>t.split(/|\n/),"splitLines"),ht=l((t,d)=>{if(t.length<=d)return t;const n=[];for(const a of t.split(/\s+/)){const o=n.length-1;o>=0&&n[o].length+1+a.length<=d?n[o]+=" "+a:n.push(a)}return n.join(` +`)},"wrapText"),Z=l((t,d,n,a,o,y,p)=>{const u=Pt(d),m=p*1.05,c=t.append("text").attr("class",o).attr("text-anchor",y).attr("x",n).attr("y",a-(u.length-1)*m/2);for(const[k,g]of u.entries())c.append("tspan").attr("x",n).attr("dy",k===0?0:m).text(g);return c},"drawMultilineText"),rt=l((t,d,n)=>t+(d-t)*n,"lerp"),z=l((t,d,n,a,o,y,p)=>{if(p){const u=p.roughSvg.line(d,n,a,o,{roughness:1.5,seed:p.seed,stroke:p.lineColor,strokeWidth:2});t.append(()=>u).attr("class",y);return}return t.append("line").attr("class",y).attr("x1",d).attr("y1",n).attr("x2",a).attr("y2",o)},"drawLine"),Bt={draw:At},Nt=l(t=>` +.ishikawa .ishikawa-spine, +.ishikawa .ishikawa-branch, +.ishikawa .ishikawa-sub-branch { + stroke: ${t.lineColor}; + stroke-width: 2; + fill: none; +} + +.ishikawa .ishikawa-sub-branch { + stroke-width: 1; +} + +.ishikawa .ishikawa-arrow { + fill: ${t.lineColor}; +} + +.ishikawa .ishikawa-head { + fill: ${t.mainBkg}; + stroke: ${t.lineColor}; + stroke-width: 2; +} + +.ishikawa .ishikawa-label-box { + fill: ${t.mainBkg}; + stroke: ${t.lineColor}; + stroke-width: 2; +} + +.ishikawa text { + font-family: ${t.fontFamily}; + font-size: ${t.fontSize}; + fill: ${t.textColor}; +} + +.ishikawa .ishikawa-head-label { + font-weight: 600; + text-anchor: middle; + dominant-baseline: middle; + font-size: 14px; +} + +.ishikawa .ishikawa-label { + text-anchor: end; +} + +.ishikawa .ishikawa-label.cause { + text-anchor: middle; + dominant-baseline: middle; +} + +.ishikawa .ishikawa-label.align { + text-anchor: end; + dominant-baseline: middle; +} + +.ishikawa .ishikawa-label.up { + dominant-baseline: baseline; +} + +.ishikawa .ishikawa-label.down { + dominant-baseline: hanging; +} +`,"getStyles"),Dt=Nt,Ct={parser:bt,get db(){return new xt},renderer:Bt,styles:Dt};export{Ct as diagram}; diff --git a/apps/kimi-code/dist-web/assets/ishikawaDiagram-FXEZZL3T-D_WjGjIa.js b/apps/kimi-code/dist-web/assets/ishikawaDiagram-FXEZZL3T-D_WjGjIa.js new file mode 100644 index 0000000000000000000000000000000000000000..b0536e0cfb5866f133f4e690f09acf6f0db57afb --- /dev/null +++ b/apps/kimi-code/dist-web/assets/ishikawaDiagram-FXEZZL3T-D_WjGjIa.js @@ -0,0 +1,70 @@ +import{_ as l,c as lt,K as ct,D as ut,al as dt,p as yt,k as ft,n as et,a as pt,b as gt,g as kt,s as mt,o as wt,e as _t}from"./mermaid.core-CCxZmhet.js";import"./index-Baap3_X9.js";import"./_commonjsHelpers-CqkleIqs.js";var Q=(function(){var t=l(function(T,e,s,i){for(s=s||{},i=T.length;i--;s[T[i]]=e);return s},"o"),d=[1,4],n=[1,14],a=[1,12],o=[1,13],y=[6,7,8],p=[1,20],u=[1,18],m=[1,19],c=[6,7,11],k=[1,6,13,14],g=[1,23],_=[1,24],x=[1,6,7,11,13,14],D={trace:l(function(){},"trace"),yy:{},symbols_:{error:2,start:3,ishikawa:4,spaceLines:5,SPACELINE:6,NL:7,ISHIKAWA:8,document:9,stop:10,EOF:11,statement:12,SPACELIST:13,TEXT:14,$accept:0,$end:1},terminals_:{2:"error",6:"SPACELINE",7:"NL",8:"ISHIKAWA",11:"EOF",13:"SPACELIST",14:"TEXT"},productions_:[0,[3,1],[3,2],[5,1],[5,2],[5,2],[4,2],[4,3],[10,1],[10,1],[10,1],[10,2],[10,2],[9,3],[9,2],[12,2],[12,1],[12,1],[12,1]],performAction:l(function(e,s,i,h,f,r,v){var w=r.length-1;switch(f){case 6:case 7:return h;case 15:h.addNode(r[w-1].length,r[w].trim());break;case 16:h.addNode(0,r[w].trim());break}},"anonymous"),table:[{3:1,4:2,5:3,6:[1,5],8:d},{1:[3]},{1:[2,1]},{4:6,6:[1,7],7:[1,8],8:d},{6:n,7:[1,10],9:9,12:11,13:a,14:o},t(y,[2,3]),{1:[2,2]},t(y,[2,4]),t(y,[2,5]),{1:[2,6],6:n,12:15,13:a,14:o},{6:n,9:16,12:11,13:a,14:o},{6:p,7:u,10:17,11:m},t(c,[2,18],{14:[1,21]}),t(c,[2,16]),t(c,[2,17]),{6:p,7:u,10:22,11:m},{1:[2,7],6:n,12:15,13:a,14:o},t(k,[2,14],{7:g,11:_}),t(x,[2,8]),t(x,[2,9]),t(x,[2,10]),t(c,[2,15]),t(k,[2,13],{7:g,11:_}),t(x,[2,11]),t(x,[2,12])],defaultActions:{2:[2,1],6:[2,2]},parseError:l(function(e,s){if(s.recoverable)this.trace(e);else{var i=new Error(e);throw i.hash=s,i}},"parseError"),parse:l(function(e){var s=this,i=[0],h=[],f=[null],r=[],v=this.table,w="",I=0,$=0,L=2,A=1,C=r.slice.call(arguments,1),b=Object.create(this.lexer),S={yy:{}};for(var P in this.yy)Object.prototype.hasOwnProperty.call(this.yy,P)&&(S.yy[P]=this.yy[P]);b.setInput(e,S.yy),S.yy.lexer=b,S.yy.parser=this,typeof b.yylloc>"u"&&(b.yylloc={});var R=b.yylloc;r.push(R);var H=b.options&&b.options.ranges;typeof S.yy.parseError=="function"?this.parseError=S.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function K(B){i.length=i.length-2*B,f.length=f.length-B,r.length=r.length-B}l(K,"popStack");function J(){var B;return B=h.pop()||b.lex()||A,typeof B!="number"&&(B instanceof Array&&(h=B,B=h.pop()),B=s.symbols_[B]||B),B}l(J,"lex");for(var M,W,N,X,F={},G,V,tt,U;;){if(W=i[i.length-1],this.defaultActions[W]?N=this.defaultActions[W]:((M===null||typeof M>"u")&&(M=J()),N=v[W]&&v[W][M]),typeof N>"u"||!N.length||!N[0]){var Y="";U=[];for(G in v[W])this.terminals_[G]&&G>L&&U.push("'"+this.terminals_[G]+"'");b.showPosition?Y="Parse error on line "+(I+1)+`: +`+b.showPosition()+` +Expecting `+U.join(", ")+", got '"+(this.terminals_[M]||M)+"'":Y="Parse error on line "+(I+1)+": Unexpected "+(M==A?"end of input":"'"+(this.terminals_[M]||M)+"'"),this.parseError(Y,{text:b.match,token:this.terminals_[M]||M,line:b.yylineno,loc:R,expected:U})}if(N[0]instanceof Array&&N.length>1)throw new Error("Parse Error: multiple actions possible at state: "+W+", token: "+M);switch(N[0]){case 1:i.push(M),f.push(b.yytext),r.push(b.yylloc),i.push(N[1]),M=null,$=b.yyleng,w=b.yytext,I=b.yylineno,R=b.yylloc;break;case 2:if(V=this.productions_[N[1]][1],F.$=f[f.length-V],F._$={first_line:r[r.length-(V||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(V||1)].first_column,last_column:r[r.length-1].last_column},H&&(F._$.range=[r[r.length-(V||1)].range[0],r[r.length-1].range[1]]),X=this.performAction.apply(F,[w,$,I,S.yy,N[1],f,r].concat(C)),typeof X<"u")return X;V&&(i=i.slice(0,-1*V*2),f=f.slice(0,-1*V),r=r.slice(0,-1*V)),i.push(this.productions_[N[1]][0]),f.push(F.$),r.push(F._$),tt=v[i[i.length-2]][i[i.length-1]],i.push(tt);break;case 3:return!0}}return!0},"parse")},O=(function(){var T={EOF:1,parseError:l(function(s,i){if(this.yy.parser)this.yy.parser.parseError(s,i);else throw new Error(s)},"parseError"),setInput:l(function(e,s){return this.yy=s||this.yy||{},this._input=e,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:l(function(){var e=this._input[0];this.yytext+=e,this.yyleng++,this.offset++,this.match+=e,this.matched+=e;var s=e.match(/(?:\r\n?|\n).*/g);return s?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),e},"input"),unput:l(function(e){var s=e.length,i=e.split(/(?:\r\n?|\n)/g);this._input=e+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-s),this.offset-=s;var h=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),i.length-1&&(this.yylineno-=i.length-1);var f=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:i?(i.length===h.length?this.yylloc.first_column:0)+h[h.length-i.length].length-i[0].length:this.yylloc.first_column-s},this.options.ranges&&(this.yylloc.range=[f[0],f[0]+this.yyleng-s]),this.yyleng=this.yytext.length,this},"unput"),more:l(function(){return this._more=!0,this},"more"),reject:l(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:l(function(e){this.unput(this.match.slice(e))},"less"),pastInput:l(function(){var e=this.matched.substr(0,this.matched.length-this.match.length);return(e.length>20?"...":"")+e.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:l(function(){var e=this.match;return e.length<20&&(e+=this._input.substr(0,20-e.length)),(e.substr(0,20)+(e.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:l(function(){var e=this.pastInput(),s=new Array(e.length+1).join("-");return e+this.upcomingInput()+` +`+s+"^"},"showPosition"),test_match:l(function(e,s){var i,h,f;if(this.options.backtrack_lexer&&(f={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&&(f.yylloc.range=this.yylloc.range.slice(0))),h=e[0].match(/(?:\r\n?|\n).*/g),h&&(this.yylineno+=h.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:h?h[h.length-1].length-h[h.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+e[0].length},this.yytext+=e[0],this.match+=e[0],this.matches=e,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(e[0].length),this.matched+=e[0],i=this.performAction.call(this,this.yy,this,s,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var r in f)this[r]=f[r];return!1}return!1},"test_match"),next:l(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var e,s,i,h;this._more||(this.yytext="",this.match="");for(var f=this._currentRules(),r=0;rs[0].length)){if(s=i,h=r,this.options.backtrack_lexer){if(e=this.test_match(i,f[r]),e!==!1)return e;if(this._backtrack){s=!1;continue}else return!1}else if(!this.options.flex)break}return s?(e=this.test_match(s,f[h]),e!==!1?e:!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:l(function(){var s=this.next();return s||this.lex()},"lex"),begin:l(function(s){this.conditionStack.push(s)},"begin"),popState:l(function(){var s=this.conditionStack.length-1;return s>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:l(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:l(function(s){return s=this.conditionStack.length-1-Math.abs(s||0),s>=0?this.conditionStack[s]:"INITIAL"},"topState"),pushState:l(function(s){this.begin(s)},"pushState"),stateStackSize:l(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:l(function(s,i,h,f){switch(h){case 0:return 6;case 1:return 8;case 2:return 8;case 3:return 6;case 4:return 7;case 5:return 13;case 6:return 14;case 7:return 11}},"anonymous"),rules:[/^(?:\s*%%.*)/i,/^(?:ishikawa-beta\b)/i,/^(?:ishikawa\b)/i,/^(?:[\s]+[\n])/i,/^(?:[\n]+)/i,/^(?:[\s]+)/i,/^(?:[^\n]+)/i,/^(?:$)/i],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7],inclusive:!0}}};return T})();D.lexer=O;function E(){this.yy={}}return l(E,"Parser"),E.prototype=D,D.Parser=E,new E})();Q.parser=Q;var bt=Q,xt=class{constructor(){this.stack=[],this.clear=this.clear.bind(this),this.addNode=this.addNode.bind(this),this.getRoot=this.getRoot.bind(this)}static{l(this,"IshikawaDB")}clear(){this.root=void 0,this.stack=[],this.baseLevel=void 0,yt()}getRoot(){return this.root}addNode(t,d){const n=ft.sanitizeText(d,lt());if(!this.root){this.root={text:n,children:[]},this.stack=[{level:0,node:this.root}],et(n);return}this.baseLevel??=t;let a=t-this.baseLevel+1;for(a<=0&&(a=1);this.stack.length>1&&this.stack[this.stack.length-1].level>=a;)this.stack.pop();const o=this.stack[this.stack.length-1].node,y={text:n,children:[]};o.children.push(y),this.stack.push({level:a,node:y})}getAccTitle(){return pt()}setAccTitle(t){gt(t)}getAccDescription(){return kt()}setAccDescription(t){mt(t)}getDiagramTitle(){return wt()}setDiagramTitle(t){et(t)}},vt=14,j=250,St=30,$t=60,Et=5,ot=82*Math.PI/180,it=Math.cos(ot),st=Math.sin(ot),nt=l((t,d,n)=>{const a=t.node().getBBox(),o=a.width+d*2,y=a.height+d*2;_t(t,y,o,n),t.attr("viewBox",`${a.x-d} ${a.y-d} ${o} ${y}`)},"applyPaddedViewBox"),At=l((t,d,n,a)=>{const y=a.db.getRoot();if(!y)return;const p=lt(),{look:u,handDrawnSeed:m,themeVariables:c}=p,k=ct(p.fontSize)[0]??vt,g=u==="handDrawn",_=y.children??[],x=p.ishikawa?.diagramPadding??20,D=p.ishikawa?.useMaxWidth??!1,O=ut(d),E=O.append("g").attr("class","ishikawa"),T=g?dt.svg(O.node()):void 0,e=T?{roughSvg:T,seed:m??0,lineColor:c?.lineColor??"#333",fillColor:c?.mainBkg??"#fff"}:void 0,s=`ishikawa-arrow-${d}`;g||E.append("defs").append("marker").attr("id",s).attr("viewBox","0 0 10 10").attr("refX",0).attr("refY",5).attr("markerWidth",6).attr("markerHeight",6).attr("orient","auto").append("path").attr("d","M 10 0 L 0 5 L 10 10 Z").attr("class","ishikawa-arrow");let i=0,h=j;const f=g?void 0:z(E,i,h,i,h,"ishikawa-spine");if(It(E,i,h,y.text,k,e),!_.length){g&&z(E,i,h,i,h,"ishikawa-spine",e),nt(O,x,D);return}i-=20;const r=_.filter((S,P)=>P%2===0),v=_.filter((S,P)=>P%2===1),w=at(r),I=at(v),$=w.total+I.total;let L=j,A=j;if($>0){const S=j*2,P=j*.3;L=Math.max(P,S*(w.total/$)),A=Math.max(P,S*(I.total/$))}const C=k*2;L=Math.max(L,w.max*C),A=Math.max(A,I.max*C),h=Math.max(L,j),f&&f.attr("y1",h).attr("y2",h),E.select(".ishikawa-head-group").attr("transform",`translate(0,${h})`);const b=Math.ceil(_.length/2);for(let S=0;SMath.min(R,H.getBBox().x),1/0)}if(g)z(E,i,h,0,h,"ishikawa-spine",e);else{f.attr("x1",i);const S=`url(#${s})`;E.selectAll("line.ishikawa-branch, line.ishikawa-sub-branch").attr("marker-start",S)}nt(O,x,D)},"draw"),at=l(t=>{const d=l(n=>n.children.reduce((a,o)=>a+1+d(o),0),"countDescendants");return t.reduce((n,a)=>{const o=d(a);return n.total+=o,n.max=Math.max(n.max,o),n},{total:0,max:0})},"sideStats"),It=l((t,d,n,a,o,y)=>{const p=Math.max(6,Math.floor(110/(o*.6))),u=t.append("g").attr("class","ishikawa-head-group").attr("transform",`translate(${d},${n})`),m=Z(u,ht(a,p),0,0,"ishikawa-head-label","start",o),c=m.node().getBBox(),k=Math.max(60,c.width+6),g=Math.max(40,c.height*2+40),_=`M 0 ${-g/2} L 0 ${g/2} Q ${k*2.4} 0 0 ${-g/2} Z`;if(y){const x=y.roughSvg.path(_,{roughness:1.5,seed:y.seed,fill:y.fillColor,fillStyle:"hachure",fillWeight:2.5,hachureGap:5,stroke:y.lineColor,strokeWidth:2});u.insert(()=>x,":first-child").attr("class","ishikawa-head")}else u.insert("path",":first-child").attr("class","ishikawa-head").attr("d",_);m.attr("transform",`translate(${(k-c.width)/2-c.x+3},${-c.y-c.height/2})`)},"drawHead"),Lt=l((t,d)=>{const n=[],a=[],o=l((y,p,u)=>{const m=d===-1?[...y].reverse():y;for(const c of m){const k=n.length,g=c.children??[];n.push({depth:u,text:ht(c.text,15),parentIndex:p,childCount:g.length}),u%2===0?(a.push(k),g.length&&o(g,k,u+1)):(g.length&&o(g,k,u+1),a.push(k))}},"walk");return o(t,-1,2),{entries:n,yOrder:a}},"flattenTree"),Tt=l((t,d,n,a,o,y,p)=>{const u=t.append("g").attr("class","ishikawa-label-group"),c=Z(u,d,n,a+11*o,"ishikawa-label cause","middle",y).node().getBBox();if(p){const k=p.roughSvg.rectangle(c.x-20,c.y-2,c.width+40,c.height+4,{roughness:1.5,seed:p.seed,fill:p.fillColor,fillStyle:"hachure",fillWeight:2.5,hachureGap:5,stroke:p.lineColor,strokeWidth:2});u.insert(()=>k,":first-child").attr("class","ishikawa-label-box")}else u.insert("rect",":first-child").attr("class","ishikawa-label-box").attr("x",c.x-20).attr("y",c.y-2).attr("width",c.width+40).attr("height",c.height+4)},"drawCauseLabel"),q=l((t,d,n,a,o,y)=>{const p=Math.sqrt(a*a+o*o);if(p===0)return;const u=a/p,m=o/p,c=6,k=-m*c,g=u*c,_=d,x=n,D=`M ${_} ${x} L ${_-u*c*2+k} ${x-m*c*2+g} L ${_-u*c*2-k} ${x-m*c*2-g} Z`,O=y.roughSvg.path(D,{roughness:1,seed:y.seed,fill:y.lineColor,fillStyle:"solid",stroke:y.lineColor,strokeWidth:1});t.append(()=>O)},"drawArrowMarker"),Mt=l((t,d,n,a,o,y,p,u)=>{const m=d.children??[],c=y*(m.length?1:.2),k=-it*c,g=st*c*o,_=n+k,x=a+g;if(z(t,n,a,_,x,"ishikawa-branch",u),u&&q(t,n,a,n-_,a-x,u),Tt(t,d.text,_,x,o,p,u),!m.length)return;const{entries:D,yOrder:O}=Lt(m,o),E=D.length,T=new Array(E);for(const[f,r]of O.entries())T[r]=a+g*((f+1)/(E+1));const e=new Map;e.set(-1,{x0:n,y0:a,x1:_,y1:x,childCount:m.length,childrenDrawn:0});const s=-it,i=st*o,h=o<0?"ishikawa-label up":"ishikawa-label down";for(const[f,r]of D.entries()){const v=T[f],w=e.get(r.parentIndex),I=t.append("g").attr("class","ishikawa-sub-group");let $=0,L=0,A=0;if(r.depth%2===0){const C=w.y1-w.y0;$=rt(w.x0,w.x1,C?(v-w.y0)/C:.5),L=v,A=$-(r.childCount>0?$t+r.childCount*Et:St),z(I,$,v,A,v,"ishikawa-sub-branch",u),u&&q(I,$,v,1,0,u),Z(I,r.text,A,v,"ishikawa-label align","end",p)}else{const C=w.childrenDrawn++;$=rt(w.x0,w.x1,(w.childCount-C)/(w.childCount+1)),L=w.y0,A=$+s*((v-L)/i),z(I,$,L,A,v,"ishikawa-sub-branch",u),u&&q(I,$,L,$-A,L-v,u),Z(I,r.text,A,v,h,"end",p)}r.childCount>0&&e.set(f,{x0:$,y0:L,x1:A,y1:v,childCount:r.childCount,childrenDrawn:0})}},"drawBranch"),Pt=l(t=>t.split(/|\n/),"splitLines"),ht=l((t,d)=>{if(t.length<=d)return t;const n=[];for(const a of t.split(/\s+/)){const o=n.length-1;o>=0&&n[o].length+1+a.length<=d?n[o]+=" "+a:n.push(a)}return n.join(` +`)},"wrapText"),Z=l((t,d,n,a,o,y,p)=>{const u=Pt(d),m=p*1.05,c=t.append("text").attr("class",o).attr("text-anchor",y).attr("x",n).attr("y",a-(u.length-1)*m/2);for(const[k,g]of u.entries())c.append("tspan").attr("x",n).attr("dy",k===0?0:m).text(g);return c},"drawMultilineText"),rt=l((t,d,n)=>t+(d-t)*n,"lerp"),z=l((t,d,n,a,o,y,p)=>{if(p){const u=p.roughSvg.line(d,n,a,o,{roughness:1.5,seed:p.seed,stroke:p.lineColor,strokeWidth:2});t.append(()=>u).attr("class",y);return}return t.append("line").attr("class",y).attr("x1",d).attr("y1",n).attr("x2",a).attr("y2",o)},"drawLine"),Bt={draw:At},Nt=l(t=>` +.ishikawa .ishikawa-spine, +.ishikawa .ishikawa-branch, +.ishikawa .ishikawa-sub-branch { + stroke: ${t.lineColor}; + stroke-width: 2; + fill: none; +} + +.ishikawa .ishikawa-sub-branch { + stroke-width: 1; +} + +.ishikawa .ishikawa-arrow { + fill: ${t.lineColor}; +} + +.ishikawa .ishikawa-head { + fill: ${t.mainBkg}; + stroke: ${t.lineColor}; + stroke-width: 2; +} + +.ishikawa .ishikawa-label-box { + fill: ${t.mainBkg}; + stroke: ${t.lineColor}; + stroke-width: 2; +} + +.ishikawa text { + font-family: ${t.fontFamily}; + font-size: ${t.fontSize}; + fill: ${t.textColor}; +} + +.ishikawa .ishikawa-head-label { + font-weight: 600; + text-anchor: middle; + dominant-baseline: middle; + font-size: 14px; +} + +.ishikawa .ishikawa-label { + text-anchor: end; +} + +.ishikawa .ishikawa-label.cause { + text-anchor: middle; + dominant-baseline: middle; +} + +.ishikawa .ishikawa-label.align { + text-anchor: end; + dominant-baseline: middle; +} + +.ishikawa .ishikawa-label.up { + dominant-baseline: baseline; +} + +.ishikawa .ishikawa-label.down { + dominant-baseline: hanging; +} +`,"getStyles"),Dt=Nt,Rt={parser:bt,get db(){return new xt},renderer:Bt,styles:Dt};export{Rt as diagram}; diff --git a/apps/kimi-code/dist-web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 b/apps/kimi-code/dist-web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..01769d9e63d89d35d21547fdcfe84382a68cfe7c Binary files /dev/null and b/apps/kimi-code/dist-web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 differ diff --git a/apps/kimi-code/dist-web/assets/journeyDiagram-5HDEW3XC-Df5gewaW.js b/apps/kimi-code/dist-web/assets/journeyDiagram-5HDEW3XC-Df5gewaW.js new file mode 100644 index 0000000000000000000000000000000000000000..79374cd2ac7a8c6a123de84b47f01de616c30ba0 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/journeyDiagram-5HDEW3XC-Df5gewaW.js @@ -0,0 +1,139 @@ +import{g as gt}from"./chunk-5VM5RSS4-g2RPEnPU.js";import{a as mt,g as lt,h as xt,d as kt}from"./chunk-32BRIVSS-DQSjSlNX.js";import{g as _t,s as vt,a as bt,b as wt,o as Tt,n as St,_ as s,c as R,d as X,e as $t,p as Mt}from"./mermaid.core-CCxZmhet.js";import{d as it}from"./arc-DQe8dUYI.js";import"./index-Baap3_X9.js";import"./_commonjsHelpers-CqkleIqs.js";var U=(function(){var t=s(function(h,r,n,l){for(n=n||{},l=h.length;l--;n[h[l]]=r);return n},"o"),e=[6,8,10,11,12,14,16,17,18],a=[1,9],f=[1,10],i=[1,11],u=[1,12],p=[1,13],o=[1,14],g={trace:s(function(){},"trace"),yy:{},symbols_:{error:2,start:3,journey:4,document:5,EOF:6,line:7,SPACE:8,statement:9,NEWLINE:10,title:11,acc_title:12,acc_title_value:13,acc_descr:14,acc_descr_value:15,acc_descr_multiline_value:16,section:17,taskName:18,taskData:19,$accept:0,$end:1},terminals_:{2:"error",4:"journey",6:"EOF",8:"SPACE",10:"NEWLINE",11:"title",12:"acc_title",13:"acc_title_value",14:"acc_descr",15:"acc_descr_value",16:"acc_descr_multiline_value",17:"section",18:"taskName",19:"taskData"},productions_:[0,[3,3],[5,0],[5,2],[7,2],[7,1],[7,1],[7,1],[9,1],[9,2],[9,2],[9,1],[9,1],[9,2]],performAction:s(function(r,n,l,y,d,c,v){var k=c.length-1;switch(d){case 1:return c[k-1];case 2:this.$=[];break;case 3:c[k-1].push(c[k]),this.$=c[k-1];break;case 4:case 5:this.$=c[k];break;case 6:case 7:this.$=[];break;case 8:y.setDiagramTitle(c[k].substr(6)),this.$=c[k].substr(6);break;case 9:this.$=c[k].trim(),y.setAccTitle(this.$);break;case 10:case 11:this.$=c[k].trim(),y.setAccDescription(this.$);break;case 12:y.addSection(c[k].substr(8)),this.$=c[k].substr(8);break;case 13:y.addTask(c[k-1],c[k]),this.$="task";break}},"anonymous"),table:[{3:1,4:[1,2]},{1:[3]},t(e,[2,2],{5:3}),{6:[1,4],7:5,8:[1,6],9:7,10:[1,8],11:a,12:f,14:i,16:u,17:p,18:o},t(e,[2,7],{1:[2,1]}),t(e,[2,3]),{9:15,11:a,12:f,14:i,16:u,17:p,18:o},t(e,[2,5]),t(e,[2,6]),t(e,[2,8]),{13:[1,16]},{15:[1,17]},t(e,[2,11]),t(e,[2,12]),{19:[1,18]},t(e,[2,4]),t(e,[2,9]),t(e,[2,10]),t(e,[2,13])],defaultActions:{},parseError:s(function(r,n){if(n.recoverable)this.trace(r);else{var l=new Error(r);throw l.hash=n,l}},"parseError"),parse:s(function(r){var n=this,l=[0],y=[],d=[null],c=[],v=this.table,k="",C=0,Q=0,yt=2,D=1,dt=c.slice.call(arguments,1),_=Object.create(this.lexer),I={yy:{}};for(var O in this.yy)Object.prototype.hasOwnProperty.call(this.yy,O)&&(I.yy[O]=this.yy[O]);_.setInput(r,I.yy),I.yy.lexer=_,I.yy.parser=this,typeof _.yylloc>"u"&&(_.yylloc={});var Y=_.yylloc;c.push(Y);var ft=_.options&&_.options.ranges;typeof I.yy.parseError=="function"?this.parseError=I.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function pt(w){l.length=l.length-2*w,d.length=d.length-w,c.length=c.length-w}s(pt,"popStack");function tt(){var w;return w=y.pop()||_.lex()||D,typeof w!="number"&&(w instanceof Array&&(y=w,w=y.pop()),w=n.symbols_[w]||w),w}s(tt,"lex");for(var b,A,T,q,F={},N,M,et,z;;){if(A=l[l.length-1],this.defaultActions[A]?T=this.defaultActions[A]:((b===null||typeof b>"u")&&(b=tt()),T=v[A]&&v[A][b]),typeof T>"u"||!T.length||!T[0]){var H="";z=[];for(N in v[A])this.terminals_[N]&&N>yt&&z.push("'"+this.terminals_[N]+"'");_.showPosition?H="Parse error on line "+(C+1)+`: +`+_.showPosition()+` +Expecting `+z.join(", ")+", got '"+(this.terminals_[b]||b)+"'":H="Parse error on line "+(C+1)+": Unexpected "+(b==D?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(H,{text:_.match,token:this.terminals_[b]||b,line:_.yylineno,loc:Y,expected:z})}if(T[0]instanceof Array&&T.length>1)throw new Error("Parse Error: multiple actions possible at state: "+A+", token: "+b);switch(T[0]){case 1:l.push(b),d.push(_.yytext),c.push(_.yylloc),l.push(T[1]),b=null,Q=_.yyleng,k=_.yytext,C=_.yylineno,Y=_.yylloc;break;case 2:if(M=this.productions_[T[1]][1],F.$=d[d.length-M],F._$={first_line:c[c.length-(M||1)].first_line,last_line:c[c.length-1].last_line,first_column:c[c.length-(M||1)].first_column,last_column:c[c.length-1].last_column},ft&&(F._$.range=[c[c.length-(M||1)].range[0],c[c.length-1].range[1]]),q=this.performAction.apply(F,[k,Q,C,I.yy,T[1],d,c].concat(dt)),typeof q<"u")return q;M&&(l=l.slice(0,-1*M*2),d=d.slice(0,-1*M),c=c.slice(0,-1*M)),l.push(this.productions_[T[1]][0]),d.push(F.$),c.push(F._$),et=v[l[l.length-2]][l[l.length-1]],l.push(et);break;case 3:return!0}}return!0},"parse")},m=(function(){var h={EOF:1,parseError:s(function(n,l){if(this.yy.parser)this.yy.parser.parseError(n,l);else throw new Error(n)},"parseError"),setInput:s(function(r,n){return this.yy=n||this.yy||{},this._input=r,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:s(function(){var r=this._input[0];this.yytext+=r,this.yyleng++,this.offset++,this.match+=r,this.matched+=r;var n=r.match(/(?:\r\n?|\n).*/g);return n?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),r},"input"),unput:s(function(r){var n=r.length,l=r.split(/(?:\r\n?|\n)/g);this._input=r+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-n),this.offset-=n;var y=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),l.length-1&&(this.yylineno-=l.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:l?(l.length===y.length?this.yylloc.first_column:0)+y[y.length-l.length].length-l[0].length:this.yylloc.first_column-n},this.options.ranges&&(this.yylloc.range=[d[0],d[0]+this.yyleng-n]),this.yyleng=this.yytext.length,this},"unput"),more:s(function(){return this._more=!0,this},"more"),reject:s(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:s(function(r){this.unput(this.match.slice(r))},"less"),pastInput:s(function(){var r=this.matched.substr(0,this.matched.length-this.match.length);return(r.length>20?"...":"")+r.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:s(function(){var r=this.match;return r.length<20&&(r+=this._input.substr(0,20-r.length)),(r.substr(0,20)+(r.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:s(function(){var r=this.pastInput(),n=new Array(r.length+1).join("-");return r+this.upcomingInput()+` +`+n+"^"},"showPosition"),test_match:s(function(r,n){var l,y,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))),y=r[0].match(/(?:\r\n?|\n).*/g),y&&(this.yylineno+=y.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:y?y[y.length-1].length-y[y.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+r[0].length},this.yytext+=r[0],this.match+=r[0],this.matches=r,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(r[0].length),this.matched+=r[0],l=this.performAction.call(this,this.yy,this,n,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),l)return l;if(this._backtrack){for(var c in d)this[c]=d[c];return!1}return!1},"test_match"),next:s(function(){if(this.done)return this.EOF;this._input||(this.done=!0);var r,n,l,y;this._more||(this.yytext="",this.match="");for(var d=this._currentRules(),c=0;cn[0].length)){if(n=l,y=c,this.options.backtrack_lexer){if(r=this.test_match(l,d[c]),r!==!1)return r;if(this._backtrack){n=!1;continue}else return!1}else if(!this.options.flex)break}return n?(r=this.test_match(n,d[y]),r!==!1?r:!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:s(function(){var n=this.next();return n||this.lex()},"lex"),begin:s(function(n){this.conditionStack.push(n)},"begin"),popState:s(function(){var n=this.conditionStack.length-1;return n>0?this.conditionStack.pop():this.conditionStack[0]},"popState"),_currentRules:s(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:s(function(n){return n=this.conditionStack.length-1-Math.abs(n||0),n>=0?this.conditionStack[n]:"INITIAL"},"topState"),pushState:s(function(n){this.begin(n)},"pushState"),stateStackSize:s(function(){return this.conditionStack.length},"stateStackSize"),options:{"case-insensitive":!0},performAction:s(function(n,l,y,d){switch(y){case 0:break;case 1:break;case 2:return 10;case 3:break;case 4:break;case 5:return 4;case 6:return 11;case 7:return this.begin("acc_title"),12;case 8:return this.popState(),"acc_title_value";case 9:return this.begin("acc_descr"),14;case 10:return this.popState(),"acc_descr_value";case 11:this.begin("acc_descr_multiline");break;case 12:this.popState();break;case 13:return"acc_descr_multiline_value";case 14:return 17;case 15:return 18;case 16:return 19;case 17:return":";case 18:return 6;case 19:return"INVALID"}},"anonymous"),rules:[/^(?:%(?!\{)[^\n]*)/i,/^(?:[^\}]%%[^\n]*)/i,/^(?:[\n]+)/i,/^(?:\s+)/i,/^(?:#[^\n]*)/i,/^(?:journey\b)/i,/^(?:title\s[^#\n;]+)/i,/^(?:accTitle\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*:\s*)/i,/^(?:(?!\n||)*[^\n]*)/i,/^(?:accDescr\s*\{\s*)/i,/^(?:[\}])/i,/^(?:[^\}]*)/i,/^(?:section\s[^#:\n;]+)/i,/^(?:[^#:\n;]+)/i,/^(?::[^#\n;]+)/i,/^(?::)/i,/^(?:$)/i,/^(?:.)/i],conditions:{acc_descr_multiline:{rules:[12,13],inclusive:!1},acc_descr:{rules:[10],inclusive:!1},acc_title:{rules:[8],inclusive:!1},INITIAL:{rules:[0,1,2,3,4,5,6,7,9,11,14,15,16,17,18,19],inclusive:!0}}};return h})();g.lexer=m;function x(){this.yy={}}return s(x,"Parser"),x.prototype=g,g.Parser=x,new x})();U.parser=U;var Et=U,V="",J=[],L=[],B=[],Ct=s(function(){J.length=0,L.length=0,V="",B.length=0,Mt()},"clear"),Pt=s(function(t){V=t,J.push(t)},"addSection"),It=s(function(){return J},"getSections"),At=s(function(){let t=rt();const e=100;let a=0;for(;!t&&a{a.people&&t.push(...a.people)}),[...new Set(t)].sort()},"updateActors"),Vt=s(function(t,e){const a=e.substr(1).split(":");let f=0,i=[];a.length===1?(f=Number(a[0]),i=[]):(f=Number(a[0]),i=a[1].split(","));const u=i.map(o=>o.trim()),p={section:V,type:V,people:u,task:t,score:f};B.push(p)},"addTask"),Rt=s(function(t){const e={section:V,type:V,description:t,task:t,classes:[]};L.push(e)},"addTaskOrg"),rt=s(function(){const t=s(function(a){return B[a].processed},"compileTask");let e=!0;for(const[a,f]of B.entries())t(a),e=e&&f.processed;return e},"compileTasks"),Lt=s(function(){return Ft()},"getActors"),nt={getConfig:s(()=>R().journey,"getConfig"),clear:Ct,setDiagramTitle:St,getDiagramTitle:Tt,setAccTitle:wt,getAccTitle:bt,setAccDescription:vt,getAccDescription:_t,addSection:Pt,getSections:It,getTasks:At,addTask:Vt,addTaskOrg:Rt,getActors:Lt},Bt=s(t=>`.label { + font-family: ${t.fontFamily}; + color: ${t.textColor}; + } + .mouth { + stroke: #666; + } + + line { + stroke: ${t.textColor} + } + + .legend { + fill: ${t.textColor}; + font-family: ${t.fontFamily}; + } + + .label text { + fill: #333; + } + .label { + color: ${t.textColor} + } + + .face { + ${t.faceColor?`fill: ${t.faceColor}`:"fill: #FFF8DC"}; + stroke: #999; + } + + .node rect, + .node circle, + .node ellipse, + .node polygon, + .node path { + fill: ${t.mainBkg}; + stroke: ${t.nodeBorder}; + stroke-width: 1px; + } + + .node .label { + text-align: center; + } + .node.clickable { + cursor: pointer; + } + + .arrowheadPath { + fill: ${t.arrowheadColor}; + } + + .edgePath .path { + stroke: ${t.lineColor}; + stroke-width: 1.5px; + } + + .flowchart-link { + stroke: ${t.lineColor}; + fill: none; + } + + .edgeLabel { + background-color: ${t.edgeLabelBackground}; + rect { + opacity: 0.5; + } + text-align: center; + } + + .cluster rect { + } + + .cluster text { + fill: ${t.titleColor}; + } + + div.mermaidTooltip { + position: absolute; + text-align: center; + max-width: 200px; + padding: 2px; + font-family: ${t.fontFamily}; + font-size: 12px; + background: ${t.tertiaryColor}; + border: 1px solid ${t.border2}; + border-radius: 2px; + pointer-events: none; + z-index: 100; + } + + .task-type-0, .section-type-0 { + ${t.fillType0?`fill: ${t.fillType0}`:""}; + } + .task-type-1, .section-type-1 { + ${t.fillType0?`fill: ${t.fillType1}`:""}; + } + .task-type-2, .section-type-2 { + ${t.fillType0?`fill: ${t.fillType2}`:""}; + } + .task-type-3, .section-type-3 { + ${t.fillType0?`fill: ${t.fillType3}`:""}; + } + .task-type-4, .section-type-4 { + ${t.fillType0?`fill: ${t.fillType4}`:""}; + } + .task-type-5, .section-type-5 { + ${t.fillType0?`fill: ${t.fillType5}`:""}; + } + .task-type-6, .section-type-6 { + ${t.fillType0?`fill: ${t.fillType6}`:""}; + } + .task-type-7, .section-type-7 { + ${t.fillType0?`fill: ${t.fillType7}`:""}; + } + + .actor-0 { + ${t.actor0?`fill: ${t.actor0}`:""}; + } + .actor-1 { + ${t.actor1?`fill: ${t.actor1}`:""}; + } + .actor-2 { + ${t.actor2?`fill: ${t.actor2}`:""}; + } + .actor-3 { + ${t.actor3?`fill: ${t.actor3}`:""}; + } + .actor-4 { + ${t.actor4?`fill: ${t.actor4}`:""}; + } + .actor-5 { + ${t.actor5?`fill: ${t.actor5}`:""}; + } + ${gt()} +`,"getStyles"),jt=Bt,K=s(function(t,e){return kt(t,e)},"drawRect"),Nt=s(function(t,e){const f=t.append("circle").attr("cx",e.cx).attr("cy",e.cy).attr("class","face").attr("r",15).attr("stroke-width",2).attr("overflow","visible"),i=t.append("g");i.append("circle").attr("cx",e.cx-15/3).attr("cy",e.cy-15/3).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666"),i.append("circle").attr("cx",e.cx+15/3).attr("cy",e.cy-15/3).attr("r",1.5).attr("stroke-width",2).attr("fill","#666").attr("stroke","#666");function u(g){const m=it().startAngle(Math.PI/2).endAngle(3*(Math.PI/2)).innerRadius(7.5).outerRadius(6.8181818181818175);g.append("path").attr("class","mouth").attr("d",m).attr("transform","translate("+e.cx+","+(e.cy+2)+")")}s(u,"smile");function p(g){const m=it().startAngle(3*Math.PI/2).endAngle(5*(Math.PI/2)).innerRadius(7.5).outerRadius(6.8181818181818175);g.append("path").attr("class","mouth").attr("d",m).attr("transform","translate("+e.cx+","+(e.cy+7)+")")}s(p,"sad");function o(g){g.append("line").attr("class","mouth").attr("stroke",2).attr("x1",e.cx-5).attr("y1",e.cy+7).attr("x2",e.cx+5).attr("y2",e.cy+7).attr("class","mouth").attr("stroke-width","1px").attr("stroke","#666")}return s(o,"ambivalent"),e.score>3?u(i):e.score<3?p(i):o(i),f},"drawFace"),ot=s(function(t,e){const a=t.append("circle");return a.attr("cx",e.cx),a.attr("cy",e.cy),a.attr("class","actor-"+e.pos),a.attr("fill",e.fill),a.attr("stroke",e.stroke),a.attr("r",e.r),a.class!==void 0&&a.attr("class",a.class),e.title!==void 0&&a.append("title").text(e.title),a},"drawCircle"),ct=s(function(t,e){return xt(t,e)},"drawText"),zt=s(function(t,e){function a(i,u,p,o,g){return i+","+u+" "+(i+p)+","+u+" "+(i+p)+","+(u+o-g)+" "+(i+p-g*1.2)+","+(u+o)+" "+i+","+(u+o)}s(a,"genPoints");const f=t.append("polygon");f.attr("points",a(e.x,e.y,50,20,7)),f.attr("class","labelBox"),e.y=e.y+e.labelMargin,e.x=e.x+.5*e.labelMargin,ct(t,e)},"drawLabel"),Wt=s(function(t,e,a){const f=t.append("g"),i=lt();i.x=e.x,i.y=e.y,i.fill=e.fill,i.width=a.width*e.taskCount+a.diagramMarginX*(e.taskCount-1),i.height=a.height,i.class="journey-section section-type-"+e.num,i.rx=3,i.ry=3,K(f,i),ht(a)(e.text,f,i.x,i.y,i.width,i.height,{class:"journey-section section-type-"+e.num},a,e.colour)},"drawSection"),Z=-1,Ot=s(function(t,e,a,f){const i=e.x+a.width/2,u=t.append("g");Z++,u.append("line").attr("id",f+"-task"+Z).attr("x1",i).attr("y1",e.y).attr("x2",i).attr("y2",450).attr("class","task-line").attr("stroke-width","1px").attr("stroke-dasharray","4 2").attr("stroke","#666"),Nt(u,{cx:i,cy:300+(5-e.score)*30,score:e.score});const o=lt();o.x=e.x,o.y=e.y,o.fill=e.fill,o.width=a.width,o.height=a.height,o.class="task task-type-"+e.num,o.rx=3,o.ry=3,K(u,o);let g=e.x+14;e.people.forEach(m=>{const x=e.actors[m].color,h={cx:g,cy:e.y,r:7,fill:x,stroke:"#000",title:m,pos:e.actors[m].position};ot(u,h),g+=10}),ht(a)(e.task,u,o.x,o.y,o.width,o.height,{class:"task"},a,e.colour)},"drawTask"),Yt=s(function(t,e){mt(t,e)},"drawBackgroundRect"),ht=(function(){function t(i,u,p,o,g,m,x,h){const r=u.append("text").attr("x",p+g/2).attr("y",o+m/2+5).style("font-color",h).style("text-anchor","middle").text(i);f(r,x)}s(t,"byText");function e(i,u,p,o,g,m,x,h,r){const{taskFontSize:n,taskFontFamily:l}=h,y=i.split(//gi);for(let d=0;d{const u=E[i].color,p={cx:20,cy:f,r:7,fill:u,stroke:"#000",pos:E[i].position};j.drawCircle(t,p);let o=t.append("text").attr("visibility","hidden").text(i);const g=o.node().getBoundingClientRect().width;o.remove();let m=[];if(g<=a)m=[i];else{const x=i.split(" ");let h="";o=t.append("text").attr("visibility","hidden"),x.forEach(r=>{const n=h?`${h} ${r}`:r;if(o.text(n),o.node().getBoundingClientRect().width>a){if(h&&m.push(h),h=r,o.text(r),o.node().getBoundingClientRect().width>a){let y="";for(const d of r)y+=d,o.text(y+"-"),o.node().getBoundingClientRect().width>a&&(m.push(y.slice(0,-1)+"-"),y=d);h=y}}else h=n}),h&&m.push(h),o.remove()}m.forEach((x,h)=>{const r={x:40,y:f+7+h*20,fill:"#666",text:x,textMargin:e.boxTextMargin??5},l=j.drawText(t,r).node().getBoundingClientRect().width;l>W&&l>e.leftMargin-l&&(W=l)}),f+=Math.max(20,m.length*20)})}s(ut,"drawActorLegend");var $=R().journey,P=0,Xt=s(function(t,e,a,f){const i=R(),u=i.journey.titleColor,p=i.journey.titleFontSize,o=i.journey.titleFontFamily,g=i.securityLevel;let m;g==="sandbox"&&(m=X("#i"+e));const x=g==="sandbox"?X(m.nodes()[0].contentDocument.body):X("body");S.init();const h=x.select("#"+e);j.initGraphics(h,e);const r=f.db.getTasks(),n=f.db.getDiagramTitle(),l=f.db.getActors();for(const C in E)delete E[C];let y=0;l.forEach(C=>{E[C]={color:$.actorColours[y%$.actorColours.length],position:y},y++}),ut(h),P=$.leftMargin+W,S.insert(0,0,P,Object.keys(E).length*50),Gt(h,r,0,e);const d=S.getBounds();n&&h.append("text").text(n).attr("x",P).attr("font-size",p).attr("font-weight","bold").attr("y",25).attr("fill",u).attr("font-family",o);const c=d.stopy-d.starty+2*$.diagramMarginY,v=P+d.stopx+2*$.diagramMarginX;$t(h,c,v,$.useMaxWidth),h.append("line").attr("x1",P).attr("y1",$.height*4).attr("x2",v-P-4).attr("y2",$.height*4).attr("stroke-width",4).attr("stroke","black").attr("marker-end","url(#"+e+"-arrowhead)");const k=n?70:0;h.attr("viewBox",`${d.startx} -25 ${v} ${c+k}`),h.attr("preserveAspectRatio","xMinYMin meet"),h.attr("height",c+k+25)},"draw"),S={data:{startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},verticalPos:0,sequenceItems:[],init:s(function(){this.sequenceItems=[],this.data={startx:void 0,stopx:void 0,starty:void 0,stopy:void 0},this.verticalPos=0},"init"),updateVal:s(function(t,e,a,f){t[e]===void 0?t[e]=a:t[e]=f(a,t[e])},"updateVal"),updateBounds:s(function(t,e,a,f){const i=R().journey,u=this;let p=0;function o(g){return s(function(x){p++;const h=u.sequenceItems.length-p+1;u.updateVal(x,"starty",e-h*i.boxMargin,Math.min),u.updateVal(x,"stopy",f+h*i.boxMargin,Math.max),u.updateVal(S.data,"startx",t-h*i.boxMargin,Math.min),u.updateVal(S.data,"stopx",a+h*i.boxMargin,Math.max),g!=="activation"&&(u.updateVal(x,"startx",t-h*i.boxMargin,Math.min),u.updateVal(x,"stopx",a+h*i.boxMargin,Math.max),u.updateVal(S.data,"starty",e-h*i.boxMargin,Math.min),u.updateVal(S.data,"stopy",f+h*i.boxMargin,Math.max))},"updateItemBounds")}s(o,"updateFn"),this.sequenceItems.forEach(o())},"updateBounds"),insert:s(function(t,e,a,f){const i=Math.min(t,a),u=Math.max(t,a),p=Math.min(e,f),o=Math.max(e,f);this.updateVal(S.data,"startx",i,Math.min),this.updateVal(S.data,"starty",p,Math.min),this.updateVal(S.data,"stopx",u,Math.max),this.updateVal(S.data,"stopy",o,Math.max),this.updateBounds(i,p,u,o)},"insert"),bumpVerticalPos:s(function(t){this.verticalPos=this.verticalPos+t,this.data.stopy=this.verticalPos},"bumpVerticalPos"),getVerticalPos:s(function(){return this.verticalPos},"getVerticalPos"),getBounds:s(function(){return this.data},"getBounds")},G=$.sectionFills,st=$.sectionColours,Gt=s(function(t,e,a,f){const i=R().journey;let u="";const p=i.height*2+i.diagramMarginY,o=a+p;let g=0,m="#CCC",x="black",h=0;for(const[r,n]of e.entries()){if(u!==n.section){m=G[g%G.length],h=g%G.length,x=st[g%st.length];let y=0;const d=n.section;for(let v=r;v(E[d]&&(y[d]=E[d]),y),{});n.x=r*i.taskMargin+r*i.width+P,n.y=o,n.width=i.diagramMarginX,n.height=i.diagramMarginY,n.colour=x,n.fill=m,n.num=h,n.actors=l,j.drawTask(t,n,i,f),S.insert(n.x,n.y,n.x+n.width+i.taskMargin,450)}},"drawTasks"),at={setConf:Ht,draw:Xt},te={parser:Et,db:nt,renderer:at,styles:jt,init:s(t=>{at.setConf(t.journey),nt.clear()},"init")};export{te as diagram}; diff --git a/apps/kimi-code/dist-web/assets/json5-C9tS-k6U.js b/apps/kimi-code/dist-web/assets/json5-C9tS-k6U.js new file mode 100644 index 0000000000000000000000000000000000000000..627f3023471851a2263a83248dd10dc338c0e8ec --- /dev/null +++ b/apps/kimi-code/dist-web/assets/json5-C9tS-k6U.js @@ -0,0 +1 @@ +const n=Object.freeze(JSON.parse(`{"displayName":"JSON5","fileTypes":["json5"],"name":"json5","patterns":[{"include":"#comments"},{"include":"#value"}],"repository":{"array":{"begin":"\\\\[","beginCaptures":{"0":{"name":"punctuation.definition.array.begin.json5"}},"end":"]","endCaptures":{"0":{"name":"punctuation.definition.array.end.json5"}},"name":"meta.structure.array.json5","patterns":[{"include":"#comments"},{"include":"#value"},{"match":",","name":"punctuation.separator.array.json5"},{"match":"[^]\\\\s]","name":"invalid.illegal.expected-array-separator.json5"}]},"comments":{"patterns":[{"match":"/{2}.*","name":"comment.single.json5"},{"begin":"/\\\\*\\\\*(?!/)","captures":{"0":{"name":"punctuation.definition.comment.json5"}},"end":"\\\\*/","name":"comment.block.documentation.json5"},{"begin":"/\\\\*","captures":{"0":{"name":"punctuation.definition.comment.json5"}},"end":"\\\\*/","name":"comment.block.json5"}]},"constant":{"match":"\\\\b(?:true|false|null|Infinity|NaN)\\\\b","name":"constant.language.json5"},"infinity":{"match":"(-)*\\\\b(?:Infinity|NaN)\\\\b","name":"constant.language.json5"},"key":{"name":"string.key.json5","patterns":[{"include":"#stringSingle"},{"include":"#stringDouble"},{"match":"[-0-9A-Z_a-z]","name":"string.key.json5"}]},"number":{"patterns":[{"match":"(0x)[0-9A-f]*","name":"constant.hex.numeric.json5"},{"match":"[+-.]?(?=[1-9]|0(?!\\\\d))\\\\d+(\\\\.\\\\d+)?([Ee][-+]?\\\\d+)?","name":"constant.dec.numeric.json5"}]},"object":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.dictionary.begin.json5"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.dictionary.end.json5"}},"name":"meta.structure.dictionary.json5","patterns":[{"include":"#comments"},{"include":"#key"},{"begin":":","beginCaptures":{"0":{"name":"punctuation.separator.dictionary.key-value.json5"}},"end":"(,)|(?=})","endCaptures":{"1":{"name":"punctuation.separator.dictionary.pair.json5"}},"name":"meta.structure.dictionary.value.json5","patterns":[{"include":"#value"},{"match":"[^,\\\\s]","name":"invalid.illegal.expected-dictionary-separator.json5"}]},{"match":"[^}\\\\s]","name":"invalid.illegal.expected-dictionary-separator.json5"}]},"stringDouble":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.json5"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.json5"}},"name":"string.quoted.json5","patterns":[{"match":"\\\\\\\\(?:[\\"/\\\\\\\\bfnrt]|u\\\\h{4})","name":"constant.character.escape.json5"},{"match":"\\\\\\\\.","name":"invalid.illegal.unrecognized-string-escape.json5"}]},"stringSingle":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.json5"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.json5"}},"name":"string.quoted.json5","patterns":[{"match":"\\\\\\\\(?:[\\"/\\\\\\\\bfnrt]|u\\\\h{4})","name":"constant.character.escape.json5"},{"match":"\\\\\\\\.","name":"invalid.illegal.unrecognized-string-escape.json5"}]},"value":{"patterns":[{"include":"#constant"},{"include":"#infinity"},{"include":"#number"},{"include":"#stringSingle"},{"include":"#stringDouble"},{"include":"#array"},{"include":"#object"}]}},"scopeName":"source.json5"}`)),e=[n];export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/julia-D7OTSIA_.js b/apps/kimi-code/dist-web/assets/julia-D7OTSIA_.js new file mode 100644 index 0000000000000000000000000000000000000000..1161657e1c88fa43591bfba32ad846638d414833 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/julia-D7OTSIA_.js @@ -0,0 +1 @@ +import e from"./cpp-UfJy6YNI.js";import n from"./python-B6aJPvgy.js";import a from"./javascript-wDzz0qaB.js";import t from"./r-Dspwwk_N.js";import i from"./sql-CRqJ_cUM.js";import"./regexp-CDVJQ6XC.js";import"./glsl-DplSGwfg.js";import"./c-BIGW1oBm.js";const p=Object.freeze(JSON.parse(`{"displayName":"Julia","name":"julia","patterns":[{"include":"#operator"},{"include":"#array"},{"include":"#string"},{"include":"#parentheses"},{"include":"#bracket"},{"include":"#function_decl"},{"include":"#function_call"},{"include":"#for_block"},{"include":"#keyword"},{"include":"#number"},{"include":"#comment"},{"include":"#type_decl"},{"include":"#symbol"},{"include":"#punctuation"}],"repository":{"array":{"patterns":[{"begin":"\\\\[","beginCaptures":{"0":{"name":"meta.bracket.julia"}},"end":"(])(\\\\.?'*)","endCaptures":{"1":{"name":"meta.bracket.julia"},"2":{"name":"keyword.operator.transpose.julia"}},"name":"meta.array.julia","patterns":[{"match":"\\\\bbegin\\\\b","name":"constant.numeric.julia"},{"match":"\\\\bend\\\\b","name":"constant.numeric.julia"},{"include":"#self_no_for_block"}]}]},"bracket":{"patterns":[{"begin":"\\\\{","beginCaptures":{"0":{"name":"meta.bracket.julia"}},"end":"(})(\\\\.?'*)","endCaptures":{"1":{"name":"meta.bracket.julia"},"2":{"name":"keyword.operator.transpose.julia"}},"patterns":[{"include":"#self_no_for_block"}]}]},"comment":{"patterns":[{"include":"#comment_block"},{"begin":"#","beginCaptures":{"0":{"name":"punctuation.definition.comment.julia"}},"end":"\\\\n","name":"comment.line.number-sign.julia","patterns":[{"include":"#comment_tags"}]}]},"comment_block":{"patterns":[{"begin":"#=","beginCaptures":{"0":{"name":"punctuation.definition.comment.begin.julia"}},"end":"=#","endCaptures":{"0":{"name":"punctuation.definition.comment.end.julia"}},"name":"comment.block.number-sign-equals.julia","patterns":[{"include":"#comment_tags"},{"include":"#comment_block"}]}]},"comment_tags":{"patterns":[{"match":"\\\\bTODO\\\\b","name":"keyword.other.comment-annotation.julia"},{"match":"\\\\bFIXME\\\\b","name":"keyword.other.comment-annotation.julia"},{"match":"\\\\bCHANGED\\\\b","name":"keyword.other.comment-annotation.julia"},{"match":"\\\\bXXX\\\\b","name":"keyword.other.comment-annotation.julia"}]},"for_block":{"patterns":[{"begin":"\\\\b(for)\\\\b","beginCaptures":{"0":{"name":"keyword.control.julia"}},"end":"(?]))"},{"captures":{"1":{"name":"keyword.other.julia"},"2":{"name":"keyword.operator.dots.julia"},"3":{"name":"entity.name.function.julia"},"4":{"name":"support.type.julia"}},"match":"\\\\b(function|macro)(?:\\\\s+(?:[_ⁱ-⁾₁-₎℘℮⅀-⅄∂∅∆∇∎-∑∞-∢∫-∳∿⊤⊥⊾-⋃◸-◿♯⟀⟁⟘⟙⦛-⦴⨀-⨆⨉-⨖⨛⨜゛゜𝛁𝛛𝛻𝜕𝜵𝝏𝝯𝞉𝞩𝟃𝟎-𝟡[:alpha:]\\\\p{Lu}\\\\p{Ll}\\\\p{Lt}\\\\p{Lm}\\\\p{Lo}\\\\p{Nl}\\\\p{Sc}[^←-⇿\\\\P{So}]][!_′-‷⁗ⁱ-⁾₁-₎℘℮⅀-⅄∂∅∆∇∎-∑∞-∢∫-∳∿⊤⊥⊾-⋃◸-◿♯⟀⟁⟘⟙⦛-⦴⨀-⨆⨉-⨖⨛⨜゛゜𝛁𝛛𝛻𝜕𝜵𝝏𝝯𝞉𝞩𝟃𝟎-𝟡[:word:]\\\\p{Lu}\\\\p{Ll}\\\\p{Lt}\\\\p{Lm}\\\\p{Lo}\\\\p{Nl}\\\\p{Sc}[^\\\\x01-¡\\\\P{Mn}][^\\\\x01-¡\\\\P{Mc}][^\\\\x01-¡\\\\D][^\\\\x01-¡\\\\P{Pc}][^\\\\x01-¡\\\\P{Sk}][^\\\\x01-¡\\\\P{Me}][^\\\\x01-¡\\\\P{No}][^←-⇿\\\\P{So}]]*(\\\\.))?([_ⁱ-⁾₁-₎℘℮⅀-⅄∂∅∆∇∎-∑∞-∢∫-∳∿⊤⊥⊾-⋃◸-◿♯⟀⟁⟘⟙⦛-⦴⨀-⨆⨉-⨖⨛⨜゛゜𝛁𝛛𝛻𝜕𝜵𝝏𝝯𝞉𝞩𝟃𝟎-𝟡[:alpha:]\\\\p{Lu}\\\\p{Ll}\\\\p{Lt}\\\\p{Lm}\\\\p{Lo}\\\\p{Nl}\\\\p{Sc}[^←-⇿\\\\P{So}]][!_′-‷⁗ⁱ-⁾₁-₎℘℮⅀-⅄∂∅∆∇∎-∑∞-∢∫-∳∿⊤⊥⊾-⋃◸-◿♯⟀⟁⟘⟙⦛-⦴⨀-⨆⨉-⨖⨛⨜゛゜𝛁𝛛𝛻𝜕𝜵𝝏𝝯𝞉𝞩𝟃𝟎-𝟡[:word:]\\\\p{Lu}\\\\p{Ll}\\\\p{Lt}\\\\p{Lm}\\\\p{Lo}\\\\p{Nl}\\\\p{Sc}[^\\\\x01-¡\\\\P{Mn}][^\\\\x01-¡\\\\P{Mc}][^\\\\x01-¡\\\\D][^\\\\x01-¡\\\\P{Pc}][^\\\\x01-¡\\\\P{Sk}][^\\\\x01-¡\\\\P{Me}][^\\\\x01-¡\\\\P{No}][^←-⇿\\\\P{So}]]*)(\\\\{(?:[^{}]|\\\\{(?:[^{}]|\\\\{[^{}]*})*})*})?|\\\\s*)(?=\\\\()"}]},"keyword":{"patterns":[{"match":"\\\\b(?|->|-->|<--|[←→↔↚-↞↠↢↣↤↦↩-↬↮↶↷↺-↽⇀⇁⇄⇆⇇⇉⇋-⇐⇒⇔⇚-⇝⇠⇢⇴⇶-⇿⟵⟶⟷⟹-⟿⤀-⤇⤌-⤑⤔-⤘⤝-⤠⥄-⥈⥊⥋⥎⥐⥒⥓⥖⥗⥚⥛⥞⥟⥢⥤⥦-⥭⥰⥷⥺⧴⬰-⭄⭇-⭌←→]|=>)","name":"keyword.operator.arrow.julia"},{"match":":=|\\\\+=|-=|\\\\*=|//=|/=|\\\\.//=|\\\\./=|\\\\.\\\\*=|\\\\\\\\=|\\\\.\\\\\\\\=|\\\\^=|\\\\.\\\\^=|%=|\\\\.%=|÷=|\\\\.÷=|\\\\|=|&=|\\\\.&=|⊻=|\\\\.⊻=|\\\\$=|<<=|>>=|>>>=|=(?!=)","name":"keyword.operator.update.julia"},{"match":"<<|>>>?|\\\\.>>>?|\\\\.<<","name":"keyword.operator.shift.julia"},{"captures":{"1":{"name":"keyword.operator.relation.types.julia"},"2":{"name":"support.type.julia"},"3":{"name":"keyword.operator.transpose.julia"}},"match":"\\\\s*([:<>]:)\\\\s*((?:Union)?\\\\([^)]*\\\\)|[$_∇[:alpha:]][!.′⁺-ₜ[:word:]]*(?:\\\\{(?:[^{}]|\\\\{(?:[^{}]|\\\\{[^{}]*})*})*}|\\".+?(?)>=|[<>≤≥]|===?|≡|!=|≠|!==|[∈-∍∝∥∦∷∺∻∽∾≁-≎≐-≓≖-≟≢≣≦-⊋⊏-⊒⊜⊢⊣⊩⊬⊮⊰-⊷⋍⋐⋑⋕-⋭⋲-⋿⟂⟈⟉⟒⦷⧀⧁⧡⧣⧤⧥⩦⩧⩪-⩳⩵-⫙⫪⫫⫷-⫺]|<:|>:))","name":"keyword.operator.relation.julia"},{"match":"(?<=\\\\s)\\\\?(?=\\\\s)","name":"keyword.operator.ternary.julia"},{"match":"(?<=\\\\s):(?=\\\\s)","name":"keyword.operator.ternary.julia"},{"match":"\\\\|\\\\||&&|(?","name":"keyword.operator.applies.julia"},{"match":"\\\\||\\\\.\\\\||&|\\\\.&|[~¬]|\\\\.~|⊻|\\\\.⊻","name":"keyword.operator.bitwise.julia"},{"match":"\\\\.?(?:\\\\+\\\\+|--|[-*+|¦±−∓∔∨∪∸≏⊎⊔⊕⊖⊞⊟⊻⊽⋎⋓⟇⧺⧻⨈⨢-⨮⨹⨺⩁⩂⩅⩊⩌⩏⩐⩒⩔⩖⩗⩛⩝⩡⩢⩣]|//?|[%\\\\&\\\\\\\\^±·×÷·⅋↑↓⇵∓∗-∜∤∧∩≀⊍⊓⊗-⊛⊠⊡⊼⋄-⋇⋉-⋌⋏⋒⌿▷⟑⟕⟖⟗⟰⟱⤈-⤋⤒⤓⥉⥌⥍⥏⥑⥔⥕⥘⥙⥜⥝⥠⥡⥣⥥⥮⥯⦸⦼⦾⦿⧶⧷⨇⨝⨟⨰-⨸⨻⨼⨽⩀⩃⩄⩋⩍⩎⩑⩓⩕⩘⩚⩜⩞⩟⩠⫛↑↓])","name":"keyword.operator.arithmetic.julia"},{"match":"∘","name":"keyword.operator.compose.julia"},{"match":"::|(?<=\\\\s)isa(?=\\\\s)","name":"keyword.operator.isa.julia"},{"match":"(?<=\\\\s)in(?=\\\\s)","name":"keyword.operator.relation.in.julia"},{"match":"\\\\.(?=[@_\\\\p{L}])|\\\\.\\\\.+|[…⁝⋮-⋱]","name":"keyword.operator.dots.julia"},{"match":"\\\\$(?=.+)","name":"keyword.operator.interpolation.julia"},{"captures":{"2":{"name":"keyword.operator.transposed-variable.julia"}},"match":"([_ⁱ-⁾₁-₎℘℮⅀-⅄∂∅∆∇∎-∑∞-∢∫-∳∿⊤⊥⊾-⋃◸-◿♯⟀⟁⟘⟙⦛-⦴⨀-⨆⨉-⨖⨛⨜゛゜𝛁𝛛𝛻𝜕𝜵𝝏𝝯𝞉𝞩𝟃𝟎-𝟡[:alpha:]\\\\p{Lu}\\\\p{Ll}\\\\p{Lt}\\\\p{Lm}\\\\p{Lo}\\\\p{Nl}\\\\p{Sc}[^←-⇿\\\\P{So}]][!_′-‷⁗ⁱ-⁾₁-₎℘℮⅀-⅄∂∅∆∇∎-∑∞-∢∫-∳∿⊤⊥⊾-⋃◸-◿♯⟀⟁⟘⟙⦛-⦴⨀-⨆⨉-⨖⨛⨜゛゜𝛁𝛛𝛻𝜕𝜵𝝏𝝯𝞉𝞩𝟃𝟎-𝟡[:word:]\\\\p{Lu}\\\\p{Ll}\\\\p{Lt}\\\\p{Lm}\\\\p{Lo}\\\\p{Nl}\\\\p{Sc}[^\\\\x01-¡\\\\P{Mn}][^\\\\x01-¡\\\\P{Mc}][^\\\\x01-¡\\\\D][^\\\\x01-¡\\\\P{Pc}][^\\\\x01-¡\\\\P{Sk}][^\\\\x01-¡\\\\P{Me}][^\\\\x01-¡\\\\P{No}][^←-⇿\\\\P{So}]]*)(('|(\\\\.'))*\\\\.?')"},{"captures":{"1":{"name":"bracket.end.julia"},"2":{"name":"keyword.operator.transposed-matrix.julia"}},"match":"(])((?:\\\\.??')*\\\\.?')"},{"captures":{"1":{"name":"bracket.end.julia"},"2":{"name":"keyword.operator.transposed-parens.julia"}},"match":"(\\\\))((?:\\\\.??')*\\\\.?')"}]},"parentheses":{"patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"meta.bracket.julia"}},"end":"(\\\\))(\\\\.?'*)","endCaptures":{"1":{"name":"meta.bracket.julia"},"2":{"name":"keyword.operator.transpose.julia"}},"patterns":[{"include":"#self_no_for_block"}]}]},"punctuation":{"patterns":[{"match":",","name":"punctuation.separator.comma.julia"},{"match":";","name":"punctuation.separator.semicolon.julia"}]},"self_no_for_block":{"patterns":[{"include":"#operator"},{"include":"#array"},{"include":"#string"},{"include":"#parentheses"},{"include":"#bracket"},{"include":"#function_decl"},{"include":"#function_call"},{"include":"#keyword"},{"include":"#number"},{"include":"#comment"},{"include":"#type_decl"},{"include":"#symbol"},{"include":"#punctuation"}]},"string":{"patterns":[{"begin":"(@doc)\\\\s((?:doc)?\\"\\"\\")|(doc\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"end":"(\\"\\"\\") ?(->)?","endCaptures":{"1":{"name":"punctuation.definition.string.end.julia"},"2":{"name":"keyword.operator.arrow.julia"}},"name":"string.docstring.julia","patterns":[{"include":"#string_escaped_char"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"(i?cxx)(\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"contentName":"meta.embedded.inline.cpp","end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"embed.cxx.julia","patterns":[{"include":"source.cpp#root_context"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"(py)(\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"contentName":"meta.embedded.inline.python","end":"([\\\\s\\\\w]*)(\\"\\"\\")","endCaptures":{"2":{"name":"punctuation.definition.string.end.julia"}},"name":"embed.python.julia","patterns":[{"include":"source.python"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"(js)(\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"contentName":"meta.embedded.inline.javascript","end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"embed.js.julia","patterns":[{"include":"source.js"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"(R)(\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"contentName":"meta.embedded.inline.r","end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"embed.R.julia","patterns":[{"include":"source.r"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"(raw)(\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"string.quoted.other.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"(raw)(\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"string.quoted.other.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"(sql)(\\"\\"\\")","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"contentName":"meta.embedded.inline.sql","end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"embed.sql.julia","patterns":[{"include":"source.sql"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"var\\"\\"\\"","end":"\\"\\"\\"","name":"constant.other.symbol.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"var\\"","end":"\\"","name":"constant.other.symbol.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"^\\\\s?(doc)?(\\"\\"\\")\\\\s?$","beginCaptures":{"1":{"name":"support.function.macro.julia"},"2":{"name":"punctuation.definition.string.begin.julia"}},"end":"(\\"\\"\\")","endCaptures":{"1":{"name":"punctuation.definition.string.end.julia"}},"name":"string.docstring.julia","patterns":[{"include":"#string_escaped_char"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.julia"}},"end":"'(?!')","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"string.quoted.single.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"\\"\\"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.multiline.begin.julia"}},"end":"\\"\\"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.multiline.end.julia"}},"name":"string.quoted.triple.double.julia","patterns":[{"include":"#string_escaped_char"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"\\"(?!\\"\\")","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.julia"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.julia"}},"name":"string.quoted.double.julia","patterns":[{"include":"#string_escaped_char"},{"include":"#string_dollar_sign_interpolate"}]},{"begin":"r\\"\\"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.regexp.begin.julia"}},"end":"(\\"\\"\\")([imsx]{0,4})?","endCaptures":{"1":{"name":"punctuation.definition.string.regexp.end.julia"},"2":{"name":"keyword.other.option-toggle.regexp.julia"}},"name":"string.regexp.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"r\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.regexp.begin.julia"}},"end":"(\\")([imsx]{0,4})?","endCaptures":{"1":{"name":"punctuation.definition.string.regexp.end.julia"},"2":{"name":"keyword.other.option-toggle.regexp.julia"}},"name":"string.regexp.julia","patterns":[{"include":"#string_escaped_char"}]},{"begin":"(?15?v="…"+h.slice(i-15,i):v=h.slice(0,i);var p;s+15r.replace(Y1,"-$1").toLowerCase(),W1={"&":"&",">":">","<":"<",'"':""","'":"'"},j1=/[&><"']/g,i0=r=>String(r).replace(j1,e=>W1[e]),Ce=r=>r.type==="ordgroup"||r.type==="color"?r.body.length===1?Ce(r.body[0]):r:r.type==="font"?Ce(r.body):r,Z1=new Set(["mathord","textord","atom"]),D0=r=>Z1.has(Ce(r).type),K1=r=>{var e=/^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(r);return e?e[2]!==":"||!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(e[1])?null:e[1].toLowerCase():"_relative"},dt={displayMode:{type:"boolean",description:"Render math in display mode, which puts the math in display style (so \\int and \\sum are large, for example), and centers the math on the page on its own line.",cli:"-d, --display-mode"},output:{type:{enum:["htmlAndMathml","html","mathml"]},description:"Determines the markup language of the output.",cli:"-F, --format "},leqno:{type:"boolean",description:"Render display math in leqno style (left-justified tags)."},fleqn:{type:"boolean",description:"Render display math flush left."},throwOnError:{type:"boolean",default:!0,cli:"-t, --no-throw-on-error",cliDescription:"Render errors (in the color given by --error-color) instead of throwing a ParseError exception when encountering an error."},errorColor:{type:"string",default:"#cc0000",cli:"-c, --error-color ",cliDescription:"A color string given in the format 'rgb' or 'rrggbb' (no #). This option determines the color of errors rendered by the -t option.",cliProcessor:r=>"#"+r},macros:{type:"object",cli:"-m, --macro ",cliDescription:"Define custom macro of the form '\\foo:expansion' (use multiple -m arguments for multiple macros).",cliDefault:[],cliProcessor:(r,e)=>(e.push(r),e)},minRuleThickness:{type:"number",description:"Specifies a minimum thickness, in ems, for fraction lines, `\\sqrt` top lines, `{array}` vertical lines, `\\hline`, `\\hdashline`, `\\underline`, `\\overline`, and the borders of `\\fbox`, `\\boxed`, and `\\fcolorbox`.",processor:r=>Math.max(0,r),cli:"--min-rule-thickness ",cliProcessor:parseFloat},colorIsTextColor:{type:"boolean",description:"Makes \\color behave like LaTeX's 2-argument \\textcolor, instead of LaTeX's one-argument \\color mode change.",cli:"-b, --color-is-text-color"},strict:{type:[{enum:["warn","ignore","error"]},"boolean","function"],description:"Turn on strict / LaTeX faithfulness mode, which throws an error if the input uses features that are not supported by LaTeX.",cli:"-S, --strict",cliDefault:!1},trust:{type:["boolean","function"],description:"Trust the input, enabling all HTML features such as \\url.",cli:"-T, --trust"},maxSize:{type:"number",default:1/0,description:"If non-zero, all user-specified sizes, e.g. in \\rule{500em}{500em}, will be capped to maxSize ems. Otherwise, elements and spaces can be arbitrarily large",processor:r=>Math.max(0,r),cli:"-s, --max-size ",cliProcessor:parseInt},maxExpand:{type:"number",default:1e3,description:"Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to Infinity, the macro expander will try to fully expand as in LaTeX.",processor:r=>Math.max(0,r),cli:"-e, --max-expand ",cliProcessor:r=>r==="Infinity"?1/0:parseInt(r)},globalGroup:{type:"boolean",cli:!1}};function J1(r){if(typeof r!="string")return r.enum[0];switch(r){case"boolean":return!1;case"string":return"";case"number":return 0;case"object":return{};default:throw new Error("Unexpected schema type; settings must declare an explicit default.")}}function Q1(r){if(r.default!==void 0)return r.default;var e=Array.isArray(r.type)?r.type[0]:r.type;return J1(e)}function _1(r,e,t,a){var i=t[e];r[e]=i!==void 0?a.processor?a.processor(i):i:Q1(a)}class Et{constructor(e){e===void 0&&(e={}),this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,this.globalGroup=void 0,e=e||{};for(var t of Object.keys(dt)){var a=dt[t];a&&_1(this,t,e,a)}}reportNonstrict(e,t,a){var i=this.strict;if(typeof i=="function"&&(i=i(e,t,a)),!(!i||i==="ignore")){if(i===!0||i==="error")throw new S("LaTeX-incompatible input and strict mode is set to 'error': "+(t+" ["+e+"]"),a);i==="warn"?typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+(t+" ["+e+"]")):typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to "+("unrecognized '"+i+"': "+t+" ["+e+"]"))}}useStrictBehavior(e,t,a){var i=this.strict;if(typeof i=="function")try{i=i(e,t,a)}catch{i="error"}return!i||i==="ignore"?!1:i===!0||i==="error"?!0:i==="warn"?(typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+(t+" ["+e+"]")),!1):(typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to "+("unrecognized '"+i+"': "+t+" ["+e+"]")),!1)}isTrusted(e){if("url"in e&&e.url&&!e.protocol){var t=K1(e.url);if(t==null)return!1;e.protocol=t}var a=typeof this.trust=="function"?this.trust(e):this.trust;return!!a}}class F0{constructor(e,t,a){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=e,this.size=t,this.cramped=a}sup(){return w0[ea[this.id]]}sub(){return w0[ta[this.id]]}fracNum(){return w0[ra[this.id]]}fracDen(){return w0[aa[this.id]]}cramp(){return w0[ia[this.id]]}text(){return w0[na[this.id]]}isTight(){return this.size>=2}}var Rt=0,qe=1,_0=2,B0=3,me=4,p0=5,ee=6,l0=7,w0=[new F0(Rt,0,!1),new F0(qe,0,!0),new F0(_0,1,!1),new F0(B0,1,!0),new F0(me,2,!1),new F0(p0,2,!0),new F0(ee,3,!1),new F0(l0,3,!0)],ea=[me,p0,me,p0,ee,l0,ee,l0],ta=[p0,p0,p0,p0,l0,l0,l0,l0],ra=[_0,B0,me,p0,ee,l0,ee,l0],aa=[B0,B0,p0,p0,l0,l0,l0,l0],ia=[qe,qe,B0,B0,p0,p0,l0,l0],na=[Rt,qe,_0,B0,_0,B0,_0,B0],N={DISPLAY:w0[Rt],TEXT:w0[_0],SCRIPT:w0[me],SCRIPTSCRIPT:w0[ee]},ft=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"armenian",blocks:[[1328,1423]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}];function sa(r){for(var e=0;e=i[0]&&r<=i[1])return t.name}return null}var De=[];ft.forEach(r=>r.blocks.forEach(e=>De.push(...e)));function Gr(r){for(var e=0;e=De[e]&&r<=De[e+1])return!0;return!1}var r0=r=>r+" "+r,Q0=80,la=function(e,t){return"M95,"+(622+e+t)+` +c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14 +c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54 +c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10 +s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429 +c69,-144,104.5,-217.7,106.5,-221 +l`+e/2.075+" -"+e+` +c5.3,-9.3,12,-14,20,-14 +H400000v`+(40+e)+`H845.2724 +s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7 +c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z +M`+(834+e)+" "+t+"h400000v"+(40+e)+"h-400000z"},ua=function(e,t){return"M263,"+(601+e+t)+`c0.7,0,18,39.7,52,119 +c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120 +c340,-704.7,510.7,-1060.3,512,-1067 +l`+e/2.084+" -"+e+` +c4.7,-7.3,11,-11,19,-11 +H40000v`+(40+e)+`H1012.3 +s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232 +c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1 +s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26 +c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z +M`+(1001+e)+" "+t+"h400000v"+(40+e)+"h-400000z"},oa=function(e,t){return"M983 "+(10+e+t)+` +l`+e/3.13+" -"+e+` +c4,-6.7,10,-10,18,-10 H400000v`+(40+e)+` +H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7 +s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744 +c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30 +c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722 +c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5 +c53.7,-170.3,84.5,-266.8,92.5,-289.5z +M`+(1001+e)+" "+t+"h400000v"+(40+e)+"h-400000z"},ha=function(e,t){return"M424,"+(2398+e+t)+` +c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514 +c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20 +s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121 +s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081 +l`+e/4.223+" -"+e+`c4,-6.7,10,-10,18,-10 H400000 +v`+(40+e)+`H1014.6 +s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185 +c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2z M`+(1001+e)+" "+t+` +h400000v`+(40+e)+"h-400000z"},ma=function(e,t){return"M473,"+(2713+e+t)+` +c339.3,-1799.3,509.3,-2700,510,-2702 l`+e/5.298+" -"+e+` +c3.3,-7.3,9.3,-11,18,-11 H400000v`+(40+e)+`H1017.7 +s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200 +c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26 +s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104, +606zM`+(1001+e)+" "+t+"h400000v"+(40+e)+"H1017.7z"},ca=function(e){var t=e/2;return"M400000 "+e+" H0 L"+t+" 0 l65 45 L145 "+(e-80)+" H400000z"},da=function(e,t,a){var i=a-54-t-e;return"M702 "+(e+t)+"H400000"+(40+e)+` +H742v`+i+`l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1 +h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170 +c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667 +219 661 l218 661zM702 `+t+"H400000v"+(40+e)+"H742z"},fa=function(e,t,a){t=1e3*t;var i="";switch(e){case"sqrtMain":i=la(t,Q0);break;case"sqrtSize1":i=ua(t,Q0);break;case"sqrtSize2":i=oa(t,Q0);break;case"sqrtSize3":i=ha(t,Q0);break;case"sqrtSize4":i=ma(t,Q0);break;case"sqrtTall":i=da(t,Q0,a)}return i},va=function(e,t){switch(e){case"⎜":return r0("M291 0 H417 V"+t+" H291z");case"∣":return r0("M145 0 H188 V"+t+" H145z");case"∥":return r0("M145 0 H188 V"+t+" H145z")+r0("M367 0 H410 V"+t+" H367z");case"⎟":return r0("M457 0 H583 V"+t+" H457z");case"⎢":return r0("M319 0 H403 V"+t+" H319z");case"⎥":return r0("M263 0 H347 V"+t+" H263z");case"⎪":return r0("M384 0 H504 V"+t+" H384z");case"⏐":return r0("M312 0 H355 V"+t+" H312z");case"‖":return r0("M257 0 H300 V"+t+" H257z")+r0("M478 0 H521 V"+t+" H478z");default:return""}},ar={doubleleftarrow:`M262 157 +l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3 + 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28 + 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5 +c2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5 + 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87 +-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7 +-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z +m8 0v40h399730v-40zm0 194v40h399730v-40z`,doublerightarrow:`M399738 392l +-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5 + 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88 +-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68 +-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18 +-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782 +c-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3 +-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z`,leftarrow:`M400000 241H110l3-3c68.7-52.7 113.7-120 + 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8 +-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247 +c-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208 + 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3 + 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202 + l-3-3h399890zM100 241v40h399900v-40z`,leftbrace:`M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117 +-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7 + 5-6 9-10 13-.7 1-7.3 1-20 1H6z`,leftbraceunder:`M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13 + 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688 + 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7 +-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z`,leftgroup:`M400000 80 +H435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0 + 435 0h399565z`,leftgroupunder:`M400000 262 +H435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219 + 435 219h399565z`,leftharpoon:`M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3 +-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5 +-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7 +-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z`,leftharpoonplus:`M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5 + 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3 +-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7 +-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z +m0 0v40h400000v-40z`,leftharpoondown:`M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333 + 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5 + 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667 +-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z`,leftharpoondownplus:`M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12 + 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7 +-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0 +v40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z`,lefthook:`M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5 +-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3 +-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21 + 71.5 23h399859zM103 281v-40h399897v40z`,leftlinesegment:r0("M40 281 V428 H0 V94 H40 V241 H400000 v40z"),leftbracketunder:r0("M0 0 h120 V290 H399995 v120 H0z"),leftbracketover:r0("M0 440 h120 V150 H399995 v-120 H0z"),leftmapsto:r0("M40 281 V448H0V74H40V241H400000v40z"),leftToFrom:`M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23 +-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8 +c28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3 + 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z`,longequal:r0("M0 50 h400000 v40H0z m0 194h40000v40H0z"),midbrace:`M200428 334 +c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14 +-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7 + 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11 + 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z`,midbraceunder:`M199572 214 +c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14 + 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3 + 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0 +-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z`,oiintSize1:`M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6 +-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z +m368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8 +60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z`,oiintSize2:`M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8 +-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z +m502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2 +c0 110 84 276 504 276s502.4-166 502.4-276z`,oiiintSize1:`M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6 +-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z +m525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0 +85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z`,oiiintSize2:`M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8 +-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z +m770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1 +c0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z`,rightarrow:`M0 241v40h399891c-47.3 35.3-84 78-110 128 +-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 + 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 + 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85 +-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 + 151.7 139 205zm0 0v40h399900v-40z`,rightbrace:`M400000 542l +-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5 +s-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1 +c124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z`,rightbraceunder:`M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3 + 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237 +-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z`,rightgroup:`M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0 + 3-1 3-3v-38c-76-158-257-219-435-219H0z`,rightgroupunder:`M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18 + 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z`,rightharpoon:`M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3 +-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2 +-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 + 69.2 92 94.5zm0 0v40h399900v-40z`,rightharpoonplus:`M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11 +-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7 + 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z +m0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z`,rightharpoondown:`M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8 + 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5 +-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95 +-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z`,rightharpoondownplus:`M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8 + 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 + 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3 +-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z +m0-194v40h400000v-40zm0 0v40h400000v-40z`,righthook:`M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3 + 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0 +-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21 + 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z`,rightlinesegment:r0("M399960 241 V94 h40 V428 h-40 V281 H0 v-40z"),rightbracketunder:r0("M399995 0 h-120 V290 H0 v120 H400000z"),rightbracketover:r0("M399995 440 h-120 V150 H0 v-120 H399995z"),rightToFrom:`M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23 + 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32 +-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142 +-167z M100 147v40h399900v-40zM0 341v40h399900v-40z`,twoheadleftarrow:`M0 167c68 40 + 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69 +-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3 +-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19 +-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101 + 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z`,twoheadrightarrow:`M400000 167 +c-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3 + 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42 + 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333 +-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70 + 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z`,tilde1:`M200 55.538c-77 0-168 73.953-177 73.953-3 0-7 +-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0 + 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0 + 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128 +-68.267.847-113-73.952-191-73.952z`,tilde2:`M344 55.266c-142 0-300.638 81.316-311.5 86.418 +-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9 + 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114 +c1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751 + 181.476 676 181.476c-149 0-189-126.21-332-126.21z`,tilde3:`M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457 +-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0 + 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697 + 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696 + -338 0-409-156.573-744-156.573z`,tilde4:`M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345 +-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409 + 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9 + 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409 + -175.236-744-175.236z`,vec:`M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5 +3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11 +10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63 +-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1 +-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59 +H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359 +c-16-25.333-24-45-24-59z`,widehat1:`M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22 +c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z`,widehat2:`M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widehat3:`M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widehat4:`M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widecheck1:`M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1, +-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z`,widecheck2:`M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,widecheck3:`M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,widecheck4:`M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,baraboveleftarrow:`M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202 +c4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5 +c-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130 +s-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47 +121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6 +s2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11 +c0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z +M100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z`,rightarrowabovebar:`M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32 +-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0 +13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39 +-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5 +-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 +151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z`,baraboveshortleftharpoon:`M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 +c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 +c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 +c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z +M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`,rightharpoonaboveshortbar:`M0,241 l0,40c399126,0,399993,0,399993,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`,shortbaraboveleftharpoon:`M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, +1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, +-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z +M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`,shortrightharpoonabovebar:`M53,241l0,40c398570,0,399437,0,399437,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`},pa=function(e,t){switch(e){case"lbrack":return"M403 1759 V84 H666 V0 H319 V1759 v"+t+` v1759 v84 h347 v-84 +H403z M403 1759 V0 H319 V1759 v`+t+" v1759 v84 h84z";case"rbrack":return"M347 1759 V0 H0 V84 H263 V1759 v"+t+` v1759 H0 v84 H347z +M347 1759 V0 H263 V1759 v`+t+" v1759 h84z";case"vert":return"M145 15 v585 v"+t+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-t+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v`+t+" v585 h43z";case"doublevert":return"M145 15 v585 v"+t+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-t+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v`+t+` v585 h43z +M367 15 v585 v`+t+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-t+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M410 15 H367 v585 v`+t+" v585 h43z";case"lfloor":return"M319 602 V0 H403 V602 v"+t+` v1715 h263 v84 H319z +MM319 602 V0 H403 V602 v`+t+" v1715 H319z";case"rfloor":return"M319 602 V0 H403 V602 v"+t+` v1799 H0 v-84 H319z +MM319 602 V0 H403 V602 v`+t+" v1715 H319z";case"lceil":return"M403 1759 V84 H666 V0 H319 V1759 v"+t+` v602 h84z +M403 1759 V0 H319 V1759 v`+t+" v602 h84z";case"rceil":return"M347 1759 V0 H0 V84 H263 V1759 v"+t+` v602 h84z +M347 1759 V0 h-84 V1759 v`+t+" v602 h84z";case"lparen":return`M863,9c0,-2,-2,-5,-6,-9c0,0,-17,0,-17,0c-12.7,0,-19.3,0.3,-20,1 +c-5.3,5.3,-10.3,11,-15,17c-242.7,294.7,-395.3,682,-458,1162c-21.3,163.3,-33.3,349, +-36,557 l0,`+(t+84)+`c0.2,6,0,26,0,60c2,159.3,10,310.7,24,454c53.3,528,210, +949.7,470,1265c4.7,6,9.7,11.7,15,17c0.7,0.7,7,1,19,1c0,0,18,0,18,0c4,-4,6,-7,6,-9 +c0,-2.7,-3.3,-8.7,-10,-18c-135.3,-192.7,-235.5,-414.3,-300.5,-665c-65,-250.7,-102.5, +-544.7,-112.5,-882c-2,-104,-3,-167,-3,-189 +l0,-`+(t+92)+`c0,-162.7,5.7,-314,17,-454c20.7,-272,63.7,-513,129,-723c65.3, +-210,155.3,-396.3,270,-559c6.7,-9.3,10,-15.3,10,-18z`;case"rparen":return`M76,0c-16.7,0,-25,3,-25,9c0,2,2,6.3,6,13c21.3,28.7,42.3,60.3, +63,95c96.7,156.7,172.8,332.5,228.5,527.5c55.7,195,92.8,416.5,111.5,664.5 +c11.3,139.3,17,290.7,17,454c0,28,1.7,43,3.3,45l0,`+(t+9)+` +c-3,4,-3.3,16.7,-3.3,38c0,162,-5.7,313.7,-17,455c-18.7,248,-55.8,469.3,-111.5,664 +c-55.7,194.7,-131.8,370.3,-228.5,527c-20.7,34.7,-41.7,66.3,-63,95c-2,3.3,-4,7,-6,11 +c0,7.3,5.7,11,17,11c0,0,11,0,11,0c9.3,0,14.3,-0.3,15,-1c5.3,-5.3,10.3,-11,15,-17 +c242.7,-294.7,395.3,-681.7,458,-1161c21.3,-164.7,33.3,-350.7,36,-558 +l0,-`+(t+144)+`c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7, +-470,-1265c-4.7,-6,-9.7,-11.7,-15,-17c-0.7,-0.7,-6.7,-1,-18,-1z`;default:throw new Error("Unknown stretchy delimiter.")}};function ga(r){return"toText"in r}class ae{constructor(e){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=e,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}hasClass(e){return this.classes.includes(e)}toNode(){for(var e=document.createDocumentFragment(),t=0;t{if(ga(e))return e.toText();throw new Error("Expected MathDomNode with toText, got "+e.constructor.name)}).join("")}}var vt={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:803/800,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:803/800},ba={ex:!0,em:!0,mu:!0},Ur=function(e){return typeof e!="string"&&(e=e.unit),e in vt||e in ba||e==="ex"},K=function(e,t){var a;if(e.unit in vt)a=vt[e.unit]/t.fontMetrics().ptPerEm/t.sizeMultiplier;else if(e.unit==="mu")a=t.fontMetrics().cssEmPerMu;else{var i;if(t.style.isTight()?i=t.havingStyle(t.style.text()):i=t,e.unit==="ex")a=i.fontMetrics().xHeight;else if(e.unit==="em")a=i.fontMetrics().quad;else throw new S("Invalid unit: '"+e.unit+"'");i!==t&&(a*=i.sizeMultiplier/t.sizeMultiplier)}return Math.min(e.number*a,t.maxSize)},A=function(e){return+e.toFixed(4)+"em"},L0=function(e){return e.filter(t=>t).join(" ")},It=function(e){var t="";for(var a of Object.keys(e)){var i=e[a];i!==void 0&&(t+=$1(a)+":"+i+";")}return t},Vr=function(e,t,a){if(this.classes=e||[],this.attributes={},this.height=0,this.depth=0,this.maxFontSize=0,this.style=a||{},t){t.style.isTight()&&this.classes.push("mtight");var i=t.getColor();i&&(this.style.color=i)}},Xr=function(e){var t=document.createElement(e);t.className=L0(this.classes),Object.assign(t.style,this.style);for(var a of Object.keys(this.attributes))t.setAttribute(a,this.attributes[a]);for(var i=0;i/=\x00-\x1f]/,Yr=function(e){var t="<"+e;this.classes.length&&(t+=' class="'+i0(L0(this.classes))+'"');var a=It(this.style);a&&(t+=' style="'+i0(a)+'"');for(var i of Object.keys(this.attributes)){if(ya.test(i))throw new S("Invalid attribute name '"+i+"'");t+=" "+i+'="'+i0(this.attributes[i])+'"'}t+=">";for(var s=0;s",t};class ie{constructor(e,t,a,i){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,this.italic=void 0,Vr.call(this,e,a,i),this.children=t||[]}setAttribute(e,t){this.attributes[e]=t}hasClass(e){return this.classes.includes(e)}toNode(){return Xr.call(this,"span")}toMarkup(){return Yr.call(this,"span")}}class Fe{constructor(e,t,a,i){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,Vr.call(this,t,i),this.children=a||[],this.setAttribute("href",e)}setAttribute(e,t){this.attributes[e]=t}hasClass(e){return this.classes.includes(e)}toNode(){return Xr.call(this,"a")}toMarkup(){return Yr.call(this,"a")}}class xa{constructor(e,t,a){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=t,this.src=e,this.classes=["mord"],this.height=0,this.depth=0,this.maxFontSize=0,this.style=a}hasClass(e){return this.classes.includes(e)}toNode(){var e=document.createElement("img");return e.src=this.src,e.alt=this.alt,e.className="mord",Object.assign(e.style,this.style),e}toMarkup(){var e=''+i0(this.alt)+'0&&(t=document.createElement("span"),t.style.marginRight=A(this.italic)),this.classes.length>0&&(t=t||document.createElement("span"),t.className=L0(this.classes)),Object.keys(this.style).length>0&&(t=t||document.createElement("span"),Object.assign(t.style,this.style)),t?(t.appendChild(e),t):e}toMarkup(){var e=!1,t="0&&(a+="margin-right:"+A(this.italic)+";"),a+=It(this.style),a&&(e=!0,t+=' style="'+i0(a)+'"');var i=i0(this.text);return e?(t+=">",t+=i,t+="",t):i}}class C0{constructor(e,t){this.children=void 0,this.attributes=void 0,this.children=e||[],this.attributes=t||{}}toNode(){var e="http://www.w3.org/2000/svg",t=document.createElementNS(e,"svg");for(var a of Object.keys(this.attributes))t.setAttribute(a,this.attributes[a]);for(var i=0;i':''}}class pt{constructor(e){this.attributes=void 0,this.attributes=e||{}}toNode(){var e="http://www.w3.org/2000/svg",t=document.createElementNS(e,"line");for(var a of Object.keys(this.attributes))t.setAttribute(a,this.attributes[a]);return t}toMarkup(){var e=" but got "+String(r)+".")}var za=r=>r instanceof ie||r instanceof Fe||r instanceof ae,k0={"AMS-Regular":{32:[0,0,0,0,.25],65:[0,.68889,0,0,.72222],66:[0,.68889,0,0,.66667],67:[0,.68889,0,0,.72222],68:[0,.68889,0,0,.72222],69:[0,.68889,0,0,.66667],70:[0,.68889,0,0,.61111],71:[0,.68889,0,0,.77778],72:[0,.68889,0,0,.77778],73:[0,.68889,0,0,.38889],74:[.16667,.68889,0,0,.5],75:[0,.68889,0,0,.77778],76:[0,.68889,0,0,.66667],77:[0,.68889,0,0,.94445],78:[0,.68889,0,0,.72222],79:[.16667,.68889,0,0,.77778],80:[0,.68889,0,0,.61111],81:[.16667,.68889,0,0,.77778],82:[0,.68889,0,0,.72222],83:[0,.68889,0,0,.55556],84:[0,.68889,0,0,.66667],85:[0,.68889,0,0,.72222],86:[0,.68889,0,0,.72222],87:[0,.68889,0,0,1],88:[0,.68889,0,0,.72222],89:[0,.68889,0,0,.72222],90:[0,.68889,0,0,.66667],107:[0,.68889,0,0,.55556],160:[0,0,0,0,.25],165:[0,.675,.025,0,.75],174:[.15559,.69224,0,0,.94666],240:[0,.68889,0,0,.55556],295:[0,.68889,0,0,.54028],710:[0,.825,0,0,2.33334],732:[0,.9,0,0,2.33334],770:[0,.825,0,0,2.33334],771:[0,.9,0,0,2.33334],989:[.08167,.58167,0,0,.77778],1008:[0,.43056,.04028,0,.66667],8245:[0,.54986,0,0,.275],8463:[0,.68889,0,0,.54028],8487:[0,.68889,0,0,.72222],8498:[0,.68889,0,0,.55556],8502:[0,.68889,0,0,.66667],8503:[0,.68889,0,0,.44445],8504:[0,.68889,0,0,.66667],8513:[0,.68889,0,0,.63889],8592:[-.03598,.46402,0,0,.5],8594:[-.03598,.46402,0,0,.5],8602:[-.13313,.36687,0,0,1],8603:[-.13313,.36687,0,0,1],8606:[.01354,.52239,0,0,1],8608:[.01354,.52239,0,0,1],8610:[.01354,.52239,0,0,1.11111],8611:[.01354,.52239,0,0,1.11111],8619:[0,.54986,0,0,1],8620:[0,.54986,0,0,1],8621:[-.13313,.37788,0,0,1.38889],8622:[-.13313,.36687,0,0,1],8624:[0,.69224,0,0,.5],8625:[0,.69224,0,0,.5],8630:[0,.43056,0,0,1],8631:[0,.43056,0,0,1],8634:[.08198,.58198,0,0,.77778],8635:[.08198,.58198,0,0,.77778],8638:[.19444,.69224,0,0,.41667],8639:[.19444,.69224,0,0,.41667],8642:[.19444,.69224,0,0,.41667],8643:[.19444,.69224,0,0,.41667],8644:[.1808,.675,0,0,1],8646:[.1808,.675,0,0,1],8647:[.1808,.675,0,0,1],8648:[.19444,.69224,0,0,.83334],8649:[.1808,.675,0,0,1],8650:[.19444,.69224,0,0,.83334],8651:[.01354,.52239,0,0,1],8652:[.01354,.52239,0,0,1],8653:[-.13313,.36687,0,0,1],8654:[-.13313,.36687,0,0,1],8655:[-.13313,.36687,0,0,1],8666:[.13667,.63667,0,0,1],8667:[.13667,.63667,0,0,1],8669:[-.13313,.37788,0,0,1],8672:[-.064,.437,0,0,1.334],8674:[-.064,.437,0,0,1.334],8705:[0,.825,0,0,.5],8708:[0,.68889,0,0,.55556],8709:[.08167,.58167,0,0,.77778],8717:[0,.43056,0,0,.42917],8722:[-.03598,.46402,0,0,.5],8724:[.08198,.69224,0,0,.77778],8726:[.08167,.58167,0,0,.77778],8733:[0,.69224,0,0,.77778],8736:[0,.69224,0,0,.72222],8737:[0,.69224,0,0,.72222],8738:[.03517,.52239,0,0,.72222],8739:[.08167,.58167,0,0,.22222],8740:[.25142,.74111,0,0,.27778],8741:[.08167,.58167,0,0,.38889],8742:[.25142,.74111,0,0,.5],8756:[0,.69224,0,0,.66667],8757:[0,.69224,0,0,.66667],8764:[-.13313,.36687,0,0,.77778],8765:[-.13313,.37788,0,0,.77778],8769:[-.13313,.36687,0,0,.77778],8770:[-.03625,.46375,0,0,.77778],8774:[.30274,.79383,0,0,.77778],8776:[-.01688,.48312,0,0,.77778],8778:[.08167,.58167,0,0,.77778],8782:[.06062,.54986,0,0,.77778],8783:[.06062,.54986,0,0,.77778],8785:[.08198,.58198,0,0,.77778],8786:[.08198,.58198,0,0,.77778],8787:[.08198,.58198,0,0,.77778],8790:[0,.69224,0,0,.77778],8791:[.22958,.72958,0,0,.77778],8796:[.08198,.91667,0,0,.77778],8806:[.25583,.75583,0,0,.77778],8807:[.25583,.75583,0,0,.77778],8808:[.25142,.75726,0,0,.77778],8809:[.25142,.75726,0,0,.77778],8812:[.25583,.75583,0,0,.5],8814:[.20576,.70576,0,0,.77778],8815:[.20576,.70576,0,0,.77778],8816:[.30274,.79383,0,0,.77778],8817:[.30274,.79383,0,0,.77778],8818:[.22958,.72958,0,0,.77778],8819:[.22958,.72958,0,0,.77778],8822:[.1808,.675,0,0,.77778],8823:[.1808,.675,0,0,.77778],8828:[.13667,.63667,0,0,.77778],8829:[.13667,.63667,0,0,.77778],8830:[.22958,.72958,0,0,.77778],8831:[.22958,.72958,0,0,.77778],8832:[.20576,.70576,0,0,.77778],8833:[.20576,.70576,0,0,.77778],8840:[.30274,.79383,0,0,.77778],8841:[.30274,.79383,0,0,.77778],8842:[.13597,.63597,0,0,.77778],8843:[.13597,.63597,0,0,.77778],8847:[.03517,.54986,0,0,.77778],8848:[.03517,.54986,0,0,.77778],8858:[.08198,.58198,0,0,.77778],8859:[.08198,.58198,0,0,.77778],8861:[.08198,.58198,0,0,.77778],8862:[0,.675,0,0,.77778],8863:[0,.675,0,0,.77778],8864:[0,.675,0,0,.77778],8865:[0,.675,0,0,.77778],8872:[0,.69224,0,0,.61111],8873:[0,.69224,0,0,.72222],8874:[0,.69224,0,0,.88889],8876:[0,.68889,0,0,.61111],8877:[0,.68889,0,0,.61111],8878:[0,.68889,0,0,.72222],8879:[0,.68889,0,0,.72222],8882:[.03517,.54986,0,0,.77778],8883:[.03517,.54986,0,0,.77778],8884:[.13667,.63667,0,0,.77778],8885:[.13667,.63667,0,0,.77778],8888:[0,.54986,0,0,1.11111],8890:[.19444,.43056,0,0,.55556],8891:[.19444,.69224,0,0,.61111],8892:[.19444,.69224,0,0,.61111],8901:[0,.54986,0,0,.27778],8903:[.08167,.58167,0,0,.77778],8905:[.08167,.58167,0,0,.77778],8906:[.08167,.58167,0,0,.77778],8907:[0,.69224,0,0,.77778],8908:[0,.69224,0,0,.77778],8909:[-.03598,.46402,0,0,.77778],8910:[0,.54986,0,0,.76042],8911:[0,.54986,0,0,.76042],8912:[.03517,.54986,0,0,.77778],8913:[.03517,.54986,0,0,.77778],8914:[0,.54986,0,0,.66667],8915:[0,.54986,0,0,.66667],8916:[0,.69224,0,0,.66667],8918:[.0391,.5391,0,0,.77778],8919:[.0391,.5391,0,0,.77778],8920:[.03517,.54986,0,0,1.33334],8921:[.03517,.54986,0,0,1.33334],8922:[.38569,.88569,0,0,.77778],8923:[.38569,.88569,0,0,.77778],8926:[.13667,.63667,0,0,.77778],8927:[.13667,.63667,0,0,.77778],8928:[.30274,.79383,0,0,.77778],8929:[.30274,.79383,0,0,.77778],8934:[.23222,.74111,0,0,.77778],8935:[.23222,.74111,0,0,.77778],8936:[.23222,.74111,0,0,.77778],8937:[.23222,.74111,0,0,.77778],8938:[.20576,.70576,0,0,.77778],8939:[.20576,.70576,0,0,.77778],8940:[.30274,.79383,0,0,.77778],8941:[.30274,.79383,0,0,.77778],8994:[.19444,.69224,0,0,.77778],8995:[.19444,.69224,0,0,.77778],9416:[.15559,.69224,0,0,.90222],9484:[0,.69224,0,0,.5],9488:[0,.69224,0,0,.5],9492:[0,.37788,0,0,.5],9496:[0,.37788,0,0,.5],9585:[.19444,.68889,0,0,.88889],9586:[.19444,.74111,0,0,.88889],9632:[0,.675,0,0,.77778],9633:[0,.675,0,0,.77778],9650:[0,.54986,0,0,.72222],9651:[0,.54986,0,0,.72222],9654:[.03517,.54986,0,0,.77778],9660:[0,.54986,0,0,.72222],9661:[0,.54986,0,0,.72222],9664:[.03517,.54986,0,0,.77778],9674:[.11111,.69224,0,0,.66667],9733:[.19444,.69224,0,0,.94445],10003:[0,.69224,0,0,.83334],10016:[0,.69224,0,0,.83334],10731:[.11111,.69224,0,0,.66667],10846:[.19444,.75583,0,0,.61111],10877:[.13667,.63667,0,0,.77778],10878:[.13667,.63667,0,0,.77778],10885:[.25583,.75583,0,0,.77778],10886:[.25583,.75583,0,0,.77778],10887:[.13597,.63597,0,0,.77778],10888:[.13597,.63597,0,0,.77778],10889:[.26167,.75726,0,0,.77778],10890:[.26167,.75726,0,0,.77778],10891:[.48256,.98256,0,0,.77778],10892:[.48256,.98256,0,0,.77778],10901:[.13667,.63667,0,0,.77778],10902:[.13667,.63667,0,0,.77778],10933:[.25142,.75726,0,0,.77778],10934:[.25142,.75726,0,0,.77778],10935:[.26167,.75726,0,0,.77778],10936:[.26167,.75726,0,0,.77778],10937:[.26167,.75726,0,0,.77778],10938:[.26167,.75726,0,0,.77778],10949:[.25583,.75583,0,0,.77778],10950:[.25583,.75583,0,0,.77778],10955:[.28481,.79383,0,0,.77778],10956:[.28481,.79383,0,0,.77778],57350:[.08167,.58167,0,0,.22222],57351:[.08167,.58167,0,0,.38889],57352:[.08167,.58167,0,0,.77778],57353:[0,.43056,.04028,0,.66667],57356:[.25142,.75726,0,0,.77778],57357:[.25142,.75726,0,0,.77778],57358:[.41951,.91951,0,0,.77778],57359:[.30274,.79383,0,0,.77778],57360:[.30274,.79383,0,0,.77778],57361:[.41951,.91951,0,0,.77778],57366:[.25142,.75726,0,0,.77778],57367:[.25142,.75726,0,0,.77778],57368:[.25142,.75726,0,0,.77778],57369:[.25142,.75726,0,0,.77778],57370:[.13597,.63597,0,0,.77778],57371:[.13597,.63597,0,0,.77778]},"Caligraphic-Regular":{32:[0,0,0,0,.25],65:[0,.68333,0,.19445,.79847],66:[0,.68333,.03041,.13889,.65681],67:[0,.68333,.05834,.13889,.52653],68:[0,.68333,.02778,.08334,.77139],69:[0,.68333,.08944,.11111,.52778],70:[0,.68333,.09931,.11111,.71875],71:[.09722,.68333,.0593,.11111,.59487],72:[0,.68333,.00965,.11111,.84452],73:[0,.68333,.07382,0,.54452],74:[.09722,.68333,.18472,.16667,.67778],75:[0,.68333,.01445,.05556,.76195],76:[0,.68333,0,.13889,.68972],77:[0,.68333,0,.13889,1.2009],78:[0,.68333,.14736,.08334,.82049],79:[0,.68333,.02778,.11111,.79611],80:[0,.68333,.08222,.08334,.69556],81:[.09722,.68333,0,.11111,.81667],82:[0,.68333,0,.08334,.8475],83:[0,.68333,.075,.13889,.60556],84:[0,.68333,.25417,0,.54464],85:[0,.68333,.09931,.08334,.62583],86:[0,.68333,.08222,0,.61278],87:[0,.68333,.08222,.08334,.98778],88:[0,.68333,.14643,.13889,.7133],89:[.09722,.68333,.08222,.08334,.66834],90:[0,.68333,.07944,.13889,.72473],160:[0,0,0,0,.25]},"Fraktur-Regular":{32:[0,0,0,0,.25],33:[0,.69141,0,0,.29574],34:[0,.69141,0,0,.21471],38:[0,.69141,0,0,.73786],39:[0,.69141,0,0,.21201],40:[.24982,.74947,0,0,.38865],41:[.24982,.74947,0,0,.38865],42:[0,.62119,0,0,.27764],43:[.08319,.58283,0,0,.75623],44:[0,.10803,0,0,.27764],45:[.08319,.58283,0,0,.75623],46:[0,.10803,0,0,.27764],47:[.24982,.74947,0,0,.50181],48:[0,.47534,0,0,.50181],49:[0,.47534,0,0,.50181],50:[0,.47534,0,0,.50181],51:[.18906,.47534,0,0,.50181],52:[.18906,.47534,0,0,.50181],53:[.18906,.47534,0,0,.50181],54:[0,.69141,0,0,.50181],55:[.18906,.47534,0,0,.50181],56:[0,.69141,0,0,.50181],57:[.18906,.47534,0,0,.50181],58:[0,.47534,0,0,.21606],59:[.12604,.47534,0,0,.21606],61:[-.13099,.36866,0,0,.75623],63:[0,.69141,0,0,.36245],65:[0,.69141,0,0,.7176],66:[0,.69141,0,0,.88397],67:[0,.69141,0,0,.61254],68:[0,.69141,0,0,.83158],69:[0,.69141,0,0,.66278],70:[.12604,.69141,0,0,.61119],71:[0,.69141,0,0,.78539],72:[.06302,.69141,0,0,.7203],73:[0,.69141,0,0,.55448],74:[.12604,.69141,0,0,.55231],75:[0,.69141,0,0,.66845],76:[0,.69141,0,0,.66602],77:[0,.69141,0,0,1.04953],78:[0,.69141,0,0,.83212],79:[0,.69141,0,0,.82699],80:[.18906,.69141,0,0,.82753],81:[.03781,.69141,0,0,.82699],82:[0,.69141,0,0,.82807],83:[0,.69141,0,0,.82861],84:[0,.69141,0,0,.66899],85:[0,.69141,0,0,.64576],86:[0,.69141,0,0,.83131],87:[0,.69141,0,0,1.04602],88:[0,.69141,0,0,.71922],89:[.18906,.69141,0,0,.83293],90:[.12604,.69141,0,0,.60201],91:[.24982,.74947,0,0,.27764],93:[.24982,.74947,0,0,.27764],94:[0,.69141,0,0,.49965],97:[0,.47534,0,0,.50046],98:[0,.69141,0,0,.51315],99:[0,.47534,0,0,.38946],100:[0,.62119,0,0,.49857],101:[0,.47534,0,0,.40053],102:[.18906,.69141,0,0,.32626],103:[.18906,.47534,0,0,.5037],104:[.18906,.69141,0,0,.52126],105:[0,.69141,0,0,.27899],106:[0,.69141,0,0,.28088],107:[0,.69141,0,0,.38946],108:[0,.69141,0,0,.27953],109:[0,.47534,0,0,.76676],110:[0,.47534,0,0,.52666],111:[0,.47534,0,0,.48885],112:[.18906,.52396,0,0,.50046],113:[.18906,.47534,0,0,.48912],114:[0,.47534,0,0,.38919],115:[0,.47534,0,0,.44266],116:[0,.62119,0,0,.33301],117:[0,.47534,0,0,.5172],118:[0,.52396,0,0,.5118],119:[0,.52396,0,0,.77351],120:[.18906,.47534,0,0,.38865],121:[.18906,.47534,0,0,.49884],122:[.18906,.47534,0,0,.39054],160:[0,0,0,0,.25],8216:[0,.69141,0,0,.21471],8217:[0,.69141,0,0,.21471],58112:[0,.62119,0,0,.49749],58113:[0,.62119,0,0,.4983],58114:[.18906,.69141,0,0,.33328],58115:[.18906,.69141,0,0,.32923],58116:[.18906,.47534,0,0,.50343],58117:[0,.69141,0,0,.33301],58118:[0,.62119,0,0,.33409],58119:[0,.47534,0,0,.50073]},"Main-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.35],34:[0,.69444,0,0,.60278],35:[.19444,.69444,0,0,.95833],36:[.05556,.75,0,0,.575],37:[.05556,.75,0,0,.95833],38:[0,.69444,0,0,.89444],39:[0,.69444,0,0,.31944],40:[.25,.75,0,0,.44722],41:[.25,.75,0,0,.44722],42:[0,.75,0,0,.575],43:[.13333,.63333,0,0,.89444],44:[.19444,.15556,0,0,.31944],45:[0,.44444,0,0,.38333],46:[0,.15556,0,0,.31944],47:[.25,.75,0,0,.575],48:[0,.64444,0,0,.575],49:[0,.64444,0,0,.575],50:[0,.64444,0,0,.575],51:[0,.64444,0,0,.575],52:[0,.64444,0,0,.575],53:[0,.64444,0,0,.575],54:[0,.64444,0,0,.575],55:[0,.64444,0,0,.575],56:[0,.64444,0,0,.575],57:[0,.64444,0,0,.575],58:[0,.44444,0,0,.31944],59:[.19444,.44444,0,0,.31944],60:[.08556,.58556,0,0,.89444],61:[-.10889,.39111,0,0,.89444],62:[.08556,.58556,0,0,.89444],63:[0,.69444,0,0,.54305],64:[0,.69444,0,0,.89444],65:[0,.68611,0,0,.86944],66:[0,.68611,0,0,.81805],67:[0,.68611,0,0,.83055],68:[0,.68611,0,0,.88194],69:[0,.68611,0,0,.75555],70:[0,.68611,0,0,.72361],71:[0,.68611,0,0,.90416],72:[0,.68611,0,0,.9],73:[0,.68611,0,0,.43611],74:[0,.68611,0,0,.59444],75:[0,.68611,0,0,.90138],76:[0,.68611,0,0,.69166],77:[0,.68611,0,0,1.09166],78:[0,.68611,0,0,.9],79:[0,.68611,0,0,.86388],80:[0,.68611,0,0,.78611],81:[.19444,.68611,0,0,.86388],82:[0,.68611,0,0,.8625],83:[0,.68611,0,0,.63889],84:[0,.68611,0,0,.8],85:[0,.68611,0,0,.88472],86:[0,.68611,.01597,0,.86944],87:[0,.68611,.01597,0,1.18888],88:[0,.68611,0,0,.86944],89:[0,.68611,.02875,0,.86944],90:[0,.68611,0,0,.70277],91:[.25,.75,0,0,.31944],92:[.25,.75,0,0,.575],93:[.25,.75,0,0,.31944],94:[0,.69444,0,0,.575],95:[.31,.13444,.03194,0,.575],97:[0,.44444,0,0,.55902],98:[0,.69444,0,0,.63889],99:[0,.44444,0,0,.51111],100:[0,.69444,0,0,.63889],101:[0,.44444,0,0,.52708],102:[0,.69444,.10903,0,.35139],103:[.19444,.44444,.01597,0,.575],104:[0,.69444,0,0,.63889],105:[0,.69444,0,0,.31944],106:[.19444,.69444,0,0,.35139],107:[0,.69444,0,0,.60694],108:[0,.69444,0,0,.31944],109:[0,.44444,0,0,.95833],110:[0,.44444,0,0,.63889],111:[0,.44444,0,0,.575],112:[.19444,.44444,0,0,.63889],113:[.19444,.44444,0,0,.60694],114:[0,.44444,0,0,.47361],115:[0,.44444,0,0,.45361],116:[0,.63492,0,0,.44722],117:[0,.44444,0,0,.63889],118:[0,.44444,.01597,0,.60694],119:[0,.44444,.01597,0,.83055],120:[0,.44444,0,0,.60694],121:[.19444,.44444,.01597,0,.60694],122:[0,.44444,0,0,.51111],123:[.25,.75,0,0,.575],124:[.25,.75,0,0,.31944],125:[.25,.75,0,0,.575],126:[.35,.34444,0,0,.575],160:[0,0,0,0,.25],163:[0,.69444,0,0,.86853],168:[0,.69444,0,0,.575],172:[0,.44444,0,0,.76666],176:[0,.69444,0,0,.86944],177:[.13333,.63333,0,0,.89444],184:[.17014,0,0,0,.51111],198:[0,.68611,0,0,1.04166],215:[.13333,.63333,0,0,.89444],216:[.04861,.73472,0,0,.89444],223:[0,.69444,0,0,.59722],230:[0,.44444,0,0,.83055],247:[.13333,.63333,0,0,.89444],248:[.09722,.54167,0,0,.575],305:[0,.44444,0,0,.31944],338:[0,.68611,0,0,1.16944],339:[0,.44444,0,0,.89444],567:[.19444,.44444,0,0,.35139],710:[0,.69444,0,0,.575],711:[0,.63194,0,0,.575],713:[0,.59611,0,0,.575],714:[0,.69444,0,0,.575],715:[0,.69444,0,0,.575],728:[0,.69444,0,0,.575],729:[0,.69444,0,0,.31944],730:[0,.69444,0,0,.86944],732:[0,.69444,0,0,.575],733:[0,.69444,0,0,.575],915:[0,.68611,0,0,.69166],916:[0,.68611,0,0,.95833],920:[0,.68611,0,0,.89444],923:[0,.68611,0,0,.80555],926:[0,.68611,0,0,.76666],928:[0,.68611,0,0,.9],931:[0,.68611,0,0,.83055],933:[0,.68611,0,0,.89444],934:[0,.68611,0,0,.83055],936:[0,.68611,0,0,.89444],937:[0,.68611,0,0,.83055],8211:[0,.44444,.03194,0,.575],8212:[0,.44444,.03194,0,1.14999],8216:[0,.69444,0,0,.31944],8217:[0,.69444,0,0,.31944],8220:[0,.69444,0,0,.60278],8221:[0,.69444,0,0,.60278],8224:[.19444,.69444,0,0,.51111],8225:[.19444,.69444,0,0,.51111],8242:[0,.55556,0,0,.34444],8407:[0,.72444,.15486,0,.575],8463:[0,.69444,0,0,.66759],8465:[0,.69444,0,0,.83055],8467:[0,.69444,0,0,.47361],8472:[.19444,.44444,0,0,.74027],8476:[0,.69444,0,0,.83055],8501:[0,.69444,0,0,.70277],8592:[-.10889,.39111,0,0,1.14999],8593:[.19444,.69444,0,0,.575],8594:[-.10889,.39111,0,0,1.14999],8595:[.19444,.69444,0,0,.575],8596:[-.10889,.39111,0,0,1.14999],8597:[.25,.75,0,0,.575],8598:[.19444,.69444,0,0,1.14999],8599:[.19444,.69444,0,0,1.14999],8600:[.19444,.69444,0,0,1.14999],8601:[.19444,.69444,0,0,1.14999],8636:[-.10889,.39111,0,0,1.14999],8637:[-.10889,.39111,0,0,1.14999],8640:[-.10889,.39111,0,0,1.14999],8641:[-.10889,.39111,0,0,1.14999],8656:[-.10889,.39111,0,0,1.14999],8657:[.19444,.69444,0,0,.70277],8658:[-.10889,.39111,0,0,1.14999],8659:[.19444,.69444,0,0,.70277],8660:[-.10889,.39111,0,0,1.14999],8661:[.25,.75,0,0,.70277],8704:[0,.69444,0,0,.63889],8706:[0,.69444,.06389,0,.62847],8707:[0,.69444,0,0,.63889],8709:[.05556,.75,0,0,.575],8711:[0,.68611,0,0,.95833],8712:[.08556,.58556,0,0,.76666],8715:[.08556,.58556,0,0,.76666],8722:[.13333,.63333,0,0,.89444],8723:[.13333,.63333,0,0,.89444],8725:[.25,.75,0,0,.575],8726:[.25,.75,0,0,.575],8727:[-.02778,.47222,0,0,.575],8728:[-.02639,.47361,0,0,.575],8729:[-.02639,.47361,0,0,.575],8730:[.18,.82,0,0,.95833],8733:[0,.44444,0,0,.89444],8734:[0,.44444,0,0,1.14999],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.31944],8741:[.25,.75,0,0,.575],8743:[0,.55556,0,0,.76666],8744:[0,.55556,0,0,.76666],8745:[0,.55556,0,0,.76666],8746:[0,.55556,0,0,.76666],8747:[.19444,.69444,.12778,0,.56875],8764:[-.10889,.39111,0,0,.89444],8768:[.19444,.69444,0,0,.31944],8771:[.00222,.50222,0,0,.89444],8773:[.027,.638,0,0,.894],8776:[.02444,.52444,0,0,.89444],8781:[.00222,.50222,0,0,.89444],8801:[.00222,.50222,0,0,.89444],8804:[.19667,.69667,0,0,.89444],8805:[.19667,.69667,0,0,.89444],8810:[.08556,.58556,0,0,1.14999],8811:[.08556,.58556,0,0,1.14999],8826:[.08556,.58556,0,0,.89444],8827:[.08556,.58556,0,0,.89444],8834:[.08556,.58556,0,0,.89444],8835:[.08556,.58556,0,0,.89444],8838:[.19667,.69667,0,0,.89444],8839:[.19667,.69667,0,0,.89444],8846:[0,.55556,0,0,.76666],8849:[.19667,.69667,0,0,.89444],8850:[.19667,.69667,0,0,.89444],8851:[0,.55556,0,0,.76666],8852:[0,.55556,0,0,.76666],8853:[.13333,.63333,0,0,.89444],8854:[.13333,.63333,0,0,.89444],8855:[.13333,.63333,0,0,.89444],8856:[.13333,.63333,0,0,.89444],8857:[.13333,.63333,0,0,.89444],8866:[0,.69444,0,0,.70277],8867:[0,.69444,0,0,.70277],8868:[0,.69444,0,0,.89444],8869:[0,.69444,0,0,.89444],8900:[-.02639,.47361,0,0,.575],8901:[-.02639,.47361,0,0,.31944],8902:[-.02778,.47222,0,0,.575],8968:[.25,.75,0,0,.51111],8969:[.25,.75,0,0,.51111],8970:[.25,.75,0,0,.51111],8971:[.25,.75,0,0,.51111],8994:[-.13889,.36111,0,0,1.14999],8995:[-.13889,.36111,0,0,1.14999],9651:[.19444,.69444,0,0,1.02222],9657:[-.02778,.47222,0,0,.575],9661:[.19444,.69444,0,0,1.02222],9667:[-.02778,.47222,0,0,.575],9711:[.19444,.69444,0,0,1.14999],9824:[.12963,.69444,0,0,.89444],9825:[.12963,.69444,0,0,.89444],9826:[.12963,.69444,0,0,.89444],9827:[.12963,.69444,0,0,.89444],9837:[0,.75,0,0,.44722],9838:[.19444,.69444,0,0,.44722],9839:[.19444,.69444,0,0,.44722],10216:[.25,.75,0,0,.44722],10217:[.25,.75,0,0,.44722],10815:[0,.68611,0,0,.9],10927:[.19667,.69667,0,0,.89444],10928:[.19667,.69667,0,0,.89444],57376:[.19444,.69444,0,0,0]},"Main-BoldItalic":{32:[0,0,0,0,.25],33:[0,.69444,.11417,0,.38611],34:[0,.69444,.07939,0,.62055],35:[.19444,.69444,.06833,0,.94444],37:[.05556,.75,.12861,0,.94444],38:[0,.69444,.08528,0,.88555],39:[0,.69444,.12945,0,.35555],40:[.25,.75,.15806,0,.47333],41:[.25,.75,.03306,0,.47333],42:[0,.75,.14333,0,.59111],43:[.10333,.60333,.03306,0,.88555],44:[.19444,.14722,0,0,.35555],45:[0,.44444,.02611,0,.41444],46:[0,.14722,0,0,.35555],47:[.25,.75,.15806,0,.59111],48:[0,.64444,.13167,0,.59111],49:[0,.64444,.13167,0,.59111],50:[0,.64444,.13167,0,.59111],51:[0,.64444,.13167,0,.59111],52:[.19444,.64444,.13167,0,.59111],53:[0,.64444,.13167,0,.59111],54:[0,.64444,.13167,0,.59111],55:[.19444,.64444,.13167,0,.59111],56:[0,.64444,.13167,0,.59111],57:[0,.64444,.13167,0,.59111],58:[0,.44444,.06695,0,.35555],59:[.19444,.44444,.06695,0,.35555],61:[-.10889,.39111,.06833,0,.88555],63:[0,.69444,.11472,0,.59111],64:[0,.69444,.09208,0,.88555],65:[0,.68611,0,0,.86555],66:[0,.68611,.0992,0,.81666],67:[0,.68611,.14208,0,.82666],68:[0,.68611,.09062,0,.87555],69:[0,.68611,.11431,0,.75666],70:[0,.68611,.12903,0,.72722],71:[0,.68611,.07347,0,.89527],72:[0,.68611,.17208,0,.8961],73:[0,.68611,.15681,0,.47166],74:[0,.68611,.145,0,.61055],75:[0,.68611,.14208,0,.89499],76:[0,.68611,0,0,.69777],77:[0,.68611,.17208,0,1.07277],78:[0,.68611,.17208,0,.8961],79:[0,.68611,.09062,0,.85499],80:[0,.68611,.0992,0,.78721],81:[.19444,.68611,.09062,0,.85499],82:[0,.68611,.02559,0,.85944],83:[0,.68611,.11264,0,.64999],84:[0,.68611,.12903,0,.7961],85:[0,.68611,.17208,0,.88083],86:[0,.68611,.18625,0,.86555],87:[0,.68611,.18625,0,1.15999],88:[0,.68611,.15681,0,.86555],89:[0,.68611,.19803,0,.86555],90:[0,.68611,.14208,0,.70888],91:[.25,.75,.1875,0,.35611],93:[.25,.75,.09972,0,.35611],94:[0,.69444,.06709,0,.59111],95:[.31,.13444,.09811,0,.59111],97:[0,.44444,.09426,0,.59111],98:[0,.69444,.07861,0,.53222],99:[0,.44444,.05222,0,.53222],100:[0,.69444,.10861,0,.59111],101:[0,.44444,.085,0,.53222],102:[.19444,.69444,.21778,0,.4],103:[.19444,.44444,.105,0,.53222],104:[0,.69444,.09426,0,.59111],105:[0,.69326,.11387,0,.35555],106:[.19444,.69326,.1672,0,.35555],107:[0,.69444,.11111,0,.53222],108:[0,.69444,.10861,0,.29666],109:[0,.44444,.09426,0,.94444],110:[0,.44444,.09426,0,.64999],111:[0,.44444,.07861,0,.59111],112:[.19444,.44444,.07861,0,.59111],113:[.19444,.44444,.105,0,.53222],114:[0,.44444,.11111,0,.50167],115:[0,.44444,.08167,0,.48694],116:[0,.63492,.09639,0,.385],117:[0,.44444,.09426,0,.62055],118:[0,.44444,.11111,0,.53222],119:[0,.44444,.11111,0,.76777],120:[0,.44444,.12583,0,.56055],121:[.19444,.44444,.105,0,.56166],122:[0,.44444,.13889,0,.49055],126:[.35,.34444,.11472,0,.59111],160:[0,0,0,0,.25],168:[0,.69444,.11473,0,.59111],176:[0,.69444,0,0,.94888],184:[.17014,0,0,0,.53222],198:[0,.68611,.11431,0,1.02277],216:[.04861,.73472,.09062,0,.88555],223:[.19444,.69444,.09736,0,.665],230:[0,.44444,.085,0,.82666],248:[.09722,.54167,.09458,0,.59111],305:[0,.44444,.09426,0,.35555],338:[0,.68611,.11431,0,1.14054],339:[0,.44444,.085,0,.82666],567:[.19444,.44444,.04611,0,.385],710:[0,.69444,.06709,0,.59111],711:[0,.63194,.08271,0,.59111],713:[0,.59444,.10444,0,.59111],714:[0,.69444,.08528,0,.59111],715:[0,.69444,0,0,.59111],728:[0,.69444,.10333,0,.59111],729:[0,.69444,.12945,0,.35555],730:[0,.69444,0,0,.94888],732:[0,.69444,.11472,0,.59111],733:[0,.69444,.11472,0,.59111],915:[0,.68611,.12903,0,.69777],916:[0,.68611,0,0,.94444],920:[0,.68611,.09062,0,.88555],923:[0,.68611,0,0,.80666],926:[0,.68611,.15092,0,.76777],928:[0,.68611,.17208,0,.8961],931:[0,.68611,.11431,0,.82666],933:[0,.68611,.10778,0,.88555],934:[0,.68611,.05632,0,.82666],936:[0,.68611,.10778,0,.88555],937:[0,.68611,.0992,0,.82666],8211:[0,.44444,.09811,0,.59111],8212:[0,.44444,.09811,0,1.18221],8216:[0,.69444,.12945,0,.35555],8217:[0,.69444,.12945,0,.35555],8220:[0,.69444,.16772,0,.62055],8221:[0,.69444,.07939,0,.62055]},"Main-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.12417,0,.30667],34:[0,.69444,.06961,0,.51444],35:[.19444,.69444,.06616,0,.81777],37:[.05556,.75,.13639,0,.81777],38:[0,.69444,.09694,0,.76666],39:[0,.69444,.12417,0,.30667],40:[.25,.75,.16194,0,.40889],41:[.25,.75,.03694,0,.40889],42:[0,.75,.14917,0,.51111],43:[.05667,.56167,.03694,0,.76666],44:[.19444,.10556,0,0,.30667],45:[0,.43056,.02826,0,.35778],46:[0,.10556,0,0,.30667],47:[.25,.75,.16194,0,.51111],48:[0,.64444,.13556,0,.51111],49:[0,.64444,.13556,0,.51111],50:[0,.64444,.13556,0,.51111],51:[0,.64444,.13556,0,.51111],52:[.19444,.64444,.13556,0,.51111],53:[0,.64444,.13556,0,.51111],54:[0,.64444,.13556,0,.51111],55:[.19444,.64444,.13556,0,.51111],56:[0,.64444,.13556,0,.51111],57:[0,.64444,.13556,0,.51111],58:[0,.43056,.0582,0,.30667],59:[.19444,.43056,.0582,0,.30667],61:[-.13313,.36687,.06616,0,.76666],63:[0,.69444,.1225,0,.51111],64:[0,.69444,.09597,0,.76666],65:[0,.68333,0,0,.74333],66:[0,.68333,.10257,0,.70389],67:[0,.68333,.14528,0,.71555],68:[0,.68333,.09403,0,.755],69:[0,.68333,.12028,0,.67833],70:[0,.68333,.13305,0,.65277],71:[0,.68333,.08722,0,.77361],72:[0,.68333,.16389,0,.74333],73:[0,.68333,.15806,0,.38555],74:[0,.68333,.14028,0,.525],75:[0,.68333,.14528,0,.76888],76:[0,.68333,0,0,.62722],77:[0,.68333,.16389,0,.89666],78:[0,.68333,.16389,0,.74333],79:[0,.68333,.09403,0,.76666],80:[0,.68333,.10257,0,.67833],81:[.19444,.68333,.09403,0,.76666],82:[0,.68333,.03868,0,.72944],83:[0,.68333,.11972,0,.56222],84:[0,.68333,.13305,0,.71555],85:[0,.68333,.16389,0,.74333],86:[0,.68333,.18361,0,.74333],87:[0,.68333,.18361,0,.99888],88:[0,.68333,.15806,0,.74333],89:[0,.68333,.19383,0,.74333],90:[0,.68333,.14528,0,.61333],91:[.25,.75,.1875,0,.30667],93:[.25,.75,.10528,0,.30667],94:[0,.69444,.06646,0,.51111],95:[.31,.12056,.09208,0,.51111],97:[0,.43056,.07671,0,.51111],98:[0,.69444,.06312,0,.46],99:[0,.43056,.05653,0,.46],100:[0,.69444,.10333,0,.51111],101:[0,.43056,.07514,0,.46],102:[.19444,.69444,.21194,0,.30667],103:[.19444,.43056,.08847,0,.46],104:[0,.69444,.07671,0,.51111],105:[0,.65536,.1019,0,.30667],106:[.19444,.65536,.14467,0,.30667],107:[0,.69444,.10764,0,.46],108:[0,.69444,.10333,0,.25555],109:[0,.43056,.07671,0,.81777],110:[0,.43056,.07671,0,.56222],111:[0,.43056,.06312,0,.51111],112:[.19444,.43056,.06312,0,.51111],113:[.19444,.43056,.08847,0,.46],114:[0,.43056,.10764,0,.42166],115:[0,.43056,.08208,0,.40889],116:[0,.61508,.09486,0,.33222],117:[0,.43056,.07671,0,.53666],118:[0,.43056,.10764,0,.46],119:[0,.43056,.10764,0,.66444],120:[0,.43056,.12042,0,.46389],121:[.19444,.43056,.08847,0,.48555],122:[0,.43056,.12292,0,.40889],126:[.35,.31786,.11585,0,.51111],160:[0,0,0,0,.25],168:[0,.66786,.10474,0,.51111],176:[0,.69444,0,0,.83129],184:[.17014,0,0,0,.46],198:[0,.68333,.12028,0,.88277],216:[.04861,.73194,.09403,0,.76666],223:[.19444,.69444,.10514,0,.53666],230:[0,.43056,.07514,0,.71555],248:[.09722,.52778,.09194,0,.51111],338:[0,.68333,.12028,0,.98499],339:[0,.43056,.07514,0,.71555],710:[0,.69444,.06646,0,.51111],711:[0,.62847,.08295,0,.51111],713:[0,.56167,.10333,0,.51111],714:[0,.69444,.09694,0,.51111],715:[0,.69444,0,0,.51111],728:[0,.69444,.10806,0,.51111],729:[0,.66786,.11752,0,.30667],730:[0,.69444,0,0,.83129],732:[0,.66786,.11585,0,.51111],733:[0,.69444,.1225,0,.51111],915:[0,.68333,.13305,0,.62722],916:[0,.68333,0,0,.81777],920:[0,.68333,.09403,0,.76666],923:[0,.68333,0,0,.69222],926:[0,.68333,.15294,0,.66444],928:[0,.68333,.16389,0,.74333],931:[0,.68333,.12028,0,.71555],933:[0,.68333,.11111,0,.76666],934:[0,.68333,.05986,0,.71555],936:[0,.68333,.11111,0,.76666],937:[0,.68333,.10257,0,.71555],8211:[0,.43056,.09208,0,.51111],8212:[0,.43056,.09208,0,1.02222],8216:[0,.69444,.12417,0,.30667],8217:[0,.69444,.12417,0,.30667],8220:[0,.69444,.1685,0,.51444],8221:[0,.69444,.06961,0,.51444],8463:[0,.68889,0,0,.54028]},"Main-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.27778],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.77778],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.19444,.10556,0,0,.27778],45:[0,.43056,0,0,.33333],46:[0,.10556,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.64444,0,0,.5],49:[0,.64444,0,0,.5],50:[0,.64444,0,0,.5],51:[0,.64444,0,0,.5],52:[0,.64444,0,0,.5],53:[0,.64444,0,0,.5],54:[0,.64444,0,0,.5],55:[0,.64444,0,0,.5],56:[0,.64444,0,0,.5],57:[0,.64444,0,0,.5],58:[0,.43056,0,0,.27778],59:[.19444,.43056,0,0,.27778],60:[.0391,.5391,0,0,.77778],61:[-.13313,.36687,0,0,.77778],62:[.0391,.5391,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.77778],65:[0,.68333,0,0,.75],66:[0,.68333,0,0,.70834],67:[0,.68333,0,0,.72222],68:[0,.68333,0,0,.76389],69:[0,.68333,0,0,.68056],70:[0,.68333,0,0,.65278],71:[0,.68333,0,0,.78472],72:[0,.68333,0,0,.75],73:[0,.68333,0,0,.36111],74:[0,.68333,0,0,.51389],75:[0,.68333,0,0,.77778],76:[0,.68333,0,0,.625],77:[0,.68333,0,0,.91667],78:[0,.68333,0,0,.75],79:[0,.68333,0,0,.77778],80:[0,.68333,0,0,.68056],81:[.19444,.68333,0,0,.77778],82:[0,.68333,0,0,.73611],83:[0,.68333,0,0,.55556],84:[0,.68333,0,0,.72222],85:[0,.68333,0,0,.75],86:[0,.68333,.01389,0,.75],87:[0,.68333,.01389,0,1.02778],88:[0,.68333,0,0,.75],89:[0,.68333,.025,0,.75],90:[0,.68333,0,0,.61111],91:[.25,.75,0,0,.27778],92:[.25,.75,0,0,.5],93:[.25,.75,0,0,.27778],94:[0,.69444,0,0,.5],95:[.31,.12056,.02778,0,.5],97:[0,.43056,0,0,.5],98:[0,.69444,0,0,.55556],99:[0,.43056,0,0,.44445],100:[0,.69444,0,0,.55556],101:[0,.43056,0,0,.44445],102:[0,.69444,.07778,0,.30556],103:[.19444,.43056,.01389,0,.5],104:[0,.69444,0,0,.55556],105:[0,.66786,0,0,.27778],106:[.19444,.66786,0,0,.30556],107:[0,.69444,0,0,.52778],108:[0,.69444,0,0,.27778],109:[0,.43056,0,0,.83334],110:[0,.43056,0,0,.55556],111:[0,.43056,0,0,.5],112:[.19444,.43056,0,0,.55556],113:[.19444,.43056,0,0,.52778],114:[0,.43056,0,0,.39167],115:[0,.43056,0,0,.39445],116:[0,.61508,0,0,.38889],117:[0,.43056,0,0,.55556],118:[0,.43056,.01389,0,.52778],119:[0,.43056,.01389,0,.72222],120:[0,.43056,0,0,.52778],121:[.19444,.43056,.01389,0,.52778],122:[0,.43056,0,0,.44445],123:[.25,.75,0,0,.5],124:[.25,.75,0,0,.27778],125:[.25,.75,0,0,.5],126:[.35,.31786,0,0,.5],160:[0,0,0,0,.25],163:[0,.69444,0,0,.76909],167:[.19444,.69444,0,0,.44445],168:[0,.66786,0,0,.5],172:[0,.43056,0,0,.66667],176:[0,.69444,0,0,.75],177:[.08333,.58333,0,0,.77778],182:[.19444,.69444,0,0,.61111],184:[.17014,0,0,0,.44445],198:[0,.68333,0,0,.90278],215:[.08333,.58333,0,0,.77778],216:[.04861,.73194,0,0,.77778],223:[0,.69444,0,0,.5],230:[0,.43056,0,0,.72222],247:[.08333,.58333,0,0,.77778],248:[.09722,.52778,0,0,.5],305:[0,.43056,0,0,.27778],338:[0,.68333,0,0,1.01389],339:[0,.43056,0,0,.77778],567:[.19444,.43056,0,0,.30556],710:[0,.69444,0,0,.5],711:[0,.62847,0,0,.5],713:[0,.56778,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.66786,0,0,.27778],730:[0,.69444,0,0,.75],732:[0,.66786,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.68333,0,0,.625],916:[0,.68333,0,0,.83334],920:[0,.68333,0,0,.77778],923:[0,.68333,0,0,.69445],926:[0,.68333,0,0,.66667],928:[0,.68333,0,0,.75],931:[0,.68333,0,0,.72222],933:[0,.68333,0,0,.77778],934:[0,.68333,0,0,.72222],936:[0,.68333,0,0,.77778],937:[0,.68333,0,0,.72222],8211:[0,.43056,.02778,0,.5],8212:[0,.43056,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5],8224:[.19444,.69444,0,0,.44445],8225:[.19444,.69444,0,0,.44445],8230:[0,.123,0,0,1.172],8242:[0,.55556,0,0,.275],8407:[0,.71444,.15382,0,.5],8463:[0,.68889,0,0,.54028],8465:[0,.69444,0,0,.72222],8467:[0,.69444,0,.11111,.41667],8472:[.19444,.43056,0,.11111,.63646],8476:[0,.69444,0,0,.72222],8501:[0,.69444,0,0,.61111],8592:[-.13313,.36687,0,0,1],8593:[.19444,.69444,0,0,.5],8594:[-.13313,.36687,0,0,1],8595:[.19444,.69444,0,0,.5],8596:[-.13313,.36687,0,0,1],8597:[.25,.75,0,0,.5],8598:[.19444,.69444,0,0,1],8599:[.19444,.69444,0,0,1],8600:[.19444,.69444,0,0,1],8601:[.19444,.69444,0,0,1],8614:[.011,.511,0,0,1],8617:[.011,.511,0,0,1.126],8618:[.011,.511,0,0,1.126],8636:[-.13313,.36687,0,0,1],8637:[-.13313,.36687,0,0,1],8640:[-.13313,.36687,0,0,1],8641:[-.13313,.36687,0,0,1],8652:[.011,.671,0,0,1],8656:[-.13313,.36687,0,0,1],8657:[.19444,.69444,0,0,.61111],8658:[-.13313,.36687,0,0,1],8659:[.19444,.69444,0,0,.61111],8660:[-.13313,.36687,0,0,1],8661:[.25,.75,0,0,.61111],8704:[0,.69444,0,0,.55556],8706:[0,.69444,.05556,.08334,.5309],8707:[0,.69444,0,0,.55556],8709:[.05556,.75,0,0,.5],8711:[0,.68333,0,0,.83334],8712:[.0391,.5391,0,0,.66667],8715:[.0391,.5391,0,0,.66667],8722:[.08333,.58333,0,0,.77778],8723:[.08333,.58333,0,0,.77778],8725:[.25,.75,0,0,.5],8726:[.25,.75,0,0,.5],8727:[-.03472,.46528,0,0,.5],8728:[-.05555,.44445,0,0,.5],8729:[-.05555,.44445,0,0,.5],8730:[.2,.8,0,0,.83334],8733:[0,.43056,0,0,.77778],8734:[0,.43056,0,0,1],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.27778],8741:[.25,.75,0,0,.5],8743:[0,.55556,0,0,.66667],8744:[0,.55556,0,0,.66667],8745:[0,.55556,0,0,.66667],8746:[0,.55556,0,0,.66667],8747:[.19444,.69444,.11111,0,.41667],8764:[-.13313,.36687,0,0,.77778],8768:[.19444,.69444,0,0,.27778],8771:[-.03625,.46375,0,0,.77778],8773:[-.022,.589,0,0,.778],8776:[-.01688,.48312,0,0,.77778],8781:[-.03625,.46375,0,0,.77778],8784:[-.133,.673,0,0,.778],8801:[-.03625,.46375,0,0,.77778],8804:[.13597,.63597,0,0,.77778],8805:[.13597,.63597,0,0,.77778],8810:[.0391,.5391,0,0,1],8811:[.0391,.5391,0,0,1],8826:[.0391,.5391,0,0,.77778],8827:[.0391,.5391,0,0,.77778],8834:[.0391,.5391,0,0,.77778],8835:[.0391,.5391,0,0,.77778],8838:[.13597,.63597,0,0,.77778],8839:[.13597,.63597,0,0,.77778],8846:[0,.55556,0,0,.66667],8849:[.13597,.63597,0,0,.77778],8850:[.13597,.63597,0,0,.77778],8851:[0,.55556,0,0,.66667],8852:[0,.55556,0,0,.66667],8853:[.08333,.58333,0,0,.77778],8854:[.08333,.58333,0,0,.77778],8855:[.08333,.58333,0,0,.77778],8856:[.08333,.58333,0,0,.77778],8857:[.08333,.58333,0,0,.77778],8866:[0,.69444,0,0,.61111],8867:[0,.69444,0,0,.61111],8868:[0,.69444,0,0,.77778],8869:[0,.69444,0,0,.77778],8872:[.249,.75,0,0,.867],8900:[-.05555,.44445,0,0,.5],8901:[-.05555,.44445,0,0,.27778],8902:[-.03472,.46528,0,0,.5],8904:[.005,.505,0,0,.9],8942:[.03,.903,0,0,.278],8943:[-.19,.313,0,0,1.172],8945:[-.1,.823,0,0,1.282],8968:[.25,.75,0,0,.44445],8969:[.25,.75,0,0,.44445],8970:[.25,.75,0,0,.44445],8971:[.25,.75,0,0,.44445],8994:[-.14236,.35764,0,0,1],8995:[-.14236,.35764,0,0,1],9136:[.244,.744,0,0,.412],9137:[.244,.745,0,0,.412],9651:[.19444,.69444,0,0,.88889],9657:[-.03472,.46528,0,0,.5],9661:[.19444,.69444,0,0,.88889],9667:[-.03472,.46528,0,0,.5],9711:[.19444,.69444,0,0,1],9824:[.12963,.69444,0,0,.77778],9825:[.12963,.69444,0,0,.77778],9826:[.12963,.69444,0,0,.77778],9827:[.12963,.69444,0,0,.77778],9837:[0,.75,0,0,.38889],9838:[.19444,.69444,0,0,.38889],9839:[.19444,.69444,0,0,.38889],10216:[.25,.75,0,0,.38889],10217:[.25,.75,0,0,.38889],10222:[.244,.744,0,0,.412],10223:[.244,.745,0,0,.412],10229:[.011,.511,0,0,1.609],10230:[.011,.511,0,0,1.638],10231:[.011,.511,0,0,1.859],10232:[.024,.525,0,0,1.609],10233:[.024,.525,0,0,1.638],10234:[.024,.525,0,0,1.858],10236:[.011,.511,0,0,1.638],10815:[0,.68333,0,0,.75],10927:[.13597,.63597,0,0,.77778],10928:[.13597,.63597,0,0,.77778],57376:[.19444,.69444,0,0,0]},"Math-BoldItalic":{32:[0,0,0,0,.25],48:[0,.44444,0,0,.575],49:[0,.44444,0,0,.575],50:[0,.44444,0,0,.575],51:[.19444,.44444,0,0,.575],52:[.19444,.44444,0,0,.575],53:[.19444,.44444,0,0,.575],54:[0,.64444,0,0,.575],55:[.19444,.44444,0,0,.575],56:[0,.64444,0,0,.575],57:[.19444,.44444,0,0,.575],65:[0,.68611,0,0,.86944],66:[0,.68611,.04835,0,.8664],67:[0,.68611,.06979,0,.81694],68:[0,.68611,.03194,0,.93812],69:[0,.68611,.05451,0,.81007],70:[0,.68611,.15972,0,.68889],71:[0,.68611,0,0,.88673],72:[0,.68611,.08229,0,.98229],73:[0,.68611,.07778,0,.51111],74:[0,.68611,.10069,0,.63125],75:[0,.68611,.06979,0,.97118],76:[0,.68611,0,0,.75555],77:[0,.68611,.11424,0,1.14201],78:[0,.68611,.11424,0,.95034],79:[0,.68611,.03194,0,.83666],80:[0,.68611,.15972,0,.72309],81:[.19444,.68611,0,0,.86861],82:[0,.68611,.00421,0,.87235],83:[0,.68611,.05382,0,.69271],84:[0,.68611,.15972,0,.63663],85:[0,.68611,.11424,0,.80027],86:[0,.68611,.25555,0,.67778],87:[0,.68611,.15972,0,1.09305],88:[0,.68611,.07778,0,.94722],89:[0,.68611,.25555,0,.67458],90:[0,.68611,.06979,0,.77257],97:[0,.44444,0,0,.63287],98:[0,.69444,0,0,.52083],99:[0,.44444,0,0,.51342],100:[0,.69444,0,0,.60972],101:[0,.44444,0,0,.55361],102:[.19444,.69444,.11042,0,.56806],103:[.19444,.44444,.03704,0,.5449],104:[0,.69444,0,0,.66759],105:[0,.69326,0,0,.4048],106:[.19444,.69326,.0622,0,.47083],107:[0,.69444,.01852,0,.6037],108:[0,.69444,.0088,0,.34815],109:[0,.44444,0,0,1.0324],110:[0,.44444,0,0,.71296],111:[0,.44444,0,0,.58472],112:[.19444,.44444,0,0,.60092],113:[.19444,.44444,.03704,0,.54213],114:[0,.44444,.03194,0,.5287],115:[0,.44444,0,0,.53125],116:[0,.63492,0,0,.41528],117:[0,.44444,0,0,.68102],118:[0,.44444,.03704,0,.56666],119:[0,.44444,.02778,0,.83148],120:[0,.44444,0,0,.65903],121:[.19444,.44444,.03704,0,.59028],122:[0,.44444,.04213,0,.55509],160:[0,0,0,0,.25],915:[0,.68611,.15972,0,.65694],916:[0,.68611,0,0,.95833],920:[0,.68611,.03194,0,.86722],923:[0,.68611,0,0,.80555],926:[0,.68611,.07458,0,.84125],928:[0,.68611,.08229,0,.98229],931:[0,.68611,.05451,0,.88507],933:[0,.68611,.15972,0,.67083],934:[0,.68611,0,0,.76666],936:[0,.68611,.11653,0,.71402],937:[0,.68611,.04835,0,.8789],945:[0,.44444,0,0,.76064],946:[.19444,.69444,.03403,0,.65972],947:[.19444,.44444,.06389,0,.59003],948:[0,.69444,.03819,0,.52222],949:[0,.44444,0,0,.52882],950:[.19444,.69444,.06215,0,.50833],951:[.19444,.44444,.03704,0,.6],952:[0,.69444,.03194,0,.5618],953:[0,.44444,0,0,.41204],954:[0,.44444,0,0,.66759],955:[0,.69444,0,0,.67083],956:[.19444,.44444,0,0,.70787],957:[0,.44444,.06898,0,.57685],958:[.19444,.69444,.03021,0,.50833],959:[0,.44444,0,0,.58472],960:[0,.44444,.03704,0,.68241],961:[.19444,.44444,0,0,.6118],962:[.09722,.44444,.07917,0,.42361],963:[0,.44444,.03704,0,.68588],964:[0,.44444,.13472,0,.52083],965:[0,.44444,.03704,0,.63055],966:[.19444,.44444,0,0,.74722],967:[.19444,.44444,0,0,.71805],968:[.19444,.69444,.03704,0,.75833],969:[0,.44444,.03704,0,.71782],977:[0,.69444,0,0,.69155],981:[.19444,.69444,0,0,.7125],982:[0,.44444,.03194,0,.975],1009:[.19444,.44444,0,0,.6118],1013:[0,.44444,0,0,.48333],57649:[0,.44444,0,0,.39352],57911:[.19444,.44444,0,0,.43889]},"Math-Italic":{32:[0,0,0,0,.25],48:[0,.43056,0,0,.5],49:[0,.43056,0,0,.5],50:[0,.43056,0,0,.5],51:[.19444,.43056,0,0,.5],52:[.19444,.43056,0,0,.5],53:[.19444,.43056,0,0,.5],54:[0,.64444,0,0,.5],55:[.19444,.43056,0,0,.5],56:[0,.64444,0,0,.5],57:[.19444,.43056,0,0,.5],65:[0,.68333,0,.13889,.75],66:[0,.68333,.05017,.08334,.75851],67:[0,.68333,.07153,.08334,.71472],68:[0,.68333,.02778,.05556,.82792],69:[0,.68333,.05764,.08334,.7382],70:[0,.68333,.13889,.08334,.64306],71:[0,.68333,0,.08334,.78625],72:[0,.68333,.08125,.05556,.83125],73:[0,.68333,.07847,.11111,.43958],74:[0,.68333,.09618,.16667,.55451],75:[0,.68333,.07153,.05556,.84931],76:[0,.68333,0,.02778,.68056],77:[0,.68333,.10903,.08334,.97014],78:[0,.68333,.10903,.08334,.80347],79:[0,.68333,.02778,.08334,.76278],80:[0,.68333,.13889,.08334,.64201],81:[.19444,.68333,0,.08334,.79056],82:[0,.68333,.00773,.08334,.75929],83:[0,.68333,.05764,.08334,.6132],84:[0,.68333,.13889,.08334,.58438],85:[0,.68333,.10903,.02778,.68278],86:[0,.68333,.22222,0,.58333],87:[0,.68333,.13889,0,.94445],88:[0,.68333,.07847,.08334,.82847],89:[0,.68333,.22222,0,.58056],90:[0,.68333,.07153,.08334,.68264],97:[0,.43056,0,0,.52859],98:[0,.69444,0,0,.42917],99:[0,.43056,0,.05556,.43276],100:[0,.69444,0,.16667,.52049],101:[0,.43056,0,.05556,.46563],102:[.19444,.69444,.10764,.16667,.48959],103:[.19444,.43056,.03588,.02778,.47697],104:[0,.69444,0,0,.57616],105:[0,.65952,0,0,.34451],106:[.19444,.65952,.05724,0,.41181],107:[0,.69444,.03148,0,.5206],108:[0,.69444,.01968,.08334,.29838],109:[0,.43056,0,0,.87801],110:[0,.43056,0,0,.60023],111:[0,.43056,0,.05556,.48472],112:[.19444,.43056,0,.08334,.50313],113:[.19444,.43056,.03588,.08334,.44641],114:[0,.43056,.02778,.05556,.45116],115:[0,.43056,0,.05556,.46875],116:[0,.61508,0,.08334,.36111],117:[0,.43056,0,.02778,.57246],118:[0,.43056,.03588,.02778,.48472],119:[0,.43056,.02691,.08334,.71592],120:[0,.43056,0,.02778,.57153],121:[.19444,.43056,.03588,.05556,.49028],122:[0,.43056,.04398,.05556,.46505],160:[0,0,0,0,.25],915:[0,.68333,.13889,.08334,.61528],916:[0,.68333,0,.16667,.83334],920:[0,.68333,.02778,.08334,.76278],923:[0,.68333,0,.16667,.69445],926:[0,.68333,.07569,.08334,.74236],928:[0,.68333,.08125,.05556,.83125],931:[0,.68333,.05764,.08334,.77986],933:[0,.68333,.13889,.05556,.58333],934:[0,.68333,0,.08334,.66667],936:[0,.68333,.11,.05556,.61222],937:[0,.68333,.05017,.08334,.7724],945:[0,.43056,.0037,.02778,.6397],946:[.19444,.69444,.05278,.08334,.56563],947:[.19444,.43056,.05556,0,.51773],948:[0,.69444,.03785,.05556,.44444],949:[0,.43056,0,.08334,.46632],950:[.19444,.69444,.07378,.08334,.4375],951:[.19444,.43056,.03588,.05556,.49653],952:[0,.69444,.02778,.08334,.46944],953:[0,.43056,0,.05556,.35394],954:[0,.43056,0,0,.57616],955:[0,.69444,0,0,.58334],956:[.19444,.43056,0,.02778,.60255],957:[0,.43056,.06366,.02778,.49398],958:[.19444,.69444,.04601,.11111,.4375],959:[0,.43056,0,.05556,.48472],960:[0,.43056,.03588,0,.57003],961:[.19444,.43056,0,.08334,.51702],962:[.09722,.43056,.07986,.08334,.36285],963:[0,.43056,.03588,0,.57141],964:[0,.43056,.1132,.02778,.43715],965:[0,.43056,.03588,.02778,.54028],966:[.19444,.43056,0,.08334,.65417],967:[.19444,.43056,0,.05556,.62569],968:[.19444,.69444,.03588,.11111,.65139],969:[0,.43056,.03588,0,.62245],977:[0,.69444,0,.08334,.59144],981:[.19444,.69444,0,.08334,.59583],982:[0,.43056,.02778,0,.82813],1009:[.19444,.43056,0,.08334,.51702],1013:[0,.43056,0,.05556,.4059],57649:[0,.43056,0,.02778,.32246],57911:[.19444,.43056,0,.08334,.38403]},"SansSerif-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.36667],34:[0,.69444,0,0,.55834],35:[.19444,.69444,0,0,.91667],36:[.05556,.75,0,0,.55],37:[.05556,.75,0,0,1.02912],38:[0,.69444,0,0,.83056],39:[0,.69444,0,0,.30556],40:[.25,.75,0,0,.42778],41:[.25,.75,0,0,.42778],42:[0,.75,0,0,.55],43:[.11667,.61667,0,0,.85556],44:[.10556,.13056,0,0,.30556],45:[0,.45833,0,0,.36667],46:[0,.13056,0,0,.30556],47:[.25,.75,0,0,.55],48:[0,.69444,0,0,.55],49:[0,.69444,0,0,.55],50:[0,.69444,0,0,.55],51:[0,.69444,0,0,.55],52:[0,.69444,0,0,.55],53:[0,.69444,0,0,.55],54:[0,.69444,0,0,.55],55:[0,.69444,0,0,.55],56:[0,.69444,0,0,.55],57:[0,.69444,0,0,.55],58:[0,.45833,0,0,.30556],59:[.10556,.45833,0,0,.30556],61:[-.09375,.40625,0,0,.85556],63:[0,.69444,0,0,.51945],64:[0,.69444,0,0,.73334],65:[0,.69444,0,0,.73334],66:[0,.69444,0,0,.73334],67:[0,.69444,0,0,.70278],68:[0,.69444,0,0,.79445],69:[0,.69444,0,0,.64167],70:[0,.69444,0,0,.61111],71:[0,.69444,0,0,.73334],72:[0,.69444,0,0,.79445],73:[0,.69444,0,0,.33056],74:[0,.69444,0,0,.51945],75:[0,.69444,0,0,.76389],76:[0,.69444,0,0,.58056],77:[0,.69444,0,0,.97778],78:[0,.69444,0,0,.79445],79:[0,.69444,0,0,.79445],80:[0,.69444,0,0,.70278],81:[.10556,.69444,0,0,.79445],82:[0,.69444,0,0,.70278],83:[0,.69444,0,0,.61111],84:[0,.69444,0,0,.73334],85:[0,.69444,0,0,.76389],86:[0,.69444,.01528,0,.73334],87:[0,.69444,.01528,0,1.03889],88:[0,.69444,0,0,.73334],89:[0,.69444,.0275,0,.73334],90:[0,.69444,0,0,.67223],91:[.25,.75,0,0,.34306],93:[.25,.75,0,0,.34306],94:[0,.69444,0,0,.55],95:[.35,.10833,.03056,0,.55],97:[0,.45833,0,0,.525],98:[0,.69444,0,0,.56111],99:[0,.45833,0,0,.48889],100:[0,.69444,0,0,.56111],101:[0,.45833,0,0,.51111],102:[0,.69444,.07639,0,.33611],103:[.19444,.45833,.01528,0,.55],104:[0,.69444,0,0,.56111],105:[0,.69444,0,0,.25556],106:[.19444,.69444,0,0,.28611],107:[0,.69444,0,0,.53056],108:[0,.69444,0,0,.25556],109:[0,.45833,0,0,.86667],110:[0,.45833,0,0,.56111],111:[0,.45833,0,0,.55],112:[.19444,.45833,0,0,.56111],113:[.19444,.45833,0,0,.56111],114:[0,.45833,.01528,0,.37222],115:[0,.45833,0,0,.42167],116:[0,.58929,0,0,.40417],117:[0,.45833,0,0,.56111],118:[0,.45833,.01528,0,.5],119:[0,.45833,.01528,0,.74445],120:[0,.45833,0,0,.5],121:[.19444,.45833,.01528,0,.5],122:[0,.45833,0,0,.47639],126:[.35,.34444,0,0,.55],160:[0,0,0,0,.25],168:[0,.69444,0,0,.55],176:[0,.69444,0,0,.73334],180:[0,.69444,0,0,.55],184:[.17014,0,0,0,.48889],305:[0,.45833,0,0,.25556],567:[.19444,.45833,0,0,.28611],710:[0,.69444,0,0,.55],711:[0,.63542,0,0,.55],713:[0,.63778,0,0,.55],728:[0,.69444,0,0,.55],729:[0,.69444,0,0,.30556],730:[0,.69444,0,0,.73334],732:[0,.69444,0,0,.55],733:[0,.69444,0,0,.55],915:[0,.69444,0,0,.58056],916:[0,.69444,0,0,.91667],920:[0,.69444,0,0,.85556],923:[0,.69444,0,0,.67223],926:[0,.69444,0,0,.73334],928:[0,.69444,0,0,.79445],931:[0,.69444,0,0,.79445],933:[0,.69444,0,0,.85556],934:[0,.69444,0,0,.79445],936:[0,.69444,0,0,.85556],937:[0,.69444,0,0,.79445],8211:[0,.45833,.03056,0,.55],8212:[0,.45833,.03056,0,1.10001],8216:[0,.69444,0,0,.30556],8217:[0,.69444,0,0,.30556],8220:[0,.69444,0,0,.55834],8221:[0,.69444,0,0,.55834]},"SansSerif-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.05733,0,.31945],34:[0,.69444,.00316,0,.5],35:[.19444,.69444,.05087,0,.83334],36:[.05556,.75,.11156,0,.5],37:[.05556,.75,.03126,0,.83334],38:[0,.69444,.03058,0,.75834],39:[0,.69444,.07816,0,.27778],40:[.25,.75,.13164,0,.38889],41:[.25,.75,.02536,0,.38889],42:[0,.75,.11775,0,.5],43:[.08333,.58333,.02536,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,.01946,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,.13164,0,.5],48:[0,.65556,.11156,0,.5],49:[0,.65556,.11156,0,.5],50:[0,.65556,.11156,0,.5],51:[0,.65556,.11156,0,.5],52:[0,.65556,.11156,0,.5],53:[0,.65556,.11156,0,.5],54:[0,.65556,.11156,0,.5],55:[0,.65556,.11156,0,.5],56:[0,.65556,.11156,0,.5],57:[0,.65556,.11156,0,.5],58:[0,.44444,.02502,0,.27778],59:[.125,.44444,.02502,0,.27778],61:[-.13,.37,.05087,0,.77778],63:[0,.69444,.11809,0,.47222],64:[0,.69444,.07555,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,.08293,0,.66667],67:[0,.69444,.11983,0,.63889],68:[0,.69444,.07555,0,.72223],69:[0,.69444,.11983,0,.59722],70:[0,.69444,.13372,0,.56945],71:[0,.69444,.11983,0,.66667],72:[0,.69444,.08094,0,.70834],73:[0,.69444,.13372,0,.27778],74:[0,.69444,.08094,0,.47222],75:[0,.69444,.11983,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,.08094,0,.875],78:[0,.69444,.08094,0,.70834],79:[0,.69444,.07555,0,.73611],80:[0,.69444,.08293,0,.63889],81:[.125,.69444,.07555,0,.73611],82:[0,.69444,.08293,0,.64584],83:[0,.69444,.09205,0,.55556],84:[0,.69444,.13372,0,.68056],85:[0,.69444,.08094,0,.6875],86:[0,.69444,.1615,0,.66667],87:[0,.69444,.1615,0,.94445],88:[0,.69444,.13372,0,.66667],89:[0,.69444,.17261,0,.66667],90:[0,.69444,.11983,0,.61111],91:[.25,.75,.15942,0,.28889],93:[.25,.75,.08719,0,.28889],94:[0,.69444,.0799,0,.5],95:[.35,.09444,.08616,0,.5],97:[0,.44444,.00981,0,.48056],98:[0,.69444,.03057,0,.51667],99:[0,.44444,.08336,0,.44445],100:[0,.69444,.09483,0,.51667],101:[0,.44444,.06778,0,.44445],102:[0,.69444,.21705,0,.30556],103:[.19444,.44444,.10836,0,.5],104:[0,.69444,.01778,0,.51667],105:[0,.67937,.09718,0,.23889],106:[.19444,.67937,.09162,0,.26667],107:[0,.69444,.08336,0,.48889],108:[0,.69444,.09483,0,.23889],109:[0,.44444,.01778,0,.79445],110:[0,.44444,.01778,0,.51667],111:[0,.44444,.06613,0,.5],112:[.19444,.44444,.0389,0,.51667],113:[.19444,.44444,.04169,0,.51667],114:[0,.44444,.10836,0,.34167],115:[0,.44444,.0778,0,.38333],116:[0,.57143,.07225,0,.36111],117:[0,.44444,.04169,0,.51667],118:[0,.44444,.10836,0,.46111],119:[0,.44444,.10836,0,.68334],120:[0,.44444,.09169,0,.46111],121:[.19444,.44444,.10836,0,.46111],122:[0,.44444,.08752,0,.43472],126:[.35,.32659,.08826,0,.5],160:[0,0,0,0,.25],168:[0,.67937,.06385,0,.5],176:[0,.69444,0,0,.73752],184:[.17014,0,0,0,.44445],305:[0,.44444,.04169,0,.23889],567:[.19444,.44444,.04169,0,.26667],710:[0,.69444,.0799,0,.5],711:[0,.63194,.08432,0,.5],713:[0,.60889,.08776,0,.5],714:[0,.69444,.09205,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,.09483,0,.5],729:[0,.67937,.07774,0,.27778],730:[0,.69444,0,0,.73752],732:[0,.67659,.08826,0,.5],733:[0,.69444,.09205,0,.5],915:[0,.69444,.13372,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,.07555,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,.12816,0,.66667],928:[0,.69444,.08094,0,.70834],931:[0,.69444,.11983,0,.72222],933:[0,.69444,.09031,0,.77778],934:[0,.69444,.04603,0,.72222],936:[0,.69444,.09031,0,.77778],937:[0,.69444,.08293,0,.72222],8211:[0,.44444,.08616,0,.5],8212:[0,.44444,.08616,0,1],8216:[0,.69444,.07816,0,.27778],8217:[0,.69444,.07816,0,.27778],8220:[0,.69444,.14205,0,.5],8221:[0,.69444,.00316,0,.5]},"SansSerif-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.31945],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.75834],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,0,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.65556,0,0,.5],49:[0,.65556,0,0,.5],50:[0,.65556,0,0,.5],51:[0,.65556,0,0,.5],52:[0,.65556,0,0,.5],53:[0,.65556,0,0,.5],54:[0,.65556,0,0,.5],55:[0,.65556,0,0,.5],56:[0,.65556,0,0,.5],57:[0,.65556,0,0,.5],58:[0,.44444,0,0,.27778],59:[.125,.44444,0,0,.27778],61:[-.13,.37,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,0,0,.66667],67:[0,.69444,0,0,.63889],68:[0,.69444,0,0,.72223],69:[0,.69444,0,0,.59722],70:[0,.69444,0,0,.56945],71:[0,.69444,0,0,.66667],72:[0,.69444,0,0,.70834],73:[0,.69444,0,0,.27778],74:[0,.69444,0,0,.47222],75:[0,.69444,0,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,0,0,.875],78:[0,.69444,0,0,.70834],79:[0,.69444,0,0,.73611],80:[0,.69444,0,0,.63889],81:[.125,.69444,0,0,.73611],82:[0,.69444,0,0,.64584],83:[0,.69444,0,0,.55556],84:[0,.69444,0,0,.68056],85:[0,.69444,0,0,.6875],86:[0,.69444,.01389,0,.66667],87:[0,.69444,.01389,0,.94445],88:[0,.69444,0,0,.66667],89:[0,.69444,.025,0,.66667],90:[0,.69444,0,0,.61111],91:[.25,.75,0,0,.28889],93:[.25,.75,0,0,.28889],94:[0,.69444,0,0,.5],95:[.35,.09444,.02778,0,.5],97:[0,.44444,0,0,.48056],98:[0,.69444,0,0,.51667],99:[0,.44444,0,0,.44445],100:[0,.69444,0,0,.51667],101:[0,.44444,0,0,.44445],102:[0,.69444,.06944,0,.30556],103:[.19444,.44444,.01389,0,.5],104:[0,.69444,0,0,.51667],105:[0,.67937,0,0,.23889],106:[.19444,.67937,0,0,.26667],107:[0,.69444,0,0,.48889],108:[0,.69444,0,0,.23889],109:[0,.44444,0,0,.79445],110:[0,.44444,0,0,.51667],111:[0,.44444,0,0,.5],112:[.19444,.44444,0,0,.51667],113:[.19444,.44444,0,0,.51667],114:[0,.44444,.01389,0,.34167],115:[0,.44444,0,0,.38333],116:[0,.57143,0,0,.36111],117:[0,.44444,0,0,.51667],118:[0,.44444,.01389,0,.46111],119:[0,.44444,.01389,0,.68334],120:[0,.44444,0,0,.46111],121:[.19444,.44444,.01389,0,.46111],122:[0,.44444,0,0,.43472],126:[.35,.32659,0,0,.5],160:[0,0,0,0,.25],168:[0,.67937,0,0,.5],176:[0,.69444,0,0,.66667],184:[.17014,0,0,0,.44445],305:[0,.44444,0,0,.23889],567:[.19444,.44444,0,0,.26667],710:[0,.69444,0,0,.5],711:[0,.63194,0,0,.5],713:[0,.60889,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.67937,0,0,.27778],730:[0,.69444,0,0,.66667],732:[0,.67659,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.69444,0,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,0,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,0,0,.66667],928:[0,.69444,0,0,.70834],931:[0,.69444,0,0,.72222],933:[0,.69444,0,0,.77778],934:[0,.69444,0,0,.72222],936:[0,.69444,0,0,.77778],937:[0,.69444,0,0,.72222],8211:[0,.44444,.02778,0,.5],8212:[0,.44444,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5]},"Script-Regular":{32:[0,0,0,0,.25],65:[0,.7,.22925,0,.80253],66:[0,.7,.04087,0,.90757],67:[0,.7,.1689,0,.66619],68:[0,.7,.09371,0,.77443],69:[0,.7,.18583,0,.56162],70:[0,.7,.13634,0,.89544],71:[0,.7,.17322,0,.60961],72:[0,.7,.29694,0,.96919],73:[0,.7,.19189,0,.80907],74:[.27778,.7,.19189,0,1.05159],75:[0,.7,.31259,0,.91364],76:[0,.7,.19189,0,.87373],77:[0,.7,.15981,0,1.08031],78:[0,.7,.3525,0,.9015],79:[0,.7,.08078,0,.73787],80:[0,.7,.08078,0,1.01262],81:[0,.7,.03305,0,.88282],82:[0,.7,.06259,0,.85],83:[0,.7,.19189,0,.86767],84:[0,.7,.29087,0,.74697],85:[0,.7,.25815,0,.79996],86:[0,.7,.27523,0,.62204],87:[0,.7,.27523,0,.80532],88:[0,.7,.26006,0,.94445],89:[0,.7,.2939,0,.70961],90:[0,.7,.24037,0,.8212],160:[0,0,0,0,.25]},"Size1-Regular":{32:[0,0,0,0,.25],40:[.35001,.85,0,0,.45834],41:[.35001,.85,0,0,.45834],47:[.35001,.85,0,0,.57778],91:[.35001,.85,0,0,.41667],92:[.35001,.85,0,0,.57778],93:[.35001,.85,0,0,.41667],123:[.35001,.85,0,0,.58334],125:[.35001,.85,0,0,.58334],160:[0,0,0,0,.25],710:[0,.72222,0,0,.55556],732:[0,.72222,0,0,.55556],770:[0,.72222,0,0,.55556],771:[0,.72222,0,0,.55556],8214:[-99e-5,.601,0,0,.77778],8593:[1e-5,.6,0,0,.66667],8595:[1e-5,.6,0,0,.66667],8657:[1e-5,.6,0,0,.77778],8659:[1e-5,.6,0,0,.77778],8719:[.25001,.75,0,0,.94445],8720:[.25001,.75,0,0,.94445],8721:[.25001,.75,0,0,1.05556],8730:[.35001,.85,0,0,1],8739:[-.00599,.606,0,0,.33333],8741:[-.00599,.606,0,0,.55556],8747:[.30612,.805,.19445,0,.47222],8748:[.306,.805,.19445,0,.47222],8749:[.306,.805,.19445,0,.47222],8750:[.30612,.805,.19445,0,.47222],8896:[.25001,.75,0,0,.83334],8897:[.25001,.75,0,0,.83334],8898:[.25001,.75,0,0,.83334],8899:[.25001,.75,0,0,.83334],8968:[.35001,.85,0,0,.47222],8969:[.35001,.85,0,0,.47222],8970:[.35001,.85,0,0,.47222],8971:[.35001,.85,0,0,.47222],9168:[-99e-5,.601,0,0,.66667],10216:[.35001,.85,0,0,.47222],10217:[.35001,.85,0,0,.47222],10752:[.25001,.75,0,0,1.11111],10753:[.25001,.75,0,0,1.11111],10754:[.25001,.75,0,0,1.11111],10756:[.25001,.75,0,0,.83334],10758:[.25001,.75,0,0,.83334]},"Size2-Regular":{32:[0,0,0,0,.25],40:[.65002,1.15,0,0,.59722],41:[.65002,1.15,0,0,.59722],47:[.65002,1.15,0,0,.81111],91:[.65002,1.15,0,0,.47222],92:[.65002,1.15,0,0,.81111],93:[.65002,1.15,0,0,.47222],123:[.65002,1.15,0,0,.66667],125:[.65002,1.15,0,0,.66667],160:[0,0,0,0,.25],710:[0,.75,0,0,1],732:[0,.75,0,0,1],770:[0,.75,0,0,1],771:[0,.75,0,0,1],8719:[.55001,1.05,0,0,1.27778],8720:[.55001,1.05,0,0,1.27778],8721:[.55001,1.05,0,0,1.44445],8730:[.65002,1.15,0,0,1],8747:[.86225,1.36,.44445,0,.55556],8748:[.862,1.36,.44445,0,.55556],8749:[.862,1.36,.44445,0,.55556],8750:[.86225,1.36,.44445,0,.55556],8896:[.55001,1.05,0,0,1.11111],8897:[.55001,1.05,0,0,1.11111],8898:[.55001,1.05,0,0,1.11111],8899:[.55001,1.05,0,0,1.11111],8968:[.65002,1.15,0,0,.52778],8969:[.65002,1.15,0,0,.52778],8970:[.65002,1.15,0,0,.52778],8971:[.65002,1.15,0,0,.52778],10216:[.65002,1.15,0,0,.61111],10217:[.65002,1.15,0,0,.61111],10752:[.55001,1.05,0,0,1.51112],10753:[.55001,1.05,0,0,1.51112],10754:[.55001,1.05,0,0,1.51112],10756:[.55001,1.05,0,0,1.11111],10758:[.55001,1.05,0,0,1.11111]},"Size3-Regular":{32:[0,0,0,0,.25],40:[.95003,1.45,0,0,.73611],41:[.95003,1.45,0,0,.73611],47:[.95003,1.45,0,0,1.04445],91:[.95003,1.45,0,0,.52778],92:[.95003,1.45,0,0,1.04445],93:[.95003,1.45,0,0,.52778],123:[.95003,1.45,0,0,.75],125:[.95003,1.45,0,0,.75],160:[0,0,0,0,.25],710:[0,.75,0,0,1.44445],732:[0,.75,0,0,1.44445],770:[0,.75,0,0,1.44445],771:[0,.75,0,0,1.44445],8730:[.95003,1.45,0,0,1],8968:[.95003,1.45,0,0,.58334],8969:[.95003,1.45,0,0,.58334],8970:[.95003,1.45,0,0,.58334],8971:[.95003,1.45,0,0,.58334],10216:[.95003,1.45,0,0,.75],10217:[.95003,1.45,0,0,.75]},"Size4-Regular":{32:[0,0,0,0,.25],40:[1.25003,1.75,0,0,.79167],41:[1.25003,1.75,0,0,.79167],47:[1.25003,1.75,0,0,1.27778],91:[1.25003,1.75,0,0,.58334],92:[1.25003,1.75,0,0,1.27778],93:[1.25003,1.75,0,0,.58334],123:[1.25003,1.75,0,0,.80556],125:[1.25003,1.75,0,0,.80556],160:[0,0,0,0,.25],710:[0,.825,0,0,1.8889],732:[0,.825,0,0,1.8889],770:[0,.825,0,0,1.8889],771:[0,.825,0,0,1.8889],8730:[1.25003,1.75,0,0,1],8968:[1.25003,1.75,0,0,.63889],8969:[1.25003,1.75,0,0,.63889],8970:[1.25003,1.75,0,0,.63889],8971:[1.25003,1.75,0,0,.63889],9115:[.64502,1.155,0,0,.875],9116:[1e-5,.6,0,0,.875],9117:[.64502,1.155,0,0,.875],9118:[.64502,1.155,0,0,.875],9119:[1e-5,.6,0,0,.875],9120:[.64502,1.155,0,0,.875],9121:[.64502,1.155,0,0,.66667],9122:[-99e-5,.601,0,0,.66667],9123:[.64502,1.155,0,0,.66667],9124:[.64502,1.155,0,0,.66667],9125:[-99e-5,.601,0,0,.66667],9126:[.64502,1.155,0,0,.66667],9127:[1e-5,.9,0,0,.88889],9128:[.65002,1.15,0,0,.88889],9129:[.90001,0,0,0,.88889],9130:[0,.3,0,0,.88889],9131:[1e-5,.9,0,0,.88889],9132:[.65002,1.15,0,0,.88889],9133:[.90001,0,0,0,.88889],9143:[.88502,.915,0,0,1.05556],10216:[1.25003,1.75,0,0,.80556],10217:[1.25003,1.75,0,0,.80556],57344:[-.00499,.605,0,0,1.05556],57345:[-.00499,.605,0,0,1.05556],57680:[0,.12,0,0,.45],57681:[0,.12,0,0,.45],57682:[0,.12,0,0,.45],57683:[0,.12,0,0,.45]},"Typewriter-Regular":{32:[0,0,0,0,.525],33:[0,.61111,0,0,.525],34:[0,.61111,0,0,.525],35:[0,.61111,0,0,.525],36:[.08333,.69444,0,0,.525],37:[.08333,.69444,0,0,.525],38:[0,.61111,0,0,.525],39:[0,.61111,0,0,.525],40:[.08333,.69444,0,0,.525],41:[.08333,.69444,0,0,.525],42:[0,.52083,0,0,.525],43:[-.08056,.53055,0,0,.525],44:[.13889,.125,0,0,.525],45:[-.08056,.53055,0,0,.525],46:[0,.125,0,0,.525],47:[.08333,.69444,0,0,.525],48:[0,.61111,0,0,.525],49:[0,.61111,0,0,.525],50:[0,.61111,0,0,.525],51:[0,.61111,0,0,.525],52:[0,.61111,0,0,.525],53:[0,.61111,0,0,.525],54:[0,.61111,0,0,.525],55:[0,.61111,0,0,.525],56:[0,.61111,0,0,.525],57:[0,.61111,0,0,.525],58:[0,.43056,0,0,.525],59:[.13889,.43056,0,0,.525],60:[-.05556,.55556,0,0,.525],61:[-.19549,.41562,0,0,.525],62:[-.05556,.55556,0,0,.525],63:[0,.61111,0,0,.525],64:[0,.61111,0,0,.525],65:[0,.61111,0,0,.525],66:[0,.61111,0,0,.525],67:[0,.61111,0,0,.525],68:[0,.61111,0,0,.525],69:[0,.61111,0,0,.525],70:[0,.61111,0,0,.525],71:[0,.61111,0,0,.525],72:[0,.61111,0,0,.525],73:[0,.61111,0,0,.525],74:[0,.61111,0,0,.525],75:[0,.61111,0,0,.525],76:[0,.61111,0,0,.525],77:[0,.61111,0,0,.525],78:[0,.61111,0,0,.525],79:[0,.61111,0,0,.525],80:[0,.61111,0,0,.525],81:[.13889,.61111,0,0,.525],82:[0,.61111,0,0,.525],83:[0,.61111,0,0,.525],84:[0,.61111,0,0,.525],85:[0,.61111,0,0,.525],86:[0,.61111,0,0,.525],87:[0,.61111,0,0,.525],88:[0,.61111,0,0,.525],89:[0,.61111,0,0,.525],90:[0,.61111,0,0,.525],91:[.08333,.69444,0,0,.525],92:[.08333,.69444,0,0,.525],93:[.08333,.69444,0,0,.525],94:[0,.61111,0,0,.525],95:[.09514,0,0,0,.525],96:[0,.61111,0,0,.525],97:[0,.43056,0,0,.525],98:[0,.61111,0,0,.525],99:[0,.43056,0,0,.525],100:[0,.61111,0,0,.525],101:[0,.43056,0,0,.525],102:[0,.61111,0,0,.525],103:[.22222,.43056,0,0,.525],104:[0,.61111,0,0,.525],105:[0,.61111,0,0,.525],106:[.22222,.61111,0,0,.525],107:[0,.61111,0,0,.525],108:[0,.61111,0,0,.525],109:[0,.43056,0,0,.525],110:[0,.43056,0,0,.525],111:[0,.43056,0,0,.525],112:[.22222,.43056,0,0,.525],113:[.22222,.43056,0,0,.525],114:[0,.43056,0,0,.525],115:[0,.43056,0,0,.525],116:[0,.55358,0,0,.525],117:[0,.43056,0,0,.525],118:[0,.43056,0,0,.525],119:[0,.43056,0,0,.525],120:[0,.43056,0,0,.525],121:[.22222,.43056,0,0,.525],122:[0,.43056,0,0,.525],123:[.08333,.69444,0,0,.525],124:[.08333,.69444,0,0,.525],125:[.08333,.69444,0,0,.525],126:[0,.61111,0,0,.525],127:[0,.61111,0,0,.525],160:[0,0,0,0,.525],176:[0,.61111,0,0,.525],184:[.19445,0,0,0,.525],305:[0,.43056,0,0,.525],567:[.22222,.43056,0,0,.525],711:[0,.56597,0,0,.525],713:[0,.56555,0,0,.525],714:[0,.61111,0,0,.525],715:[0,.61111,0,0,.525],728:[0,.61111,0,0,.525],730:[0,.61111,0,0,.525],770:[0,.61111,0,0,.525],771:[0,.61111,0,0,.525],776:[0,.61111,0,0,.525],915:[0,.61111,0,0,.525],916:[0,.61111,0,0,.525],920:[0,.61111,0,0,.525],923:[0,.61111,0,0,.525],926:[0,.61111,0,0,.525],928:[0,.61111,0,0,.525],931:[0,.61111,0,0,.525],933:[0,.61111,0,0,.525],934:[0,.61111,0,0,.525],936:[0,.61111,0,0,.525],937:[0,.61111,0,0,.525],8216:[0,.61111,0,0,.525],8217:[0,.61111,0,0,.525],8242:[0,.61111,0,0,.525],9251:[.11111,.21944,0,0,.525]}},we={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25],defaultRuleThickness:[.04,.049,.049],bigOpSpacing1:[.111,.111,.111],bigOpSpacing2:[.166,.166,.166],bigOpSpacing3:[.2,.2,.2],bigOpSpacing4:[.6,.611,.611],bigOpSpacing5:[.1,.143,.143],sqrtRuleThickness:[.04,.04,.04],ptPerEm:[10,10,10],doubleRuleSep:[.2,.2,.2],arrayRuleWidth:[.04,.04,.04],fboxsep:[.3,.3,.3],fboxrule:[.04,.04,.04]},ir={Å:"A",Ð:"D",Þ:"o",å:"a",ð:"d",þ:"o",А:"A",Б:"B",В:"B",Г:"F",Д:"A",Е:"E",Ж:"K",З:"3",И:"N",Й:"N",К:"K",Л:"N",М:"M",Н:"H",О:"O",П:"N",Р:"P",С:"C",Т:"T",У:"y",Ф:"O",Х:"X",Ц:"U",Ч:"h",Ш:"W",Щ:"W",Ъ:"B",Ы:"X",Ь:"B",Э:"3",Ю:"X",Я:"R",а:"a",б:"b",в:"a",г:"r",д:"y",е:"e",ж:"m",з:"e",и:"n",й:"n",к:"n",л:"n",м:"m",н:"n",о:"o",п:"n",р:"p",с:"c",т:"o",у:"y",ф:"b",х:"x",ц:"n",ч:"n",ш:"w",щ:"w",ъ:"a",ы:"m",ь:"a",э:"e",ю:"m",я:"r"};function Aa(r,e){k0[r]=e}function Nt(r,e,t){if(!k0[e])throw new Error("Font metrics not found for font: "+e+".");var a=r.charCodeAt(0),i=k0[e][a];if(!i&&r[0]in ir&&(a=ir[r[0]].charCodeAt(0),i=k0[e][a]),!i&&t==="text"&&Gr(a)&&(i=k0[e][77]),i)return{depth:i[0],height:i[1],italic:i[2],skew:i[3],width:i[4]}}var Je={};function Ma(r){var e;if(r>=5?e=0:r>=3?e=1:e=2,!Je[e]){var t=Je[e]={cssEmPerMu:we.quad[e]/18};for(var a in we)we.hasOwnProperty(a)&&(t[a]=we[a][e])}return Je[e]}var W={math:{},text:{}};function n(r,e,t,a,i,s){W[r][i]={font:e,group:t,replace:a},s&&a&&(W[r][a]=W[r][i])}var l="math",w="text",o="main",d="ams",j="accent-token",D="bin",u0="close",ne="inner",E="mathord",t0="op-token",f0="open",de="punct",f="rel",q0="spacing",g="textord";n(l,o,f,"≡","\\equiv",!0);n(l,o,f,"≺","\\prec",!0);n(l,o,f,"≻","\\succ",!0);n(l,o,f,"∼","\\sim",!0);n(l,o,f,"⊥","\\perp");n(l,o,f,"⪯","\\preceq",!0);n(l,o,f,"⪰","\\succeq",!0);n(l,o,f,"≃","\\simeq",!0);n(l,o,f,"∣","\\mid",!0);n(l,o,f,"≪","\\ll",!0);n(l,o,f,"≫","\\gg",!0);n(l,o,f,"≍","\\asymp",!0);n(l,o,f,"∥","\\parallel");n(l,o,f,"⋈","\\bowtie",!0);n(l,o,f,"⌣","\\smile",!0);n(l,o,f,"⊑","\\sqsubseteq",!0);n(l,o,f,"⊒","\\sqsupseteq",!0);n(l,o,f,"≐","\\doteq",!0);n(l,o,f,"⌢","\\frown",!0);n(l,o,f,"∋","\\ni",!0);n(l,o,f,"∝","\\propto",!0);n(l,o,f,"⊢","\\vdash",!0);n(l,o,f,"⊣","\\dashv",!0);n(l,o,f,"∋","\\owns");n(l,o,de,".","\\ldotp");n(l,o,de,"⋅","\\cdotp");n(l,o,de,"⋅","·");n(w,o,g,"⋅","·");n(l,o,g,"#","\\#");n(w,o,g,"#","\\#");n(l,o,g,"&","\\&");n(w,o,g,"&","\\&");n(l,o,g,"ℵ","\\aleph",!0);n(l,o,g,"∀","\\forall",!0);n(l,o,g,"ℏ","\\hbar",!0);n(l,o,g,"∃","\\exists",!0);n(l,o,g,"∇","\\nabla",!0);n(l,o,g,"♭","\\flat",!0);n(l,o,g,"ℓ","\\ell",!0);n(l,o,g,"♮","\\natural",!0);n(l,o,g,"♣","\\clubsuit",!0);n(l,o,g,"℘","\\wp",!0);n(l,o,g,"♯","\\sharp",!0);n(l,o,g,"♢","\\diamondsuit",!0);n(l,o,g,"ℜ","\\Re",!0);n(l,o,g,"♡","\\heartsuit",!0);n(l,o,g,"ℑ","\\Im",!0);n(l,o,g,"♠","\\spadesuit",!0);n(l,o,g,"§","\\S",!0);n(w,o,g,"§","\\S");n(l,o,g,"¶","\\P",!0);n(w,o,g,"¶","\\P");n(l,o,g,"†","\\dag");n(w,o,g,"†","\\dag");n(w,o,g,"†","\\textdagger");n(l,o,g,"‡","\\ddag");n(w,o,g,"‡","\\ddag");n(w,o,g,"‡","\\textdaggerdbl");n(l,o,u0,"⎱","\\rmoustache",!0);n(l,o,f0,"⎰","\\lmoustache",!0);n(l,o,u0,"⟯","\\rgroup",!0);n(l,o,f0,"⟮","\\lgroup",!0);n(l,o,D,"∓","\\mp",!0);n(l,o,D,"⊖","\\ominus",!0);n(l,o,D,"⊎","\\uplus",!0);n(l,o,D,"⊓","\\sqcap",!0);n(l,o,D,"∗","\\ast");n(l,o,D,"⊔","\\sqcup",!0);n(l,o,D,"◯","\\bigcirc",!0);n(l,o,D,"∙","\\bullet",!0);n(l,o,D,"‡","\\ddagger");n(l,o,D,"≀","\\wr",!0);n(l,o,D,"⨿","\\amalg");n(l,o,D,"&","\\And");n(l,o,f,"⟵","\\longleftarrow",!0);n(l,o,f,"⇐","\\Leftarrow",!0);n(l,o,f,"⟸","\\Longleftarrow",!0);n(l,o,f,"⟶","\\longrightarrow",!0);n(l,o,f,"⇒","\\Rightarrow",!0);n(l,o,f,"⟹","\\Longrightarrow",!0);n(l,o,f,"↔","\\leftrightarrow",!0);n(l,o,f,"⟷","\\longleftrightarrow",!0);n(l,o,f,"⇔","\\Leftrightarrow",!0);n(l,o,f,"⟺","\\Longleftrightarrow",!0);n(l,o,f,"↦","\\mapsto",!0);n(l,o,f,"⟼","\\longmapsto",!0);n(l,o,f,"↗","\\nearrow",!0);n(l,o,f,"↩","\\hookleftarrow",!0);n(l,o,f,"↪","\\hookrightarrow",!0);n(l,o,f,"↘","\\searrow",!0);n(l,o,f,"↼","\\leftharpoonup",!0);n(l,o,f,"⇀","\\rightharpoonup",!0);n(l,o,f,"↙","\\swarrow",!0);n(l,o,f,"↽","\\leftharpoondown",!0);n(l,o,f,"⇁","\\rightharpoondown",!0);n(l,o,f,"↖","\\nwarrow",!0);n(l,o,f,"⇌","\\rightleftharpoons",!0);n(l,d,f,"≮","\\nless",!0);n(l,d,f,"","\\@nleqslant");n(l,d,f,"","\\@nleqq");n(l,d,f,"⪇","\\lneq",!0);n(l,d,f,"≨","\\lneqq",!0);n(l,d,f,"","\\@lvertneqq");n(l,d,f,"⋦","\\lnsim",!0);n(l,d,f,"⪉","\\lnapprox",!0);n(l,d,f,"⊀","\\nprec",!0);n(l,d,f,"⋠","\\npreceq",!0);n(l,d,f,"⋨","\\precnsim",!0);n(l,d,f,"⪹","\\precnapprox",!0);n(l,d,f,"≁","\\nsim",!0);n(l,d,f,"","\\@nshortmid");n(l,d,f,"∤","\\nmid",!0);n(l,d,f,"⊬","\\nvdash",!0);n(l,d,f,"⊭","\\nvDash",!0);n(l,d,f,"⋪","\\ntriangleleft");n(l,d,f,"⋬","\\ntrianglelefteq",!0);n(l,d,f,"⊊","\\subsetneq",!0);n(l,d,f,"","\\@varsubsetneq");n(l,d,f,"⫋","\\subsetneqq",!0);n(l,d,f,"","\\@varsubsetneqq");n(l,d,f,"≯","\\ngtr",!0);n(l,d,f,"","\\@ngeqslant");n(l,d,f,"","\\@ngeqq");n(l,d,f,"⪈","\\gneq",!0);n(l,d,f,"≩","\\gneqq",!0);n(l,d,f,"","\\@gvertneqq");n(l,d,f,"⋧","\\gnsim",!0);n(l,d,f,"⪊","\\gnapprox",!0);n(l,d,f,"⊁","\\nsucc",!0);n(l,d,f,"⋡","\\nsucceq",!0);n(l,d,f,"⋩","\\succnsim",!0);n(l,d,f,"⪺","\\succnapprox",!0);n(l,d,f,"≆","\\ncong",!0);n(l,d,f,"","\\@nshortparallel");n(l,d,f,"∦","\\nparallel",!0);n(l,d,f,"⊯","\\nVDash",!0);n(l,d,f,"⋫","\\ntriangleright");n(l,d,f,"⋭","\\ntrianglerighteq",!0);n(l,d,f,"","\\@nsupseteqq");n(l,d,f,"⊋","\\supsetneq",!0);n(l,d,f,"","\\@varsupsetneq");n(l,d,f,"⫌","\\supsetneqq",!0);n(l,d,f,"","\\@varsupsetneqq");n(l,d,f,"⊮","\\nVdash",!0);n(l,d,f,"⪵","\\precneqq",!0);n(l,d,f,"⪶","\\succneqq",!0);n(l,d,f,"","\\@nsubseteqq");n(l,d,D,"⊴","\\unlhd");n(l,d,D,"⊵","\\unrhd");n(l,d,f,"↚","\\nleftarrow",!0);n(l,d,f,"↛","\\nrightarrow",!0);n(l,d,f,"⇍","\\nLeftarrow",!0);n(l,d,f,"⇏","\\nRightarrow",!0);n(l,d,f,"↮","\\nleftrightarrow",!0);n(l,d,f,"⇎","\\nLeftrightarrow",!0);n(l,d,f,"△","\\vartriangle");n(l,d,g,"ℏ","\\hslash");n(l,d,g,"▽","\\triangledown");n(l,d,g,"◊","\\lozenge");n(l,d,g,"Ⓢ","\\circledS");n(l,d,g,"®","\\circledR");n(w,d,g,"®","\\circledR");n(l,d,g,"∡","\\measuredangle",!0);n(l,d,g,"∄","\\nexists");n(l,d,g,"℧","\\mho");n(l,d,g,"Ⅎ","\\Finv",!0);n(l,d,g,"⅁","\\Game",!0);n(l,d,g,"‵","\\backprime");n(l,d,g,"▲","\\blacktriangle");n(l,d,g,"▼","\\blacktriangledown");n(l,d,g,"■","\\blacksquare");n(l,d,g,"⧫","\\blacklozenge");n(l,d,g,"★","\\bigstar");n(l,d,g,"∢","\\sphericalangle",!0);n(l,d,g,"∁","\\complement",!0);n(l,d,g,"ð","\\eth",!0);n(w,o,g,"ð","ð");n(l,d,g,"╱","\\diagup");n(l,d,g,"╲","\\diagdown");n(l,d,g,"□","\\square");n(l,d,g,"□","\\Box");n(l,d,g,"◊","\\Diamond");n(l,d,g,"¥","\\yen",!0);n(w,d,g,"¥","\\yen",!0);n(l,d,g,"✓","\\checkmark",!0);n(w,d,g,"✓","\\checkmark");n(l,d,g,"ℶ","\\beth",!0);n(l,d,g,"ℸ","\\daleth",!0);n(l,d,g,"ℷ","\\gimel",!0);n(l,d,g,"ϝ","\\digamma",!0);n(l,d,g,"ϰ","\\varkappa");n(l,d,f0,"┌","\\@ulcorner",!0);n(l,d,u0,"┐","\\@urcorner",!0);n(l,d,f0,"└","\\@llcorner",!0);n(l,d,u0,"┘","\\@lrcorner",!0);n(l,d,f,"≦","\\leqq",!0);n(l,d,f,"⩽","\\leqslant",!0);n(l,d,f,"⪕","\\eqslantless",!0);n(l,d,f,"≲","\\lesssim",!0);n(l,d,f,"⪅","\\lessapprox",!0);n(l,d,f,"≊","\\approxeq",!0);n(l,d,D,"⋖","\\lessdot");n(l,d,f,"⋘","\\lll",!0);n(l,d,f,"≶","\\lessgtr",!0);n(l,d,f,"⋚","\\lesseqgtr",!0);n(l,d,f,"⪋","\\lesseqqgtr",!0);n(l,d,f,"≑","\\doteqdot");n(l,d,f,"≓","\\risingdotseq",!0);n(l,d,f,"≒","\\fallingdotseq",!0);n(l,d,f,"∽","\\backsim",!0);n(l,d,f,"⋍","\\backsimeq",!0);n(l,d,f,"⫅","\\subseteqq",!0);n(l,d,f,"⋐","\\Subset",!0);n(l,d,f,"⊏","\\sqsubset",!0);n(l,d,f,"≼","\\preccurlyeq",!0);n(l,d,f,"⋞","\\curlyeqprec",!0);n(l,d,f,"≾","\\precsim",!0);n(l,d,f,"⪷","\\precapprox",!0);n(l,d,f,"⊲","\\vartriangleleft");n(l,d,f,"⊴","\\trianglelefteq");n(l,d,f,"⊨","\\vDash",!0);n(l,d,f,"⊪","\\Vvdash",!0);n(l,d,f,"⌣","\\smallsmile");n(l,d,f,"⌢","\\smallfrown");n(l,d,f,"≏","\\bumpeq",!0);n(l,d,f,"≎","\\Bumpeq",!0);n(l,d,f,"≧","\\geqq",!0);n(l,d,f,"⩾","\\geqslant",!0);n(l,d,f,"⪖","\\eqslantgtr",!0);n(l,d,f,"≳","\\gtrsim",!0);n(l,d,f,"⪆","\\gtrapprox",!0);n(l,d,D,"⋗","\\gtrdot");n(l,d,f,"⋙","\\ggg",!0);n(l,d,f,"≷","\\gtrless",!0);n(l,d,f,"⋛","\\gtreqless",!0);n(l,d,f,"⪌","\\gtreqqless",!0);n(l,d,f,"≖","\\eqcirc",!0);n(l,d,f,"≗","\\circeq",!0);n(l,d,f,"≜","\\triangleq",!0);n(l,d,f,"∼","\\thicksim");n(l,d,f,"≈","\\thickapprox");n(l,d,f,"⫆","\\supseteqq",!0);n(l,d,f,"⋑","\\Supset",!0);n(l,d,f,"⊐","\\sqsupset",!0);n(l,d,f,"≽","\\succcurlyeq",!0);n(l,d,f,"⋟","\\curlyeqsucc",!0);n(l,d,f,"≿","\\succsim",!0);n(l,d,f,"⪸","\\succapprox",!0);n(l,d,f,"⊳","\\vartriangleright");n(l,d,f,"⊵","\\trianglerighteq");n(l,d,f,"⊩","\\Vdash",!0);n(l,d,f,"∣","\\shortmid");n(l,d,f,"∥","\\shortparallel");n(l,d,f,"≬","\\between",!0);n(l,d,f,"⋔","\\pitchfork",!0);n(l,d,f,"∝","\\varpropto");n(l,d,f,"◀","\\blacktriangleleft");n(l,d,f,"∴","\\therefore",!0);n(l,d,f,"∍","\\backepsilon");n(l,d,f,"▶","\\blacktriangleright");n(l,d,f,"∵","\\because",!0);n(l,d,f,"⋘","\\llless");n(l,d,f,"⋙","\\gggtr");n(l,d,D,"⊲","\\lhd");n(l,d,D,"⊳","\\rhd");n(l,d,f,"≂","\\eqsim",!0);n(l,o,f,"⋈","\\Join");n(l,d,f,"≑","\\Doteq",!0);n(l,d,D,"∔","\\dotplus",!0);n(l,d,D,"∖","\\smallsetminus");n(l,d,D,"⋒","\\Cap",!0);n(l,d,D,"⋓","\\Cup",!0);n(l,d,D,"⩞","\\doublebarwedge",!0);n(l,d,D,"⊟","\\boxminus",!0);n(l,d,D,"⊞","\\boxplus",!0);n(l,d,D,"⋇","\\divideontimes",!0);n(l,d,D,"⋉","\\ltimes",!0);n(l,d,D,"⋊","\\rtimes",!0);n(l,d,D,"⋋","\\leftthreetimes",!0);n(l,d,D,"⋌","\\rightthreetimes",!0);n(l,d,D,"⋏","\\curlywedge",!0);n(l,d,D,"⋎","\\curlyvee",!0);n(l,d,D,"⊝","\\circleddash",!0);n(l,d,D,"⊛","\\circledast",!0);n(l,d,D,"⋅","\\centerdot");n(l,d,D,"⊺","\\intercal",!0);n(l,d,D,"⋒","\\doublecap");n(l,d,D,"⋓","\\doublecup");n(l,d,D,"⊠","\\boxtimes",!0);n(l,d,f,"⇢","\\dashrightarrow",!0);n(l,d,f,"⇠","\\dashleftarrow",!0);n(l,d,f,"⇇","\\leftleftarrows",!0);n(l,d,f,"⇆","\\leftrightarrows",!0);n(l,d,f,"⇚","\\Lleftarrow",!0);n(l,d,f,"↞","\\twoheadleftarrow",!0);n(l,d,f,"↢","\\leftarrowtail",!0);n(l,d,f,"↫","\\looparrowleft",!0);n(l,d,f,"⇋","\\leftrightharpoons",!0);n(l,d,f,"↶","\\curvearrowleft",!0);n(l,d,f,"↺","\\circlearrowleft",!0);n(l,d,f,"↰","\\Lsh",!0);n(l,d,f,"⇈","\\upuparrows",!0);n(l,d,f,"↿","\\upharpoonleft",!0);n(l,d,f,"⇃","\\downharpoonleft",!0);n(l,o,f,"⊶","\\origof",!0);n(l,o,f,"⊷","\\imageof",!0);n(l,d,f,"⊸","\\multimap",!0);n(l,d,f,"↭","\\leftrightsquigarrow",!0);n(l,d,f,"⇉","\\rightrightarrows",!0);n(l,d,f,"⇄","\\rightleftarrows",!0);n(l,d,f,"↠","\\twoheadrightarrow",!0);n(l,d,f,"↣","\\rightarrowtail",!0);n(l,d,f,"↬","\\looparrowright",!0);n(l,d,f,"↷","\\curvearrowright",!0);n(l,d,f,"↻","\\circlearrowright",!0);n(l,d,f,"↱","\\Rsh",!0);n(l,d,f,"⇊","\\downdownarrows",!0);n(l,d,f,"↾","\\upharpoonright",!0);n(l,d,f,"⇂","\\downharpoonright",!0);n(l,d,f,"⇝","\\rightsquigarrow",!0);n(l,d,f,"⇝","\\leadsto");n(l,d,f,"⇛","\\Rrightarrow",!0);n(l,d,f,"↾","\\restriction");n(l,o,g,"‘","`");n(l,o,g,"$","\\$");n(w,o,g,"$","\\$");n(w,o,g,"$","\\textdollar");n(l,o,g,"%","\\%");n(w,o,g,"%","\\%");n(l,o,g,"_","\\_");n(w,o,g,"_","\\_");n(w,o,g,"_","\\textunderscore");n(l,o,g,"∠","\\angle",!0);n(l,o,g,"∞","\\infty",!0);n(l,o,g,"′","\\prime");n(l,o,g,"△","\\triangle");n(l,o,g,"Γ","\\Gamma",!0);n(l,o,g,"Δ","\\Delta",!0);n(l,o,g,"Θ","\\Theta",!0);n(l,o,g,"Λ","\\Lambda",!0);n(l,o,g,"Ξ","\\Xi",!0);n(l,o,g,"Π","\\Pi",!0);n(l,o,g,"Σ","\\Sigma",!0);n(l,o,g,"Υ","\\Upsilon",!0);n(l,o,g,"Φ","\\Phi",!0);n(l,o,g,"Ψ","\\Psi",!0);n(l,o,g,"Ω","\\Omega",!0);n(l,o,g,"A","Α");n(l,o,g,"B","Β");n(l,o,g,"E","Ε");n(l,o,g,"Z","Ζ");n(l,o,g,"H","Η");n(l,o,g,"I","Ι");n(l,o,g,"K","Κ");n(l,o,g,"M","Μ");n(l,o,g,"N","Ν");n(l,o,g,"O","Ο");n(l,o,g,"P","Ρ");n(l,o,g,"T","Τ");n(l,o,g,"X","Χ");n(l,o,g,"¬","\\neg",!0);n(l,o,g,"¬","\\lnot");n(l,o,g,"⊤","\\top");n(l,o,g,"⊥","\\bot");n(l,o,g,"∅","\\emptyset");n(l,d,g,"∅","\\varnothing");n(l,o,E,"α","\\alpha",!0);n(l,o,E,"β","\\beta",!0);n(l,o,E,"γ","\\gamma",!0);n(l,o,E,"δ","\\delta",!0);n(l,o,E,"ϵ","\\epsilon",!0);n(l,o,E,"ζ","\\zeta",!0);n(l,o,E,"η","\\eta",!0);n(l,o,E,"θ","\\theta",!0);n(l,o,E,"ι","\\iota",!0);n(l,o,E,"κ","\\kappa",!0);n(l,o,E,"λ","\\lambda",!0);n(l,o,E,"μ","\\mu",!0);n(l,o,E,"ν","\\nu",!0);n(l,o,E,"ξ","\\xi",!0);n(l,o,E,"ο","\\omicron",!0);n(l,o,E,"π","\\pi",!0);n(l,o,E,"ρ","\\rho",!0);n(l,o,E,"σ","\\sigma",!0);n(l,o,E,"τ","\\tau",!0);n(l,o,E,"υ","\\upsilon",!0);n(l,o,E,"ϕ","\\phi",!0);n(l,o,E,"χ","\\chi",!0);n(l,o,E,"ψ","\\psi",!0);n(l,o,E,"ω","\\omega",!0);n(l,o,E,"ε","\\varepsilon",!0);n(l,o,E,"ϑ","\\vartheta",!0);n(l,o,E,"ϖ","\\varpi",!0);n(l,o,E,"ϱ","\\varrho",!0);n(l,o,E,"ς","\\varsigma",!0);n(l,o,E,"φ","\\varphi",!0);n(l,o,D,"∗","*",!0);n(l,o,D,"+","+");n(l,o,D,"−","-",!0);n(l,o,D,"⋅","\\cdot",!0);n(l,o,D,"∘","\\circ",!0);n(l,o,D,"÷","\\div",!0);n(l,o,D,"±","\\pm",!0);n(l,o,D,"×","\\times",!0);n(l,o,D,"∩","\\cap",!0);n(l,o,D,"∪","\\cup",!0);n(l,o,D,"∖","\\setminus",!0);n(l,o,D,"∧","\\land");n(l,o,D,"∨","\\lor");n(l,o,D,"∧","\\wedge",!0);n(l,o,D,"∨","\\vee",!0);n(l,o,g,"√","\\surd");n(l,o,f0,"⟨","\\langle",!0);n(l,o,f0,"∣","\\lvert");n(l,o,f0,"∥","\\lVert");n(l,o,u0,"?","?");n(l,o,u0,"!","!");n(l,o,u0,"⟩","\\rangle",!0);n(l,o,u0,"∣","\\rvert");n(l,o,u0,"∥","\\rVert");n(l,o,f,"=","=");n(l,o,f,":",":");n(l,o,f,"≈","\\approx",!0);n(l,o,f,"≅","\\cong",!0);n(l,o,f,"≥","\\ge");n(l,o,f,"≥","\\geq",!0);n(l,o,f,"←","\\gets");n(l,o,f,">","\\gt",!0);n(l,o,f,"∈","\\in",!0);n(l,o,f,"","\\@not");n(l,o,f,"⊂","\\subset",!0);n(l,o,f,"⊃","\\supset",!0);n(l,o,f,"⊆","\\subseteq",!0);n(l,o,f,"⊇","\\supseteq",!0);n(l,d,f,"⊈","\\nsubseteq",!0);n(l,d,f,"⊉","\\nsupseteq",!0);n(l,o,f,"⊨","\\models");n(l,o,f,"←","\\leftarrow",!0);n(l,o,f,"≤","\\le");n(l,o,f,"≤","\\leq",!0);n(l,o,f,"<","\\lt",!0);n(l,o,f,"→","\\rightarrow",!0);n(l,o,f,"→","\\to");n(l,d,f,"≱","\\ngeq",!0);n(l,d,f,"≰","\\nleq",!0);n(l,o,q0," ","\\ ");n(l,o,q0," ","\\space");n(l,o,q0," ","\\nobreakspace");n(w,o,q0," ","\\ ");n(w,o,q0," "," ");n(w,o,q0," ","\\space");n(w,o,q0," ","\\nobreakspace");n(l,o,q0,"","\\nobreak");n(l,o,q0,"","\\allowbreak");n(l,o,de,",",",");n(l,o,de,";",";");n(l,d,D,"⊼","\\barwedge",!0);n(l,d,D,"⊻","\\veebar",!0);n(l,o,D,"⊙","\\odot",!0);n(l,o,D,"⊕","\\oplus",!0);n(l,o,D,"⊗","\\otimes",!0);n(l,o,g,"∂","\\partial",!0);n(l,o,D,"⊘","\\oslash",!0);n(l,d,D,"⊚","\\circledcirc",!0);n(l,d,D,"⊡","\\boxdot",!0);n(l,o,D,"△","\\bigtriangleup");n(l,o,D,"▽","\\bigtriangledown");n(l,o,D,"†","\\dagger");n(l,o,D,"⋄","\\diamond");n(l,o,D,"⋆","\\star");n(l,o,D,"◃","\\triangleleft");n(l,o,D,"▹","\\triangleright");n(l,o,f0,"{","\\{");n(w,o,g,"{","\\{");n(w,o,g,"{","\\textbraceleft");n(l,o,u0,"}","\\}");n(w,o,g,"}","\\}");n(w,o,g,"}","\\textbraceright");n(l,o,f0,"{","\\lbrace");n(l,o,u0,"}","\\rbrace");n(l,o,f0,"[","\\lbrack",!0);n(w,o,g,"[","\\lbrack",!0);n(l,o,u0,"]","\\rbrack",!0);n(w,o,g,"]","\\rbrack",!0);n(l,o,f0,"(","\\lparen",!0);n(l,o,u0,")","\\rparen",!0);n(w,o,g,"<","\\textless",!0);n(w,o,g,">","\\textgreater",!0);n(l,o,f0,"⌊","\\lfloor",!0);n(l,o,u0,"⌋","\\rfloor",!0);n(l,o,f0,"⌈","\\lceil",!0);n(l,o,u0,"⌉","\\rceil",!0);n(l,o,g,"\\","\\backslash");n(l,o,g,"∣","|");n(l,o,g,"∣","\\vert");n(w,o,g,"|","\\textbar",!0);n(l,o,g,"∥","\\|");n(l,o,g,"∥","\\Vert");n(w,o,g,"∥","\\textbardbl");n(w,o,g,"~","\\textasciitilde");n(w,o,g,"\\","\\textbackslash");n(w,o,g,"^","\\textasciicircum");n(l,o,f,"↑","\\uparrow",!0);n(l,o,f,"⇑","\\Uparrow",!0);n(l,o,f,"↓","\\downarrow",!0);n(l,o,f,"⇓","\\Downarrow",!0);n(l,o,f,"↕","\\updownarrow",!0);n(l,o,f,"⇕","\\Updownarrow",!0);n(l,o,t0,"∐","\\coprod");n(l,o,t0,"⋁","\\bigvee");n(l,o,t0,"⋀","\\bigwedge");n(l,o,t0,"⨄","\\biguplus");n(l,o,t0,"⋂","\\bigcap");n(l,o,t0,"⋃","\\bigcup");n(l,o,t0,"∫","\\int");n(l,o,t0,"∫","\\intop");n(l,o,t0,"∬","\\iint");n(l,o,t0,"∭","\\iiint");n(l,o,t0,"∏","\\prod");n(l,o,t0,"∑","\\sum");n(l,o,t0,"⨂","\\bigotimes");n(l,o,t0,"⨁","\\bigoplus");n(l,o,t0,"⨀","\\bigodot");n(l,o,t0,"∮","\\oint");n(l,o,t0,"∯","\\oiint");n(l,o,t0,"∰","\\oiiint");n(l,o,t0,"⨆","\\bigsqcup");n(l,o,t0,"∫","\\smallint");n(w,o,ne,"…","\\textellipsis");n(l,o,ne,"…","\\mathellipsis");n(w,o,ne,"…","\\ldots",!0);n(l,o,ne,"…","\\ldots",!0);n(l,o,ne,"⋯","\\@cdots",!0);n(l,o,ne,"⋱","\\ddots",!0);n(l,o,g,"⋮","\\varvdots");n(w,o,g,"⋮","\\varvdots");n(l,o,j,"ˊ","\\acute");n(l,o,j,"ˋ","\\grave");n(l,o,j,"¨","\\ddot");n(l,o,j,"~","\\tilde");n(l,o,j,"ˉ","\\bar");n(l,o,j,"˘","\\breve");n(l,o,j,"ˇ","\\check");n(l,o,j,"^","\\hat");n(l,o,j,"⃗","\\vec");n(l,o,j,"˙","\\dot");n(l,o,j,"˚","\\mathring");n(l,o,E,"","\\@imath");n(l,o,E,"","\\@jmath");n(l,o,g,"ı","ı");n(l,o,g,"ȷ","ȷ");n(w,o,g,"ı","\\i",!0);n(w,o,g,"ȷ","\\j",!0);n(w,o,g,"ß","\\ss",!0);n(w,o,g,"æ","\\ae",!0);n(w,o,g,"œ","\\oe",!0);n(w,o,g,"ø","\\o",!0);n(w,o,g,"Æ","\\AE",!0);n(w,o,g,"Œ","\\OE",!0);n(w,o,g,"Ø","\\O",!0);n(w,o,j,"ˊ","\\'");n(w,o,j,"ˋ","\\`");n(w,o,j,"ˆ","\\^");n(w,o,j,"˜","\\~");n(w,o,j,"ˉ","\\=");n(w,o,j,"˘","\\u");n(w,o,j,"˙","\\.");n(w,o,j,"¸","\\c");n(w,o,j,"˚","\\r");n(w,o,j,"ˇ","\\v");n(w,o,j,"¨",'\\"');n(w,o,j,"˝","\\H");n(w,o,j,"◯","\\textcircled");var $r={"--":!0,"---":!0,"``":!0,"''":!0};n(w,o,g,"–","--",!0);n(w,o,g,"–","\\textendash");n(w,o,g,"—","---",!0);n(w,o,g,"—","\\textemdash");n(w,o,g,"‘","`",!0);n(w,o,g,"‘","\\textquoteleft");n(w,o,g,"’","'",!0);n(w,o,g,"’","\\textquoteright");n(w,o,g,"“","``",!0);n(w,o,g,"“","\\textquotedblleft");n(w,o,g,"”","''",!0);n(w,o,g,"”","\\textquotedblright");n(l,o,g,"°","\\degree",!0);n(w,o,g,"°","\\degree");n(w,o,g,"°","\\textdegree",!0);n(l,o,g,"£","\\pounds");n(l,o,g,"£","\\mathsterling",!0);n(w,o,g,"£","\\pounds");n(w,o,g,"£","\\textsterling",!0);n(l,d,g,"✠","\\maltese");n(w,d,g,"✠","\\maltese");var nr='0123456789/@."';for(var Qe=0;Qe{var e=r.charCodeAt(0),t=r.charCodeAt(1),a=(e-55296)*1024+(t-56320)+65536;if(119808<=a&&a<120484){var i=Math.floor((a-119808)/26);return vr[i]}else if(120782<=a&&a<=120831){var s=Math.floor((a-120782)/10);return Ba[s]}else{if(a===120485||a===120486)return vr[0];if(120486{if(L0(r.classes)!==L0(e.classes)||r.skew!==e.skew||r.maxFontSize!==e.maxFontSize||r.italic!==0&&r.hasClass("mathnormal"))return!1;if(r.classes.length===1){var t=r.classes[0];if(t==="mbin"||t==="mord")return!1}for(var a of Object.keys(r.style))if(r.style[a]!==e.style[a])return!1;for(var i of Object.keys(e.style))if(r.style[i]!==e.style[i])return!1;return!0},Wr=r=>{for(var e=0;et&&(t=u.height),u.depth>a&&(a=u.depth),u.maxFontSize>i&&(i=u.maxFontSize)}e.height=t,e.depth=a,e.maxFontSize=i},k=function(e,t,a,i){var s=new ie(e,t,a,i);return Ht(s),s},G0=(r,e,t,a)=>new ie(r,e,t,a),te=function(e,t,a){var i=k([e],[],t);return i.height=Math.max(a||t.fontMetrics().defaultRuleThickness,t.minRuleThickness),i.style.borderBottomWidth=A(i.height),i.maxFontSize=1,i},Ea=function(e,t,a,i){var s=new Fe(e,t,a,i);return Ht(s),s},E0=function(e){var t=new ae(e);return Ht(t),t},re=function(e,t){return e instanceof ae?k([],[e],t):e},Ra=function(e){if(e.positionType==="individualShift"){for(var t=e.children,a=[t[0]],i=-t[0].shift-t[0].elem.depth,s=i,u=1;u{var t=k(["mspace"],[],e),a=K(r,e);return t.style.marginRight=A(a),t},ze=(r,e,t)=>{var a,i;switch(r){case"amsrm":a="AMS";break;case"textrm":a="Main";break;case"textsf":a="SansSerif";break;case"texttt":a="Typewriter";break;default:a=r}return e==="textbf"&&t==="textit"?i="BoldItalic":e==="textbf"?i="Bold":t==="textit"?i="Italic":i="Regular",a+"-"+i},kt={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathnormal:{variant:"italic",fontName:"Math-Italic"},mathsfit:{variant:"sans-serif-italic",fontName:"SansSerif-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},Zr={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},Kr=function(e,t){var[a,i,s]=Zr[e],u=new P0(a),h=new C0([u],{width:A(i),height:A(s),style:"width:"+A(i),viewBox:"0 0 "+1e3*i+" "+1e3*s,preserveAspectRatio:"xMinYMin"}),c=G0(["overlay"],[h],t);return c.height=s,c.style.height=A(s),c.style.width=A(i),c},Z={number:3,unit:"mu"},Y0={number:4,unit:"mu"},M0={number:5,unit:"mu"},Ia={mord:{mop:Z,mbin:Y0,mrel:M0,minner:Z},mop:{mord:Z,mop:Z,mrel:M0,minner:Z},mbin:{mord:Y0,mop:Y0,mopen:Y0,minner:Y0},mrel:{mord:M0,mop:M0,mopen:M0,minner:M0},mopen:{},mclose:{mop:Z,mbin:Y0,mrel:M0,minner:Z},mpunct:{mord:Z,mop:Z,mrel:M0,mopen:Z,mclose:Z,mpunct:Z,minner:Z},minner:{mord:Z,mop:Z,mbin:Y0,mrel:M0,mopen:Z,mpunct:Z,minner:Z}},Na={mord:{mop:Z},mop:{mord:Z,mop:Z},mbin:{},mrel:{},mopen:{},mclose:{mop:Z},mpunct:{},minner:{mop:Z}},Jr={},Re={},Ie={};function B(r){for(var{type:e,names:t,props:a,handler:i,htmlBuilder:s,mathmlBuilder:u}=r,h={type:e,numArgs:a.numArgs,argTypes:a.argTypes,allowedInArgument:!!a.allowedInArgument,allowedInText:!!a.allowedInText,allowedInMath:a.allowedInMath===void 0?!0:a.allowedInMath,numOptionalArgs:a.numOptionalArgs||0,infix:!!a.infix,primitive:!!a.primitive,handler:i},c=0;c{var q=M.classes[0],C=T.classes[0];q==="mbin"&&Ha.has(C)?M.classes[0]="mord":C==="mbin"&&Fa.has(q)&&(T.classes[0]="mord")},{node:b},x,y),St(s,(T,M)=>{var q,C,R=At(M),F=At(T),L=R&&F?T.hasClass("mtight")?(q=Na[R])==null?void 0:q[F]:(C=Ia[R])==null?void 0:C[F]:null;if(L)return jr(L,v)},{node:b},x,y),s},St=function(e,t,a,i,s){i&&e.push(i);for(var u=0;ux=>{e.splice(b+1,0,x),u++})(u)}i&&e.pop()},Qr=function(e){return e instanceof ae||e instanceof Fe||e instanceof ie&&e.hasClass("enclosing")?e:null},zt=function(e,t){var a=Qr(e);if(a){var i=a.children;if(i.length){if(t==="right")return zt(i[i.length-1],"right");if(t==="left")return zt(i[0],"left")}}return e},At=function(e,t){if(!e)return null;t&&(e=zt(e,t));var a=e.classes[0];return La[a]||null},ce=function(e,t){var a=["nulldelimiter"].concat(e.baseSizingClasses());return k(t.concat(a))},X=function(e,t,a){if(!e)return k();if(Re[e.type]){var i=Re[e.type](e,t);if(a&&t.size!==a.size){i=k(t.sizingClasses(a),[i],t);var s=t.sizeMultiplier/a.sizeMultiplier;i.height*=s,i.depth*=s}return i}else throw new S("Got group of unknown type: '"+e.type+"'")};function Ae(r,e){var t=k(["base"],r,e),a=k(["strut"]);return a.style.height=A(t.height+t.depth),t.depth&&(a.style.verticalAlign=A(-t.depth)),t.children.unshift(a),t}function Mt(r,e){var t=null;r.length===1&&r[0].type==="tag"&&(t=r[0].tag,r=r[0].body);var a=a0(r,e,"root"),i;a.length===2&&a[1].hasClass("tag")&&(i=a.pop());for(var s=[],u=[],h=0;h0&&(s.push(Ae(u,e)),u=[]),s.push(a[h]));u.length>0&&s.push(Ae(u,e));var v;t?(v=Ae(a0(t,e,!0),e),v.classes=["tag"],s.push(v)):i&&s.push(i);var p=k(["katex-html"],s);if(p.setAttribute("aria-hidden","true"),v){var b=v.children[0];b.style.height=A(p.height+p.depth),p.depth&&(b.style.verticalAlign=A(-p.depth))}return p}function _r(r){return new ae(r)}class z{constructor(e,t,a){this.type=void 0,this.attributes=void 0,this.children=void 0,this.classes=void 0,this.type=e,this.attributes={},this.children=t||[],this.classes=a||[]}setAttribute(e,t){this.attributes[e]=t}getAttribute(e){return this.attributes[e]}toNode(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);this.classes.length>0&&(e.className=L0(this.classes));for(var a=0;a0&&(e+=' class ="'+i0(L0(this.classes))+'"'),e+=">";for(var a=0;a",e}toText(){return this.children.map(e=>e.toText()).join("")}}class e0{constructor(e){this.text=void 0,this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return i0(this.toText())}toText(){return this.text}}class e1{constructor(e){this.width=void 0,this.character=void 0,this.width=e,e>=.05555&&e<=.05556?this.character=" ":e>=.1666&&e<=.1667?this.character=" ":e>=.2222&&e<=.2223?this.character=" ":e>=.2777&&e<=.2778?this.character="  ":e>=-.05556&&e<=-.05555?this.character=" ⁣":e>=-.1667&&e<=-.1666?this.character=" ⁣":e>=-.2223&&e<=-.2222?this.character=" ⁣":e>=-.2778&&e<=-.2777?this.character=" ⁣":this.character=null}toNode(){if(this.character)return document.createTextNode(this.character);var e=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return e.setAttribute("width",A(this.width)),e}toMarkup(){return this.character?""+this.character+"":''}toText(){return this.character?this.character:" "}}var Pa=new Set(["\\imath","\\jmath"]),Ga=new Set(["mrow","mtable"]),g0=function(e,t,a){return W[t][e]&&W[t][e].replace&&e.charCodeAt(0)!==55349&&!($r.hasOwnProperty(e)&&a&&(a.fontFamily&&a.fontFamily.slice(4,6)==="tt"||a.font&&a.font.slice(4,6)==="tt"))&&(e=W[t][e].replace),new e0(e)},Ot=function(e){return e.length===1?e[0]:new z("mrow",e)},Ua={mathit:"italic",boldsymbol:r=>r.type==="textord"?"bold":"bold-italic",mathbf:"bold",mathbb:"double-struck",mathsfit:"sans-serif-italic",mathfrak:"fraktur",mathscr:"script",mathcal:"script",mathsf:"sans-serif",mathtt:"monospace"},Lt=(r,e)=>{if(r.mode==="text"){if(e.fontFamily==="texttt")return"monospace";if(e.fontFamily==="textsf")return e.fontShape==="textit"&&e.fontWeight==="textbf"?"sans-serif-bold-italic":e.fontShape==="textit"?"sans-serif-italic":e.fontWeight==="textbf"?"bold-sans-serif":"sans-serif";if(e.fontShape==="textit"&&e.fontWeight==="textbf")return"bold-italic";if(e.fontShape==="textit")return"italic";if(e.fontWeight==="textbf")return"bold"}var t=e.font;if(!t||t==="mathnormal")return null;var a=r.mode,i=Ua[t];if(i)return typeof i=="function"?i(r):i;var s=r.text;if(Pa.has(s))return null;if(W[a][s]){var u=W[a][s].replace;u&&(s=u)}var h=kt[t].fontName;return Nt(s,h,a)?kt[t].variant:null};function rt(r){if(!r)return!1;if(r.type==="mi"&&r.children.length===1){var e=r.children[0];return e instanceof e0&&e.text==="."}else if(r.type==="mo"&&r.children.length===1&&r.getAttribute("separator")==="true"&&r.getAttribute("lspace")==="0em"&&r.getAttribute("rspace")==="0em"){var t=r.children[0];return t instanceof e0&&t.text===","}else return!1}var v0=function(e,t,a){if(e.length===1){var i=$(e[0],t);return a&&i instanceof z&&i.type==="mo"&&(i.setAttribute("lspace","0em"),i.setAttribute("rspace","0em")),[i]}for(var s=[],u,h=0;h=1&&(u.type==="mn"||rt(u))){var v=c.children[0];v instanceof z&&v.type==="mn"&&(v.children=[...u.children,...v.children],s.pop())}else if(u.type==="mi"&&u.children.length===1){var p=u.children[0];if(p instanceof e0&&p.text==="̸"&&(c.type==="mo"||c.type==="mi"||c.type==="mn")){var b=c.children[0];b instanceof e0&&b.text.length>0&&(b.text=b.text.slice(0,1)+"̸"+b.text.slice(1),s.pop())}}}s.push(c),u=c}return s},U0=function(e,t,a){return Ot(v0(e,t,a))},$=function(e,t){if(!e)return new z("mrow");if(Ie[e.type])return Ie[e.type](e,t);throw new S("Got group of unknown type: '"+e.type+"'")};function pr(r,e,t,a,i){var s=v0(r,t),u;s.length===1&&s[0]instanceof z&&Ga.has(s[0].type)?u=s[0]:u=new z("mrow",s);var h=new z("annotation",[new e0(e)]);h.setAttribute("encoding","application/x-tex");var c=new z("semantics",[u,h]),v=new z("math",[c]);v.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),a&&v.setAttribute("display","block");var p=i?"katex":"katex-mathml";return k([p],[v])}var Va=[[1,1,1],[2,1,1],[3,1,1],[4,2,1],[5,2,1],[6,3,1],[7,4,2],[8,6,3],[9,7,6],[10,8,7],[11,10,9]],gr=[.5,.6,.7,.8,.9,1,1.2,1.44,1.728,2.074,2.488],br=function(e,t){return t.size<2?e:Va[e-1][t.size-1]};class T0{constructor(e){this.style=void 0,this.color=void 0,this.size=void 0,this.textSize=void 0,this.phantom=void 0,this.font=void 0,this.fontFamily=void 0,this.fontWeight=void 0,this.fontShape=void 0,this.sizeMultiplier=void 0,this.maxSize=void 0,this.minRuleThickness=void 0,this._fontMetrics=void 0,this.style=e.style,this.color=e.color,this.size=e.size||T0.BASESIZE,this.textSize=e.textSize||this.size,this.phantom=!!e.phantom,this.font=e.font||"",this.fontFamily=e.fontFamily||"",this.fontWeight=e.fontWeight||"",this.fontShape=e.fontShape||"",this.sizeMultiplier=gr[this.size-1],this.maxSize=e.maxSize,this.minRuleThickness=e.minRuleThickness,this._fontMetrics=void 0}extend(e){var t={style:this.style,size:this.size,textSize:this.textSize,color:this.color,phantom:this.phantom,font:this.font,fontFamily:this.fontFamily,fontWeight:this.fontWeight,fontShape:this.fontShape,maxSize:this.maxSize,minRuleThickness:this.minRuleThickness};return Object.assign(t,e),new T0(t)}havingStyle(e){return this.style===e?this:this.extend({style:e,size:br(this.textSize,e)})}havingCrampedStyle(){return this.havingStyle(this.style.cramp())}havingSize(e){return this.size===e&&this.textSize===e?this:this.extend({style:this.style.text(),size:e,textSize:e,sizeMultiplier:gr[e-1]})}havingBaseStyle(e){e=e||this.style.text();var t=br(T0.BASESIZE,e);return this.size===t&&this.textSize===T0.BASESIZE&&this.style===e?this:this.extend({style:e,size:t})}havingBaseSizing(){var e;switch(this.style.id){case 4:case 5:e=3;break;case 6:case 7:e=1;break;default:e=6}return this.extend({style:this.style.text(),size:e})}withColor(e){return this.extend({color:e})}withPhantom(){return this.extend({phantom:!0})}withFont(e){return this.extend({font:e})}withTextFontFamily(e){return this.extend({fontFamily:e,font:""})}withTextFontWeight(e){return this.extend({fontWeight:e,font:""})}withTextFontShape(e){return this.extend({fontShape:e,font:""})}sizingClasses(e){return e.size!==this.size?["sizing","reset-size"+e.size,"size"+this.size]:[]}baseSizingClasses(){return this.size!==T0.BASESIZE?["sizing","reset-size"+this.size,"size"+T0.BASESIZE]:[]}fontMetrics(){return this._fontMetrics||(this._fontMetrics=Ma(this.size)),this._fontMetrics}getColor(){return this.phantom?"transparent":this.color}}T0.BASESIZE=6;var t1=function(e){return new T0({style:e.displayMode?N.DISPLAY:N.TEXT,maxSize:e.maxSize,minRuleThickness:e.minRuleThickness})},r1=function(e,t){if(t.displayMode){var a=["katex-display"];t.leqno&&a.push("leqno"),t.fleqn&&a.push("fleqn"),e=k(a,[e])}return e},Xa=function(e,t,a){var i=t1(a),s;if(a.output==="mathml")return pr(e,t,i,a.displayMode,!0);if(a.output==="html"){var u=Mt(e,i);s=k(["katex"],[u])}else{var h=pr(e,t,i,a.displayMode,!1),c=Mt(e,i);s=k(["katex"],[h,c])}return r1(s,a)},Ya=function(e,t,a){var i=t1(a),s=Mt(e,i),u=k(["katex"],[s]);return r1(u,a)},$a={widehat:"^",widecheck:"ˇ",widetilde:"~",utilde:"~",overleftarrow:"←",underleftarrow:"←",xleftarrow:"←",overrightarrow:"→",underrightarrow:"→",xrightarrow:"→",underbrace:"⏟",overbrace:"⏞",underbracket:"⎵",overbracket:"⎴",overgroup:"⏠",undergroup:"⏡",overleftrightarrow:"↔",underleftrightarrow:"↔",xleftrightarrow:"↔",Overrightarrow:"⇒",xRightarrow:"⇒",overleftharpoon:"↼",xleftharpoonup:"↼",overrightharpoon:"⇀",xrightharpoonup:"⇀",xLeftarrow:"⇐",xLeftrightarrow:"⇔",xhookleftarrow:"↩",xhookrightarrow:"↪",xmapsto:"↦",xrightharpoondown:"⇁",xleftharpoondown:"↽",xrightleftharpoons:"⇌",xleftrightharpoons:"⇋",xtwoheadleftarrow:"↞",xtwoheadrightarrow:"↠",xlongequal:"=",xtofrom:"⇄",xrightleftarrows:"⇄",xrightequilibrium:"⇌",xleftequilibrium:"⇋","\\cdrightarrow":"→","\\cdleftarrow":"←","\\cdlongequal":"="},Le=function(e){var t=new z("mo",[new e0($a[e.replace(/^\\/,"")])]);return t.setAttribute("stretchy","true"),t},Wa={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],"\\cdrightarrow":[["rightarrow"],3,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],"\\cdleftarrow":[["leftarrow"],3,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],"\\cdlongequal":[["longequal"],3,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overbracket:[["leftbracketover","rightbracketover"],1.6,440],underbracket:[["leftbracketunder","rightbracketunder"],1.6,410],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},ja=new Set(["widehat","widecheck","widetilde","utilde"]),Pe=function(e,t){function a(){var h=4e5,c=e.label.slice(1);if(ja.has(c)&&"base"in e){var v=e.base.type==="ordgroup"?e.base.body.length:1,p,b,x;if(v>5)c==="widehat"||c==="widecheck"?(p=420,h=2364,x=.42,b=c+"4"):(p=312,h=2340,x=.34,b="tilde4");else{var y=[1,1,2,2,3,3][v];c==="widehat"||c==="widecheck"?(h=[0,1062,2364,2364,2364][y],p=[0,239,300,360,420][y],x=[0,.24,.3,.3,.36,.42][y],b=c+y):(h=[0,600,1033,2339,2340][y],p=[0,260,286,306,312][y],x=[0,.26,.286,.3,.306,.34][y],b="tilde"+y)}var T=new P0(b),M=new C0([T],{width:"100%",height:A(x),viewBox:"0 0 "+h+" "+p,preserveAspectRatio:"none"});return{span:G0([],[M],t),minWidth:0,height:x}}else{var q=[],C=Wa[c];if(!C)throw new Error('No SVG data for "'+c+'".');var[R,F,L]=C,O=L/1e3,P=R.length,G,Y;if(P===1){if(C.length!==4)throw new Error('Expected 4-tuple for single-path SVG data "'+c+'".');G=["hide-tail"],Y=[C[3]]}else if(P===2)G=["halfarrow-left","halfarrow-right"],Y=["xMinYMin","xMaxYMin"];else if(P===3)G=["brace-left","brace-center","brace-right"],Y=["xMinYMin","xMidYMin","xMaxYMin"];else throw new Error(`Correct katexImagesData or update code here to support + `+P+" children.");for(var U=0;U0&&(i.style.minWidth=A(s)),i},Za=function(e,t,a,i,s){var u,h=e.height+e.depth+a+i;if(/fbox|color|angl/.test(t)){if(u=k(["stretchy",t],[],s),t==="fbox"){var c=s.color&&s.getColor();c&&(u.style.borderColor=c)}}else{var v=[];/^[bx]cancel$/.test(t)&&v.push(new pt({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(t)&&v.push(new pt({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var p=new C0(v,{width:"100%",height:A(h)});u=G0([],[p],s)}return u.height=h,u.style.height=A(h),u},Ka={bin:1,close:1,inner:1,open:1,punct:1,rel:1},Ja={"accent-token":1,mathord:1,"op-token":1,spacing:1,textord:1};function Qa(r){return r in Ka}function H(r,e){if(!r||r.type!==e)throw new Error("Expected node of type "+e+", but got "+(r?"node of type "+r.type:String(r)));return r}function Ge(r){var e=Ue(r);if(!e)throw new Error("Expected node of symbol group type, but got "+(r?"node of type "+r.type:String(r)));return e}function Ue(r){return r&&(r.type==="atom"||Ja.hasOwnProperty(r.type))?r:null}var a1=r=>{if(r instanceof d0)return r;if(za(r)&&r.children.length===1)return a1(r.children[0])},Pt=(r,e)=>{var t,a,i;r&&r.type==="supsub"?(a=H(r.base,"accent"),t=a.base,r.base=t,i=Sa(X(r,e)),r.base=a):(a=H(r,"accent"),t=a.base);var s=X(t,e.havingCrampedStyle()),u=a.isShifty&&D0(t),h=0;if(u){var c,v;h=(c=(v=a1(s))==null?void 0:v.skew)!=null?c:0}var p=a.label==="\\c",b=p?s.height+s.depth:Math.min(s.height,e.fontMetrics().xHeight),x;if(a.isStretchy)x=Pe(a,e),x=V({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"elem",elem:x,wrapperClasses:["svg-align"],wrapperStyle:h>0?{width:"calc(100% - "+A(2*h)+")",marginLeft:A(2*h)}:void 0}]});else{var y,T;a.label==="\\vec"?(y=Kr("vec",e),T=Zr.vec[1]):(y=Oe({mode:a.mode,text:a.label},e,"textord"),y=ka(y),y.italic=0,T=y.width,p&&(b+=y.depth)),x=k(["accent-body"],[y]);var M=a.label==="\\textcircled";M&&(x.classes.push("accent-full"),b=s.height);var q=h;M||(q-=T/2),x.style.left=A(q),a.label==="\\textcircled"&&(x.style.top=".2em"),x=V({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"kern",size:-b},{type:"elem",elem:x}]})}var C=k(["mord","accent"],[x],e);return i?(i.children[0]=C,i.height=Math.max(C.height,i.height),i.classes[0]="mord",i):C},i1=(r,e)=>{var t=r.isStretchy?Le(r.label):new z("mo",[g0(r.label,r.mode)]),a=new z("mover",[$(r.base,e),t]);return a.setAttribute("accent","true"),a},_a=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map(r=>"\\"+r).join("|"));B({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],props:{numArgs:1},handler:(r,e)=>{var t=Ne(e[0]),a=!_a.test(r.funcName),i=!a||r.funcName==="\\widehat"||r.funcName==="\\widetilde"||r.funcName==="\\widecheck";return{type:"accent",mode:r.parser.mode,label:r.funcName,isStretchy:a,isShifty:i,base:t}},htmlBuilder:Pt,mathmlBuilder:i1});B({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\c","\\r","\\H","\\v","\\textcircled"],props:{numArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["primitive"]},handler:(r,e)=>{var t=e[0],a=r.parser.mode;return a==="math"&&(r.parser.settings.reportNonstrict("mathVsTextAccents","LaTeX's accent "+r.funcName+" works only in text mode"),a="text"),{type:"accent",mode:a,label:r.funcName,isStretchy:!1,isShifty:!0,base:t}},htmlBuilder:Pt,mathmlBuilder:i1});B({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],props:{numArgs:1},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=e[0];return{type:"accentUnder",mode:t.mode,label:a,base:i}},htmlBuilder:(r,e)=>{var t=X(r.base,e),a=Pe(r,e),i=r.label==="\\utilde"?.12:0,s=V({positionType:"top",positionData:t.height,children:[{type:"elem",elem:a,wrapperClasses:["svg-align"]},{type:"kern",size:i},{type:"elem",elem:t}]});return k(["mord","accentunder"],[s],e)},mathmlBuilder:(r,e)=>{var t=Le(r.label),a=new z("munder",[$(r.base,e),t]);return a.setAttribute("accentunder","true"),a}});var Me=r=>{var e=new z("mpadded",r?[r]:[]);return e.setAttribute("width","+0.6em"),e.setAttribute("lspace","0.3em"),e};B({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium","\\\\cdrightarrow","\\\\cdleftarrow","\\\\cdlongequal"],props:{numArgs:1,numOptionalArgs:1},handler(r,e,t){var{parser:a,funcName:i}=r;return{type:"xArrow",mode:a.mode,label:i,body:e[0],below:t[0]}},htmlBuilder(r,e){var t=e.style,a=e.havingStyle(t.sup()),i=re(X(r.body,a,e),e),s=r.label.slice(0,2)==="\\x"?"x":"cd";i.classes.push(s+"-arrow-pad");var u;r.below&&(a=e.havingStyle(t.sub()),u=re(X(r.below,a,e),e),u.classes.push(s+"-arrow-pad"));var h=Pe(r,e),c=-e.fontMetrics().axisHeight+.5*h.height,v=-e.fontMetrics().axisHeight-.5*h.height-.111;(i.depth>.25||r.label==="\\xleftequilibrium")&&(v-=i.depth);var p;if(u){var b=-e.fontMetrics().axisHeight+u.height+.5*h.height+.111;p=V({positionType:"individualShift",children:[{type:"elem",elem:i,shift:v},{type:"elem",elem:h,shift:c,wrapperClasses:["svg-align"]},{type:"elem",elem:u,shift:b}]})}else p=V({positionType:"individualShift",children:[{type:"elem",elem:i,shift:v},{type:"elem",elem:h,shift:c,wrapperClasses:["svg-align"]}]});return k(["mrel","x-arrow"],[p],e)},mathmlBuilder(r,e){var t=Le(r.label);t.setAttribute("minsize",r.label.charAt(0)==="x"?"1.75em":"3.0em");var a;if(r.body){var i=Me($(r.body,e));if(r.below){var s=Me($(r.below,e));a=new z("munderover",[t,s,i])}else a=new z("mover",[t,i])}else if(r.below){var u=Me($(r.below,e));a=new z("munder",[t,u])}else a=Me(),a=new z("mover",[t,a]);return a}});function n1(r,e){var t=a0(r.body,e,!0);return k([r.mclass],t,e)}function s1(r,e){var t,a=v0(r.body,e);return r.mclass==="minner"?t=new z("mpadded",a):r.mclass==="mord"?r.isCharacterBox?(t=a[0],t.type="mi"):t=new z("mi",a):(r.isCharacterBox?(t=a[0],t.type="mo"):t=new z("mo",a),r.mclass==="mbin"?(t.attributes.lspace="0.22em",t.attributes.rspace="0.22em"):r.mclass==="mpunct"?(t.attributes.lspace="0em",t.attributes.rspace="0.17em"):r.mclass==="mopen"||r.mclass==="mclose"?(t.attributes.lspace="0em",t.attributes.rspace="0em"):r.mclass==="minner"&&(t.attributes.lspace="0.0556em",t.attributes.width="+0.1111em")),t}B({type:"mclass",names:["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],props:{numArgs:1,primitive:!0},handler(r,e){var{parser:t,funcName:a}=r,i=e[0];return{type:"mclass",mode:t.mode,mclass:"m"+a.slice(5),body:_(i),isCharacterBox:D0(i)}},htmlBuilder:n1,mathmlBuilder:s1});var Ve=r=>{var e=r.type==="ordgroup"&&r.body.length?r.body[0]:r;return e.type==="atom"&&(e.family==="bin"||e.family==="rel")?"m"+e.family:"mord"};B({type:"mclass",names:["\\@binrel"],props:{numArgs:2},handler(r,e){var{parser:t}=r;return{type:"mclass",mode:t.mode,mclass:Ve(e[0]),body:_(e[1]),isCharacterBox:D0(e[1])}}});B({type:"mclass",names:["\\stackrel","\\overset","\\underset"],props:{numArgs:2},handler(r,e){var{parser:t,funcName:a}=r,i=e[1],s=e[0],u;a!=="\\stackrel"?u=Ve(i):u="mrel";var h={type:"op",mode:i.mode,limits:!0,alwaysHandleSupSub:!0,parentIsSupSub:!1,symbol:!1,suppressBaseShift:a!=="\\stackrel",body:_(i)},c={type:"supsub",mode:s.mode,base:h,sup:a==="\\underset"?null:s,sub:a==="\\underset"?s:null};return{type:"mclass",mode:t.mode,mclass:u,body:[c],isCharacterBox:D0(c)}},htmlBuilder:n1,mathmlBuilder:s1});B({type:"pmb",names:["\\pmb"],props:{numArgs:1,allowedInText:!0},handler(r,e){var{parser:t}=r;return{type:"pmb",mode:t.mode,mclass:Ve(e[0]),body:_(e[0])}},htmlBuilder(r,e){var t=a0(r.body,e,!0),a=k([r.mclass],t,e);return a.style.textShadow="0.02em 0.01em 0.04px",a},mathmlBuilder(r,e){var t=v0(r.body,e),a=new z("mstyle",t);return a.setAttribute("style","text-shadow: 0.02em 0.01em 0.04px"),a}});var e4={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},yr=()=>({type:"styling",body:[],mode:"math",style:"display",resetFont:!0}),xr=r=>r.type==="textord"&&r.text==="@",t4=(r,e)=>(r.type==="mathord"||r.type==="atom")&&r.text===e;function r4(r,e,t){var a=e4[r];switch(a){case"\\\\cdrightarrow":case"\\\\cdleftarrow":return t.callFunction(a,[e[0]],[e[1]]);case"\\uparrow":case"\\downarrow":{var i=t.callFunction("\\\\cdleft",[e[0]],[]),s={type:"atom",text:a,mode:"math",family:"rel"},u=t.callFunction("\\Big",[s],[]),h=t.callFunction("\\\\cdright",[e[1]],[]),c={type:"ordgroup",mode:"math",body:[i,u,h]};return t.callFunction("\\\\cdparent",[c],[])}case"\\\\cdlongequal":return t.callFunction("\\\\cdlongequal",[],[]);case"\\Vert":{var v={type:"textord",text:"\\Vert",mode:"math"};return t.callFunction("\\Big",[v],[])}default:return{type:"textord",text:" ",mode:"math"}}}function a4(r){var e=[];for(r.gullet.beginGroup(),r.gullet.macros.set("\\cr","\\\\\\relax"),r.gullet.beginGroup();;){e.push(r.parseExpression(!1,"\\\\")),r.gullet.endGroup(),r.gullet.beginGroup();var t=r.fetch().text;if(t==="&"||t==="\\\\")r.consume();else if(t==="\\end"){e[e.length-1].length===0&&e.pop();break}else throw new S("Expected \\\\ or \\cr or \\end",r.nextToken)}for(var a=[],i=[a],s=0;sAV".includes(v))for(var b=0;b<2;b++){for(var x=!0,y=c+1;yAV=|." after @',u[c]);var T=r4(v,p,r),M={type:"styling",body:[T],mode:"math",style:"display",resetFont:!0};a.push(M),h=yr()}s%2===0?a.push(h):a.shift(),a=[],i.push(a)}r.gullet.endGroup(),r.gullet.endGroup();var q=new Array(i[0].length).fill({type:"align",align:"c",pregap:.25,postgap:.25});return{type:"array",mode:"math",body:i,arraystretch:1,addJot:!0,rowGaps:[null],cols:q,colSeparationType:"CD",hLinesBeforeRow:new Array(i.length+1).fill([])}}B({type:"cdlabel",names:["\\\\cdleft","\\\\cdright"],props:{numArgs:1},handler(r,e){var{parser:t,funcName:a}=r;return{type:"cdlabel",mode:t.mode,side:a.slice(4),label:e[0]}},htmlBuilder(r,e){var t=e.havingStyle(e.style.sup()),a=re(X(r.label,t,e),e);return a.classes.push("cd-label-"+r.side),a.style.bottom=A(.8-a.depth),a.height=0,a.depth=0,a},mathmlBuilder(r,e){var t=new z("mrow",[$(r.label,e)]);return t=new z("mpadded",[t]),t.setAttribute("width","0"),r.side==="left"&&t.setAttribute("lspace","-1width"),t.setAttribute("voffset","0.7em"),t=new z("mstyle",[t]),t.setAttribute("displaystyle","false"),t.setAttribute("scriptlevel","1"),t}});B({type:"cdlabelparent",names:["\\\\cdparent"],props:{numArgs:1},handler(r,e){var{parser:t}=r;return{type:"cdlabelparent",mode:t.mode,fragment:e[0]}},htmlBuilder(r,e){var t=re(X(r.fragment,e),e);return t.classes.push("cd-vert-arrow"),t},mathmlBuilder(r,e){return new z("mrow",[$(r.fragment,e)])}});B({type:"textord",names:["\\@char"],props:{numArgs:1,allowedInText:!0},handler(r,e){for(var{parser:t}=r,a=H(e[0],"ordgroup"),i=a.body,s="",u=0;u=1114111)throw new S("\\@char with invalid code point "+s);return c<=65535?v=String.fromCharCode(c):(c-=65536,v=String.fromCharCode((c>>10)+55296,(c&1023)+56320)),{type:"textord",mode:t.mode,text:v}}});var l1=(r,e)=>{var t=a0(r.body,e.withColor(r.color),!1);return E0(t)},u1=(r,e)=>{var t=v0(r.body,e.withColor(r.color)),a=new z("mstyle",t);return a.setAttribute("mathcolor",r.color),a};B({type:"color",names:["\\textcolor"],props:{numArgs:2,allowedInText:!0,argTypes:["color","original"]},handler(r,e){var{parser:t}=r,a=H(e[0],"color-token").color,i=e[1];return{type:"color",mode:t.mode,color:a,body:_(i)}},htmlBuilder:l1,mathmlBuilder:u1});B({type:"color",names:["\\color"],props:{numArgs:1,allowedInText:!0,argTypes:["color"]},handler(r,e){var{parser:t,breakOnTokenText:a}=r,i=H(e[0],"color-token").color;t.gullet.macros.set("\\current@color",i);var s=t.parseExpression(!0,a);return{type:"color",mode:t.mode,color:i,body:s}},htmlBuilder:l1,mathmlBuilder:u1});B({type:"cr",names:["\\\\"],props:{numArgs:0,numOptionalArgs:0,allowedInText:!0},handler(r,e,t){var{parser:a}=r,i=a.gullet.future().text==="["?a.parseSizeGroup(!0):null,s=!a.settings.displayMode||!a.settings.useStrictBehavior("newLineInDisplayMode","In LaTeX, \\\\ or \\newline does nothing in display mode");return{type:"cr",mode:a.mode,newLine:s,size:i&&H(i,"size").value}},htmlBuilder(r,e){var t=k(["mspace"],[],e);return r.newLine&&(t.classes.push("newline"),r.size&&(t.style.marginTop=A(K(r.size,e)))),t},mathmlBuilder(r,e){var t=new z("mspace");return r.newLine&&(t.setAttribute("linebreak","newline"),r.size&&t.setAttribute("height",A(K(r.size,e)))),t}});var Tt={"\\global":"\\global","\\long":"\\\\globallong","\\\\globallong":"\\\\globallong","\\def":"\\gdef","\\gdef":"\\gdef","\\edef":"\\xdef","\\xdef":"\\xdef","\\let":"\\\\globallet","\\futurelet":"\\\\globalfuture"},o1=r=>{var e=r.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(e))throw new S("Expected a control sequence",r);return e},i4=r=>{var e=r.gullet.popToken();return e.text==="="&&(e=r.gullet.popToken(),e.text===" "&&(e=r.gullet.popToken())),e},h1=(r,e,t,a)=>{var i=r.gullet.macros.get(t.text);i==null&&(t.noexpand=!0,i={tokens:[t],numArgs:0,unexpandable:!r.gullet.isExpandable(t.text)}),r.gullet.macros.set(e,i,a)};B({type:"internal",names:["\\global","\\long","\\\\globallong"],props:{numArgs:0,allowedInText:!0},handler(r){var{parser:e,funcName:t}=r;e.consumeSpaces();var a=e.fetch();if(Tt[a.text])return(t==="\\global"||t==="\\\\globallong")&&(a.text=Tt[a.text]),H(e.parseFunction(),"internal");throw new S("Invalid token after macro prefix",a)}});B({type:"internal",names:["\\def","\\gdef","\\edef","\\xdef"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(r){var{parser:e,funcName:t}=r,a=e.gullet.popToken(),i=a.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(i))throw new S("Expected a control sequence",a);for(var s=0,u,h=[[]];e.gullet.future().text!=="{";)if(a=e.gullet.popToken(),a.text==="#"){if(e.gullet.future().text==="{"){u=e.gullet.future(),h[s].push("{");break}if(a=e.gullet.popToken(),!/^[1-9]$/.test(a.text))throw new S('Invalid argument number "'+a.text+'"');if(parseInt(a.text)!==s+1)throw new S('Argument number "'+a.text+'" out of order');s++,h.push([])}else{if(a.text==="EOF")throw new S("Expected a macro definition");h[s].push(a.text)}var{tokens:c}=e.gullet.consumeArg();return u&&c.unshift(u),(t==="\\edef"||t==="\\xdef")&&(c=e.gullet.expandTokens(c),c.reverse()),e.gullet.macros.set(i,{tokens:c,numArgs:s,delimiters:h},t===Tt[t]),{type:"internal",mode:e.mode}}});B({type:"internal",names:["\\let","\\\\globallet"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(r){var{parser:e,funcName:t}=r,a=o1(e.gullet.popToken());e.gullet.consumeSpaces();var i=i4(e);return h1(e,a,i,t==="\\\\globallet"),{type:"internal",mode:e.mode}}});B({type:"internal",names:["\\futurelet","\\\\globalfuture"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(r){var{parser:e,funcName:t}=r,a=o1(e.gullet.popToken()),i=e.gullet.popToken(),s=e.gullet.popToken();return h1(e,a,s,t==="\\\\globalfuture"),e.gullet.pushToken(s),e.gullet.pushToken(i),{type:"internal",mode:e.mode}}});var oe=function(e,t,a){var i=W.math[e]&&W.math[e].replace,s=Nt(i||e,t,a);if(!s)throw new Error("Unsupported symbol "+e+" and font size "+t+".");return s},Gt=function(e,t,a,i){var s=a.havingBaseStyle(t),u=k(i.concat(s.sizingClasses(a)),[e],a),h=s.sizeMultiplier/a.sizeMultiplier;return u.height*=h,u.depth*=h,u.maxFontSize=s.sizeMultiplier,u},m1=function(e,t,a){var i=t.havingBaseStyle(a),s=(1-t.sizeMultiplier/i.sizeMultiplier)*t.fontMetrics().axisHeight;e.classes.push("delimcenter"),e.style.top=A(s),e.height-=s,e.depth+=s},n4=function(e,t,a,i,s,u){var h=s0(e,"Main-Regular",s,i),c=Gt(h,t,i,u);return m1(c,i,t),c},s4=function(e,t,a,i){return s0(e,"Size"+t+"-Regular",a,i)},c1=function(e,t,a,i,s,u){var h=s4(e,t,s,i),c=Gt(k(["delimsizing","size"+t],[h],i),N.TEXT,i,u);return a&&m1(c,i,N.TEXT),c},at=function(e,t,a){var i;t==="Size1-Regular"?i="delim-size1":i="delim-size4";var s=k(["delimsizinginner",i],[k([],[s0(e,t,a)])]);return{type:"elem",elem:s}},it=function(e,t,a){var i=k0["Size4-Regular"][e.charCodeAt(0)]?k0["Size4-Regular"][e.charCodeAt(0)][4]:k0["Size1-Regular"][e.charCodeAt(0)][4],s=new P0("inner",va(e,Math.round(1e3*t))),u=new C0([s],{width:A(i),height:A(t),style:"width:"+A(i),viewBox:"0 0 "+1e3*i+" "+Math.round(1e3*t),preserveAspectRatio:"xMinYMin"}),h=G0([],[u],a);return h.height=t,h.style.height=A(t),h.style.width=A(i),{type:"elem",elem:h}},Bt=.008,Te={type:"kern",size:-1*Bt},l4=new Set(["|","\\lvert","\\rvert","\\vert"]),u4=new Set(["\\|","\\lVert","\\rVert","\\Vert"]),d1=function(e,t,a,i,s,u){var h,c,v,p,b="",x=0;h=v=p=e,c=null;var y="Size1-Regular";e==="\\uparrow"?v=p="⏐":e==="\\Uparrow"?v=p="‖":e==="\\downarrow"?h=v="⏐":e==="\\Downarrow"?h=v="‖":e==="\\updownarrow"?(h="\\uparrow",v="⏐",p="\\downarrow"):e==="\\Updownarrow"?(h="\\Uparrow",v="‖",p="\\Downarrow"):l4.has(e)?(v="∣",b="vert",x=333):u4.has(e)?(v="∥",b="doublevert",x=556):e==="["||e==="\\lbrack"?(h="⎡",v="⎢",p="⎣",y="Size4-Regular",b="lbrack",x=667):e==="]"||e==="\\rbrack"?(h="⎤",v="⎥",p="⎦",y="Size4-Regular",b="rbrack",x=667):e==="\\lfloor"||e==="⌊"?(v=h="⎢",p="⎣",y="Size4-Regular",b="lfloor",x=667):e==="\\lceil"||e==="⌈"?(h="⎡",v=p="⎢",y="Size4-Regular",b="lceil",x=667):e==="\\rfloor"||e==="⌋"?(v=h="⎥",p="⎦",y="Size4-Regular",b="rfloor",x=667):e==="\\rceil"||e==="⌉"?(h="⎤",v=p="⎥",y="Size4-Regular",b="rceil",x=667):e==="("||e==="\\lparen"?(h="⎛",v="⎜",p="⎝",y="Size4-Regular",b="lparen",x=875):e===")"||e==="\\rparen"?(h="⎞",v="⎟",p="⎠",y="Size4-Regular",b="rparen",x=875):e==="\\{"||e==="\\lbrace"?(h="⎧",c="⎨",p="⎩",v="⎪",y="Size4-Regular"):e==="\\}"||e==="\\rbrace"?(h="⎫",c="⎬",p="⎭",v="⎪",y="Size4-Regular"):e==="\\lgroup"||e==="⟮"?(h="⎧",p="⎩",v="⎪",y="Size4-Regular"):e==="\\rgroup"||e==="⟯"?(h="⎫",p="⎭",v="⎪",y="Size4-Regular"):e==="\\lmoustache"||e==="⎰"?(h="⎧",p="⎭",v="⎪",y="Size4-Regular"):(e==="\\rmoustache"||e==="⎱")&&(h="⎫",p="⎩",v="⎪",y="Size4-Regular");var T=oe(h,y,s),M=T.height+T.depth,q=oe(v,y,s),C=q.height+q.depth,R=oe(p,y,s),F=R.height+R.depth,L=0,O=1;if(c!==null){var P=oe(c,y,s);L=P.height+P.depth,O=2}var G=M+F+L,Y=Math.max(0,Math.ceil((t-G)/(O*C))),U=G+Y*O*C,o0=i.fontMetrics().axisHeight;a&&(o0*=i.sizeMultiplier);var m0=U/2-o0,Q=[];if(b.length>0){var le=U-M-F,x0=Math.round(U*1e3),b0=pa(b,Math.round(le*1e3)),R0=new P0(b,b0),j0=A(x/1e3),Z0=A(x0/1e3),Ze=new C0([R0],{width:j0,height:Z0,viewBox:"0 0 "+x+" "+x0}),I0=G0([],[Ze],i);I0.height=x0/1e3,I0.style.width=j0,I0.style.height=Z0,Q.push({type:"elem",elem:I0})}else{if(Q.push(at(p,y,s)),Q.push(Te),c===null){var N0=U-M-F+2*Bt;Q.push(it(v,N0,i))}else{var ue=(U-M-F-L)/2+2*Bt;Q.push(it(v,ue,i)),Q.push(Te),Q.push(at(c,y,s)),Q.push(Te),Q.push(it(v,ue,i))}Q.push(Te),Q.push(at(h,y,s))}var y0=i.havingBaseStyle(N.TEXT),ve=V({positionType:"bottom",positionData:m0,children:Q});return Gt(k(["delimsizing","mult"],[ve],y0),N.TEXT,i,u)},nt=80,st=.08,lt=function(e,t,a,i,s){var u=fa(e,i,a),h=new P0(e,u),c=new C0([h],{width:"400em",height:A(t),viewBox:"0 0 400000 "+a,preserveAspectRatio:"xMinYMin slice"});return G0(["hide-tail"],[c],s)},o4=function(e,t){var a=t.havingBaseSizing(),i=b1("\\surd",e*a.sizeMultiplier,g1,a),s=a.sizeMultiplier,u=Math.max(0,t.minRuleThickness-t.fontMetrics().sqrtRuleThickness),h,c,v,p,b;return i.type==="small"?(p=1e3+1e3*u+nt,e<1?s=1:e<1.4&&(s=.7),c=(1+u+st)/s,v=(1+u)/s,h=lt("sqrtMain",c,p,u,t),h.style.minWidth="0.853em",b=.833/s):i.type==="large"?(p=(1e3+nt)*he[i.size],v=(he[i.size]+u)/s,c=(he[i.size]+u+st)/s,h=lt("sqrtSize"+i.size,c,p,u,t),h.style.minWidth="1.02em",b=1/s):(c=e+u+st,v=e+u,p=Math.floor(1e3*e+u)+nt,h=lt("sqrtTall",c,p,u,t),h.style.minWidth="0.742em",b=1.056),h.height=v,h.style.height=A(c),{span:h,advanceWidth:b,ruleWidth:(t.fontMetrics().sqrtRuleThickness+u)*s}},f1=new Set(["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","\\surd"]),h4=new Set(["\\uparrow","\\downarrow","\\updownarrow","\\Uparrow","\\Downarrow","\\Updownarrow","|","\\|","\\vert","\\Vert","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱"]),v1=new Set(["<",">","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"]),he=[0,1.2,1.8,2.4,3],p1=function(e,t,a,i,s){if(e==="<"||e==="\\lt"||e==="⟨"?e="\\langle":(e===">"||e==="\\gt"||e==="⟩")&&(e="\\rangle"),f1.has(e)||v1.has(e))return c1(e,t,!1,a,i,s);if(h4.has(e))return d1(e,he[t],!1,a,i,s);throw new S("Illegal delimiter: '"+e+"'")},m4=[{type:"small",style:N.SCRIPTSCRIPT},{type:"small",style:N.SCRIPT},{type:"small",style:N.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],c4=[{type:"small",style:N.SCRIPTSCRIPT},{type:"small",style:N.SCRIPT},{type:"small",style:N.TEXT},{type:"stack"}],g1=[{type:"small",style:N.SCRIPTSCRIPT},{type:"small",style:N.SCRIPT},{type:"small",style:N.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],d4=function(e){if(e.type==="small")return"Main-Regular";if(e.type==="large")return"Size"+e.size+"-Regular";if(e.type==="stack")return"Size4-Regular";var t=e.type;throw new Error("Add support for delim type '"+t+"' here.")},b1=function(e,t,a,i){for(var s=Math.min(2,3-i.style.size),u=s;ut)return h}return a[a.length-1]},Ct=function(e,t,a,i,s,u){e==="<"||e==="\\lt"||e==="⟨"?e="\\langle":(e===">"||e==="\\gt"||e==="⟩")&&(e="\\rangle");var h;v1.has(e)?h=m4:f1.has(e)?h=g1:h=c4;var c=b1(e,t,h,i);return c.type==="small"?n4(e,c.style,a,i,s,u):c.type==="large"?c1(e,c.size,a,i,s,u):d1(e,t,a,i,s,u)},ut=function(e,t,a,i,s,u){var h=i.fontMetrics().axisHeight*i.sizeMultiplier,c=901,v=5/i.fontMetrics().ptPerEm,p=Math.max(t-h,a+h),b=Math.max(p/500*c,2*p-v);return Ct(e,b,!0,i,s,u)},wr={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},f4=new Set(["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","<",">","\\langle","⟨","\\rangle","⟩","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."]);function kr(r){return"isMiddle"in r}function Xe(r,e){var t=Ue(r);if(t&&f4.has(t.text))return t;throw t?new S("Invalid delimiter '"+t.text+"' after '"+e.funcName+"'",r):new S("Invalid delimiter type '"+r.type+"'",r)}B({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],props:{numArgs:1,argTypes:["primitive"]},handler:(r,e)=>{var t=Xe(e[0],r);return{type:"delimsizing",mode:r.parser.mode,size:wr[r.funcName].size,mclass:wr[r.funcName].mclass,delim:t.text}},htmlBuilder:(r,e)=>r.delim==="."?k([r.mclass]):p1(r.delim,r.size,e,r.mode,[r.mclass]),mathmlBuilder:r=>{var e=[];r.delim!=="."&&e.push(g0(r.delim,r.mode));var t=new z("mo",e);r.mclass==="mopen"||r.mclass==="mclose"?t.setAttribute("fence","true"):t.setAttribute("fence","false"),t.setAttribute("stretchy","true");var a=A(he[r.size]);return t.setAttribute("minsize",a),t.setAttribute("maxsize",a),t}});function Sr(r){if(!r.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}B({type:"leftright-right",names:["\\right"],props:{numArgs:1,primitive:!0},handler:(r,e)=>{var t=r.parser.gullet.macros.get("\\current@color");if(t&&typeof t!="string")throw new S("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:r.parser.mode,delim:Xe(e[0],r).text,color:t}}});B({type:"leftright",names:["\\left"],props:{numArgs:1,primitive:!0},handler:(r,e)=>{var t=Xe(e[0],r),a=r.parser;++a.leftrightDepth;var i=a.parseExpression(!1);--a.leftrightDepth,a.expect("\\right",!1);var s=H(a.parseFunction(),"leftright-right");return{type:"leftright",mode:a.mode,body:i,left:t.text,right:s.delim,rightColor:s.color}},htmlBuilder:(r,e)=>{Sr(r);for(var t=a0(r.body,e,!0,["mopen","mclose"]),a=0,i=0,s=!1,u=0;u{Sr(r);var t=v0(r.body,e);if(r.left!=="."){var a=new z("mo",[g0(r.left,r.mode)]);a.setAttribute("fence","true"),t.unshift(a)}if(r.right!=="."){var i=new z("mo",[g0(r.right,r.mode)]);i.setAttribute("fence","true"),r.rightColor&&i.setAttribute("mathcolor",r.rightColor),t.push(i)}return Ot(t)}});B({type:"middle",names:["\\middle"],props:{numArgs:1,primitive:!0},handler:(r,e)=>{var t=Xe(e[0],r);if(!r.parser.leftrightDepth)throw new S("\\middle without preceding \\left",t);return{type:"middle",mode:r.parser.mode,delim:t.text}},htmlBuilder:(r,e)=>{var t;return r.delim==="."?t=ce(e,[]):(t=p1(r.delim,1,e,r.mode,[]),t.isMiddle={delim:r.delim,options:e}),t},mathmlBuilder:(r,e)=>{var t=r.delim==="\\vert"||r.delim==="|"?g0("|","text"):g0(r.delim,r.mode),a=new z("mo",[t]);return a.setAttribute("fence","true"),a.setAttribute("lspace","0.05em"),a.setAttribute("rspace","0.05em"),a}});var Ye=(r,e)=>{var t=re(X(r.body,e),e),a=r.label.slice(1),i=e.sizeMultiplier,s,u,h=D0(r.body);if(a==="sout")s=k(["stretchy","sout"]),s.height=e.fontMetrics().defaultRuleThickness/i,u=-.5*e.fontMetrics().xHeight;else if(a==="phase"){var c=K({number:.6,unit:"pt"},e),v=K({number:.35,unit:"ex"},e),p=e.havingBaseSizing();i=i/p.sizeMultiplier;var b=t.height+t.depth+c+v;t.style.paddingLeft=A(b/2+c);var x=Math.floor(1e3*b*i),y=ca(x),T=new C0([new P0("phase",y)],{width:"400em",height:A(x/1e3),viewBox:"0 0 400000 "+x,preserveAspectRatio:"xMinYMin slice"});s=G0(["hide-tail"],[T],e),s.style.height=A(b),u=t.depth+c+v}else{/cancel/.test(a)?h||t.classes.push("cancel-pad"):a==="angl"?t.classes.push("anglpad"):t.classes.push("boxpad");var M,q,C=0;/box/.test(a)?(C=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness),M=e.fontMetrics().fboxsep+(a==="colorbox"?0:C),q=M):a==="angl"?(C=Math.max(e.fontMetrics().defaultRuleThickness,e.minRuleThickness),M=4*C,q=Math.max(0,.25-t.depth)):(M=h?.2:0,q=M),s=Za(t,a,M,q,e),/fbox|boxed|fcolorbox/.test(a)?(s.style.borderStyle="solid",s.style.borderWidth=A(C)):a==="angl"&&C!==.049&&(s.style.borderTopWidth=A(C),s.style.borderRightWidth=A(C)),u=t.depth+q,r.backgroundColor&&(s.style.backgroundColor=r.backgroundColor,r.borderColor&&(s.style.borderColor=r.borderColor))}var R;if(r.backgroundColor)R=V({positionType:"individualShift",children:[{type:"elem",elem:s,shift:u},{type:"elem",elem:t,shift:0}]});else{var F=/cancel|phase/.test(a)?["svg-align"]:[];R=V({positionType:"individualShift",children:[{type:"elem",elem:t,shift:0},{type:"elem",elem:s,shift:u,wrapperClasses:F}]})}return/cancel/.test(a)&&(R.height=t.height,R.depth=t.depth),/cancel/.test(a)&&!h?k(["mord","cancel-lap"],[R],e):k(["mord"],[R],e)},$e=(r,e)=>{var t,a=new z(r.label.includes("colorbox")?"mpadded":"menclose",[$(r.body,e)]);switch(r.label){case"\\cancel":a.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":a.setAttribute("notation","downdiagonalstrike");break;case"\\phase":a.setAttribute("notation","phasorangle");break;case"\\sout":a.setAttribute("notation","horizontalstrike");break;case"\\fbox":a.setAttribute("notation","box");break;case"\\angl":a.setAttribute("notation","actuarial");break;case"\\fcolorbox":case"\\colorbox":if(t=e.fontMetrics().fboxsep*e.fontMetrics().ptPerEm,a.setAttribute("width","+"+2*t+"pt"),a.setAttribute("height","+"+2*t+"pt"),a.setAttribute("lspace",t+"pt"),a.setAttribute("voffset",t+"pt"),r.label==="\\fcolorbox"){var i=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness);a.setAttribute("style","border: "+A(i)+" solid "+r.borderColor)}break;case"\\xcancel":a.setAttribute("notation","updiagonalstrike downdiagonalstrike");break}return r.backgroundColor&&a.setAttribute("mathbackground",r.backgroundColor),a};B({type:"enclose",names:["\\colorbox"],props:{numArgs:2,allowedInText:!0,argTypes:["color","hbox"]},handler(r,e,t){var{parser:a,funcName:i}=r,s=H(e[0],"color-token").color,u=e[1];return{type:"enclose",mode:a.mode,label:i,backgroundColor:s,body:u}},htmlBuilder:Ye,mathmlBuilder:$e});B({type:"enclose",names:["\\fcolorbox"],props:{numArgs:3,allowedInText:!0,argTypes:["color","color","hbox"]},handler(r,e,t){var{parser:a,funcName:i}=r,s=H(e[0],"color-token").color,u=H(e[1],"color-token").color,h=e[2];return{type:"enclose",mode:a.mode,label:i,backgroundColor:u,borderColor:s,body:h}},htmlBuilder:Ye,mathmlBuilder:$e});B({type:"enclose",names:["\\fbox"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!0},handler(r,e){var{parser:t}=r;return{type:"enclose",mode:t.mode,label:"\\fbox",body:e[0]}}});B({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\phase"],props:{numArgs:1},handler(r,e){var{parser:t,funcName:a}=r,i=e[0];return{type:"enclose",mode:t.mode,label:a,body:i}},htmlBuilder:Ye,mathmlBuilder:$e});B({type:"enclose",names:["\\sout"],props:{numArgs:1,allowedInText:!0},handler(r,e){var{parser:t,funcName:a}=r;t.mode==="math"&&t.settings.reportNonstrict("mathVsSout","LaTeX's \\sout works only in text mode");var i=e[0];return{type:"enclose",mode:t.mode,label:a,body:i}},htmlBuilder:Ye,mathmlBuilder:$e});B({type:"enclose",names:["\\angl"],props:{numArgs:1,argTypes:["hbox"],allowedInText:!1},handler(r,e){var{parser:t}=r;return{type:"enclose",mode:t.mode,label:"\\angl",body:e[0]}}});var y1={};function S0(r){for(var{type:e,names:t,props:a,handler:i,htmlBuilder:s,mathmlBuilder:u}=r,h={type:e,numArgs:a.numArgs||0,allowedInText:!1,numOptionalArgs:0,handler:i},c=0;c{var e=r.parser.settings;if(!e.displayMode)throw new S("{"+r.envName+"} can be used only in display mode.")},v4=new Set(["gather","gather*"]);function Ut(r){if(!r.includes("ed"))return!r.includes("*")}function V0(r,e,t){var{hskipBeforeAndAfter:a,addJot:i,cols:s,arraystretch:u,colSeparationType:h,autoTag:c,singleRow:v,emptySingleRow:p,maxNumCols:b,leqno:x}=e;if(r.gullet.beginGroup(),v||r.gullet.macros.set("\\cr","\\\\\\relax"),!u){var y=r.gullet.expandMacroAsText("\\arraystretch");if(y==null)u=1;else if(u=parseFloat(y),!u||u<0)throw new S("Invalid \\arraystretch: "+y)}r.gullet.beginGroup();var T=[],M=[T],q=[],C=[],R=c!=null?[]:void 0;function F(){c&&r.gullet.macros.set("\\@eqnsw","1",!0)}function L(){R&&(r.gullet.macros.get("\\df@tag")?(R.push(r.subparse([new c0("\\df@tag")])),r.gullet.macros.set("\\df@tag",void 0,!0)):R.push(!!c&&r.gullet.macros.get("\\@eqnsw")==="1"))}for(F(),C.push(zr(r));;){var O=r.parseExpression(!1,v?"\\end":"\\\\");r.gullet.endGroup(),r.gullet.beginGroup();var P={type:"ordgroup",mode:r.mode,body:O};t&&(P={type:"styling",mode:r.mode,style:t,resetFont:!0,body:[P]}),T.push(P);var G=r.fetch().text;if(G==="&"){if(b&&T.length===b){if(v||h)throw new S("Too many tab characters: &",r.nextToken);r.settings.reportNonstrict("textEnv","Too few columns specified in the {array} column argument.")}r.consume()}else if(G==="\\end"){L(),T.length===1&&P.type==="styling"&&P.body.length===1&&P.body[0].type==="ordgroup"&&P.body[0].body.length===0&&(M.length>1||!p)&&M.pop(),C.length0&&(F+=.25),v.push({pos:F,isDashed:ye[xe]})}for(L(u[0]),a=0;a0&&(m0+=R,Gye))for(a=0;a=h)){var J0=void 0;if(i>0||e.hskipBeforeAndAfter){var Kt,Jt;J0=(Kt=(Jt=y0)==null?void 0:Jt.pregap)!=null?Kt:x,J0!==0&&(b0=k(["arraycolsep"],[]),b0.style.width=A(J0),x0.push(b0))}var Qt=[];for(a=0;a0){for(var G1=te("hline",t,p),U1=te("hdashline",t,p),Ke=[{type:"elem",elem:be,shift:0}];v.length>0;){var tr=v.pop(),rr=tr.pos-Q;tr.isDashed?Ke.push({type:"elem",elem:U1,shift:rr}):Ke.push({type:"elem",elem:G1,shift:rr})}be=V({positionType:"individualShift",children:Ke})}if(j0.length===0)return k(["mord"],[be],t);var V1=V({positionType:"individualShift",children:j0}),X1=k(["tag"],[V1],t);return E0([be,X1])},p4={c:"center ",l:"left ",r:"right "},A0=function(e,t){for(var a=[],i=new z("mtd",[],["mtr-glue"]),s=new z("mtd",[],["mml-eqn-num"]),u=0;u0){var T=e.cols,M="",q=!1,C=0,R=T.length;T[0].type==="separator"&&(x+="top ",C=1),T[T.length-1].type==="separator"&&(x+="bottom ",R-=1);for(var F=C;F0?"left ":"",x+=U[U.length-1].length>0?"right ":"";for(var o0=1;o00&&y&&(q=1),a[T]={type:"align",align:M,pregap:q,postgap:0}}return u.colSeparationType=y?"align":"alignat",u};S0({type:"array",names:["array","darray"],props:{numArgs:1},handler(r,e){var t=Ue(e[0]),a=t?[e[0]]:H(e[0],"ordgroup").body,i=a.map(function(u){var h=Ge(u),c=h.text;if("lcr".includes(c))return{type:"align",align:c};if(c==="|")return{type:"separator",separator:"|"};if(c===":")return{type:"separator",separator:":"};throw new S("Unknown column alignment: "+c,u)}),s={cols:i,hskipBeforeAndAfter:!0,maxNumCols:i.length};return V0(r.parser,s,Vt(r.envName))},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix","matrix*","pmatrix*","bmatrix*","Bmatrix*","vmatrix*","Vmatrix*"],props:{numArgs:0},handler(r){var e={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[r.envName.replace("*","")],t="c",a={hskipBeforeAndAfter:!1,cols:[{type:"align",align:t}]};if(r.envName.charAt(r.envName.length-1)==="*"){var i=r.parser;if(i.consumeSpaces(),i.fetch().text==="["){if(i.consume(),i.consumeSpaces(),t=i.fetch().text,!"lcr".includes(t))throw new S("Expected l or c or r",i.nextToken);i.consume(),i.consumeSpaces(),i.expect("]"),i.consume(),a.cols=[{type:"align",align:t}]}}var s=V0(r.parser,a,Vt(r.envName)),u=Math.max(0,...s.body.map(h=>h.length));return s.cols=new Array(u).fill({type:"align",align:t}),e?{type:"leftright",mode:r.mode,body:[s],left:e[0],right:e[1],rightColor:void 0}:s},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["smallmatrix"],props:{numArgs:0},handler(r){var e={arraystretch:.5},t=V0(r.parser,e,"script");return t.colSeparationType="small",t},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["subarray"],props:{numArgs:1},handler(r,e){var t=Ue(e[0]),a=t?[e[0]]:H(e[0],"ordgroup").body,i=a.map(function(h){var c=Ge(h),v=c.text;if("lc".includes(v))return{type:"align",align:v};throw new S("Unknown column alignment: "+v,h)});if(i.length>1)throw new S("{subarray} can contain only one column");var s={cols:i,hskipBeforeAndAfter:!1,arraystretch:.5},u=V0(r.parser,s,"script");if(u.body.length>0&&u.body[0].length>1)throw new S("{subarray} can contain only one column");return u},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler(r){var e={arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},t=V0(r.parser,e,Vt(r.envName));return{type:"leftright",mode:r.mode,body:[t],left:r.envName.includes("r")?".":"\\{",right:r.envName.includes("r")?"\\}":".",rightColor:void 0}},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:w1,htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler(r){v4.has(r.envName)&&We(r);var e={cols:[{type:"align",align:"c"}],addJot:!0,colSeparationType:"gather",autoTag:Ut(r.envName),emptySingleRow:!0,leqno:r.parser.settings.leqno};return V0(r.parser,e,"display")},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:w1,htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["equation","equation*"],props:{numArgs:0},handler(r){We(r);var e={autoTag:Ut(r.envName),emptySingleRow:!0,singleRow:!0,maxNumCols:1,leqno:r.parser.settings.leqno};return V0(r.parser,e,"display")},htmlBuilder:z0,mathmlBuilder:A0});S0({type:"array",names:["CD"],props:{numArgs:0},handler(r){return We(r),a4(r.parser)},htmlBuilder:z0,mathmlBuilder:A0});m("\\nonumber","\\gdef\\@eqnsw{0}");m("\\notag","\\nonumber");B({type:"text",names:["\\hline","\\hdashline"],props:{numArgs:0,allowedInText:!0,allowedInMath:!0},handler(r,e){throw new S(r.funcName+" valid only within array environment")}});var Ar=y1;B({type:"environment",names:["\\begin","\\end"],props:{numArgs:1,argTypes:["text"]},handler(r,e){var{parser:t,funcName:a}=r,i=e[0];if(i.type!=="ordgroup")throw new S("Invalid environment name",i);for(var s="",u=0;u{var t=r.font,a=e.withFont(t);return X(r.body,a)},S1=(r,e)=>{var t=r.font,a=e.withFont(t);return $(r.body,a)},Mr={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak"};B({type:"font",names:["\\mathrm","\\mathit","\\mathbf","\\mathnormal","\\mathsfit","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],props:{numArgs:1,allowedInArgument:!0},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=Ne(e[0]),s=a;return s in Mr&&(s=Mr[s]),{type:"font",mode:t.mode,font:s.slice(1),body:i}},htmlBuilder:k1,mathmlBuilder:S1});B({type:"mclass",names:["\\boldsymbol","\\bm"],props:{numArgs:1},handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"mclass",mode:t.mode,mclass:Ve(a),body:[{type:"font",mode:t.mode,font:"boldsymbol",body:a}],isCharacterBox:D0(a)}}});B({type:"font",names:["\\rm","\\sf","\\tt","\\bf","\\it","\\cal"],props:{numArgs:0,allowedInText:!0},handler:(r,e)=>{var{parser:t,funcName:a,breakOnTokenText:i}=r,{mode:s}=t,u=t.parseExpression(!0,i);return{type:"font",mode:s,font:"math"+a.slice(1),body:{type:"ordgroup",mode:t.mode,body:u}}},htmlBuilder:k1,mathmlBuilder:S1});var g4=(r,e)=>{var t=e.style,a=t.fracNum(),i=t.fracDen(),s;s=e.havingStyle(a);var u=X(r.numer,s,e);if(r.continued){var h=8.5/e.fontMetrics().ptPerEm,c=3.5/e.fontMetrics().ptPerEm;u.height=u.height0?T=3*x:T=7*x,M=e.fontMetrics().denom1):(b>0?(y=e.fontMetrics().num2,T=x):(y=e.fontMetrics().num3,T=3*x),M=e.fontMetrics().denom2);var q;if(p){var R=e.fontMetrics().axisHeight;y-u.depth-(R+.5*b){var t=new z("mfrac",[$(r.numer,e),$(r.denom,e)]);if(!r.hasBarLine)t.setAttribute("linethickness","0px");else if(r.barSize){var a=K(r.barSize,e);t.setAttribute("linethickness",A(a))}if(r.leftDelim!=null||r.rightDelim!=null){var i=[];if(r.leftDelim!=null){var s=new z("mo",[new e0(r.leftDelim.replace("\\",""))]);s.setAttribute("fence","true"),i.push(s)}if(i.push(t),r.rightDelim!=null){var u=new z("mo",[new e0(r.rightDelim.replace("\\",""))]);u.setAttribute("fence","true"),i.push(u)}return Ot(i)}return t},z1=(r,e)=>{if(!e)return r;var t={type:"styling",mode:r.mode,style:e,body:[r]};return t};B({type:"genfrac",names:["\\cfrac","\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac","\\\\bracefrac","\\\\brackfrac"],props:{numArgs:2,allowedInArgument:!0},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=e[0],s=e[1],u,h=null,c=null;switch(a){case"\\cfrac":case"\\dfrac":case"\\frac":case"\\tfrac":u=!0;break;case"\\\\atopfrac":u=!1;break;case"\\dbinom":case"\\binom":case"\\tbinom":u=!1,h="(",c=")";break;case"\\\\bracefrac":u=!1,h="\\{",c="\\}";break;case"\\\\brackfrac":u=!1,h="[",c="]";break;default:throw new Error("Unrecognized genfrac command")}var v=a==="\\cfrac",p=null;return v||a.startsWith("\\d")?p="display":a.startsWith("\\t")&&(p="text"),z1({type:"genfrac",mode:t.mode,numer:i,denom:s,continued:v,hasBarLine:u,leftDelim:h,rightDelim:c,barSize:null},p)},htmlBuilder:g4,mathmlBuilder:b4});B({type:"infix",names:["\\over","\\choose","\\atop","\\brace","\\brack"],props:{numArgs:0,infix:!0},handler(r){var{parser:e,funcName:t,token:a}=r,i;switch(t){case"\\over":i="\\frac";break;case"\\choose":i="\\binom";break;case"\\atop":i="\\\\atopfrac";break;case"\\brace":i="\\\\bracefrac";break;case"\\brack":i="\\\\brackfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",mode:e.mode,replaceWith:i,token:a}}});var Tr=["display","text","script","scriptscript"],Br=function(e){var t=null;return e.length>0&&(t=e,t=t==="."?null:t),t};B({type:"genfrac",names:["\\genfrac"],props:{numArgs:6,allowedInArgument:!0,argTypes:["math","math","size","text","math","math"]},handler(r,e){var{parser:t}=r,a=e[4],i=e[5],s=Ne(e[0]),u=s.type==="atom"&&s.family==="open"?Br(s.text):null,h=Ne(e[1]),c=h.type==="atom"&&h.family==="close"?Br(h.text):null,v=H(e[2],"size"),p,b=null;v.isBlank?p=!0:(b=v.value,p=b.number>0);var x=null,y=e[3];if(y.type==="ordgroup"){if(y.body.length>0){var T=H(y.body[0],"textord");x=Tr[Number(T.text)]}}else y=H(y,"textord"),x=Tr[Number(y.text)];return z1({type:"genfrac",mode:t.mode,numer:a,denom:i,continued:!1,hasBarLine:p,barSize:b,leftDelim:u,rightDelim:c},x)}});B({type:"infix",names:["\\above"],props:{numArgs:1,argTypes:["size"],infix:!0},handler(r,e){var{parser:t,funcName:a,token:i}=r;return{type:"infix",mode:t.mode,replaceWith:"\\\\abovefrac",size:H(e[0],"size").value,token:i}}});B({type:"genfrac",names:["\\\\abovefrac"],props:{numArgs:3,argTypes:["math","size","math"]},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=e[0],s=H(e[1],"infix").size;if(!s)throw new Error("\\\\abovefrac expected size, but got "+String(s));var u=e[2],h=s.number>0;return{type:"genfrac",mode:t.mode,numer:i,denom:u,continued:!1,hasBarLine:h,barSize:s,leftDelim:null,rightDelim:null}}});var A1=(r,e)=>{var t=e.style,a,i;r.type==="supsub"?(a=r.sup?X(r.sup,e.havingStyle(t.sup()),e):X(r.sub,e.havingStyle(t.sub()),e),i=H(r.base,"horizBrace")):i=H(r,"horizBrace");var s=X(i.base,e.havingBaseStyle(N.DISPLAY)),u=Pe(i,e),h;if(i.isOver?h=V({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:u,wrapperClasses:["svg-align"]}]}):h=V({positionType:"bottom",positionData:s.depth+.1+u.height,children:[{type:"elem",elem:u,wrapperClasses:["svg-align"]},{type:"kern",size:.1},{type:"elem",elem:s}]}),a){var c=k(["minner",i.isOver?"mover":"munder"],[h],e);i.isOver?h=V({positionType:"firstBaseline",children:[{type:"elem",elem:c},{type:"kern",size:.2},{type:"elem",elem:a}]}):h=V({positionType:"bottom",positionData:c.depth+.2+a.height+a.depth,children:[{type:"elem",elem:a},{type:"kern",size:.2},{type:"elem",elem:c}]})}return k(["minner",i.isOver?"mover":"munder"],[h],e)},y4=(r,e)=>{var t=Le(r.label);return new z(r.isOver?"mover":"munder",[$(r.base,e),t])};B({type:"horizBrace",names:["\\overbrace","\\underbrace","\\overbracket","\\underbracket"],props:{numArgs:1},handler(r,e){var{parser:t,funcName:a}=r;return{type:"horizBrace",mode:t.mode,label:a,isOver:a.includes("\\over"),base:e[0]}},htmlBuilder:A1,mathmlBuilder:y4});B({type:"href",names:["\\href"],props:{numArgs:2,argTypes:["url","original"],allowedInText:!0},handler:(r,e)=>{var{parser:t}=r,a=e[1],i=H(e[0],"url").url;return t.settings.isTrusted({command:"\\href",url:i})?{type:"href",mode:t.mode,href:i,body:_(a)}:t.formatUnsupportedCmd("\\href")},htmlBuilder:(r,e)=>{var t=a0(r.body,e,!1);return Ea(r.href,[],t,e)},mathmlBuilder:(r,e)=>{var t=U0(r.body,e);return t instanceof z||(t=new z("mrow",[t])),t.setAttribute("href",r.href),t}});B({type:"href",names:["\\url"],props:{numArgs:1,argTypes:["url"],allowedInText:!0},handler:(r,e)=>{var{parser:t}=r,a=H(e[0],"url").url;if(!t.settings.isTrusted({command:"\\url",url:a}))return t.formatUnsupportedCmd("\\url");for(var i=[],s=0;s{var{parser:t,funcName:a,token:i}=r,s=H(e[0],"raw").string,u=e[1];t.settings.strict&&t.settings.reportNonstrict("htmlExtension","HTML extension is disabled on strict mode");var h,c={};switch(a){case"\\htmlClass":c.class=s,h={command:"\\htmlClass",class:s};break;case"\\htmlId":c.id=s,h={command:"\\htmlId",id:s};break;case"\\htmlStyle":c.style=s,h={command:"\\htmlStyle",style:s};break;case"\\htmlData":{for(var v=s.split(","),p=0;p{var t=a0(r.body,e,!1),a=["enclosing"];r.attributes.class&&a.push(...r.attributes.class.trim().split(/\s+/));var i=k(a,t,e);for(var s in r.attributes)s!=="class"&&r.attributes.hasOwnProperty(s)&&i.setAttribute(s,r.attributes[s]);return i},mathmlBuilder:(r,e)=>U0(r.body,e)});B({type:"htmlmathml",names:["\\html@mathml"],props:{numArgs:2,allowedInArgument:!0,allowedInText:!0},handler:(r,e)=>{var{parser:t}=r;return{type:"htmlmathml",mode:t.mode,html:_(e[0]),mathml:_(e[1])}},htmlBuilder:(r,e)=>{var t=a0(r.html,e,!1);return E0(t)},mathmlBuilder:(r,e)=>U0(r.mathml,e)});var ot=function(e){if(/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(e))return{number:+e,unit:"bp"};var t=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(e);if(!t)throw new S("Invalid size: '"+e+"' in \\includegraphics");var a={number:+(t[1]+t[2]),unit:t[3]};if(!Ur(a))throw new S("Invalid unit: '"+a.unit+"' in \\includegraphics.");return a};B({type:"includegraphics",names:["\\includegraphics"],props:{numArgs:1,numOptionalArgs:1,argTypes:["raw","url"],allowedInText:!1},handler:(r,e,t)=>{var{parser:a}=r,i={number:0,unit:"em"},s={number:.9,unit:"em"},u={number:0,unit:"em"},h="";if(t[0])for(var c=H(t[0],"raw").string,v=c.split(","),p=0;p{var t=K(r.height,e),a=0;r.totalheight.number>0&&(a=K(r.totalheight,e)-t);var i=0;r.width.number>0&&(i=K(r.width,e));var s={height:A(t+a)};i>0&&(s.width=A(i)),a>0&&(s.verticalAlign=A(-a));var u=new xa(r.src,r.alt,s);return u.height=t,u.depth=a,u},mathmlBuilder:(r,e)=>{var t=new z("mglyph",[]);t.setAttribute("alt",r.alt);var a=K(r.height,e),i=0;if(r.totalheight.number>0&&(i=K(r.totalheight,e)-a,t.setAttribute("valign",A(-i))),t.setAttribute("height",A(a+i)),r.width.number>0){var s=K(r.width,e);t.setAttribute("width",A(s))}return t.setAttribute("src",r.src),t}});B({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],props:{numArgs:1,argTypes:["size"],primitive:!0,allowedInText:!0},handler(r,e){var{parser:t,funcName:a}=r,i=H(e[0],"size");if(t.settings.strict){var s=a[1]==="m",u=i.value.unit==="mu";s?(u||t.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" supports only mu units, "+("not "+i.value.unit+" units")),t.mode!=="math"&&t.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" works only in math mode")):u&&t.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" doesn't support mu units")}return{type:"kern",mode:t.mode,dimension:i.value}},htmlBuilder(r,e){return jr(r.dimension,e)},mathmlBuilder(r,e){var t=K(r.dimension,e);return new e1(t)}});B({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],props:{numArgs:1,allowedInText:!0},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=e[0];return{type:"lap",mode:t.mode,alignment:a.slice(5),body:i}},htmlBuilder:(r,e)=>{var t;r.alignment==="clap"?(t=k([],[X(r.body,e)]),t=k(["inner"],[t],e)):t=k(["inner"],[X(r.body,e)]);var a=k(["fix"],[]),i=k([r.alignment],[t,a],e),s=k(["strut"]);return s.style.height=A(i.height+i.depth),i.depth&&(s.style.verticalAlign=A(-i.depth)),i.children.unshift(s),i=k(["thinbox"],[i],e),k(["mord","vbox"],[i],e)},mathmlBuilder:(r,e)=>{var t=new z("mpadded",[$(r.body,e)]);if(r.alignment!=="rlap"){var a=r.alignment==="llap"?"-1":"-0.5";t.setAttribute("lspace",a+"width")}return t.setAttribute("width","0px"),t}});B({type:"styling",names:["\\(","$"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(r,e){var{funcName:t,parser:a}=r,i=a.mode;a.switchMode("math");var s=t==="\\("?"\\)":"$",u=a.parseExpression(!1,s);return a.expect(s),a.switchMode(i),{type:"styling",mode:a.mode,style:"text",resetFont:!0,body:u}}});B({type:"text",names:["\\)","\\]"],props:{numArgs:0,allowedInText:!0,allowedInMath:!1},handler(r,e){throw new S("Mismatched "+r.funcName)}});var Cr=(r,e)=>{switch(e.style.size){case N.DISPLAY.size:return r.display;case N.TEXT.size:return r.text;case N.SCRIPT.size:return r.script;case N.SCRIPTSCRIPT.size:return r.scriptscript;default:return r.text}};B({type:"mathchoice",names:["\\mathchoice"],props:{numArgs:4,primitive:!0},handler:(r,e)=>{var{parser:t}=r;return{type:"mathchoice",mode:t.mode,display:_(e[0]),text:_(e[1]),script:_(e[2]),scriptscript:_(e[3])}},htmlBuilder:(r,e)=>{var t=Cr(r,e),a=a0(t,e,!1);return E0(a)},mathmlBuilder:(r,e)=>{var t=Cr(r,e);return U0(t,e)}});var M1=(r,e,t,a,i,s,u)=>{r=k([],[r]);var h=t&&D0(t),c,v;if(e){var p=X(e,a.havingStyle(i.sup()),a);v={elem:p,kern:Math.max(a.fontMetrics().bigOpSpacing1,a.fontMetrics().bigOpSpacing3-p.depth)}}if(t){var b=X(t,a.havingStyle(i.sub()),a);c={elem:b,kern:Math.max(a.fontMetrics().bigOpSpacing2,a.fontMetrics().bigOpSpacing4-b.height)}}var x;if(v&&c){var y=a.fontMetrics().bigOpSpacing5+c.elem.height+c.elem.depth+c.kern+r.depth+u;x=V({positionType:"bottom",positionData:y,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:c.elem,marginLeft:A(-s)},{type:"kern",size:c.kern},{type:"elem",elem:r},{type:"kern",size:v.kern},{type:"elem",elem:v.elem,marginLeft:A(s)},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]})}else if(c){var T=r.height-u;x=V({positionType:"top",positionData:T,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:c.elem,marginLeft:A(-s)},{type:"kern",size:c.kern},{type:"elem",elem:r}]})}else if(v){var M=r.depth+u;x=V({positionType:"bottom",positionData:M,children:[{type:"elem",elem:r},{type:"kern",size:v.kern},{type:"elem",elem:v.elem,marginLeft:A(s)},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]})}else return r;var q=[x];if(c&&s!==0&&!h){var C=k(["mspace"],[],a);C.style.marginRight=A(s),q.unshift(C)}return k(["mop","op-limits"],q,a)},T1=new Set(["\\smallint"]),se=(r,e)=>{var t,a,i=!1,s;r.type==="supsub"?(t=r.sup,a=r.sub,s=H(r.base,"op"),i=!0):s=H(r,"op");var u=e.style,h=!1;u.size===N.DISPLAY.size&&s.symbol&&!T1.has(s.name)&&(h=!0);var c,v;if(s.symbol){var p=h?"Size2-Regular":"Size1-Regular",b="";if((s.name==="\\oiint"||s.name==="\\oiiint")&&(b=s.name.slice(1),s.name=b==="oiint"?"\\iint":"\\iiint"),c=s0(s.name,p,"math",e,["mop","op-symbol",h?"large-op":"small-op"]),v=c.italic,b.length>0){var x=Kr(b+"Size"+(h?"2":"1"),e);c=V({positionType:"individualShift",children:[{type:"elem",elem:c,shift:0},{type:"elem",elem:x,shift:h?.08:0}]}),s.name="\\"+b,c.classes.unshift("mop"),c.italic=v}}else if(s.body){var y=a0(s.body,e,!0);y.length===1&&y[0]instanceof d0?(c=y[0],c.classes[0]="mop"):c=k(["mop"],y,e)}else{for(var T=[],M=1;M{var t;if(r.symbol)t=new z("mo",[g0(r.name,r.mode)]),T1.has(r.name)&&t.setAttribute("largeop","false");else if(r.body)t=new z("mo",v0(r.body,e));else{t=new z("mi",[new e0(r.name.slice(1))]);var a=new z("mo",[g0("⁡","text")]);r.parentIsSupSub?t=new z("mrow",[t,a]):t=_r([t,a])}return t},x4={"∏":"\\prod","∐":"\\coprod","∑":"\\sum","⋀":"\\bigwedge","⋁":"\\bigvee","⋂":"\\bigcap","⋃":"\\bigcup","⨀":"\\bigodot","⨁":"\\bigoplus","⨂":"\\bigotimes","⨄":"\\biguplus","⨆":"\\bigsqcup"};B({type:"op",names:["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint","∏","∐","∑","⋀","⋁","⋂","⋃","⨀","⨁","⨂","⨄","⨆"],props:{numArgs:0},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=a;return i.length===1&&(i=x4[i]),{type:"op",mode:t.mode,limits:!0,parentIsSupSub:!1,symbol:!0,name:i}},htmlBuilder:se,mathmlBuilder:fe});B({type:"op",names:["\\mathop"],props:{numArgs:1,primitive:!0},handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"op",mode:t.mode,limits:!1,parentIsSupSub:!1,symbol:!1,body:_(a)}},htmlBuilder:se,mathmlBuilder:fe});var w4={"∫":"\\int","∬":"\\iint","∭":"\\iiint","∮":"\\oint","∯":"\\oiint","∰":"\\oiiint"};B({type:"op",names:["\\arcsin","\\arccos","\\arctan","\\arctg","\\arcctg","\\arg","\\ch","\\cos","\\cosec","\\cosh","\\cot","\\cotg","\\coth","\\csc","\\ctg","\\cth","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\sh","\\tan","\\tanh","\\tg","\\th"],props:{numArgs:0},handler(r){var{parser:e,funcName:t}=r;return{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!1,name:t}},htmlBuilder:se,mathmlBuilder:fe});B({type:"op",names:["\\det","\\gcd","\\inf","\\lim","\\max","\\min","\\Pr","\\sup"],props:{numArgs:0},handler(r){var{parser:e,funcName:t}=r;return{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:!1,name:t}},htmlBuilder:se,mathmlBuilder:fe});B({type:"op",names:["\\int","\\iint","\\iiint","\\oint","\\oiint","\\oiiint","∫","∬","∭","∮","∯","∰"],props:{numArgs:0,allowedInArgument:!0},handler(r){var{parser:e,funcName:t}=r,a=t;return a.length===1&&(a=w4[a]),{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!0,name:a}},htmlBuilder:se,mathmlBuilder:fe});var B1=(r,e)=>{var t,a,i=!1,s;r.type==="supsub"?(t=r.sup,a=r.sub,s=H(r.base,"operatorname"),i=!0):s=H(r,"operatorname");var u;if(s.body.length>0){for(var h=s.body.map(b=>{var x="text"in b?b.text:void 0;return typeof x=="string"?{type:"textord",mode:b.mode,text:x}:b}),c=a0(h,e.withFont("mathrm"),!0),v=0;v{for(var t=v0(r.body,e.withFont("mathrm")),a=!0,i=0;ip.toText()).join("");t=[new e0(h)]}var c=new z("mi",t);c.setAttribute("mathvariant","normal");var v=new z("mo",[g0("⁡","text")]);return r.parentIsSupSub?new z("mrow",[c,v]):_r([c,v])};B({type:"operatorname",names:["\\operatorname@","\\operatornamewithlimits"],props:{numArgs:1},handler:(r,e)=>{var{parser:t,funcName:a}=r,i=e[0];return{type:"operatorname",mode:t.mode,body:_(i),alwaysHandleSupSub:a==="\\operatornamewithlimits",limits:!1,parentIsSupSub:!1}},htmlBuilder:B1,mathmlBuilder:k4});m("\\operatorname","\\@ifstar\\operatornamewithlimits\\operatorname@");W0({type:"ordgroup",htmlBuilder(r,e){return r.semisimple?E0(a0(r.body,e,!1)):k(["mord"],a0(r.body,e,!0),e)},mathmlBuilder(r,e){return U0(r.body,e,!0)}});B({type:"overline",names:["\\overline"],props:{numArgs:1},handler(r,e){var{parser:t}=r,a=e[0];return{type:"overline",mode:t.mode,body:a}},htmlBuilder(r,e){var t=X(r.body,e.havingCrampedStyle()),a=te("overline-line",e),i=e.fontMetrics().defaultRuleThickness,s=V({positionType:"firstBaseline",children:[{type:"elem",elem:t},{type:"kern",size:3*i},{type:"elem",elem:a},{type:"kern",size:i}]});return k(["mord","overline"],[s],e)},mathmlBuilder(r,e){var t=new z("mo",[new e0("‾")]);t.setAttribute("stretchy","true");var a=new z("mover",[$(r.body,e),t]);return a.setAttribute("accent","true"),a}});B({type:"phantom",names:["\\phantom"],props:{numArgs:1,allowedInText:!0},handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"phantom",mode:t.mode,body:_(a)}},htmlBuilder:(r,e)=>{var t=a0(r.body,e.withPhantom(),!1);return E0(t)},mathmlBuilder:(r,e)=>{var t=v0(r.body,e);return new z("mphantom",t)}});m("\\hphantom","\\smash{\\phantom{#1}}");B({type:"vphantom",names:["\\vphantom"],props:{numArgs:1,allowedInText:!0},handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"vphantom",mode:t.mode,body:a}},htmlBuilder:(r,e)=>{var t=k(["inner"],[X(r.body,e.withPhantom())]),a=k(["fix"],[]);return k(["mord","rlap"],[t,a],e)},mathmlBuilder:(r,e)=>{var t=v0(_(r.body),e),a=new z("mphantom",t),i=new z("mpadded",[a]);return i.setAttribute("width","0px"),i}});B({type:"raisebox",names:["\\raisebox"],props:{numArgs:2,argTypes:["size","hbox"],allowedInText:!0},handler(r,e){var{parser:t}=r,a=H(e[0],"size").value,i=e[1];return{type:"raisebox",mode:t.mode,dy:a,body:i}},htmlBuilder(r,e){var t=X(r.body,e),a=K(r.dy,e);return V({positionType:"shift",positionData:-a,children:[{type:"elem",elem:t}]})},mathmlBuilder(r,e){var t=new z("mpadded",[$(r.body,e)]),a=r.dy.number+r.dy.unit;return t.setAttribute("voffset",a),t}});B({type:"internal",names:["\\relax"],props:{numArgs:0,allowedInText:!0,allowedInArgument:!0},handler(r){var{parser:e}=r;return{type:"internal",mode:e.mode}}});B({type:"rule",names:["\\rule"],props:{numArgs:2,numOptionalArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["size","size","size"]},handler(r,e,t){var{parser:a}=r,i=t[0],s=H(e[0],"size"),u=H(e[1],"size");return{type:"rule",mode:a.mode,shift:i&&H(i,"size").value,width:s.value,height:u.value}},htmlBuilder(r,e){var t=k(["mord","rule"],[],e),a=K(r.width,e),i=K(r.height,e),s=r.shift?K(r.shift,e):0;return t.style.borderRightWidth=A(a),t.style.borderTopWidth=A(i),t.style.bottom=A(s),t.width=a,t.height=i+s,t.depth=-s,t.maxFontSize=i*1.125*e.sizeMultiplier,t},mathmlBuilder(r,e){var t=K(r.width,e),a=K(r.height,e),i=r.shift?K(r.shift,e):0,s=e.color&&e.getColor()||"black",u=new z("mspace");u.setAttribute("mathbackground",s),u.setAttribute("width",A(t)),u.setAttribute("height",A(a));var h=new z("mpadded",[u]);return i>=0?h.setAttribute("height",A(i)):(h.setAttribute("height",A(i)),h.setAttribute("depth",A(-i))),h.setAttribute("voffset",A(i)),h}});function C1(r,e,t){for(var a=a0(r,e,!1),i=e.sizeMultiplier/t.sizeMultiplier,s=0;s{var t=e.havingSize(r.size);return C1(r.body,t,e)};B({type:"sizing",names:Dr,props:{numArgs:0,allowedInText:!0},handler:(r,e)=>{var{breakOnTokenText:t,funcName:a,parser:i}=r,s=i.parseExpression(!1,t);return{type:"sizing",mode:i.mode,size:Dr.indexOf(a)+1,body:s}},htmlBuilder:S4,mathmlBuilder:(r,e)=>{var t=e.havingSize(r.size),a=v0(r.body,t),i=new z("mstyle",a);return i.setAttribute("mathsize",A(t.sizeMultiplier)),i}});B({type:"smash",names:["\\smash"],props:{numArgs:1,numOptionalArgs:1,allowedInText:!0},handler:(r,e,t)=>{var{parser:a}=r,i=!1,s=!1,u=t[0]&&H(t[0],"ordgroup");if(u)for(var h,c=0;c{var t=k([],[X(r.body,e)]);if(!r.smashHeight&&!r.smashDepth)return t;if(r.smashHeight&&(t.height=0),r.smashDepth&&(t.depth=0),r.smashHeight&&r.smashDepth)return k(["mord","smash"],[t],e);if(t.children)for(var a=0;a{var t=new z("mpadded",[$(r.body,e)]);return r.smashHeight&&t.setAttribute("height","0px"),r.smashDepth&&t.setAttribute("depth","0px"),t}});B({type:"sqrt",names:["\\sqrt"],props:{numArgs:1,numOptionalArgs:1},handler(r,e,t){var{parser:a}=r,i=t[0],s=e[0];return{type:"sqrt",mode:a.mode,body:s,index:i}},htmlBuilder(r,e){var t=X(r.body,e.havingCrampedStyle());t.height===0&&(t.height=e.fontMetrics().xHeight),t=re(t,e);var a=e.fontMetrics(),i=a.defaultRuleThickness,s=i;e.style.idt.height+t.depth+u&&(u=(u+b-t.height-t.depth)/2);var x=c.height-t.height-u-v;t.style.paddingLeft=A(p);var y=V({positionType:"firstBaseline",children:[{type:"elem",elem:t,wrapperClasses:["svg-align"]},{type:"kern",size:-(t.height+x)},{type:"elem",elem:c},{type:"kern",size:v}]});if(r.index){var T=e.havingStyle(N.SCRIPTSCRIPT),M=X(r.index,T,e),q=.6*(y.height-y.depth),C=V({positionType:"shift",positionData:-q,children:[{type:"elem",elem:M}]}),R=k(["root"],[C]);return k(["mord","sqrt"],[R,y],e)}else return k(["mord","sqrt"],[y],e)},mathmlBuilder(r,e){var{body:t,index:a}=r;return a?new z("mroot",[$(t,e),$(a,e)]):new z("msqrt",[$(t,e)])}});var Dt={display:N.DISPLAY,text:N.TEXT,script:N.SCRIPT,scriptscript:N.SCRIPTSCRIPT};function z4(r){return r in Dt}B({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],props:{numArgs:0,allowedInText:!0,primitive:!0},handler(r,e){var{breakOnTokenText:t,funcName:a,parser:i}=r,s=i.parseExpression(!0,t),u=a.slice(1,a.length-5);if(!z4(u))throw new Error("Unknown style: "+u);return{type:"styling",mode:i.mode,style:u,body:s}},htmlBuilder(r,e){var t=Dt[r.style],a=e.havingStyle(t);return r.resetFont&&(a=a.withFont("")),C1(r.body,a,e)},mathmlBuilder(r,e){var t=Dt[r.style],a=e.havingStyle(t);r.resetFont&&(a=a.withFont(""));var i=v0(r.body,a),s=new z("mstyle",i),u={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]},h=u[r.style];return s.setAttribute("scriptlevel",h[0]),s.setAttribute("displaystyle",h[1]),s}});var A4=function(e,t){var a=e.base;if(a)if(a.type==="op"){var i=a.limits&&(t.style.size===N.DISPLAY.size||a.alwaysHandleSupSub);return i?se:null}else if(a.type==="operatorname"){var s=a.alwaysHandleSupSub&&(t.style.size===N.DISPLAY.size||a.limits);return s?B1:null}else{if(a.type==="accent")return D0(a.base)?Pt:null;if(a.type==="horizBrace"){var u=!e.sub;return u===a.isOver?A1:null}else return null}else return null};W0({type:"supsub",htmlBuilder(r,e){var t=A4(r,e);if(t)return t(r,e);var{base:a,sup:i,sub:s}=r,u=X(a,e),h,c,v=e.fontMetrics(),p=0,b=0,x=a&&D0(a);if(i){var y=e.havingStyle(e.style.sup());h=X(i,y,e),x||(p=u.height-y.fontMetrics().supDrop*y.sizeMultiplier/e.sizeMultiplier)}if(s){var T=e.havingStyle(e.style.sub());c=X(s,T,e),x||(b=u.depth+T.fontMetrics().subDrop*T.sizeMultiplier/e.sizeMultiplier)}var M;e.style===N.DISPLAY?M=v.sup1:e.style.cramped?M=v.sup3:M=v.sup2;var q=e.sizeMultiplier,C=A(.5/v.ptPerEm/q),R=null;if(c){var F=r.base&&r.base.type==="op"&&r.base.name&&(r.base.name==="\\oiint"||r.base.name==="\\oiiint");if(u instanceof d0||F){var L;R=A(-((L=u.italic)!=null?L:0))}}var O;if(h&&c){p=Math.max(p,M,h.depth+.25*v.xHeight),b=Math.max(b,v.sub2);var P=v.defaultRuleThickness,G=4*P;if(p-h.depth-(c.height-b)0&&(p+=Y,b-=Y)}var U=[{type:"elem",elem:c,shift:b,marginRight:C,marginLeft:R},{type:"elem",elem:h,shift:-p,marginRight:C}];O=V({positionType:"individualShift",children:U})}else if(c){b=Math.max(b,v.sub1,c.height-.8*v.xHeight);var o0=[{type:"elem",elem:c,marginLeft:R,marginRight:C}];O=V({positionType:"shift",positionData:b,children:o0})}else if(h)p=Math.max(p,M,h.depth+.25*v.xHeight),O=V({positionType:"shift",positionData:-p,children:[{type:"elem",elem:h,marginRight:C}]});else throw new Error("supsub must have either sup or sub.");var m0=At(u,"right")||"mord";return k([m0],[u,k(["msupsub"],[O])],e)},mathmlBuilder(r,e){var t=!1,a,i;r.base&&r.base.type==="horizBrace"&&(i=!!r.sup,i===r.base.isOver&&(t=!0,a=r.base.isOver)),r.base&&(r.base.type==="op"||r.base.type==="operatorname")&&(r.base.parentIsSupSub=!0);var s=[$(r.base,e)];r.sub&&s.push($(r.sub,e)),r.sup&&s.push($(r.sup,e));var u;if(t)u=a?"mover":"munder";else if(r.sub)if(r.sup){var v=r.base;v&&v.type==="op"&&v.limits&&e.style===N.DISPLAY||v&&v.type==="operatorname"&&v.alwaysHandleSupSub&&(e.style===N.DISPLAY||v.limits)?u="munderover":u="msubsup"}else{var c=r.base;c&&c.type==="op"&&c.limits&&(e.style===N.DISPLAY||c.alwaysHandleSupSub)||c&&c.type==="operatorname"&&c.alwaysHandleSupSub&&(c.limits||e.style===N.DISPLAY)?u="munder":u="msub"}else{var h=r.base;h&&h.type==="op"&&h.limits&&(e.style===N.DISPLAY||h.alwaysHandleSupSub)||h&&h.type==="operatorname"&&h.alwaysHandleSupSub&&(h.limits||e.style===N.DISPLAY)?u="mover":u="msup"}return new z(u,s)}});W0({type:"atom",htmlBuilder(r,e){return Ft(r.text,r.mode,e,["m"+r.family])},mathmlBuilder(r,e){var t=new z("mo",[g0(r.text,r.mode)]);if(r.family==="bin"){var a=Lt(r,e);a==="bold-italic"&&t.setAttribute("mathvariant",a)}else r.family==="punct"?t.setAttribute("separator","true"):(r.family==="open"||r.family==="close")&&t.setAttribute("stretchy","false");return t}});var D1={mi:"italic",mn:"normal",mtext:"normal"};W0({type:"mathord",htmlBuilder(r,e){return Oe(r,e,"mathord")},mathmlBuilder(r,e){var t=new z("mi",[g0(r.text,r.mode,e)]),a=Lt(r,e)||"italic";return a!==D1[t.type]&&t.setAttribute("mathvariant",a),t}});W0({type:"textord",htmlBuilder(r,e){return Oe(r,e,"textord")},mathmlBuilder(r,e){var t=g0(r.text,r.mode,e),a=Lt(r,e)||"normal",i;return r.mode==="text"?i=new z("mtext",[t]):/[0-9]/.test(r.text)?i=new z("mn",[t]):r.text==="\\prime"?i=new z("mo",[t]):i=new z("mi",[t]),a!==D1[i.type]&&i.setAttribute("mathvariant",a),i}});var ht={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},mt={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};W0({type:"spacing",htmlBuilder(r,e){if(mt.hasOwnProperty(r.text)){var t=mt[r.text].className||"";if(r.mode==="text"){var a=Oe(r,e,"textord");return a.classes.push(t),a}else return k(["mspace",t],[Ft(r.text,r.mode,e)],e)}else{if(ht.hasOwnProperty(r.text))return k(["mspace",ht[r.text]],[],e);throw new S('Unknown type of space "'+r.text+'"')}},mathmlBuilder(r,e){var t;if(mt.hasOwnProperty(r.text))t=new z("mtext",[new e0(" ")]);else{if(ht.hasOwnProperty(r.text))return new z("mspace");throw new S('Unknown type of space "'+r.text+'"')}return t}});var qr=()=>{var r=new z("mtd",[]);return r.setAttribute("width","50%"),r};W0({type:"tag",mathmlBuilder(r,e){var t=new z("mtable",[new z("mtr",[qr(),new z("mtd",[U0(r.body,e)]),qr(),new z("mtd",[U0(r.tag,e)])])]);return t.setAttribute("width","100%"),t}});var Er={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},Rr={"\\textbf":"textbf","\\textmd":"textmd"},M4={"\\textit":"textit","\\textup":"textup"},Ir=(r,e)=>{var t=r.font;if(t){if(Er[t])return e.withTextFontFamily(Er[t]);if(Rr[t])return e.withTextFontWeight(Rr[t]);if(t==="\\emph")return e.fontShape==="textit"?e.withTextFontShape("textup"):e.withTextFontShape("textit")}else return e;return e.withTextFontShape(M4[t])};B({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup","\\emph"],props:{numArgs:1,argTypes:["text"],allowedInArgument:!0,allowedInText:!0},handler(r,e){var{parser:t,funcName:a}=r,i=e[0];return{type:"text",mode:t.mode,body:_(i),font:a}},htmlBuilder(r,e){var t=Ir(r,e),a=a0(r.body,t,!0);return k(["mord","text"],a,t)},mathmlBuilder(r,e){var t=Ir(r,e);return U0(r.body,t)}});B({type:"underline",names:["\\underline"],props:{numArgs:1,allowedInText:!0},handler(r,e){var{parser:t}=r;return{type:"underline",mode:t.mode,body:e[0]}},htmlBuilder(r,e){var t=X(r.body,e),a=te("underline-line",e),i=e.fontMetrics().defaultRuleThickness,s=V({positionType:"top",positionData:t.height,children:[{type:"kern",size:i},{type:"elem",elem:a},{type:"kern",size:3*i},{type:"elem",elem:t}]});return k(["mord","underline"],[s],e)},mathmlBuilder(r,e){var t=new z("mo",[new e0("‾")]);t.setAttribute("stretchy","true");var a=new z("munder",[$(r.body,e),t]);return a.setAttribute("accentunder","true"),a}});B({type:"vcenter",names:["\\vcenter"],props:{numArgs:1,argTypes:["original"],allowedInText:!1},handler(r,e){var{parser:t}=r;return{type:"vcenter",mode:t.mode,body:e[0]}},htmlBuilder(r,e){var t=X(r.body,e),a=e.fontMetrics().axisHeight,i=.5*(t.height-a-(t.depth+a));return V({positionType:"shift",positionData:i,children:[{type:"elem",elem:t}]})},mathmlBuilder(r,e){var t=new z("mpadded",[$(r.body,e)],["vcenter"]);return new z("mrow",[t])}});B({type:"verb",names:["\\verb"],props:{numArgs:0,allowedInText:!0},handler(r,e,t){throw new S("\\verb ended by end of line instead of matching delimiter")},htmlBuilder(r,e){for(var t=Nr(r),a=[],i=e.havingStyle(e.style.text()),s=0;sr.body.replace(/ /g,r.star?"␣":" "),O0=Jr,q1=`[ \r + ]`,T4="\\\\[a-zA-Z@]+",B4="\\\\[^\uD800-\uDFFF]",C4="("+T4+")"+q1+"*",D4=`\\\\( +|[ \r ]+ +?)[ \r ]*`,qt="[̀-ͯ]",q4=new RegExp(qt+"+$"),E4="("+q1+"+)|"+(D4+"|")+"([!-\\[\\]-‧‪-퟿豈-￿]"+(qt+"*")+"|[\uD800-\uDBFF][\uDC00-\uDFFF]"+(qt+"*")+"|\\\\verb\\*([^]).*?\\4|\\\\verb([^*a-zA-Z]).*?\\5"+("|"+C4)+("|"+B4+")");class Fr{constructor(e,t){this.input=void 0,this.settings=void 0,this.tokenRegex=void 0,this.catcodes=void 0,this.input=e,this.settings=t,this.tokenRegex=new RegExp(E4,"g"),this.catcodes={"%":14,"~":13}}setCatcode(e,t){this.catcodes[e]=t}lex(){var e=this.input,t=this.tokenRegex.lastIndex;if(t===e.length)return new c0("EOF",new h0(this,t,t));var a=this.tokenRegex.exec(e);if(a===null||a.index!==t)throw new S("Unexpected character: '"+e[t]+"'",new c0(e[t],new h0(this,t,t+1)));var i=a[6]||a[3]||(a[2]?"\\ ":" ");if(this.catcodes[i]===14){var s=e.indexOf(` +`,this.tokenRegex.lastIndex);return s===-1?(this.tokenRegex.lastIndex=e.length,this.settings.reportNonstrict("commentAtEnd","% comment has no terminating newline; LaTeX would fail because of commenting the end of math mode (e.g. $)")):this.tokenRegex.lastIndex=s+1,this.lex()}return new c0(i,new h0(this,t,this.tokenRegex.lastIndex))}}class R4{constructor(e,t){e===void 0&&(e={}),t===void 0&&(t={}),this.current=void 0,this.builtins=void 0,this.undefStack=void 0,this.current=t,this.builtins=e,this.undefStack=[]}beginGroup(){this.undefStack.push({})}endGroup(){if(this.undefStack.length===0)throw new S("Unbalanced namespace destruction: attempt to pop global namespace; please report this as a bug");var e=this.undefStack.pop();for(var t in e)e.hasOwnProperty(t)&&(e[t]==null?delete this.current[t]:this.current[t]=e[t])}endGroups(){for(;this.undefStack.length>0;)this.endGroup()}has(e){return this.current.hasOwnProperty(e)||this.builtins.hasOwnProperty(e)}get(e){return this.current.hasOwnProperty(e)?this.current[e]:this.builtins[e]}set(e,t,a){if(a===void 0&&(a=!1),a){for(var i=0;i0&&(this.undefStack[this.undefStack.length-1][e]=t)}else{var s=this.undefStack[this.undefStack.length-1];s&&!s.hasOwnProperty(e)&&(s[e]=this.current[e])}t==null?delete this.current[e]:this.current[e]=t}}var I4=x1;m("\\noexpand",function(r){var e=r.popToken();return r.isExpandable(e.text)&&(e.noexpand=!0,e.treatAsRelax=!0),{tokens:[e],numArgs:0}});m("\\expandafter",function(r){var e=r.popToken();return r.expandOnce(!0),{tokens:[e],numArgs:0}});m("\\@firstoftwo",function(r){var e=r.consumeArgs(2);return{tokens:e[0],numArgs:0}});m("\\@secondoftwo",function(r){var e=r.consumeArgs(2);return{tokens:e[1],numArgs:0}});m("\\@ifnextchar",function(r){var e=r.consumeArgs(3);r.consumeSpaces();var t=r.future();return e[0].length===1&&e[0][0].text===t.text?{tokens:e[1],numArgs:0}:{tokens:e[2],numArgs:0}});m("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}");m("\\TextOrMath",function(r){var e=r.consumeArgs(2);return r.mode==="text"?{tokens:e[0],numArgs:0}:{tokens:e[1],numArgs:0}});var Hr={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15};m("\\char",function(r){var e=r.popToken(),t,a=0;if(e.text==="'")t=8,e=r.popToken();else if(e.text==='"')t=16,e=r.popToken();else if(e.text==="`")if(e=r.popToken(),e.text[0]==="\\")a=e.text.charCodeAt(1);else{if(e.text==="EOF")throw new S("\\char` missing argument");a=e.text.charCodeAt(0)}else t=10;if(t){if(a=Hr[e.text],a==null||a>=t)throw new S("Invalid base-"+t+" digit "+e.text);for(var i;(i=Hr[r.future().text])!=null&&i{var i=r.consumeArg().tokens;if(i.length!==1)throw new S("\\newcommand's first argument must be a macro name");var s=i[0].text,u=r.isDefined(s);if(u&&!e)throw new S("\\newcommand{"+s+"} attempting to redefine "+(s+"; use \\renewcommand"));if(!u&&!t)throw new S("\\renewcommand{"+s+"} when command "+s+" does not yet exist; use \\newcommand");var h=0;if(i=r.consumeArg().tokens,i.length===1&&i[0].text==="["){for(var c="",v=r.expandNextToken();v.text!=="]"&&v.text!=="EOF";)c+=v.text,v=r.expandNextToken();if(!c.match(/^\s*[0-9]+\s*$/))throw new S("Invalid number of arguments: "+c);h=parseInt(c),i=r.consumeArg().tokens}return u&&a||r.macros.set(s,{tokens:i,numArgs:h}),""};m("\\newcommand",r=>Xt(r,!1,!0,!1));m("\\renewcommand",r=>Xt(r,!0,!1,!1));m("\\providecommand",r=>Xt(r,!0,!0,!0));m("\\message",r=>{var e=r.consumeArgs(1)[0];return console.log(e.reverse().map(t=>t.text).join("")),""});m("\\errmessage",r=>{var e=r.consumeArgs(1)[0];return console.error(e.reverse().map(t=>t.text).join("")),""});m("\\show",r=>{var e=r.popToken(),t=e.text;return console.log(e,r.macros.get(t),O0[t],W.math[t],W.text[t]),""});m("\\bgroup","{");m("\\egroup","}");m("~","\\nobreakspace");m("\\lq","`");m("\\rq","'");m("\\aa","\\r a");m("\\AA","\\r A");m("\\textcopyright","\\html@mathml{\\textcircled{c}}{\\char`©}");m("\\copyright","\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}");m("\\textregistered","\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`®}");m("ℬ","\\mathscr{B}");m("ℰ","\\mathscr{E}");m("ℱ","\\mathscr{F}");m("ℋ","\\mathscr{H}");m("ℐ","\\mathscr{I}");m("ℒ","\\mathscr{L}");m("ℳ","\\mathscr{M}");m("ℛ","\\mathscr{R}");m("ℭ","\\mathfrak{C}");m("ℌ","\\mathfrak{H}");m("ℨ","\\mathfrak{Z}");m("\\Bbbk","\\Bbb{k}");m("\\llap","\\mathllap{\\textrm{#1}}");m("\\rlap","\\mathrlap{\\textrm{#1}}");m("\\clap","\\mathclap{\\textrm{#1}}");m("\\mathstrut","\\vphantom{(}");m("\\underbar","\\underline{\\text{#1}}");m("\\not",'\\html@mathml{\\mathrel{\\mathrlap\\@not}\\nobreak}{\\char"338}');m("\\neq","\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}");m("\\ne","\\neq");m("≠","\\neq");m("\\notin","\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}{\\mathrel{\\char`∉}}");m("∉","\\notin");m("≘","\\html@mathml{\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}}{\\mathrel{\\char`≘}}");m("≙","\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`≘}}");m("≚","\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`≚}}");m("≛","\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}{\\mathrel{\\char`≛}}");m("≝","\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}{\\mathrel{\\char`≝}}");m("≞","\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}{\\mathrel{\\char`≞}}");m("≟","\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`≟}}");m("⟂","\\perp");m("‼","\\mathclose{!\\mkern-0.8mu!}");m("∌","\\notni");m("⌜","\\ulcorner");m("⌝","\\urcorner");m("⌞","\\llcorner");m("⌟","\\lrcorner");m("©","\\copyright");m("®","\\textregistered");m("\\ulcorner",'\\html@mathml{\\@ulcorner}{\\mathop{\\char"231c}}');m("\\urcorner",'\\html@mathml{\\@urcorner}{\\mathop{\\char"231d}}');m("\\llcorner",'\\html@mathml{\\@llcorner}{\\mathop{\\char"231e}}');m("\\lrcorner",'\\html@mathml{\\@lrcorner}{\\mathop{\\char"231f}}');m("\\vdots","{\\varvdots\\rule{0pt}{15pt}}");m("⋮","\\vdots");m("\\varGamma","\\mathit{\\Gamma}");m("\\varDelta","\\mathit{\\Delta}");m("\\varTheta","\\mathit{\\Theta}");m("\\varLambda","\\mathit{\\Lambda}");m("\\varXi","\\mathit{\\Xi}");m("\\varPi","\\mathit{\\Pi}");m("\\varSigma","\\mathit{\\Sigma}");m("\\varUpsilon","\\mathit{\\Upsilon}");m("\\varPhi","\\mathit{\\Phi}");m("\\varPsi","\\mathit{\\Psi}");m("\\varOmega","\\mathit{\\Omega}");m("\\substack","\\begin{subarray}{c}#1\\end{subarray}");m("\\colon","\\nobreak\\mskip2mu\\mathpunct{}\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu\\relax");m("\\boxed","\\fbox{$\\displaystyle{#1}$}");m("\\iff","\\DOTSB\\;\\Longleftrightarrow\\;");m("\\implies","\\DOTSB\\;\\Longrightarrow\\;");m("\\impliedby","\\DOTSB\\;\\Longleftarrow\\;");m("\\dddot","{\\overset{\\raisebox{-0.1ex}{\\normalsize ...}}{#1}}");m("\\ddddot","{\\overset{\\raisebox{-0.1ex}{\\normalsize ....}}{#1}}");var Or={",":"\\dotsc","\\not":"\\dotsb","+":"\\dotsb","=":"\\dotsb","<":"\\dotsb",">":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"},N4=new Set(["bin","rel"]);m("\\dots",function(r){var e="\\dotso",t=r.expandAfterFuture().text;return t in Or?e=Or[t]:(t.slice(0,4)==="\\not"||t in W.math&&N4.has(W.math[t].group))&&(e="\\dotsb"),e});var Yt={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};m("\\dotso",function(r){var e=r.future().text;return e in Yt?"\\ldots\\,":"\\ldots"});m("\\dotsc",function(r){var e=r.future().text;return e in Yt&&e!==","?"\\ldots\\,":"\\ldots"});m("\\cdots",function(r){var e=r.future().text;return e in Yt?"\\@cdots\\,":"\\@cdots"});m("\\dotsb","\\cdots");m("\\dotsm","\\cdots");m("\\dotsi","\\!\\cdots");m("\\dotsx","\\ldots\\,");m("\\DOTSI","\\relax");m("\\DOTSB","\\relax");m("\\DOTSX","\\relax");m("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax");m("\\,","\\tmspace+{3mu}{.1667em}");m("\\thinspace","\\,");m("\\>","\\mskip{4mu}");m("\\:","\\tmspace+{4mu}{.2222em}");m("\\medspace","\\:");m("\\;","\\tmspace+{5mu}{.2777em}");m("\\thickspace","\\;");m("\\!","\\tmspace-{3mu}{.1667em}");m("\\negthinspace","\\!");m("\\negmedspace","\\tmspace-{4mu}{.2222em}");m("\\negthickspace","\\tmspace-{5mu}{.277em}");m("\\enspace","\\kern.5em ");m("\\enskip","\\hskip.5em\\relax");m("\\quad","\\hskip1em\\relax");m("\\qquad","\\hskip2em\\relax");m("\\tag","\\@ifstar\\tag@literal\\tag@paren");m("\\tag@paren","\\tag@literal{({#1})}");m("\\tag@literal",r=>{if(r.macros.get("\\df@tag"))throw new S("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"});m("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}");m("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)");m("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}");m("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1");m("\\newline","\\\\\\relax");m("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");var E1=A(k0["Main-Regular"][84][1]-.7*k0["Main-Regular"][65][1]);m("\\LaTeX","\\textrm{\\html@mathml{"+("L\\kern-.36em\\raisebox{"+E1+"}{\\scriptstyle A}")+"\\kern-.15em\\TeX}{LaTeX}}");m("\\KaTeX","\\textrm{\\html@mathml{"+("K\\kern-.17em\\raisebox{"+E1+"}{\\scriptstyle A}")+"\\kern-.15em\\TeX}{KaTeX}}");m("\\hspace","\\@ifstar\\@hspacer\\@hspace");m("\\@hspace","\\hskip #1\\relax");m("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax");m("\\ordinarycolon",":");m("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}");m("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}');m("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}');m("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}');m("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}');m("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}');m("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}');m("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}');m("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}');m("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}');m("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}');m("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}');m("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}');m("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}');m("∷","\\dblcolon");m("∹","\\eqcolon");m("≔","\\coloneqq");m("≕","\\eqqcolon");m("⩴","\\Coloneqq");m("\\ratio","\\vcentcolon");m("\\coloncolon","\\dblcolon");m("\\colonequals","\\coloneqq");m("\\coloncolonequals","\\Coloneqq");m("\\equalscolon","\\eqqcolon");m("\\equalscoloncolon","\\Eqqcolon");m("\\colonminus","\\coloneq");m("\\coloncolonminus","\\Coloneq");m("\\minuscolon","\\eqcolon");m("\\minuscoloncolon","\\Eqcolon");m("\\coloncolonapprox","\\Colonapprox");m("\\coloncolonsim","\\Colonsim");m("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}");m("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}");m("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}");m("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}");m("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`∌}}");m("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}");m("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}");m("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}");m("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}");m("\\varlimsup","\\DOTSB\\operatorname*{\\overline{lim}}");m("\\varliminf","\\DOTSB\\operatorname*{\\underline{lim}}");m("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{lim}}");m("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{lim}}");m("\\gvertneqq","\\html@mathml{\\@gvertneqq}{≩}");m("\\lvertneqq","\\html@mathml{\\@lvertneqq}{≨}");m("\\ngeqq","\\html@mathml{\\@ngeqq}{≱}");m("\\ngeqslant","\\html@mathml{\\@ngeqslant}{≱}");m("\\nleqq","\\html@mathml{\\@nleqq}{≰}");m("\\nleqslant","\\html@mathml{\\@nleqslant}{≰}");m("\\nshortmid","\\html@mathml{\\@nshortmid}{∤}");m("\\nshortparallel","\\html@mathml{\\@nshortparallel}{∦}");m("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{⊈}");m("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{⊉}");m("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{⊊}");m("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{⫋}");m("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{⊋}");m("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{⫌}");m("\\imath","\\html@mathml{\\@imath}{ı}");m("\\jmath","\\html@mathml{\\@jmath}{ȷ}");m("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`⟦}}");m("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`⟧}}");m("⟦","\\llbracket");m("⟧","\\rrbracket");m("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`⦃}}");m("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`⦄}}");m("⦃","\\lBrace");m("⦄","\\rBrace");m("\\minuso","\\mathbin{\\html@mathml{{\\mathrlap{\\mathchoice{\\kern{0.145em}}{\\kern{0.145em}}{\\kern{0.1015em}}{\\kern{0.0725em}}\\circ}{-}}}{\\char`⦵}}");m("⦵","\\minuso");m("\\darr","\\downarrow");m("\\dArr","\\Downarrow");m("\\Darr","\\Downarrow");m("\\lang","\\langle");m("\\rang","\\rangle");m("\\uarr","\\uparrow");m("\\uArr","\\Uparrow");m("\\Uarr","\\Uparrow");m("\\N","\\mathbb{N}");m("\\R","\\mathbb{R}");m("\\Z","\\mathbb{Z}");m("\\alef","\\aleph");m("\\alefsym","\\aleph");m("\\Alpha","\\mathrm{A}");m("\\Beta","\\mathrm{B}");m("\\bull","\\bullet");m("\\Chi","\\mathrm{X}");m("\\clubs","\\clubsuit");m("\\cnums","\\mathbb{C}");m("\\Complex","\\mathbb{C}");m("\\Dagger","\\ddagger");m("\\diamonds","\\diamondsuit");m("\\empty","\\emptyset");m("\\Epsilon","\\mathrm{E}");m("\\Eta","\\mathrm{H}");m("\\exist","\\exists");m("\\harr","\\leftrightarrow");m("\\hArr","\\Leftrightarrow");m("\\Harr","\\Leftrightarrow");m("\\hearts","\\heartsuit");m("\\image","\\Im");m("\\infin","\\infty");m("\\Iota","\\mathrm{I}");m("\\isin","\\in");m("\\Kappa","\\mathrm{K}");m("\\larr","\\leftarrow");m("\\lArr","\\Leftarrow");m("\\Larr","\\Leftarrow");m("\\lrarr","\\leftrightarrow");m("\\lrArr","\\Leftrightarrow");m("\\Lrarr","\\Leftrightarrow");m("\\Mu","\\mathrm{M}");m("\\natnums","\\mathbb{N}");m("\\Nu","\\mathrm{N}");m("\\Omicron","\\mathrm{O}");m("\\plusmn","\\pm");m("\\rarr","\\rightarrow");m("\\rArr","\\Rightarrow");m("\\Rarr","\\Rightarrow");m("\\real","\\Re");m("\\reals","\\mathbb{R}");m("\\Reals","\\mathbb{R}");m("\\Rho","\\mathrm{P}");m("\\sdot","\\cdot");m("\\sect","\\S");m("\\spades","\\spadesuit");m("\\sub","\\subset");m("\\sube","\\subseteq");m("\\supe","\\supseteq");m("\\Tau","\\mathrm{T}");m("\\thetasym","\\vartheta");m("\\weierp","\\wp");m("\\Zeta","\\mathrm{Z}");m("\\argmin","\\DOTSB\\operatorname*{arg\\,min}");m("\\argmax","\\DOTSB\\operatorname*{arg\\,max}");m("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits");m("\\bra","\\mathinner{\\langle{#1}|}");m("\\ket","\\mathinner{|{#1}\\rangle}");m("\\braket","\\mathinner{\\langle{#1}\\rangle}");m("\\Bra","\\left\\langle#1\\right|");m("\\Ket","\\left|#1\\right\\rangle");var R1=r=>e=>{var t=e.consumeArg().tokens,a=e.consumeArg().tokens,i=e.consumeArg().tokens,s=e.consumeArg().tokens,u=e.macros.get("|"),h=e.macros.get("\\|");e.macros.beginGroup();var c=b=>x=>{r&&(x.macros.set("|",u),i.length&&x.macros.set("\\|",h));var y=b;if(!b&&i.length){var T=x.future();T.text==="|"&&(x.popToken(),y=!0)}return{tokens:y?i:a,numArgs:0}};e.macros.set("|",c(!1)),i.length&&e.macros.set("\\|",c(!0));var v=e.consumeArg().tokens,p=e.expandTokens([...s,...v,...t]);return e.macros.endGroup(),{tokens:p.reverse(),numArgs:0}};m("\\bra@ket",R1(!1));m("\\bra@set",R1(!0));m("\\Braket","\\bra@ket{\\left\\langle}{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}");m("\\Set","\\bra@set{\\left\\{\\:}{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}");m("\\set","\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}");m("\\angln","{\\angl n}");m("\\blue","\\textcolor{##6495ed}{#1}");m("\\orange","\\textcolor{##ffa500}{#1}");m("\\pink","\\textcolor{##ff00af}{#1}");m("\\red","\\textcolor{##df0030}{#1}");m("\\green","\\textcolor{##28ae7b}{#1}");m("\\gray","\\textcolor{gray}{#1}");m("\\purple","\\textcolor{##9d38bd}{#1}");m("\\blueA","\\textcolor{##ccfaff}{#1}");m("\\blueB","\\textcolor{##80f6ff}{#1}");m("\\blueC","\\textcolor{##63d9ea}{#1}");m("\\blueD","\\textcolor{##11accd}{#1}");m("\\blueE","\\textcolor{##0c7f99}{#1}");m("\\tealA","\\textcolor{##94fff5}{#1}");m("\\tealB","\\textcolor{##26edd5}{#1}");m("\\tealC","\\textcolor{##01d1c1}{#1}");m("\\tealD","\\textcolor{##01a995}{#1}");m("\\tealE","\\textcolor{##208170}{#1}");m("\\greenA","\\textcolor{##b6ffb0}{#1}");m("\\greenB","\\textcolor{##8af281}{#1}");m("\\greenC","\\textcolor{##74cf70}{#1}");m("\\greenD","\\textcolor{##1fab54}{#1}");m("\\greenE","\\textcolor{##0d923f}{#1}");m("\\goldA","\\textcolor{##ffd0a9}{#1}");m("\\goldB","\\textcolor{##ffbb71}{#1}");m("\\goldC","\\textcolor{##ff9c39}{#1}");m("\\goldD","\\textcolor{##e07d10}{#1}");m("\\goldE","\\textcolor{##a75a05}{#1}");m("\\redA","\\textcolor{##fca9a9}{#1}");m("\\redB","\\textcolor{##ff8482}{#1}");m("\\redC","\\textcolor{##f9685d}{#1}");m("\\redD","\\textcolor{##e84d39}{#1}");m("\\redE","\\textcolor{##bc2612}{#1}");m("\\maroonA","\\textcolor{##ffbde0}{#1}");m("\\maroonB","\\textcolor{##ff92c6}{#1}");m("\\maroonC","\\textcolor{##ed5fa6}{#1}");m("\\maroonD","\\textcolor{##ca337c}{#1}");m("\\maroonE","\\textcolor{##9e034e}{#1}");m("\\purpleA","\\textcolor{##ddd7ff}{#1}");m("\\purpleB","\\textcolor{##c6b9fc}{#1}");m("\\purpleC","\\textcolor{##aa87ff}{#1}");m("\\purpleD","\\textcolor{##7854ab}{#1}");m("\\purpleE","\\textcolor{##543b78}{#1}");m("\\mintA","\\textcolor{##f5f9e8}{#1}");m("\\mintB","\\textcolor{##edf2df}{#1}");m("\\mintC","\\textcolor{##e0e5cc}{#1}");m("\\grayA","\\textcolor{##f6f7f7}{#1}");m("\\grayB","\\textcolor{##f0f1f2}{#1}");m("\\grayC","\\textcolor{##e3e5e6}{#1}");m("\\grayD","\\textcolor{##d6d8da}{#1}");m("\\grayE","\\textcolor{##babec2}{#1}");m("\\grayF","\\textcolor{##888d93}{#1}");m("\\grayG","\\textcolor{##626569}{#1}");m("\\grayH","\\textcolor{##3b3e40}{#1}");m("\\grayI","\\textcolor{##21242c}{#1}");m("\\kaBlue","\\textcolor{##314453}{#1}");m("\\kaGreen","\\textcolor{##71B307}{#1}");var I1={"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0};class F4{constructor(e,t,a){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=t,this.expansionCount=0,this.feed(e),this.macros=new R4(I4,t.macros),this.mode=a,this.stack=[]}feed(e){this.lexer=new Fr(e,this.settings)}switchMode(e){this.mode=e}beginGroup(){this.macros.beginGroup()}endGroup(){this.macros.endGroup()}endGroups(){this.macros.endGroups()}future(){return this.stack.length===0&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]}popToken(){return this.future(),this.stack.pop()}pushToken(e){this.stack.push(e)}pushTokens(e){this.stack.push(...e)}scanArgument(e){var t,a,i;if(e){if(this.consumeSpaces(),this.future().text!=="[")return null;t=this.popToken(),{tokens:i,end:a}=this.consumeArg(["]"])}else({tokens:i,start:t,end:a}=this.consumeArg());return this.pushToken(new c0("EOF",a.loc)),this.pushTokens(i),new c0("",h0.range(t,a))}consumeSpaces(){for(;;){var e=this.future();if(e.text===" ")this.stack.pop();else break}}consumeArg(e){var t=[],a=e&&e.length>0;a||this.consumeSpaces();var i=this.future(),s,u=0,h=0;do{if(s=this.popToken(),t.push(s),s.text==="{")++u;else if(s.text==="}"){if(--u,u===-1)throw new S("Extra }",s)}else if(s.text==="EOF")throw new S("Unexpected end of input in a macro argument, expected '"+(e&&a?e[h]:"}")+"'",s);if(e&&a)if((u===0||u===1&&e[h]==="{")&&s.text===e[h]){if(++h,h===e.length){t.splice(-h,h);break}}else h=0}while(u!==0||a);return i.text==="{"&&t[t.length-1].text==="}"&&(t.pop(),t.shift()),t.reverse(),{tokens:t,start:i,end:s}}consumeArgs(e,t){if(t){if(t.length!==e+1)throw new S("The length of delimiters doesn't match the number of args!");for(var a=t[0],i=0;ithis.settings.maxExpand)throw new S("Too many expansions: infinite loop or need to increase maxExpand setting")}expandOnce(e){var t=this.popToken(),a=t.text,i=t.noexpand?null:this._getExpansion(a);if(i==null||e&&i.unexpandable){if(e&&i==null&&a[0]==="\\"&&!this.isDefined(a))throw new S("Undefined control sequence: "+a);return this.pushToken(t),!1}this.countExpansion(1);var s=i.tokens,u=this.consumeArgs(i.numArgs,i.delimiters);if(i.numArgs){s=s.slice();for(var h=s.length-1;h>=0;--h){var c=s[h];if(c.text==="#"){if(h===0)throw new S("Incomplete placeholder at end of macro body",c);if(c=s[--h],c.text==="#")s.splice(h+1,1);else if(/^[1-9]$/.test(c.text))s.splice(h,2,...u[+c.text-1]);else throw new S("Not a valid argument number",c)}}}return this.pushTokens(s),s.length}expandAfterFuture(){return this.expandOnce(),this.future()}expandNextToken(){for(;;)if(this.expandOnce()===!1){var e=this.stack.pop();return e.treatAsRelax&&(e.text="\\relax"),e}}expandMacro(e){return this.macros.has(e)?this.expandTokens([new c0(e)]):void 0}expandTokens(e){var t=[],a=this.stack.length;for(this.pushTokens(e);this.stack.length>a;)if(this.expandOnce(!0)===!1){var i=this.stack.pop();i.treatAsRelax&&(i.noexpand=!1,i.treatAsRelax=!1),t.push(i)}return this.countExpansion(t.length),t}expandMacroAsText(e){var t=this.expandMacro(e);return t&&t.map(a=>a.text).join("")}_getExpansion(e){var t=this.macros.get(e);if(t==null)return t;if(e.length===1){var a=this.lexer.catcodes[e];if(a!=null&&a!==13)return}var i=typeof t=="function"?t(this):t;if(typeof i=="string"){var s=0;if(i.includes("#"))for(var u=i.replace(/##/g,"");u.includes("#"+(s+1));)++s;for(var h=new Fr(i,this.settings),c=[],v=h.lex();v.text!=="EOF";)c.push(v),v=h.lex();c.reverse();var p={tokens:c,numArgs:s};return p}return i}isDefined(e){return this.macros.has(e)||O0.hasOwnProperty(e)||W.math.hasOwnProperty(e)||W.text.hasOwnProperty(e)||I1.hasOwnProperty(e)}isExpandable(e){var t=this.macros.get(e);return t!=null?typeof t=="string"||typeof t=="function"||!t.unexpandable:O0.hasOwnProperty(e)&&!O0[e].primitive}}var Lr=/^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/,Be=Object.freeze({"₊":"+","₋":"-","₌":"=","₍":"(","₎":")","₀":"0","₁":"1","₂":"2","₃":"3","₄":"4","₅":"5","₆":"6","₇":"7","₈":"8","₉":"9","ₐ":"a","ₑ":"e","ₕ":"h","ᵢ":"i","ⱼ":"j","ₖ":"k","ₗ":"l","ₘ":"m","ₙ":"n","ₒ":"o","ₚ":"p","ᵣ":"r","ₛ":"s","ₜ":"t","ᵤ":"u","ᵥ":"v","ₓ":"x","ᵦ":"β","ᵧ":"γ","ᵨ":"ρ","ᵩ":"ϕ","ᵪ":"χ","⁺":"+","⁻":"-","⁼":"=","⁽":"(","⁾":")","⁰":"0","¹":"1","²":"2","³":"3","⁴":"4","⁵":"5","⁶":"6","⁷":"7","⁸":"8","⁹":"9","ᴬ":"A","ᴮ":"B","ᴰ":"D","ᴱ":"E","ᴳ":"G","ᴴ":"H","ᴵ":"I","ᴶ":"J","ᴷ":"K","ᴸ":"L","ᴹ":"M","ᴺ":"N","ᴼ":"O","ᴾ":"P","ᴿ":"R","ᵀ":"T","ᵁ":"U","ⱽ":"V","ᵂ":"W","ᵃ":"a","ᵇ":"b","ᶜ":"c","ᵈ":"d","ᵉ":"e","ᶠ":"f","ᵍ":"g",ʰ:"h","ⁱ":"i",ʲ:"j","ᵏ":"k",ˡ:"l","ᵐ":"m",ⁿ:"n","ᵒ":"o","ᵖ":"p",ʳ:"r",ˢ:"s","ᵗ":"t","ᵘ":"u","ᵛ":"v",ʷ:"w",ˣ:"x",ʸ:"y","ᶻ":"z","ᵝ":"β","ᵞ":"γ","ᵟ":"δ","ᵠ":"ϕ","ᵡ":"χ","ᶿ":"θ"}),ct={"́":{text:"\\'",math:"\\acute"},"̀":{text:"\\`",math:"\\grave"},"̈":{text:'\\"',math:"\\ddot"},"̃":{text:"\\~",math:"\\tilde"},"̄":{text:"\\=",math:"\\bar"},"̆":{text:"\\u",math:"\\breve"},"̌":{text:"\\v",math:"\\check"},"̂":{text:"\\^",math:"\\hat"},"̇":{text:"\\.",math:"\\dot"},"̊":{text:"\\r",math:"\\mathring"},"̋":{text:"\\H"},"̧":{text:"\\c"}},Pr={á:"á",à:"à",ä:"ä",ǟ:"ǟ",ã:"ã",ā:"ā",ă:"ă",ắ:"ắ",ằ:"ằ",ẵ:"ẵ",ǎ:"ǎ",â:"â",ấ:"ấ",ầ:"ầ",ẫ:"ẫ",ȧ:"ȧ",ǡ:"ǡ",å:"å",ǻ:"ǻ",ḃ:"ḃ",ć:"ć",ḉ:"ḉ",č:"č",ĉ:"ĉ",ċ:"ċ",ç:"ç",ď:"ď",ḋ:"ḋ",ḑ:"ḑ",é:"é",è:"è",ë:"ë",ẽ:"ẽ",ē:"ē",ḗ:"ḗ",ḕ:"ḕ",ĕ:"ĕ",ḝ:"ḝ",ě:"ě",ê:"ê",ế:"ế",ề:"ề",ễ:"ễ",ė:"ė",ȩ:"ȩ",ḟ:"ḟ",ǵ:"ǵ",ḡ:"ḡ",ğ:"ğ",ǧ:"ǧ",ĝ:"ĝ",ġ:"ġ",ģ:"ģ",ḧ:"ḧ",ȟ:"ȟ",ĥ:"ĥ",ḣ:"ḣ",ḩ:"ḩ",í:"í",ì:"ì",ï:"ï",ḯ:"ḯ",ĩ:"ĩ",ī:"ī",ĭ:"ĭ",ǐ:"ǐ",î:"î",ǰ:"ǰ",ĵ:"ĵ",ḱ:"ḱ",ǩ:"ǩ",ķ:"ķ",ĺ:"ĺ",ľ:"ľ",ļ:"ļ",ḿ:"ḿ",ṁ:"ṁ",ń:"ń",ǹ:"ǹ",ñ:"ñ",ň:"ň",ṅ:"ṅ",ņ:"ņ",ó:"ó",ò:"ò",ö:"ö",ȫ:"ȫ",õ:"õ",ṍ:"ṍ",ṏ:"ṏ",ȭ:"ȭ",ō:"ō",ṓ:"ṓ",ṑ:"ṑ",ŏ:"ŏ",ǒ:"ǒ",ô:"ô",ố:"ố",ồ:"ồ",ỗ:"ỗ",ȯ:"ȯ",ȱ:"ȱ",ő:"ő",ṕ:"ṕ",ṗ:"ṗ",ŕ:"ŕ",ř:"ř",ṙ:"ṙ",ŗ:"ŗ",ś:"ś",ṥ:"ṥ",š:"š",ṧ:"ṧ",ŝ:"ŝ",ṡ:"ṡ",ş:"ş",ẗ:"ẗ",ť:"ť",ṫ:"ṫ",ţ:"ţ",ú:"ú",ù:"ù",ü:"ü",ǘ:"ǘ",ǜ:"ǜ",ǖ:"ǖ",ǚ:"ǚ",ũ:"ũ",ṹ:"ṹ",ū:"ū",ṻ:"ṻ",ŭ:"ŭ",ǔ:"ǔ",û:"û",ů:"ů",ű:"ű",ṽ:"ṽ",ẃ:"ẃ",ẁ:"ẁ",ẅ:"ẅ",ŵ:"ŵ",ẇ:"ẇ",ẘ:"ẘ",ẍ:"ẍ",ẋ:"ẋ",ý:"ý",ỳ:"ỳ",ÿ:"ÿ",ỹ:"ỹ",ȳ:"ȳ",ŷ:"ŷ",ẏ:"ẏ",ẙ:"ẙ",ź:"ź",ž:"ž",ẑ:"ẑ",ż:"ż",Á:"Á",À:"À",Ä:"Ä",Ǟ:"Ǟ",Ã:"Ã",Ā:"Ā",Ă:"Ă",Ắ:"Ắ",Ằ:"Ằ",Ẵ:"Ẵ",Ǎ:"Ǎ",Â:"Â",Ấ:"Ấ",Ầ:"Ầ",Ẫ:"Ẫ",Ȧ:"Ȧ",Ǡ:"Ǡ",Å:"Å",Ǻ:"Ǻ",Ḃ:"Ḃ",Ć:"Ć",Ḉ:"Ḉ",Č:"Č",Ĉ:"Ĉ",Ċ:"Ċ",Ç:"Ç",Ď:"Ď",Ḋ:"Ḋ",Ḑ:"Ḑ",É:"É",È:"È",Ë:"Ë",Ẽ:"Ẽ",Ē:"Ē",Ḗ:"Ḗ",Ḕ:"Ḕ",Ĕ:"Ĕ",Ḝ:"Ḝ",Ě:"Ě",Ê:"Ê",Ế:"Ế",Ề:"Ề",Ễ:"Ễ",Ė:"Ė",Ȩ:"Ȩ",Ḟ:"Ḟ",Ǵ:"Ǵ",Ḡ:"Ḡ",Ğ:"Ğ",Ǧ:"Ǧ",Ĝ:"Ĝ",Ġ:"Ġ",Ģ:"Ģ",Ḧ:"Ḧ",Ȟ:"Ȟ",Ĥ:"Ĥ",Ḣ:"Ḣ",Ḩ:"Ḩ",Í:"Í",Ì:"Ì",Ï:"Ï",Ḯ:"Ḯ",Ĩ:"Ĩ",Ī:"Ī",Ĭ:"Ĭ",Ǐ:"Ǐ",Î:"Î",İ:"İ",Ĵ:"Ĵ",Ḱ:"Ḱ",Ǩ:"Ǩ",Ķ:"Ķ",Ĺ:"Ĺ",Ľ:"Ľ",Ļ:"Ļ",Ḿ:"Ḿ",Ṁ:"Ṁ",Ń:"Ń",Ǹ:"Ǹ",Ñ:"Ñ",Ň:"Ň",Ṅ:"Ṅ",Ņ:"Ņ",Ó:"Ó",Ò:"Ò",Ö:"Ö",Ȫ:"Ȫ",Õ:"Õ",Ṍ:"Ṍ",Ṏ:"Ṏ",Ȭ:"Ȭ",Ō:"Ō",Ṓ:"Ṓ",Ṑ:"Ṑ",Ŏ:"Ŏ",Ǒ:"Ǒ",Ô:"Ô",Ố:"Ố",Ồ:"Ồ",Ỗ:"Ỗ",Ȯ:"Ȯ",Ȱ:"Ȱ",Ő:"Ő",Ṕ:"Ṕ",Ṗ:"Ṗ",Ŕ:"Ŕ",Ř:"Ř",Ṙ:"Ṙ",Ŗ:"Ŗ",Ś:"Ś",Ṥ:"Ṥ",Š:"Š",Ṧ:"Ṧ",Ŝ:"Ŝ",Ṡ:"Ṡ",Ş:"Ş",Ť:"Ť",Ṫ:"Ṫ",Ţ:"Ţ",Ú:"Ú",Ù:"Ù",Ü:"Ü",Ǘ:"Ǘ",Ǜ:"Ǜ",Ǖ:"Ǖ",Ǚ:"Ǚ",Ũ:"Ũ",Ṹ:"Ṹ",Ū:"Ū",Ṻ:"Ṻ",Ŭ:"Ŭ",Ǔ:"Ǔ",Û:"Û",Ů:"Ů",Ű:"Ű",Ṽ:"Ṽ",Ẃ:"Ẃ",Ẁ:"Ẁ",Ẅ:"Ẅ",Ŵ:"Ŵ",Ẇ:"Ẇ",Ẍ:"Ẍ",Ẋ:"Ẋ",Ý:"Ý",Ỳ:"Ỳ",Ÿ:"Ÿ",Ỹ:"Ỹ",Ȳ:"Ȳ",Ŷ:"Ŷ",Ẏ:"Ẏ",Ź:"Ź",Ž:"Ž",Ẑ:"Ẑ",Ż:"Ż",ά:"ά",ὰ:"ὰ",ᾱ:"ᾱ",ᾰ:"ᾰ",έ:"έ",ὲ:"ὲ",ή:"ή",ὴ:"ὴ",ί:"ί",ὶ:"ὶ",ϊ:"ϊ",ΐ:"ΐ",ῒ:"ῒ",ῑ:"ῑ",ῐ:"ῐ",ό:"ό",ὸ:"ὸ",ύ:"ύ",ὺ:"ὺ",ϋ:"ϋ",ΰ:"ΰ",ῢ:"ῢ",ῡ:"ῡ",ῠ:"ῠ",ώ:"ώ",ὼ:"ὼ",Ύ:"Ύ",Ὺ:"Ὺ",Ϋ:"Ϋ",Ῡ:"Ῡ",Ῠ:"Ῠ",Ώ:"Ώ",Ὼ:"Ὼ"};class je{constructor(e,t){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new F4(e,t,this.mode),this.settings=t,this.leftrightDepth=0,this.nextToken=null}expect(e,t){if(t===void 0&&(t=!0),this.fetch().text!==e)throw new S("Expected '"+e+"', got '"+this.fetch().text+"'",this.fetch());t&&this.consume()}consume(){this.nextToken=null}fetch(){return this.nextToken==null&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken}switchMode(e){this.mode=e,this.gullet.switchMode(e)}parse(){this.settings.globalGroup||this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");try{var e=this.parseExpression(!1);return this.expect("EOF"),this.settings.globalGroup||this.gullet.endGroup(),e}finally{this.gullet.endGroups()}}subparse(e){var t=this.nextToken;this.consume(),this.gullet.pushToken(new c0("}")),this.gullet.pushTokens(e);var a=this.parseExpression(!1);return this.expect("}"),this.nextToken=t,a}parseExpression(e,t){for(var a=[];;){this.mode==="math"&&this.consumeSpaces();var i=this.fetch();if(je.endOfExpression.has(i.text)||t&&i.text===t||e&&O0[i.text]&&O0[i.text].infix)break;var s=this.parseAtom(t);if(s){if(s.type==="internal")continue}else break;a.push(s)}return this.mode==="text"&&this.formLigatures(a),this.handleInfixNodes(a)}handleInfixNodes(e){for(var t=-1,a,i=0;i=128)this.settings.strict&&(Gr(t.charCodeAt(0))?this.mode==="math"&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+t[0]+'" used in math mode',e):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+t[0]+'"'+(" ("+t.charCodeAt(0)+")"),e)),u={type:"textord",mode:"text",loc:h0.range(e),text:t};else return null;if(this.consume(),s)for(var p=0;p15?d="…"+c.slice(n-15,n):d=c.slice(0,n);var v;s+15r.replace(Ha,"-$1").toLowerCase(),Ga={"&":"&",">":">","<":"<",'"':""","'":"'"},Pa=/[&><"']/g,s0=r=>String(r).replace(Pa,e=>Ga[e]),_e=r=>r.type==="ordgroup"||r.type==="color"?r.body.length===1?_e(r.body[0]):r:r.type==="font"?_e(r.body):r,Ua=new Set(["mathord","textord","atom"]),_0=r=>Ua.has(_e(r).type),Va=r=>{var e=/^[\x00-\x20]*([^\\/#?]*?)(:|�*58|�*3a|&colon)/i.exec(r);return e?e[2]!==":"||!/^[a-zA-Z][a-zA-Z0-9+\-.]*$/.test(e[1])?null:e[1].toLowerCase():"_relative"},dt={displayMode:{type:"boolean",description:"Render math in display mode, which puts the math in display style (so \\int and \\sum are large, for example), and centers the math on the page on its own line.",cli:"-d, --display-mode"},output:{type:{enum:["htmlAndMathml","html","mathml"]},description:"Determines the markup language of the output.",cli:"-F, --format "},leqno:{type:"boolean",description:"Render display math in leqno style (left-justified tags)."},fleqn:{type:"boolean",description:"Render display math flush left."},throwOnError:{type:"boolean",default:!0,cli:"-t, --no-throw-on-error",cliDescription:"Render errors (in the color given by --error-color) instead of throwing a ParseError exception when encountering an error."},errorColor:{type:"string",default:"#cc0000",cli:"-c, --error-color ",cliDescription:"A color string given in the format 'rgb' or 'rrggbb' (no #). This option determines the color of errors rendered by the -t option.",cliProcessor:r=>"#"+r},macros:{type:"object",cli:"-m, --macro ",cliDescription:"Define custom macro of the form '\\foo:expansion' (use multiple -m arguments for multiple macros).",cliDefault:[],cliProcessor:(r,e)=>(e.push(r),e)},minRuleThickness:{type:"number",description:"Specifies a minimum thickness, in ems, for fraction lines, `\\sqrt` top lines, `{array}` vertical lines, `\\hline`, `\\hdashline`, `\\underline`, `\\overline`, and the borders of `\\fbox`, `\\boxed`, and `\\fcolorbox`.",processor:r=>Math.max(0,r),cli:"--min-rule-thickness ",cliProcessor:parseFloat},colorIsTextColor:{type:"boolean",description:"Makes \\color behave like LaTeX's 2-argument \\textcolor, instead of LaTeX's one-argument \\color mode change.",cli:"-b, --color-is-text-color"},strict:{type:[{enum:["warn","ignore","error"]},"boolean","function"],description:"Turn on strict / LaTeX faithfulness mode, which throws an error if the input uses features that are not supported by LaTeX.",cli:"-S, --strict",cliDefault:!1},trust:{type:["boolean","function"],description:"Trust the input, enabling all HTML features such as \\url.",cli:"-T, --trust"},maxSize:{type:"number",default:1/0,description:"If non-zero, all user-specified sizes, e.g. in \\rule{500em}{500em}, will be capped to maxSize ems. Otherwise, elements and spaces can be arbitrarily large",processor:r=>Math.max(0,r),cli:"-s, --max-size ",cliProcessor:parseInt},maxExpand:{type:"number",default:1e3,description:"Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to Infinity, the macro expander will try to fully expand as in LaTeX.",processor:r=>Math.max(0,r),cli:"-e, --max-expand ",cliProcessor:r=>r==="Infinity"?1/0:parseInt(r)},globalGroup:{type:"boolean",cli:!1}};function Xa(r){if(typeof r!="string")return r.enum[0];switch(r){case"boolean":return!1;case"string":return"";case"number":return 0;case"object":return{};default:throw new Error("Unexpected schema type; settings must declare an explicit default.")}}function Wa(r){if(r.default!==void 0)return r.default;var e=Array.isArray(r.type)?r.type[0]:r.type;return Xa(e)}function Ya(r,e,t,a){var n=t[e];r[e]=n!==void 0?a.processor?a.processor(n):n:Wa(a)}class _t{constructor(e){e===void 0&&(e={}),this.displayMode=void 0,this.output=void 0,this.leqno=void 0,this.fleqn=void 0,this.throwOnError=void 0,this.errorColor=void 0,this.macros=void 0,this.minRuleThickness=void 0,this.colorIsTextColor=void 0,this.strict=void 0,this.trust=void 0,this.maxSize=void 0,this.maxExpand=void 0,this.globalGroup=void 0,e=e||{};for(var t of Object.keys(dt)){var a=dt[t];a&&Ya(this,t,e,a)}}reportNonstrict(e,t,a){var n=this.strict;if(typeof n=="function"&&(n=n(e,t,a)),!(!n||n==="ignore")){if(n===!0||n==="error")throw new z("LaTeX-incompatible input and strict mode is set to 'error': "+(t+" ["+e+"]"),a);n==="warn"?typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+(t+" ["+e+"]")):typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to "+("unrecognized '"+n+"': "+t+" ["+e+"]"))}}useStrictBehavior(e,t,a){var n=this.strict;if(typeof n=="function")try{n=n(e,t,a)}catch{n="error"}return!n||n==="ignore"?!1:n===!0||n==="error"?!0:n==="warn"?(typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to 'warn': "+(t+" ["+e+"]")),!1):(typeof console<"u"&&console.warn("LaTeX-incompatible input and strict mode is set to "+("unrecognized '"+n+"': "+t+" ["+e+"]")),!1)}isTrusted(e){if("url"in e&&e.url&&!e.protocol){var t=Va(e.url);if(t==null)return!1;e.protocol=t}var a=typeof this.trust=="function"?this.trust(e):this.trust;return!!a}}class N0{constructor(e,t,a){this.id=void 0,this.size=void 0,this.cramped=void 0,this.id=e,this.size=t,this.cramped=a}sup(){return k0[Za[this.id]]}sub(){return k0[ja[this.id]]}fracNum(){return k0[Ka[this.id]]}fracDen(){return k0[Ja[this.id]]}cramp(){return k0[Qa[this.id]]}text(){return k0[e1[this.id]]}isTight(){return this.size>=2}}var Et=0,Ie=1,te=2,C0=3,me=4,b0=5,re=6,u0=7,k0=[new N0(Et,0,!1),new N0(Ie,0,!0),new N0(te,1,!1),new N0(C0,1,!0),new N0(me,2,!1),new N0(b0,2,!0),new N0(re,3,!1),new N0(u0,3,!0)],Za=[me,b0,me,b0,re,u0,re,u0],ja=[b0,b0,b0,b0,u0,u0,u0,u0],Ka=[te,C0,me,b0,re,u0,re,u0],Ja=[C0,C0,b0,b0,u0,u0,u0,u0],Qa=[Ie,Ie,C0,C0,b0,b0,u0,u0],e1=[Et,Ie,te,C0,te,C0,te,C0],N={DISPLAY:k0[Et],TEXT:k0[te],SCRIPT:k0[me],SCRIPTSCRIPT:k0[re]},pt=[{name:"latin",blocks:[[256,591],[768,879]]},{name:"cyrillic",blocks:[[1024,1279]]},{name:"armenian",blocks:[[1328,1423]]},{name:"brahmic",blocks:[[2304,4255]]},{name:"georgian",blocks:[[4256,4351]]},{name:"cjk",blocks:[[12288,12543],[19968,40879],[65280,65376]]},{name:"hangul",blocks:[[44032,55215]]}];function t1(r){for(var e=0;e=n[0]&&r<=n[1])return t.name}return null}var Ee=[];pt.forEach(r=>r.blocks.forEach(e=>Ee.push(...e)));function Hr(r){for(var e=0;e=Ee[e]&&r<=Ee[e+1])return!0;return!1}var n0=r=>r+" "+r,ee=80,r1=function(e,t){return"M95,"+(622+e+t)+` +c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14 +c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54 +c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10 +s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429 +c69,-144,104.5,-217.7,106.5,-221 +l`+e/2.075+" -"+e+` +c5.3,-9.3,12,-14,20,-14 +H400000v`+(40+e)+`H845.2724 +s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7 +c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z +M`+(834+e)+" "+t+"h400000v"+(40+e)+"h-400000z"},a1=function(e,t){return"M263,"+(601+e+t)+`c0.7,0,18,39.7,52,119 +c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120 +c340,-704.7,510.7,-1060.3,512,-1067 +l`+e/2.084+" -"+e+` +c4.7,-7.3,11,-11,19,-11 +H40000v`+(40+e)+`H1012.3 +s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232 +c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1 +s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26 +c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z +M`+(1001+e)+" "+t+"h400000v"+(40+e)+"h-400000z"},n1=function(e,t){return"M983 "+(10+e+t)+` +l`+e/3.13+" -"+e+` +c4,-6.7,10,-10,18,-10 H400000v`+(40+e)+` +H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7 +s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744 +c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30 +c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722 +c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5 +c53.7,-170.3,84.5,-266.8,92.5,-289.5z +M`+(1001+e)+" "+t+"h400000v"+(40+e)+"h-400000z"},i1=function(e,t){return"M424,"+(2398+e+t)+` +c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514 +c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20 +s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121 +s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081 +l`+e/4.223+" -"+e+`c4,-6.7,10,-10,18,-10 H400000 +v`+(40+e)+`H1014.6 +s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185 +c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2z M`+(1001+e)+" "+t+` +h400000v`+(40+e)+"h-400000z"},s1=function(e,t){return"M473,"+(2713+e+t)+` +c339.3,-1799.3,509.3,-2700,510,-2702 l`+e/5.298+" -"+e+` +c3.3,-7.3,9.3,-11,18,-11 H400000v`+(40+e)+`H1017.7 +s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9 +c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200 +c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26 +s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104, +606zM`+(1001+e)+" "+t+"h400000v"+(40+e)+"H1017.7z"},o1=function(e){var t=e/2;return"M400000 "+e+" H0 L"+t+" 0 l65 45 L145 "+(e-80)+" H400000z"},l1=function(e,t,a){var n=a-54-t-e;return"M702 "+(e+t)+"H400000"+(40+e)+` +H742v`+n+`l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1 +h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170 +c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667 +219 661 l218 661zM702 `+t+"H400000v"+(40+e)+"H742z"},u1=function(e,t,a){t=1e3*t;var n="";switch(e){case"sqrtMain":n=r1(t,ee);break;case"sqrtSize1":n=a1(t,ee);break;case"sqrtSize2":n=n1(t,ee);break;case"sqrtSize3":n=i1(t,ee);break;case"sqrtSize4":n=s1(t,ee);break;case"sqrtTall":n=l1(t,ee,a)}return n},c1=function(e,t){switch(e){case"⎜":return n0("M291 0 H417 V"+t+" H291z");case"∣":return n0("M145 0 H188 V"+t+" H145z");case"∥":return n0("M145 0 H188 V"+t+" H145z")+n0("M367 0 H410 V"+t+" H367z");case"⎟":return n0("M457 0 H583 V"+t+" H457z");case"⎢":return n0("M319 0 H403 V"+t+" H319z");case"⎥":return n0("M263 0 H347 V"+t+" H263z");case"⎪":return n0("M384 0 H504 V"+t+" H384z");case"⏐":return n0("M312 0 H355 V"+t+" H312z");case"‖":return n0("M257 0 H300 V"+t+" H257z")+n0("M478 0 H521 V"+t+" H478z");default:return""}},rr={doubleleftarrow:`M262 157 +l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3 + 0-12.2.5-14.5 1.5-2.3 1-4.8 4.5-7.5 10.5-49.3 97.3-121.7 169.3-217 216-28 + 14-57.3 25-88 33-6.7 2-11 3.8-13 5.5-2 1.7-3 4.2-3 7.5s1 5.8 3 7.5 +c2 1.7 6.3 3.5 13 5.5 68 17.3 128.2 47.8 180.5 91.5 52.3 43.7 93.8 96.2 124.5 + 157.5 9.3 8 15.3 12.3 18 13h6c12-.7 18-4 18-10 0-2-1.7-7-5-15-23.3-46-52-87 +-86-123l-10-10h399738v-40H218c328 0 0 0 0 0l-10-8c-26.7-20-65.7-43-117-69 2.7 +-2 6-3.7 10-5 36.7-16 72.3-37.3 107-64l10-8h399782v-40z +m8 0v40h399730v-40zm0 194v40h399730v-40z`,doublerightarrow:`M399738 392l +-10 10c-34 36-62.7 77-86 123-3.3 8-5 13.3-5 16 0 5.3 6.7 8 20 8 7.3 0 12.2-.5 + 14.5-1.5 2.3-1 4.8-4.5 7.5-10.5 49.3-97.3 121.7-169.3 217-216 28-14 57.3-25 88 +-33 6.7-2 11-3.8 13-5.5 2-1.7 3-4.2 3-7.5s-1-5.8-3-7.5c-2-1.7-6.3-3.5-13-5.5-68 +-17.3-128.2-47.8-180.5-91.5-52.3-43.7-93.8-96.2-124.5-157.5-9.3-8-15.3-12.3-18 +-13h-6c-12 .7-18 4-18 10 0 2 1.7 7 5 15 23.3 46 52 87 86 123l10 10H0v40h399782 +c-328 0 0 0 0 0l10 8c26.7 20 65.7 43 117 69-2.7 2-6 3.7-10 5-36.7 16-72.3 37.3 +-107 64l-10 8H0v40zM0 157v40h399730v-40zm0 194v40h399730v-40z`,leftarrow:`M400000 241H110l3-3c68.7-52.7 113.7-120 + 135-202 4-14.7 6-23 6-25 0-7.3-7-11-21-11-8 0-13.2.8-15.5 2.5-2.3 1.7-4.2 5.8 +-5.5 12.5-1.3 4.7-2.7 10.3-4 17-12 48.7-34.8 92-68.5 130S65.3 228.3 18 247 +c-10 4-16 7.7-18 11 0 8.7 6 14.3 18 17 47.3 18.7 87.8 47 121.5 85S196 441.3 208 + 490c.7 2 1.3 5 2 9s1.2 6.7 1.5 8c.3 1.3 1 3.3 2 6s2.2 4.5 3.5 5.5c1.3 1 3.3 + 1.8 6 2.5s6 1 10 1c14 0 21-3.7 21-11 0-2-2-10.3-6-25-20-79.3-65-146.7-135-202 + l-3-3h399890zM100 241v40h399900v-40z`,leftbrace:`M6 548l-6-6v-35l6-11c56-104 135.3-181.3 238-232 57.3-28.7 117 +-45 179-50h399577v120H403c-43.3 7-81 15-113 26-100.7 33-179.7 91-237 174-2.7 + 5-6 9-10 13-.7 1-7.3 1-20 1H6z`,leftbraceunder:`M0 6l6-6h17c12.688 0 19.313.3 20 1 4 4 7.313 8.3 10 13 + 35.313 51.3 80.813 93.8 136.5 127.5 55.688 33.7 117.188 55.8 184.5 66.5.688 + 0 2 .3 4 1 18.688 2.7 76 4.3 172 5h399450v120H429l-6-1c-124.688-8-235-61.7 +-331-161C60.687 138.7 32.312 99.3 7 54L0 41V6z`,leftgroup:`M400000 80 +H435C64 80 168.3 229.4 21 260c-5.9 1.2-18 0-18 0-2 0-3-1-3-3v-38C76 61 257 0 + 435 0h399565z`,leftgroupunder:`M400000 262 +H435C64 262 168.3 112.6 21 82c-5.9-1.2-18 0-18 0-2 0-3 1-3 3v38c76 158 257 219 + 435 219h399565z`,leftharpoon:`M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3 +-3.3 10.2-9.5 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5 +-18.3 3-21-1.3-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7 +-196 228-6.7 4.7-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40z`,leftharpoonplus:`M0 267c.7 5.3 3 10 7 14h399993v-40H93c3.3-3.3 10.2-9.5 + 20.5-18.5s17.8-15.8 22.5-20.5c50.7-52 88-110.3 112-175 4-11.3 5-18.3 3-21-1.3 +-4-7.3-6-18-6-8 0-13 .7-15 2s-4.7 6.7-8 16c-42 98.7-107.3 174.7-196 228-6.7 4.7 +-10.7 8-12 10-1.3 2-2 5.7-2 11zm100-26v40h399900v-40zM0 435v40h400000v-40z +m0 0v40h400000v-40z`,leftharpoondown:`M7 241c-4 4-6.333 8.667-7 14 0 5.333.667 9 2 11s5.333 + 5.333 12 10c90.667 54 156 130 196 228 3.333 10.667 6.333 16.333 9 17 2 .667 5 + 1 9 1h5c10.667 0 16.667-2 18-6 2-2.667 1-9.667-3-21-32-87.333-82.667-157.667 +-152-211l-3-3h399907v-40zM93 281 H400000 v-40L7 241z`,leftharpoondownplus:`M7 435c-4 4-6.3 8.7-7 14 0 5.3.7 9 2 11s5.3 5.3 12 + 10c90.7 54 156 130 196 228 3.3 10.7 6.3 16.3 9 17 2 .7 5 1 9 1h5c10.7 0 16.7 +-2 18-6 2-2.7 1-9.7-3-21-32-87.3-82.7-157.7-152-211l-3-3h399907v-40H7zm93 0 +v40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z`,lefthook:`M400000 281 H103s-33-11.2-61-33.5S0 197.3 0 164s14.2-61.2 42.5 +-83.5C70.8 58.2 104 47 142 47 c16.7 0 25 6.7 25 20 0 12-8.7 18.7-26 20-40 3.3 +-68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21 + 71.5 23h399859zM103 281v-40h399897v40z`,leftlinesegment:n0("M40 281 V428 H0 V94 H40 V241 H400000 v40z"),leftbracketunder:n0("M0 0 h120 V290 H399995 v120 H0z"),leftbracketover:n0("M0 440 h120 V150 H399995 v-120 H0z"),leftmapsto:n0("M40 281 V448H0V74H40V241H400000v40z"),leftToFrom:`M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23 +-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69-70-101l-7-8h399905v-40H95l7-8 +c28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3 + 68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z`,longequal:n0("M0 50 h400000 v40H0z m0 194h40000v40H0z"),midbrace:`M200428 334 +c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14 +-53.3 86.7-123.7 153-211 199-66.7 36-137.3 56.3-212 62H0V214h199568c178.3-11.7 + 311.7-78.3 403-201 6-8 9.7-12 11-12 .7-.7 6.7-1 18-1s17.3.3 18 1c1.3 0 5 4 11 + 12 44.7 59.3 101.3 106.3 170 141s145.3 54.3 229 60h199572v120z`,midbraceunder:`M199572 214 +c100.7 8.3 195.3 44 280 108 55.3 42 101.7 93 139 153l9 14c2.7-4 5.7-8.7 9-14 + 53.3-86.7 123.7-153 211-199 66.7-36 137.3-56.3 212-62h199568v120H200432c-178.3 + 11.7-311.7 78.3-403 201-6 8-9.7 12-11 12-.7.7-6.7 1-18 1s-17.3-.3-18-1c-1.3 0 +-5-4-11-12-44.7-59.3-101.3-106.3-170-141s-145.3-54.3-229-60H0V214z`,oiintSize1:`M512.6 71.6c272.6 0 320.3 106.8 320.3 178.2 0 70.8-47.7 177.6 +-320.3 177.6S193.1 320.6 193.1 249.8c0-71.4 46.9-178.2 319.5-178.2z +m368.1 178.2c0-86.4-60.9-215.4-368.1-215.4-306.4 0-367.3 129-367.3 215.4 0 85.8 +60.9 214.8 367.3 214.8 307.2 0 368.1-129 368.1-214.8z`,oiintSize2:`M757.8 100.1c384.7 0 451.1 137.6 451.1 230 0 91.3-66.4 228.8 +-451.1 228.8-386.3 0-452.7-137.5-452.7-228.8 0-92.4 66.4-230 452.7-230z +m502.4 230c0-111.2-82.4-277.2-502.4-277.2s-504 166-504 277.2 +c0 110 84 276 504 276s502.4-166 502.4-276z`,oiiintSize1:`M681.4 71.6c408.9 0 480.5 106.8 480.5 178.2 0 70.8-71.6 177.6 +-480.5 177.6S202.1 320.6 202.1 249.8c0-71.4 70.5-178.2 479.3-178.2z +m525.8 178.2c0-86.4-86.8-215.4-525.7-215.4-437.9 0-524.7 129-524.7 215.4 0 +85.8 86.8 214.8 524.7 214.8 438.9 0 525.7-129 525.7-214.8z`,oiiintSize2:`M1021.2 53c603.6 0 707.8 165.8 707.8 277.2 0 110-104.2 275.8 +-707.8 275.8-606 0-710.2-165.8-710.2-275.8C311 218.8 415.2 53 1021.2 53z +m770.4 277.1c0-131.2-126.4-327.6-770.5-327.6S248.4 198.9 248.4 330.1 +c0 130 128.8 326.4 772.7 326.4s770.5-196.4 770.5-326.4z`,rightarrow:`M0 241v40h399891c-47.3 35.3-84 78-110 128 +-16.7 32-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 + 11 8 0 13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 + 39-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85 +-40.5-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 + 151.7 139 205zm0 0v40h399900v-40z`,rightbrace:`M400000 542l +-6 6h-17c-12.7 0-19.3-.3-20-1-4-4-7.3-8.3-10-13-35.3-51.3-80.8-93.8-136.5-127.5 +s-117.2-55.8-184.5-66.5c-.7 0-2-.3-4-1-18.7-2.7-76-4.3-172-5H0V214h399571l6 1 +c124.7 8 235 61.7 331 161 31.3 33.3 59.7 72.7 85 118l7 13v35z`,rightbraceunder:`M399994 0l6 6v35l-6 11c-56 104-135.3 181.3-238 232-57.3 + 28.7-117 45-179 50H-300V214h399897c43.3-7 81-15 113-26 100.7-33 179.7-91 237 +-174 2.7-5 6-9 10-13 .7-1 7.3-1 20-1h17z`,rightgroup:`M0 80h399565c371 0 266.7 149.4 414 180 5.9 1.2 18 0 18 0 2 0 + 3-1 3-3v-38c-76-158-257-219-435-219H0z`,rightgroupunder:`M0 262h399565c371 0 266.7-149.4 414-180 5.9-1.2 18 0 18 + 0 2 0 3 1 3 3v38c-76 158-257 219-435 219H0z`,rightharpoon:`M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3 +-3.7-15.3-11-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2 +-10.7 0-16.7 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 + 69.2 92 94.5zm0 0v40h399900v-40z`,rightharpoonplus:`M0 241v40h399993c4.7-4.7 7-9.3 7-14 0-9.3-3.7-15.3-11 +-18-92.7-56.7-159-133.7-199-231-3.3-9.3-6-14.7-8-16-2-1.3-7-2-15-2-10.7 0-16.7 + 2-18 6-2 2.7-1 9.7 3 21 15.3 42 36.7 81.8 64 119.5 27.3 37.7 58 69.2 92 94.5z +m0 0v40h399900v-40z m100 194v40h399900v-40zm0 0v40h399900v-40z`,rightharpoondown:`M399747 511c0 7.3 6.7 11 20 11 8 0 13-.8 15-2.5s4.7-6.8 + 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 8.5-5.8 9.5 +-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3-64.7 57-92 95 +-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 241v40h399900v-40z`,rightharpoondownplus:`M399747 705c0 7.3 6.7 11 20 11 8 0 13-.8 + 15-2.5s4.7-6.8 8-15.5c40-94 99.3-166.3 178-217 13.3-8 20.3-12.3 21-13 5.3-3.3 + 8.5-5.8 9.5-7.5 1-1.7 1.5-5.2 1.5-10.5s-2.3-10.3-7-15H0v40h399908c-34 25.3 +-64.7 57-92 95-27.3 38-48.7 77.7-64 119-3.3 8.7-5 14-5 16zM0 435v40h399900v-40z +m0-194v40h400000v-40zm0 0v40h400000v-40z`,righthook:`M399859 241c-764 0 0 0 0 0 40-3.3 68.7-15.7 86-37 10-12 15-25.3 + 15-40 0-22.7-9.8-40.7-29.5-54-19.7-13.3-43.5-21-71.5-23-17.3-1.3-26-8-26-20 0 +-13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21 + 66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z`,rightlinesegment:n0("M399960 241 V94 h40 V428 h-40 V281 H0 v-40z"),rightbracketunder:n0("M399995 0 h-120 V290 H0 v120 H400000z"),rightbracketover:n0("M399995 440 h-120 V150 H0 v-120 H399995z"),rightToFrom:`M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23 + 1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32 +-52 65.7-70 101-10.7 23.3-16 35.7-16 37 0 .7 7.7 1 23 1h23c24-69.3 71.3-125 142 +-167z M100 147v40h399900v-40zM0 341v40h399900v-40z`,twoheadleftarrow:`M0 167c68 40 + 115.7 95.7 143 167h22c15.3 0 23-.3 23-1 0-1.3-5.3-13.7-16-37-18-35.3-41.3-69 +-70-101l-7-8h125l9 7c50.7 39.3 85 86 103 140h46c0-4.7-6.3-18.7-19-42-18-35.3 +-40-67.3-66-96l-9-9h399716v-40H284l9-9c26-28.7 48-60.7 66-96 12.7-23.333 19 +-37.333 19-42h-46c-18 54-52.3 100.7-103 140l-9 7H95l7-8c28.7-32 52-65.7 70-101 + 10.7-23.333 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 71.3 68 127 0 167z`,twoheadrightarrow:`M400000 167 +c-68-40-115.7-95.7-143-167h-22c-15.3 0-23 .3-23 1 0 1.3 5.3 13.7 16 37 18 35.3 + 41.3 69 70 101l7 8h-125l-9-7c-50.7-39.3-85-86-103-140h-46c0 4.7 6.3 18.7 19 42 + 18 35.3 40 67.3 66 96l9 9H0v40h399716l-9 9c-26 28.7-48 60.7-66 96-12.7 23.333 +-19 37.333-19 42h46c18-54 52.3-100.7 103-140l9-7h125l-7 8c-28.7 32-52 65.7-70 + 101-10.7 23.333-16 35.7-16 37 0 .7 7.7 1 23 1h22c27.3-71.3 75-127 143-167z`,tilde1:`M200 55.538c-77 0-168 73.953-177 73.953-3 0-7 +-2.175-9-5.437L2 97c-1-2-2-4-2-6 0-4 2-7 5-9l20-12C116 12 171 0 207 0c86 0 + 114 68 191 68 78 0 168-68 177-68 4 0 7 2 9 5l12 19c1 2.175 2 4.35 2 6.525 0 + 4.35-2 7.613-5 9.788l-19 13.05c-92 63.077-116.937 75.308-183 76.128 +-68.267.847-113-73.952-191-73.952z`,tilde2:`M344 55.266c-142 0-300.638 81.316-311.5 86.418 +-8.01 3.762-22.5 10.91-23.5 5.562L1 120c-1-2-1-3-1-4 0-5 3-9 8-10l18.4-9C160.9 + 31.9 283 0 358 0c148 0 188 122 331 122s314-97 326-97c4 0 8 2 10 7l7 21.114 +c1 2.14 1 3.21 1 4.28 0 5.347-3 9.626-7 10.696l-22.3 12.622C852.6 158.372 751 + 181.476 676 181.476c-149 0-189-126.21-332-126.21z`,tilde3:`M786 59C457 59 32 175.242 13 175.242c-6 0-10-3.457 +-11-10.37L.15 138c-1-7 3-12 10-13l19.2-6.4C378.4 40.7 634.3 0 804.3 0c337 0 + 411.8 157 746.8 157 328 0 754-112 773-112 5 0 10 3 11 9l1 14.075c1 8.066-.697 + 16.595-6.697 17.492l-21.052 7.31c-367.9 98.146-609.15 122.696-778.15 122.696 + -338 0-409-156.573-744-156.573z`,tilde4:`M786 58C457 58 32 177.487 13 177.487c-6 0-10-3.345 +-11-10.035L.15 143c-1-7 3-12 10-13l22-6.7C381.2 35 637.15 0 807.15 0c337 0 409 + 177 744 177 328 0 754-127 773-127 5 0 10 3 11 9l1 14.794c1 7.805-3 13.38-9 + 14.495l-20.7 5.574c-366.85 99.79-607.3 139.372-776.3 139.372-338 0-409 + -175.236-744-175.236z`,vec:`M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 5 +3.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 11 +10.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63 +-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1 +-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59 +H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359 +c-16-25.333-24-45-24-59z`,widehat1:`M529 0h5l519 115c5 1 9 5 9 10 0 1-1 2-1 3l-4 22 +c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z`,widehat2:`M1181 0h2l1171 176c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 220h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widehat3:`M1181 0h2l1171 236c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 280h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widehat4:`M1181 0h2l1171 296c6 0 10 5 10 11l-2 23c-1 6-5 10 +-11 10h-1L1182 67 15 340h-1c-6 0-10-4-11-10l-2-23c-1-6 4-11 10-11z`,widecheck1:`M529,159h5l519,-115c5,-1,9,-5,9,-10c0,-1,-1,-2,-1,-3l-4,-22c-1, +-5,-5,-9,-11,-9h-2l-512,92l-513,-92h-2c-5,0,-9,4,-11,9l-5,22c-1,6,2,12,8,13z`,widecheck2:`M1181,220h2l1171,-176c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,153l-1167,-153h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,widecheck3:`M1181,280h2l1171,-236c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,213l-1167,-213h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,widecheck4:`M1181,340h2l1171,-296c6,0,10,-5,10,-11l-2,-23c-1,-6,-5,-10, +-11,-10h-1l-1168,273l-1167,-273h-1c-6,0,-10,4,-11,10l-2,23c-1,6,4,11,10,11z`,baraboveleftarrow:`M400000 620h-399890l3 -3c68.7 -52.7 113.7 -120 135 -202 +c4 -14.7 6 -23 6 -25c0 -7.3 -7 -11 -21 -11c-8 0 -13.2 0.8 -15.5 2.5 +c-2.3 1.7 -4.2 5.8 -5.5 12.5c-1.3 4.7 -2.7 10.3 -4 17c-12 48.7 -34.8 92 -68.5 130 +s-74.2 66.3 -121.5 85c-10 4 -16 7.7 -18 11c0 8.7 6 14.3 18 17c47.3 18.7 87.8 47 +121.5 85s56.5 81.3 68.5 130c0.7 2 1.3 5 2 9s1.2 6.7 1.5 8c0.3 1.3 1 3.3 2 6 +s2.2 4.5 3.5 5.5c1.3 1 3.3 1.8 6 2.5s6 1 10 1c14 0 21 -3.7 21 -11 +c0 -2 -2 -10.3 -6 -25c-20 -79.3 -65 -146.7 -135 -202l-3 -3h399890z +M100 620v40h399900v-40z M0 241v40h399900v-40zM0 241v40h399900v-40z`,rightarrowabovebar:`M0 241v40h399891c-47.3 35.3-84 78-110 128-16.7 32 +-27.7 63.7-33 95 0 1.3-.2 2.7-.5 4-.3 1.3-.5 2.3-.5 3 0 7.3 6.7 11 20 11 8 0 +13.2-.8 15.5-2.5 2.3-1.7 4.2-5.5 5.5-11.5 2-13.3 5.7-27 11-41 14.7-44.7 39 +-84.5 73-119.5s73.7-60.2 119-75.5c6-2 9-5.7 9-11s-3-9-9-11c-45.3-15.3-85-40.5 +-119-75.5s-58.3-74.8-73-119.5c-4.7-14-8.3-27.3-11-40-1.3-6.7-3.2-10.8-5.5 +-12.5-2.3-1.7-7.5-2.5-15.5-2.5-14 0-21 3.7-21 11 0 2 2 10.3 6 25 20.7 83.3 67 +151.7 139 205zm96 379h399894v40H0zm0 0h399904v40H0z`,baraboveshortleftharpoon:`M507,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17 +c2,0.7,5,1,9,1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21 +c-32,-87.3,-82.7,-157.7,-152,-211c0,0,-3,-3,-3,-3l399351,0l0,-40 +c-398570,0,-399437,0,-399437,0z M593 435 v40 H399500 v-40z +M0 281 v-40 H399908 v40z M0 281 v-40 H399908 v40z`,rightharpoonaboveshortbar:`M0,241 l0,40c399126,0,399993,0,399993,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M0 241 v40 H399908 v-40z M0 475 v-40 H399500 v40z M0 475 v-40 H399500 v40z`,shortbaraboveleftharpoon:`M7,435c-4,4,-6.3,8.7,-7,14c0,5.3,0.7,9,2,11 +c1.3,2,5.3,5.3,12,10c90.7,54,156,130,196,228c3.3,10.7,6.3,16.3,9,17c2,0.7,5,1,9, +1c0,0,5,0,5,0c10.7,0,16.7,-2,18,-6c2,-2.7,1,-9.7,-3,-21c-32,-87.3,-82.7,-157.7, +-152,-211c0,0,-3,-3,-3,-3l399907,0l0,-40c-399126,0,-399993,0,-399993,0z +M93 435 v40 H400000 v-40z M500 241 v40 H400000 v-40z M500 241 v40 H400000 v-40z`,shortrightharpoonabovebar:`M53,241l0,40c398570,0,399437,0,399437,0 +c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199, +-231c-3.3,-9.3,-6,-14.7,-8,-16c-2,-1.3,-7,-2,-15,-2c-10.7,0,-16.7,2,-18,6 +c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z +M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`},h1=function(e,t){switch(e){case"lbrack":return"M403 1759 V84 H666 V0 H319 V1759 v"+t+` v1759 v84 h347 v-84 +H403z M403 1759 V0 H319 V1759 v`+t+" v1759 v84 h84z";case"rbrack":return"M347 1759 V0 H0 V84 H263 V1759 v"+t+` v1759 H0 v84 H347z +M347 1759 V0 H263 V1759 v`+t+" v1759 h84z";case"vert":return"M145 15 v585 v"+t+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-t+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v`+t+" v585 h43z";case"doublevert":return"M145 15 v585 v"+t+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-t+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v`+t+` v585 h43z +M367 15 v585 v`+t+` v585 c2.667,10,9.667,15,21,15 +c10,0,16.667,-5,20,-15 v-585 v`+-t+` v-585 c-2.667,-10,-9.667,-15,-21,-15 +c-10,0,-16.667,5,-20,15z M410 15 H367 v585 v`+t+" v585 h43z";case"lfloor":return"M319 602 V0 H403 V602 v"+t+` v1715 h263 v84 H319z +MM319 602 V0 H403 V602 v`+t+" v1715 H319z";case"rfloor":return"M319 602 V0 H403 V602 v"+t+` v1799 H0 v-84 H319z +MM319 602 V0 H403 V602 v`+t+" v1715 H319z";case"lceil":return"M403 1759 V84 H666 V0 H319 V1759 v"+t+` v602 h84z +M403 1759 V0 H319 V1759 v`+t+" v602 h84z";case"rceil":return"M347 1759 V0 H0 V84 H263 V1759 v"+t+` v602 h84z +M347 1759 V0 h-84 V1759 v`+t+" v602 h84z";case"lparen":return`M863,9c0,-2,-2,-5,-6,-9c0,0,-17,0,-17,0c-12.7,0,-19.3,0.3,-20,1 +c-5.3,5.3,-10.3,11,-15,17c-242.7,294.7,-395.3,682,-458,1162c-21.3,163.3,-33.3,349, +-36,557 l0,`+(t+84)+`c0.2,6,0,26,0,60c2,159.3,10,310.7,24,454c53.3,528,210, +949.7,470,1265c4.7,6,9.7,11.7,15,17c0.7,0.7,7,1,19,1c0,0,18,0,18,0c4,-4,6,-7,6,-9 +c0,-2.7,-3.3,-8.7,-10,-18c-135.3,-192.7,-235.5,-414.3,-300.5,-665c-65,-250.7,-102.5, +-544.7,-112.5,-882c-2,-104,-3,-167,-3,-189 +l0,-`+(t+92)+`c0,-162.7,5.7,-314,17,-454c20.7,-272,63.7,-513,129,-723c65.3, +-210,155.3,-396.3,270,-559c6.7,-9.3,10,-15.3,10,-18z`;case"rparen":return`M76,0c-16.7,0,-25,3,-25,9c0,2,2,6.3,6,13c21.3,28.7,42.3,60.3, +63,95c96.7,156.7,172.8,332.5,228.5,527.5c55.7,195,92.8,416.5,111.5,664.5 +c11.3,139.3,17,290.7,17,454c0,28,1.7,43,3.3,45l0,`+(t+9)+` +c-3,4,-3.3,16.7,-3.3,38c0,162,-5.7,313.7,-17,455c-18.7,248,-55.8,469.3,-111.5,664 +c-55.7,194.7,-131.8,370.3,-228.5,527c-20.7,34.7,-41.7,66.3,-63,95c-2,3.3,-4,7,-6,11 +c0,7.3,5.7,11,17,11c0,0,11,0,11,0c9.3,0,14.3,-0.3,15,-1c5.3,-5.3,10.3,-11,15,-17 +c242.7,-294.7,395.3,-681.7,458,-1161c21.3,-164.7,33.3,-350.7,36,-558 +l0,-`+(t+144)+`c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7, +-470,-1265c-4.7,-6,-9.7,-11.7,-15,-17c-0.7,-0.7,-6.7,-1,-18,-1z`;default:throw new Error("Unknown stretchy delimiter.")}};function m1(r){return"toText"in r}class ie{constructor(e){this.children=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.children=e,this.classes=[],this.height=0,this.depth=0,this.maxFontSize=0,this.style={}}hasClass(e){return this.classes.includes(e)}toNode(){for(var e=document.createDocumentFragment(),t=0;t{if(m1(e))return e.toText();throw new Error("Expected MathDomNode with toText, got "+e.constructor.name)}).join("")}}var ft={pt:1,mm:7227/2540,cm:7227/254,in:72.27,bp:803/800,pc:12,dd:1238/1157,cc:14856/1157,nd:685/642,nc:1370/107,sp:1/65536,px:803/800},d1={ex:!0,em:!0,mu:!0},Lr=function(e){return typeof e!="string"&&(e=e.unit),e in ft||e in d1||e==="ex"},J=function(e,t){var a;if(e.unit in ft)a=ft[e.unit]/t.fontMetrics().ptPerEm/t.sizeMultiplier;else if(e.unit==="mu")a=t.fontMetrics().cssEmPerMu;else{var n;if(t.style.isTight()?n=t.havingStyle(t.style.text()):n=t,e.unit==="ex")a=n.fontMetrics().xHeight;else if(e.unit==="em")a=n.fontMetrics().quad;else throw new z("Invalid unit: '"+e.unit+"'");n!==t&&(a*=n.sizeMultiplier/t.sizeMultiplier)}return Math.min(e.number*a,t.maxSize)},M=function(e){return+e.toFixed(4)+"em"},L0=function(e){return e.filter(t=>t).join(" ")},It=function(e){var t="";for(var a of Object.keys(e)){var n=e[a];n!==void 0&&(t+=La(a)+":"+n+";")}return t},Gr=function(e,t,a){if(this.classes=e||[],this.attributes={},this.height=0,this.depth=0,this.maxFontSize=0,this.style=a||{},t){t.style.isTight()&&this.classes.push("mtight");var n=t.getColor();n&&(this.style.color=n)}},Pr=function(e){var t=document.createElement(e);t.className=L0(this.classes),Object.assign(t.style,this.style);for(var a of Object.keys(this.attributes))t.setAttribute(a,this.attributes[a]);for(var n=0;n/=\x00-\x1f]/,Ur=function(e){var t="<"+e;this.classes.length&&(t+=' class="'+s0(L0(this.classes))+'"');var a=It(this.style);a&&(t+=' style="'+s0(a)+'"');for(var n of Object.keys(this.attributes)){if(p1.test(n))throw new z("Invalid attribute name '"+n+"'");t+=" "+n+'="'+s0(this.attributes[n])+'"'}t+=">";for(var s=0;s",t};class se{constructor(e,t,a,n){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.width=void 0,this.maxFontSize=void 0,this.style=void 0,this.italic=void 0,Gr.call(this,e,a,n),this.children=t||[]}setAttribute(e,t){this.attributes[e]=t}hasClass(e){return this.classes.includes(e)}toNode(){return Pr.call(this,"span")}toMarkup(){return Ur.call(this,"span")}}class Re{constructor(e,t,a,n){this.children=void 0,this.attributes=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,Gr.call(this,t,n),this.children=a||[],this.setAttribute("href",e)}setAttribute(e,t){this.attributes[e]=t}hasClass(e){return this.classes.includes(e)}toNode(){return Pr.call(this,"a")}toMarkup(){return Ur.call(this,"a")}}class f1{constructor(e,t,a){this.src=void 0,this.alt=void 0,this.classes=void 0,this.height=void 0,this.depth=void 0,this.maxFontSize=void 0,this.style=void 0,this.alt=t,this.src=e,this.classes=["mord"],this.height=0,this.depth=0,this.maxFontSize=0,this.style=a}hasClass(e){return this.classes.includes(e)}toNode(){var e=document.createElement("img");return e.src=this.src,e.alt=this.alt,e.className="mord",Object.assign(e.style,this.style),e}toMarkup(){var e=''+s0(this.alt)+'0&&(t=document.createElement("span"),t.style.marginRight=M(this.italic)),this.classes.length>0&&(t=t||document.createElement("span"),t.className=L0(this.classes)),Object.keys(this.style).length>0&&(t=t||document.createElement("span"),Object.assign(t.style,this.style)),t?(t.appendChild(e),t):e}toMarkup(){var e=!1,t="0&&(a+="margin-right:"+M(this.italic)+";"),a+=It(this.style),a&&(e=!0,t+=' style="'+s0(a)+'"');var n=s0(this.text);return e?(t+=">",t+=n,t+="",t):n}}class B0{constructor(e,t){this.children=void 0,this.attributes=void 0,this.children=e||[],this.attributes=t||{}}toNode(){var e="http://www.w3.org/2000/svg",t=document.createElementNS(e,"svg");for(var a of Object.keys(this.attributes))t.setAttribute(a,this.attributes[a]);for(var n=0;n':''}}class vt{constructor(e){this.attributes=void 0,this.attributes=e||{}}toNode(){var e="http://www.w3.org/2000/svg",t=document.createElementNS(e,"line");for(var a of Object.keys(this.attributes))t.setAttribute(a,this.attributes[a]);return t}toMarkup(){var e=" but got "+String(r)+".")}var y1=r=>r instanceof se||r instanceof Re||r instanceof ie,z0={"AMS-Regular":{32:[0,0,0,0,.25],65:[0,.68889,0,0,.72222],66:[0,.68889,0,0,.66667],67:[0,.68889,0,0,.72222],68:[0,.68889,0,0,.72222],69:[0,.68889,0,0,.66667],70:[0,.68889,0,0,.61111],71:[0,.68889,0,0,.77778],72:[0,.68889,0,0,.77778],73:[0,.68889,0,0,.38889],74:[.16667,.68889,0,0,.5],75:[0,.68889,0,0,.77778],76:[0,.68889,0,0,.66667],77:[0,.68889,0,0,.94445],78:[0,.68889,0,0,.72222],79:[.16667,.68889,0,0,.77778],80:[0,.68889,0,0,.61111],81:[.16667,.68889,0,0,.77778],82:[0,.68889,0,0,.72222],83:[0,.68889,0,0,.55556],84:[0,.68889,0,0,.66667],85:[0,.68889,0,0,.72222],86:[0,.68889,0,0,.72222],87:[0,.68889,0,0,1],88:[0,.68889,0,0,.72222],89:[0,.68889,0,0,.72222],90:[0,.68889,0,0,.66667],107:[0,.68889,0,0,.55556],160:[0,0,0,0,.25],165:[0,.675,.025,0,.75],174:[.15559,.69224,0,0,.94666],240:[0,.68889,0,0,.55556],295:[0,.68889,0,0,.54028],710:[0,.825,0,0,2.33334],732:[0,.9,0,0,2.33334],770:[0,.825,0,0,2.33334],771:[0,.9,0,0,2.33334],989:[.08167,.58167,0,0,.77778],1008:[0,.43056,.04028,0,.66667],8245:[0,.54986,0,0,.275],8463:[0,.68889,0,0,.54028],8487:[0,.68889,0,0,.72222],8498:[0,.68889,0,0,.55556],8502:[0,.68889,0,0,.66667],8503:[0,.68889,0,0,.44445],8504:[0,.68889,0,0,.66667],8513:[0,.68889,0,0,.63889],8592:[-.03598,.46402,0,0,.5],8594:[-.03598,.46402,0,0,.5],8602:[-.13313,.36687,0,0,1],8603:[-.13313,.36687,0,0,1],8606:[.01354,.52239,0,0,1],8608:[.01354,.52239,0,0,1],8610:[.01354,.52239,0,0,1.11111],8611:[.01354,.52239,0,0,1.11111],8619:[0,.54986,0,0,1],8620:[0,.54986,0,0,1],8621:[-.13313,.37788,0,0,1.38889],8622:[-.13313,.36687,0,0,1],8624:[0,.69224,0,0,.5],8625:[0,.69224,0,0,.5],8630:[0,.43056,0,0,1],8631:[0,.43056,0,0,1],8634:[.08198,.58198,0,0,.77778],8635:[.08198,.58198,0,0,.77778],8638:[.19444,.69224,0,0,.41667],8639:[.19444,.69224,0,0,.41667],8642:[.19444,.69224,0,0,.41667],8643:[.19444,.69224,0,0,.41667],8644:[.1808,.675,0,0,1],8646:[.1808,.675,0,0,1],8647:[.1808,.675,0,0,1],8648:[.19444,.69224,0,0,.83334],8649:[.1808,.675,0,0,1],8650:[.19444,.69224,0,0,.83334],8651:[.01354,.52239,0,0,1],8652:[.01354,.52239,0,0,1],8653:[-.13313,.36687,0,0,1],8654:[-.13313,.36687,0,0,1],8655:[-.13313,.36687,0,0,1],8666:[.13667,.63667,0,0,1],8667:[.13667,.63667,0,0,1],8669:[-.13313,.37788,0,0,1],8672:[-.064,.437,0,0,1.334],8674:[-.064,.437,0,0,1.334],8705:[0,.825,0,0,.5],8708:[0,.68889,0,0,.55556],8709:[.08167,.58167,0,0,.77778],8717:[0,.43056,0,0,.42917],8722:[-.03598,.46402,0,0,.5],8724:[.08198,.69224,0,0,.77778],8726:[.08167,.58167,0,0,.77778],8733:[0,.69224,0,0,.77778],8736:[0,.69224,0,0,.72222],8737:[0,.69224,0,0,.72222],8738:[.03517,.52239,0,0,.72222],8739:[.08167,.58167,0,0,.22222],8740:[.25142,.74111,0,0,.27778],8741:[.08167,.58167,0,0,.38889],8742:[.25142,.74111,0,0,.5],8756:[0,.69224,0,0,.66667],8757:[0,.69224,0,0,.66667],8764:[-.13313,.36687,0,0,.77778],8765:[-.13313,.37788,0,0,.77778],8769:[-.13313,.36687,0,0,.77778],8770:[-.03625,.46375,0,0,.77778],8774:[.30274,.79383,0,0,.77778],8776:[-.01688,.48312,0,0,.77778],8778:[.08167,.58167,0,0,.77778],8782:[.06062,.54986,0,0,.77778],8783:[.06062,.54986,0,0,.77778],8785:[.08198,.58198,0,0,.77778],8786:[.08198,.58198,0,0,.77778],8787:[.08198,.58198,0,0,.77778],8790:[0,.69224,0,0,.77778],8791:[.22958,.72958,0,0,.77778],8796:[.08198,.91667,0,0,.77778],8806:[.25583,.75583,0,0,.77778],8807:[.25583,.75583,0,0,.77778],8808:[.25142,.75726,0,0,.77778],8809:[.25142,.75726,0,0,.77778],8812:[.25583,.75583,0,0,.5],8814:[.20576,.70576,0,0,.77778],8815:[.20576,.70576,0,0,.77778],8816:[.30274,.79383,0,0,.77778],8817:[.30274,.79383,0,0,.77778],8818:[.22958,.72958,0,0,.77778],8819:[.22958,.72958,0,0,.77778],8822:[.1808,.675,0,0,.77778],8823:[.1808,.675,0,0,.77778],8828:[.13667,.63667,0,0,.77778],8829:[.13667,.63667,0,0,.77778],8830:[.22958,.72958,0,0,.77778],8831:[.22958,.72958,0,0,.77778],8832:[.20576,.70576,0,0,.77778],8833:[.20576,.70576,0,0,.77778],8840:[.30274,.79383,0,0,.77778],8841:[.30274,.79383,0,0,.77778],8842:[.13597,.63597,0,0,.77778],8843:[.13597,.63597,0,0,.77778],8847:[.03517,.54986,0,0,.77778],8848:[.03517,.54986,0,0,.77778],8858:[.08198,.58198,0,0,.77778],8859:[.08198,.58198,0,0,.77778],8861:[.08198,.58198,0,0,.77778],8862:[0,.675,0,0,.77778],8863:[0,.675,0,0,.77778],8864:[0,.675,0,0,.77778],8865:[0,.675,0,0,.77778],8872:[0,.69224,0,0,.61111],8873:[0,.69224,0,0,.72222],8874:[0,.69224,0,0,.88889],8876:[0,.68889,0,0,.61111],8877:[0,.68889,0,0,.61111],8878:[0,.68889,0,0,.72222],8879:[0,.68889,0,0,.72222],8882:[.03517,.54986,0,0,.77778],8883:[.03517,.54986,0,0,.77778],8884:[.13667,.63667,0,0,.77778],8885:[.13667,.63667,0,0,.77778],8888:[0,.54986,0,0,1.11111],8890:[.19444,.43056,0,0,.55556],8891:[.19444,.69224,0,0,.61111],8892:[.19444,.69224,0,0,.61111],8901:[0,.54986,0,0,.27778],8903:[.08167,.58167,0,0,.77778],8905:[.08167,.58167,0,0,.77778],8906:[.08167,.58167,0,0,.77778],8907:[0,.69224,0,0,.77778],8908:[0,.69224,0,0,.77778],8909:[-.03598,.46402,0,0,.77778],8910:[0,.54986,0,0,.76042],8911:[0,.54986,0,0,.76042],8912:[.03517,.54986,0,0,.77778],8913:[.03517,.54986,0,0,.77778],8914:[0,.54986,0,0,.66667],8915:[0,.54986,0,0,.66667],8916:[0,.69224,0,0,.66667],8918:[.0391,.5391,0,0,.77778],8919:[.0391,.5391,0,0,.77778],8920:[.03517,.54986,0,0,1.33334],8921:[.03517,.54986,0,0,1.33334],8922:[.38569,.88569,0,0,.77778],8923:[.38569,.88569,0,0,.77778],8926:[.13667,.63667,0,0,.77778],8927:[.13667,.63667,0,0,.77778],8928:[.30274,.79383,0,0,.77778],8929:[.30274,.79383,0,0,.77778],8934:[.23222,.74111,0,0,.77778],8935:[.23222,.74111,0,0,.77778],8936:[.23222,.74111,0,0,.77778],8937:[.23222,.74111,0,0,.77778],8938:[.20576,.70576,0,0,.77778],8939:[.20576,.70576,0,0,.77778],8940:[.30274,.79383,0,0,.77778],8941:[.30274,.79383,0,0,.77778],8994:[.19444,.69224,0,0,.77778],8995:[.19444,.69224,0,0,.77778],9416:[.15559,.69224,0,0,.90222],9484:[0,.69224,0,0,.5],9488:[0,.69224,0,0,.5],9492:[0,.37788,0,0,.5],9496:[0,.37788,0,0,.5],9585:[.19444,.68889,0,0,.88889],9586:[.19444,.74111,0,0,.88889],9632:[0,.675,0,0,.77778],9633:[0,.675,0,0,.77778],9650:[0,.54986,0,0,.72222],9651:[0,.54986,0,0,.72222],9654:[.03517,.54986,0,0,.77778],9660:[0,.54986,0,0,.72222],9661:[0,.54986,0,0,.72222],9664:[.03517,.54986,0,0,.77778],9674:[.11111,.69224,0,0,.66667],9733:[.19444,.69224,0,0,.94445],10003:[0,.69224,0,0,.83334],10016:[0,.69224,0,0,.83334],10731:[.11111,.69224,0,0,.66667],10846:[.19444,.75583,0,0,.61111],10877:[.13667,.63667,0,0,.77778],10878:[.13667,.63667,0,0,.77778],10885:[.25583,.75583,0,0,.77778],10886:[.25583,.75583,0,0,.77778],10887:[.13597,.63597,0,0,.77778],10888:[.13597,.63597,0,0,.77778],10889:[.26167,.75726,0,0,.77778],10890:[.26167,.75726,0,0,.77778],10891:[.48256,.98256,0,0,.77778],10892:[.48256,.98256,0,0,.77778],10901:[.13667,.63667,0,0,.77778],10902:[.13667,.63667,0,0,.77778],10933:[.25142,.75726,0,0,.77778],10934:[.25142,.75726,0,0,.77778],10935:[.26167,.75726,0,0,.77778],10936:[.26167,.75726,0,0,.77778],10937:[.26167,.75726,0,0,.77778],10938:[.26167,.75726,0,0,.77778],10949:[.25583,.75583,0,0,.77778],10950:[.25583,.75583,0,0,.77778],10955:[.28481,.79383,0,0,.77778],10956:[.28481,.79383,0,0,.77778],57350:[.08167,.58167,0,0,.22222],57351:[.08167,.58167,0,0,.38889],57352:[.08167,.58167,0,0,.77778],57353:[0,.43056,.04028,0,.66667],57356:[.25142,.75726,0,0,.77778],57357:[.25142,.75726,0,0,.77778],57358:[.41951,.91951,0,0,.77778],57359:[.30274,.79383,0,0,.77778],57360:[.30274,.79383,0,0,.77778],57361:[.41951,.91951,0,0,.77778],57366:[.25142,.75726,0,0,.77778],57367:[.25142,.75726,0,0,.77778],57368:[.25142,.75726,0,0,.77778],57369:[.25142,.75726,0,0,.77778],57370:[.13597,.63597,0,0,.77778],57371:[.13597,.63597,0,0,.77778]},"Caligraphic-Regular":{32:[0,0,0,0,.25],65:[0,.68333,0,.19445,.79847],66:[0,.68333,.03041,.13889,.65681],67:[0,.68333,.05834,.13889,.52653],68:[0,.68333,.02778,.08334,.77139],69:[0,.68333,.08944,.11111,.52778],70:[0,.68333,.09931,.11111,.71875],71:[.09722,.68333,.0593,.11111,.59487],72:[0,.68333,.00965,.11111,.84452],73:[0,.68333,.07382,0,.54452],74:[.09722,.68333,.18472,.16667,.67778],75:[0,.68333,.01445,.05556,.76195],76:[0,.68333,0,.13889,.68972],77:[0,.68333,0,.13889,1.2009],78:[0,.68333,.14736,.08334,.82049],79:[0,.68333,.02778,.11111,.79611],80:[0,.68333,.08222,.08334,.69556],81:[.09722,.68333,0,.11111,.81667],82:[0,.68333,0,.08334,.8475],83:[0,.68333,.075,.13889,.60556],84:[0,.68333,.25417,0,.54464],85:[0,.68333,.09931,.08334,.62583],86:[0,.68333,.08222,0,.61278],87:[0,.68333,.08222,.08334,.98778],88:[0,.68333,.14643,.13889,.7133],89:[.09722,.68333,.08222,.08334,.66834],90:[0,.68333,.07944,.13889,.72473],160:[0,0,0,0,.25]},"Fraktur-Regular":{32:[0,0,0,0,.25],33:[0,.69141,0,0,.29574],34:[0,.69141,0,0,.21471],38:[0,.69141,0,0,.73786],39:[0,.69141,0,0,.21201],40:[.24982,.74947,0,0,.38865],41:[.24982,.74947,0,0,.38865],42:[0,.62119,0,0,.27764],43:[.08319,.58283,0,0,.75623],44:[0,.10803,0,0,.27764],45:[.08319,.58283,0,0,.75623],46:[0,.10803,0,0,.27764],47:[.24982,.74947,0,0,.50181],48:[0,.47534,0,0,.50181],49:[0,.47534,0,0,.50181],50:[0,.47534,0,0,.50181],51:[.18906,.47534,0,0,.50181],52:[.18906,.47534,0,0,.50181],53:[.18906,.47534,0,0,.50181],54:[0,.69141,0,0,.50181],55:[.18906,.47534,0,0,.50181],56:[0,.69141,0,0,.50181],57:[.18906,.47534,0,0,.50181],58:[0,.47534,0,0,.21606],59:[.12604,.47534,0,0,.21606],61:[-.13099,.36866,0,0,.75623],63:[0,.69141,0,0,.36245],65:[0,.69141,0,0,.7176],66:[0,.69141,0,0,.88397],67:[0,.69141,0,0,.61254],68:[0,.69141,0,0,.83158],69:[0,.69141,0,0,.66278],70:[.12604,.69141,0,0,.61119],71:[0,.69141,0,0,.78539],72:[.06302,.69141,0,0,.7203],73:[0,.69141,0,0,.55448],74:[.12604,.69141,0,0,.55231],75:[0,.69141,0,0,.66845],76:[0,.69141,0,0,.66602],77:[0,.69141,0,0,1.04953],78:[0,.69141,0,0,.83212],79:[0,.69141,0,0,.82699],80:[.18906,.69141,0,0,.82753],81:[.03781,.69141,0,0,.82699],82:[0,.69141,0,0,.82807],83:[0,.69141,0,0,.82861],84:[0,.69141,0,0,.66899],85:[0,.69141,0,0,.64576],86:[0,.69141,0,0,.83131],87:[0,.69141,0,0,1.04602],88:[0,.69141,0,0,.71922],89:[.18906,.69141,0,0,.83293],90:[.12604,.69141,0,0,.60201],91:[.24982,.74947,0,0,.27764],93:[.24982,.74947,0,0,.27764],94:[0,.69141,0,0,.49965],97:[0,.47534,0,0,.50046],98:[0,.69141,0,0,.51315],99:[0,.47534,0,0,.38946],100:[0,.62119,0,0,.49857],101:[0,.47534,0,0,.40053],102:[.18906,.69141,0,0,.32626],103:[.18906,.47534,0,0,.5037],104:[.18906,.69141,0,0,.52126],105:[0,.69141,0,0,.27899],106:[0,.69141,0,0,.28088],107:[0,.69141,0,0,.38946],108:[0,.69141,0,0,.27953],109:[0,.47534,0,0,.76676],110:[0,.47534,0,0,.52666],111:[0,.47534,0,0,.48885],112:[.18906,.52396,0,0,.50046],113:[.18906,.47534,0,0,.48912],114:[0,.47534,0,0,.38919],115:[0,.47534,0,0,.44266],116:[0,.62119,0,0,.33301],117:[0,.47534,0,0,.5172],118:[0,.52396,0,0,.5118],119:[0,.52396,0,0,.77351],120:[.18906,.47534,0,0,.38865],121:[.18906,.47534,0,0,.49884],122:[.18906,.47534,0,0,.39054],160:[0,0,0,0,.25],8216:[0,.69141,0,0,.21471],8217:[0,.69141,0,0,.21471],58112:[0,.62119,0,0,.49749],58113:[0,.62119,0,0,.4983],58114:[.18906,.69141,0,0,.33328],58115:[.18906,.69141,0,0,.32923],58116:[.18906,.47534,0,0,.50343],58117:[0,.69141,0,0,.33301],58118:[0,.62119,0,0,.33409],58119:[0,.47534,0,0,.50073]},"Main-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.35],34:[0,.69444,0,0,.60278],35:[.19444,.69444,0,0,.95833],36:[.05556,.75,0,0,.575],37:[.05556,.75,0,0,.95833],38:[0,.69444,0,0,.89444],39:[0,.69444,0,0,.31944],40:[.25,.75,0,0,.44722],41:[.25,.75,0,0,.44722],42:[0,.75,0,0,.575],43:[.13333,.63333,0,0,.89444],44:[.19444,.15556,0,0,.31944],45:[0,.44444,0,0,.38333],46:[0,.15556,0,0,.31944],47:[.25,.75,0,0,.575],48:[0,.64444,0,0,.575],49:[0,.64444,0,0,.575],50:[0,.64444,0,0,.575],51:[0,.64444,0,0,.575],52:[0,.64444,0,0,.575],53:[0,.64444,0,0,.575],54:[0,.64444,0,0,.575],55:[0,.64444,0,0,.575],56:[0,.64444,0,0,.575],57:[0,.64444,0,0,.575],58:[0,.44444,0,0,.31944],59:[.19444,.44444,0,0,.31944],60:[.08556,.58556,0,0,.89444],61:[-.10889,.39111,0,0,.89444],62:[.08556,.58556,0,0,.89444],63:[0,.69444,0,0,.54305],64:[0,.69444,0,0,.89444],65:[0,.68611,0,0,.86944],66:[0,.68611,0,0,.81805],67:[0,.68611,0,0,.83055],68:[0,.68611,0,0,.88194],69:[0,.68611,0,0,.75555],70:[0,.68611,0,0,.72361],71:[0,.68611,0,0,.90416],72:[0,.68611,0,0,.9],73:[0,.68611,0,0,.43611],74:[0,.68611,0,0,.59444],75:[0,.68611,0,0,.90138],76:[0,.68611,0,0,.69166],77:[0,.68611,0,0,1.09166],78:[0,.68611,0,0,.9],79:[0,.68611,0,0,.86388],80:[0,.68611,0,0,.78611],81:[.19444,.68611,0,0,.86388],82:[0,.68611,0,0,.8625],83:[0,.68611,0,0,.63889],84:[0,.68611,0,0,.8],85:[0,.68611,0,0,.88472],86:[0,.68611,.01597,0,.86944],87:[0,.68611,.01597,0,1.18888],88:[0,.68611,0,0,.86944],89:[0,.68611,.02875,0,.86944],90:[0,.68611,0,0,.70277],91:[.25,.75,0,0,.31944],92:[.25,.75,0,0,.575],93:[.25,.75,0,0,.31944],94:[0,.69444,0,0,.575],95:[.31,.13444,.03194,0,.575],97:[0,.44444,0,0,.55902],98:[0,.69444,0,0,.63889],99:[0,.44444,0,0,.51111],100:[0,.69444,0,0,.63889],101:[0,.44444,0,0,.52708],102:[0,.69444,.10903,0,.35139],103:[.19444,.44444,.01597,0,.575],104:[0,.69444,0,0,.63889],105:[0,.69444,0,0,.31944],106:[.19444,.69444,0,0,.35139],107:[0,.69444,0,0,.60694],108:[0,.69444,0,0,.31944],109:[0,.44444,0,0,.95833],110:[0,.44444,0,0,.63889],111:[0,.44444,0,0,.575],112:[.19444,.44444,0,0,.63889],113:[.19444,.44444,0,0,.60694],114:[0,.44444,0,0,.47361],115:[0,.44444,0,0,.45361],116:[0,.63492,0,0,.44722],117:[0,.44444,0,0,.63889],118:[0,.44444,.01597,0,.60694],119:[0,.44444,.01597,0,.83055],120:[0,.44444,0,0,.60694],121:[.19444,.44444,.01597,0,.60694],122:[0,.44444,0,0,.51111],123:[.25,.75,0,0,.575],124:[.25,.75,0,0,.31944],125:[.25,.75,0,0,.575],126:[.35,.34444,0,0,.575],160:[0,0,0,0,.25],163:[0,.69444,0,0,.86853],168:[0,.69444,0,0,.575],172:[0,.44444,0,0,.76666],176:[0,.69444,0,0,.86944],177:[.13333,.63333,0,0,.89444],184:[.17014,0,0,0,.51111],198:[0,.68611,0,0,1.04166],215:[.13333,.63333,0,0,.89444],216:[.04861,.73472,0,0,.89444],223:[0,.69444,0,0,.59722],230:[0,.44444,0,0,.83055],247:[.13333,.63333,0,0,.89444],248:[.09722,.54167,0,0,.575],305:[0,.44444,0,0,.31944],338:[0,.68611,0,0,1.16944],339:[0,.44444,0,0,.89444],567:[.19444,.44444,0,0,.35139],710:[0,.69444,0,0,.575],711:[0,.63194,0,0,.575],713:[0,.59611,0,0,.575],714:[0,.69444,0,0,.575],715:[0,.69444,0,0,.575],728:[0,.69444,0,0,.575],729:[0,.69444,0,0,.31944],730:[0,.69444,0,0,.86944],732:[0,.69444,0,0,.575],733:[0,.69444,0,0,.575],915:[0,.68611,0,0,.69166],916:[0,.68611,0,0,.95833],920:[0,.68611,0,0,.89444],923:[0,.68611,0,0,.80555],926:[0,.68611,0,0,.76666],928:[0,.68611,0,0,.9],931:[0,.68611,0,0,.83055],933:[0,.68611,0,0,.89444],934:[0,.68611,0,0,.83055],936:[0,.68611,0,0,.89444],937:[0,.68611,0,0,.83055],8211:[0,.44444,.03194,0,.575],8212:[0,.44444,.03194,0,1.14999],8216:[0,.69444,0,0,.31944],8217:[0,.69444,0,0,.31944],8220:[0,.69444,0,0,.60278],8221:[0,.69444,0,0,.60278],8224:[.19444,.69444,0,0,.51111],8225:[.19444,.69444,0,0,.51111],8242:[0,.55556,0,0,.34444],8407:[0,.72444,.15486,0,.575],8463:[0,.69444,0,0,.66759],8465:[0,.69444,0,0,.83055],8467:[0,.69444,0,0,.47361],8472:[.19444,.44444,0,0,.74027],8476:[0,.69444,0,0,.83055],8501:[0,.69444,0,0,.70277],8592:[-.10889,.39111,0,0,1.14999],8593:[.19444,.69444,0,0,.575],8594:[-.10889,.39111,0,0,1.14999],8595:[.19444,.69444,0,0,.575],8596:[-.10889,.39111,0,0,1.14999],8597:[.25,.75,0,0,.575],8598:[.19444,.69444,0,0,1.14999],8599:[.19444,.69444,0,0,1.14999],8600:[.19444,.69444,0,0,1.14999],8601:[.19444,.69444,0,0,1.14999],8636:[-.10889,.39111,0,0,1.14999],8637:[-.10889,.39111,0,0,1.14999],8640:[-.10889,.39111,0,0,1.14999],8641:[-.10889,.39111,0,0,1.14999],8656:[-.10889,.39111,0,0,1.14999],8657:[.19444,.69444,0,0,.70277],8658:[-.10889,.39111,0,0,1.14999],8659:[.19444,.69444,0,0,.70277],8660:[-.10889,.39111,0,0,1.14999],8661:[.25,.75,0,0,.70277],8704:[0,.69444,0,0,.63889],8706:[0,.69444,.06389,0,.62847],8707:[0,.69444,0,0,.63889],8709:[.05556,.75,0,0,.575],8711:[0,.68611,0,0,.95833],8712:[.08556,.58556,0,0,.76666],8715:[.08556,.58556,0,0,.76666],8722:[.13333,.63333,0,0,.89444],8723:[.13333,.63333,0,0,.89444],8725:[.25,.75,0,0,.575],8726:[.25,.75,0,0,.575],8727:[-.02778,.47222,0,0,.575],8728:[-.02639,.47361,0,0,.575],8729:[-.02639,.47361,0,0,.575],8730:[.18,.82,0,0,.95833],8733:[0,.44444,0,0,.89444],8734:[0,.44444,0,0,1.14999],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.31944],8741:[.25,.75,0,0,.575],8743:[0,.55556,0,0,.76666],8744:[0,.55556,0,0,.76666],8745:[0,.55556,0,0,.76666],8746:[0,.55556,0,0,.76666],8747:[.19444,.69444,.12778,0,.56875],8764:[-.10889,.39111,0,0,.89444],8768:[.19444,.69444,0,0,.31944],8771:[.00222,.50222,0,0,.89444],8773:[.027,.638,0,0,.894],8776:[.02444,.52444,0,0,.89444],8781:[.00222,.50222,0,0,.89444],8801:[.00222,.50222,0,0,.89444],8804:[.19667,.69667,0,0,.89444],8805:[.19667,.69667,0,0,.89444],8810:[.08556,.58556,0,0,1.14999],8811:[.08556,.58556,0,0,1.14999],8826:[.08556,.58556,0,0,.89444],8827:[.08556,.58556,0,0,.89444],8834:[.08556,.58556,0,0,.89444],8835:[.08556,.58556,0,0,.89444],8838:[.19667,.69667,0,0,.89444],8839:[.19667,.69667,0,0,.89444],8846:[0,.55556,0,0,.76666],8849:[.19667,.69667,0,0,.89444],8850:[.19667,.69667,0,0,.89444],8851:[0,.55556,0,0,.76666],8852:[0,.55556,0,0,.76666],8853:[.13333,.63333,0,0,.89444],8854:[.13333,.63333,0,0,.89444],8855:[.13333,.63333,0,0,.89444],8856:[.13333,.63333,0,0,.89444],8857:[.13333,.63333,0,0,.89444],8866:[0,.69444,0,0,.70277],8867:[0,.69444,0,0,.70277],8868:[0,.69444,0,0,.89444],8869:[0,.69444,0,0,.89444],8900:[-.02639,.47361,0,0,.575],8901:[-.02639,.47361,0,0,.31944],8902:[-.02778,.47222,0,0,.575],8968:[.25,.75,0,0,.51111],8969:[.25,.75,0,0,.51111],8970:[.25,.75,0,0,.51111],8971:[.25,.75,0,0,.51111],8994:[-.13889,.36111,0,0,1.14999],8995:[-.13889,.36111,0,0,1.14999],9651:[.19444,.69444,0,0,1.02222],9657:[-.02778,.47222,0,0,.575],9661:[.19444,.69444,0,0,1.02222],9667:[-.02778,.47222,0,0,.575],9711:[.19444,.69444,0,0,1.14999],9824:[.12963,.69444,0,0,.89444],9825:[.12963,.69444,0,0,.89444],9826:[.12963,.69444,0,0,.89444],9827:[.12963,.69444,0,0,.89444],9837:[0,.75,0,0,.44722],9838:[.19444,.69444,0,0,.44722],9839:[.19444,.69444,0,0,.44722],10216:[.25,.75,0,0,.44722],10217:[.25,.75,0,0,.44722],10815:[0,.68611,0,0,.9],10927:[.19667,.69667,0,0,.89444],10928:[.19667,.69667,0,0,.89444],57376:[.19444,.69444,0,0,0]},"Main-BoldItalic":{32:[0,0,0,0,.25],33:[0,.69444,.11417,0,.38611],34:[0,.69444,.07939,0,.62055],35:[.19444,.69444,.06833,0,.94444],37:[.05556,.75,.12861,0,.94444],38:[0,.69444,.08528,0,.88555],39:[0,.69444,.12945,0,.35555],40:[.25,.75,.15806,0,.47333],41:[.25,.75,.03306,0,.47333],42:[0,.75,.14333,0,.59111],43:[.10333,.60333,.03306,0,.88555],44:[.19444,.14722,0,0,.35555],45:[0,.44444,.02611,0,.41444],46:[0,.14722,0,0,.35555],47:[.25,.75,.15806,0,.59111],48:[0,.64444,.13167,0,.59111],49:[0,.64444,.13167,0,.59111],50:[0,.64444,.13167,0,.59111],51:[0,.64444,.13167,0,.59111],52:[.19444,.64444,.13167,0,.59111],53:[0,.64444,.13167,0,.59111],54:[0,.64444,.13167,0,.59111],55:[.19444,.64444,.13167,0,.59111],56:[0,.64444,.13167,0,.59111],57:[0,.64444,.13167,0,.59111],58:[0,.44444,.06695,0,.35555],59:[.19444,.44444,.06695,0,.35555],61:[-.10889,.39111,.06833,0,.88555],63:[0,.69444,.11472,0,.59111],64:[0,.69444,.09208,0,.88555],65:[0,.68611,0,0,.86555],66:[0,.68611,.0992,0,.81666],67:[0,.68611,.14208,0,.82666],68:[0,.68611,.09062,0,.87555],69:[0,.68611,.11431,0,.75666],70:[0,.68611,.12903,0,.72722],71:[0,.68611,.07347,0,.89527],72:[0,.68611,.17208,0,.8961],73:[0,.68611,.15681,0,.47166],74:[0,.68611,.145,0,.61055],75:[0,.68611,.14208,0,.89499],76:[0,.68611,0,0,.69777],77:[0,.68611,.17208,0,1.07277],78:[0,.68611,.17208,0,.8961],79:[0,.68611,.09062,0,.85499],80:[0,.68611,.0992,0,.78721],81:[.19444,.68611,.09062,0,.85499],82:[0,.68611,.02559,0,.85944],83:[0,.68611,.11264,0,.64999],84:[0,.68611,.12903,0,.7961],85:[0,.68611,.17208,0,.88083],86:[0,.68611,.18625,0,.86555],87:[0,.68611,.18625,0,1.15999],88:[0,.68611,.15681,0,.86555],89:[0,.68611,.19803,0,.86555],90:[0,.68611,.14208,0,.70888],91:[.25,.75,.1875,0,.35611],93:[.25,.75,.09972,0,.35611],94:[0,.69444,.06709,0,.59111],95:[.31,.13444,.09811,0,.59111],97:[0,.44444,.09426,0,.59111],98:[0,.69444,.07861,0,.53222],99:[0,.44444,.05222,0,.53222],100:[0,.69444,.10861,0,.59111],101:[0,.44444,.085,0,.53222],102:[.19444,.69444,.21778,0,.4],103:[.19444,.44444,.105,0,.53222],104:[0,.69444,.09426,0,.59111],105:[0,.69326,.11387,0,.35555],106:[.19444,.69326,.1672,0,.35555],107:[0,.69444,.11111,0,.53222],108:[0,.69444,.10861,0,.29666],109:[0,.44444,.09426,0,.94444],110:[0,.44444,.09426,0,.64999],111:[0,.44444,.07861,0,.59111],112:[.19444,.44444,.07861,0,.59111],113:[.19444,.44444,.105,0,.53222],114:[0,.44444,.11111,0,.50167],115:[0,.44444,.08167,0,.48694],116:[0,.63492,.09639,0,.385],117:[0,.44444,.09426,0,.62055],118:[0,.44444,.11111,0,.53222],119:[0,.44444,.11111,0,.76777],120:[0,.44444,.12583,0,.56055],121:[.19444,.44444,.105,0,.56166],122:[0,.44444,.13889,0,.49055],126:[.35,.34444,.11472,0,.59111],160:[0,0,0,0,.25],168:[0,.69444,.11473,0,.59111],176:[0,.69444,0,0,.94888],184:[.17014,0,0,0,.53222],198:[0,.68611,.11431,0,1.02277],216:[.04861,.73472,.09062,0,.88555],223:[.19444,.69444,.09736,0,.665],230:[0,.44444,.085,0,.82666],248:[.09722,.54167,.09458,0,.59111],305:[0,.44444,.09426,0,.35555],338:[0,.68611,.11431,0,1.14054],339:[0,.44444,.085,0,.82666],567:[.19444,.44444,.04611,0,.385],710:[0,.69444,.06709,0,.59111],711:[0,.63194,.08271,0,.59111],713:[0,.59444,.10444,0,.59111],714:[0,.69444,.08528,0,.59111],715:[0,.69444,0,0,.59111],728:[0,.69444,.10333,0,.59111],729:[0,.69444,.12945,0,.35555],730:[0,.69444,0,0,.94888],732:[0,.69444,.11472,0,.59111],733:[0,.69444,.11472,0,.59111],915:[0,.68611,.12903,0,.69777],916:[0,.68611,0,0,.94444],920:[0,.68611,.09062,0,.88555],923:[0,.68611,0,0,.80666],926:[0,.68611,.15092,0,.76777],928:[0,.68611,.17208,0,.8961],931:[0,.68611,.11431,0,.82666],933:[0,.68611,.10778,0,.88555],934:[0,.68611,.05632,0,.82666],936:[0,.68611,.10778,0,.88555],937:[0,.68611,.0992,0,.82666],8211:[0,.44444,.09811,0,.59111],8212:[0,.44444,.09811,0,1.18221],8216:[0,.69444,.12945,0,.35555],8217:[0,.69444,.12945,0,.35555],8220:[0,.69444,.16772,0,.62055],8221:[0,.69444,.07939,0,.62055]},"Main-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.12417,0,.30667],34:[0,.69444,.06961,0,.51444],35:[.19444,.69444,.06616,0,.81777],37:[.05556,.75,.13639,0,.81777],38:[0,.69444,.09694,0,.76666],39:[0,.69444,.12417,0,.30667],40:[.25,.75,.16194,0,.40889],41:[.25,.75,.03694,0,.40889],42:[0,.75,.14917,0,.51111],43:[.05667,.56167,.03694,0,.76666],44:[.19444,.10556,0,0,.30667],45:[0,.43056,.02826,0,.35778],46:[0,.10556,0,0,.30667],47:[.25,.75,.16194,0,.51111],48:[0,.64444,.13556,0,.51111],49:[0,.64444,.13556,0,.51111],50:[0,.64444,.13556,0,.51111],51:[0,.64444,.13556,0,.51111],52:[.19444,.64444,.13556,0,.51111],53:[0,.64444,.13556,0,.51111],54:[0,.64444,.13556,0,.51111],55:[.19444,.64444,.13556,0,.51111],56:[0,.64444,.13556,0,.51111],57:[0,.64444,.13556,0,.51111],58:[0,.43056,.0582,0,.30667],59:[.19444,.43056,.0582,0,.30667],61:[-.13313,.36687,.06616,0,.76666],63:[0,.69444,.1225,0,.51111],64:[0,.69444,.09597,0,.76666],65:[0,.68333,0,0,.74333],66:[0,.68333,.10257,0,.70389],67:[0,.68333,.14528,0,.71555],68:[0,.68333,.09403,0,.755],69:[0,.68333,.12028,0,.67833],70:[0,.68333,.13305,0,.65277],71:[0,.68333,.08722,0,.77361],72:[0,.68333,.16389,0,.74333],73:[0,.68333,.15806,0,.38555],74:[0,.68333,.14028,0,.525],75:[0,.68333,.14528,0,.76888],76:[0,.68333,0,0,.62722],77:[0,.68333,.16389,0,.89666],78:[0,.68333,.16389,0,.74333],79:[0,.68333,.09403,0,.76666],80:[0,.68333,.10257,0,.67833],81:[.19444,.68333,.09403,0,.76666],82:[0,.68333,.03868,0,.72944],83:[0,.68333,.11972,0,.56222],84:[0,.68333,.13305,0,.71555],85:[0,.68333,.16389,0,.74333],86:[0,.68333,.18361,0,.74333],87:[0,.68333,.18361,0,.99888],88:[0,.68333,.15806,0,.74333],89:[0,.68333,.19383,0,.74333],90:[0,.68333,.14528,0,.61333],91:[.25,.75,.1875,0,.30667],93:[.25,.75,.10528,0,.30667],94:[0,.69444,.06646,0,.51111],95:[.31,.12056,.09208,0,.51111],97:[0,.43056,.07671,0,.51111],98:[0,.69444,.06312,0,.46],99:[0,.43056,.05653,0,.46],100:[0,.69444,.10333,0,.51111],101:[0,.43056,.07514,0,.46],102:[.19444,.69444,.21194,0,.30667],103:[.19444,.43056,.08847,0,.46],104:[0,.69444,.07671,0,.51111],105:[0,.65536,.1019,0,.30667],106:[.19444,.65536,.14467,0,.30667],107:[0,.69444,.10764,0,.46],108:[0,.69444,.10333,0,.25555],109:[0,.43056,.07671,0,.81777],110:[0,.43056,.07671,0,.56222],111:[0,.43056,.06312,0,.51111],112:[.19444,.43056,.06312,0,.51111],113:[.19444,.43056,.08847,0,.46],114:[0,.43056,.10764,0,.42166],115:[0,.43056,.08208,0,.40889],116:[0,.61508,.09486,0,.33222],117:[0,.43056,.07671,0,.53666],118:[0,.43056,.10764,0,.46],119:[0,.43056,.10764,0,.66444],120:[0,.43056,.12042,0,.46389],121:[.19444,.43056,.08847,0,.48555],122:[0,.43056,.12292,0,.40889],126:[.35,.31786,.11585,0,.51111],160:[0,0,0,0,.25],168:[0,.66786,.10474,0,.51111],176:[0,.69444,0,0,.83129],184:[.17014,0,0,0,.46],198:[0,.68333,.12028,0,.88277],216:[.04861,.73194,.09403,0,.76666],223:[.19444,.69444,.10514,0,.53666],230:[0,.43056,.07514,0,.71555],248:[.09722,.52778,.09194,0,.51111],338:[0,.68333,.12028,0,.98499],339:[0,.43056,.07514,0,.71555],710:[0,.69444,.06646,0,.51111],711:[0,.62847,.08295,0,.51111],713:[0,.56167,.10333,0,.51111],714:[0,.69444,.09694,0,.51111],715:[0,.69444,0,0,.51111],728:[0,.69444,.10806,0,.51111],729:[0,.66786,.11752,0,.30667],730:[0,.69444,0,0,.83129],732:[0,.66786,.11585,0,.51111],733:[0,.69444,.1225,0,.51111],915:[0,.68333,.13305,0,.62722],916:[0,.68333,0,0,.81777],920:[0,.68333,.09403,0,.76666],923:[0,.68333,0,0,.69222],926:[0,.68333,.15294,0,.66444],928:[0,.68333,.16389,0,.74333],931:[0,.68333,.12028,0,.71555],933:[0,.68333,.11111,0,.76666],934:[0,.68333,.05986,0,.71555],936:[0,.68333,.11111,0,.76666],937:[0,.68333,.10257,0,.71555],8211:[0,.43056,.09208,0,.51111],8212:[0,.43056,.09208,0,1.02222],8216:[0,.69444,.12417,0,.30667],8217:[0,.69444,.12417,0,.30667],8220:[0,.69444,.1685,0,.51444],8221:[0,.69444,.06961,0,.51444],8463:[0,.68889,0,0,.54028]},"Main-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.27778],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.77778],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.19444,.10556,0,0,.27778],45:[0,.43056,0,0,.33333],46:[0,.10556,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.64444,0,0,.5],49:[0,.64444,0,0,.5],50:[0,.64444,0,0,.5],51:[0,.64444,0,0,.5],52:[0,.64444,0,0,.5],53:[0,.64444,0,0,.5],54:[0,.64444,0,0,.5],55:[0,.64444,0,0,.5],56:[0,.64444,0,0,.5],57:[0,.64444,0,0,.5],58:[0,.43056,0,0,.27778],59:[.19444,.43056,0,0,.27778],60:[.0391,.5391,0,0,.77778],61:[-.13313,.36687,0,0,.77778],62:[.0391,.5391,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.77778],65:[0,.68333,0,0,.75],66:[0,.68333,0,0,.70834],67:[0,.68333,0,0,.72222],68:[0,.68333,0,0,.76389],69:[0,.68333,0,0,.68056],70:[0,.68333,0,0,.65278],71:[0,.68333,0,0,.78472],72:[0,.68333,0,0,.75],73:[0,.68333,0,0,.36111],74:[0,.68333,0,0,.51389],75:[0,.68333,0,0,.77778],76:[0,.68333,0,0,.625],77:[0,.68333,0,0,.91667],78:[0,.68333,0,0,.75],79:[0,.68333,0,0,.77778],80:[0,.68333,0,0,.68056],81:[.19444,.68333,0,0,.77778],82:[0,.68333,0,0,.73611],83:[0,.68333,0,0,.55556],84:[0,.68333,0,0,.72222],85:[0,.68333,0,0,.75],86:[0,.68333,.01389,0,.75],87:[0,.68333,.01389,0,1.02778],88:[0,.68333,0,0,.75],89:[0,.68333,.025,0,.75],90:[0,.68333,0,0,.61111],91:[.25,.75,0,0,.27778],92:[.25,.75,0,0,.5],93:[.25,.75,0,0,.27778],94:[0,.69444,0,0,.5],95:[.31,.12056,.02778,0,.5],97:[0,.43056,0,0,.5],98:[0,.69444,0,0,.55556],99:[0,.43056,0,0,.44445],100:[0,.69444,0,0,.55556],101:[0,.43056,0,0,.44445],102:[0,.69444,.07778,0,.30556],103:[.19444,.43056,.01389,0,.5],104:[0,.69444,0,0,.55556],105:[0,.66786,0,0,.27778],106:[.19444,.66786,0,0,.30556],107:[0,.69444,0,0,.52778],108:[0,.69444,0,0,.27778],109:[0,.43056,0,0,.83334],110:[0,.43056,0,0,.55556],111:[0,.43056,0,0,.5],112:[.19444,.43056,0,0,.55556],113:[.19444,.43056,0,0,.52778],114:[0,.43056,0,0,.39167],115:[0,.43056,0,0,.39445],116:[0,.61508,0,0,.38889],117:[0,.43056,0,0,.55556],118:[0,.43056,.01389,0,.52778],119:[0,.43056,.01389,0,.72222],120:[0,.43056,0,0,.52778],121:[.19444,.43056,.01389,0,.52778],122:[0,.43056,0,0,.44445],123:[.25,.75,0,0,.5],124:[.25,.75,0,0,.27778],125:[.25,.75,0,0,.5],126:[.35,.31786,0,0,.5],160:[0,0,0,0,.25],163:[0,.69444,0,0,.76909],167:[.19444,.69444,0,0,.44445],168:[0,.66786,0,0,.5],172:[0,.43056,0,0,.66667],176:[0,.69444,0,0,.75],177:[.08333,.58333,0,0,.77778],182:[.19444,.69444,0,0,.61111],184:[.17014,0,0,0,.44445],198:[0,.68333,0,0,.90278],215:[.08333,.58333,0,0,.77778],216:[.04861,.73194,0,0,.77778],223:[0,.69444,0,0,.5],230:[0,.43056,0,0,.72222],247:[.08333,.58333,0,0,.77778],248:[.09722,.52778,0,0,.5],305:[0,.43056,0,0,.27778],338:[0,.68333,0,0,1.01389],339:[0,.43056,0,0,.77778],567:[.19444,.43056,0,0,.30556],710:[0,.69444,0,0,.5],711:[0,.62847,0,0,.5],713:[0,.56778,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.66786,0,0,.27778],730:[0,.69444,0,0,.75],732:[0,.66786,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.68333,0,0,.625],916:[0,.68333,0,0,.83334],920:[0,.68333,0,0,.77778],923:[0,.68333,0,0,.69445],926:[0,.68333,0,0,.66667],928:[0,.68333,0,0,.75],931:[0,.68333,0,0,.72222],933:[0,.68333,0,0,.77778],934:[0,.68333,0,0,.72222],936:[0,.68333,0,0,.77778],937:[0,.68333,0,0,.72222],8211:[0,.43056,.02778,0,.5],8212:[0,.43056,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5],8224:[.19444,.69444,0,0,.44445],8225:[.19444,.69444,0,0,.44445],8230:[0,.123,0,0,1.172],8242:[0,.55556,0,0,.275],8407:[0,.71444,.15382,0,.5],8463:[0,.68889,0,0,.54028],8465:[0,.69444,0,0,.72222],8467:[0,.69444,0,.11111,.41667],8472:[.19444,.43056,0,.11111,.63646],8476:[0,.69444,0,0,.72222],8501:[0,.69444,0,0,.61111],8592:[-.13313,.36687,0,0,1],8593:[.19444,.69444,0,0,.5],8594:[-.13313,.36687,0,0,1],8595:[.19444,.69444,0,0,.5],8596:[-.13313,.36687,0,0,1],8597:[.25,.75,0,0,.5],8598:[.19444,.69444,0,0,1],8599:[.19444,.69444,0,0,1],8600:[.19444,.69444,0,0,1],8601:[.19444,.69444,0,0,1],8614:[.011,.511,0,0,1],8617:[.011,.511,0,0,1.126],8618:[.011,.511,0,0,1.126],8636:[-.13313,.36687,0,0,1],8637:[-.13313,.36687,0,0,1],8640:[-.13313,.36687,0,0,1],8641:[-.13313,.36687,0,0,1],8652:[.011,.671,0,0,1],8656:[-.13313,.36687,0,0,1],8657:[.19444,.69444,0,0,.61111],8658:[-.13313,.36687,0,0,1],8659:[.19444,.69444,0,0,.61111],8660:[-.13313,.36687,0,0,1],8661:[.25,.75,0,0,.61111],8704:[0,.69444,0,0,.55556],8706:[0,.69444,.05556,.08334,.5309],8707:[0,.69444,0,0,.55556],8709:[.05556,.75,0,0,.5],8711:[0,.68333,0,0,.83334],8712:[.0391,.5391,0,0,.66667],8715:[.0391,.5391,0,0,.66667],8722:[.08333,.58333,0,0,.77778],8723:[.08333,.58333,0,0,.77778],8725:[.25,.75,0,0,.5],8726:[.25,.75,0,0,.5],8727:[-.03472,.46528,0,0,.5],8728:[-.05555,.44445,0,0,.5],8729:[-.05555,.44445,0,0,.5],8730:[.2,.8,0,0,.83334],8733:[0,.43056,0,0,.77778],8734:[0,.43056,0,0,1],8736:[0,.69224,0,0,.72222],8739:[.25,.75,0,0,.27778],8741:[.25,.75,0,0,.5],8743:[0,.55556,0,0,.66667],8744:[0,.55556,0,0,.66667],8745:[0,.55556,0,0,.66667],8746:[0,.55556,0,0,.66667],8747:[.19444,.69444,.11111,0,.41667],8764:[-.13313,.36687,0,0,.77778],8768:[.19444,.69444,0,0,.27778],8771:[-.03625,.46375,0,0,.77778],8773:[-.022,.589,0,0,.778],8776:[-.01688,.48312,0,0,.77778],8781:[-.03625,.46375,0,0,.77778],8784:[-.133,.673,0,0,.778],8801:[-.03625,.46375,0,0,.77778],8804:[.13597,.63597,0,0,.77778],8805:[.13597,.63597,0,0,.77778],8810:[.0391,.5391,0,0,1],8811:[.0391,.5391,0,0,1],8826:[.0391,.5391,0,0,.77778],8827:[.0391,.5391,0,0,.77778],8834:[.0391,.5391,0,0,.77778],8835:[.0391,.5391,0,0,.77778],8838:[.13597,.63597,0,0,.77778],8839:[.13597,.63597,0,0,.77778],8846:[0,.55556,0,0,.66667],8849:[.13597,.63597,0,0,.77778],8850:[.13597,.63597,0,0,.77778],8851:[0,.55556,0,0,.66667],8852:[0,.55556,0,0,.66667],8853:[.08333,.58333,0,0,.77778],8854:[.08333,.58333,0,0,.77778],8855:[.08333,.58333,0,0,.77778],8856:[.08333,.58333,0,0,.77778],8857:[.08333,.58333,0,0,.77778],8866:[0,.69444,0,0,.61111],8867:[0,.69444,0,0,.61111],8868:[0,.69444,0,0,.77778],8869:[0,.69444,0,0,.77778],8872:[.249,.75,0,0,.867],8900:[-.05555,.44445,0,0,.5],8901:[-.05555,.44445,0,0,.27778],8902:[-.03472,.46528,0,0,.5],8904:[.005,.505,0,0,.9],8942:[.03,.903,0,0,.278],8943:[-.19,.313,0,0,1.172],8945:[-.1,.823,0,0,1.282],8968:[.25,.75,0,0,.44445],8969:[.25,.75,0,0,.44445],8970:[.25,.75,0,0,.44445],8971:[.25,.75,0,0,.44445],8994:[-.14236,.35764,0,0,1],8995:[-.14236,.35764,0,0,1],9136:[.244,.744,0,0,.412],9137:[.244,.745,0,0,.412],9651:[.19444,.69444,0,0,.88889],9657:[-.03472,.46528,0,0,.5],9661:[.19444,.69444,0,0,.88889],9667:[-.03472,.46528,0,0,.5],9711:[.19444,.69444,0,0,1],9824:[.12963,.69444,0,0,.77778],9825:[.12963,.69444,0,0,.77778],9826:[.12963,.69444,0,0,.77778],9827:[.12963,.69444,0,0,.77778],9837:[0,.75,0,0,.38889],9838:[.19444,.69444,0,0,.38889],9839:[.19444,.69444,0,0,.38889],10216:[.25,.75,0,0,.38889],10217:[.25,.75,0,0,.38889],10222:[.244,.744,0,0,.412],10223:[.244,.745,0,0,.412],10229:[.011,.511,0,0,1.609],10230:[.011,.511,0,0,1.638],10231:[.011,.511,0,0,1.859],10232:[.024,.525,0,0,1.609],10233:[.024,.525,0,0,1.638],10234:[.024,.525,0,0,1.858],10236:[.011,.511,0,0,1.638],10815:[0,.68333,0,0,.75],10927:[.13597,.63597,0,0,.77778],10928:[.13597,.63597,0,0,.77778],57376:[.19444,.69444,0,0,0]},"Math-BoldItalic":{32:[0,0,0,0,.25],48:[0,.44444,0,0,.575],49:[0,.44444,0,0,.575],50:[0,.44444,0,0,.575],51:[.19444,.44444,0,0,.575],52:[.19444,.44444,0,0,.575],53:[.19444,.44444,0,0,.575],54:[0,.64444,0,0,.575],55:[.19444,.44444,0,0,.575],56:[0,.64444,0,0,.575],57:[.19444,.44444,0,0,.575],65:[0,.68611,0,0,.86944],66:[0,.68611,.04835,0,.8664],67:[0,.68611,.06979,0,.81694],68:[0,.68611,.03194,0,.93812],69:[0,.68611,.05451,0,.81007],70:[0,.68611,.15972,0,.68889],71:[0,.68611,0,0,.88673],72:[0,.68611,.08229,0,.98229],73:[0,.68611,.07778,0,.51111],74:[0,.68611,.10069,0,.63125],75:[0,.68611,.06979,0,.97118],76:[0,.68611,0,0,.75555],77:[0,.68611,.11424,0,1.14201],78:[0,.68611,.11424,0,.95034],79:[0,.68611,.03194,0,.83666],80:[0,.68611,.15972,0,.72309],81:[.19444,.68611,0,0,.86861],82:[0,.68611,.00421,0,.87235],83:[0,.68611,.05382,0,.69271],84:[0,.68611,.15972,0,.63663],85:[0,.68611,.11424,0,.80027],86:[0,.68611,.25555,0,.67778],87:[0,.68611,.15972,0,1.09305],88:[0,.68611,.07778,0,.94722],89:[0,.68611,.25555,0,.67458],90:[0,.68611,.06979,0,.77257],97:[0,.44444,0,0,.63287],98:[0,.69444,0,0,.52083],99:[0,.44444,0,0,.51342],100:[0,.69444,0,0,.60972],101:[0,.44444,0,0,.55361],102:[.19444,.69444,.11042,0,.56806],103:[.19444,.44444,.03704,0,.5449],104:[0,.69444,0,0,.66759],105:[0,.69326,0,0,.4048],106:[.19444,.69326,.0622,0,.47083],107:[0,.69444,.01852,0,.6037],108:[0,.69444,.0088,0,.34815],109:[0,.44444,0,0,1.0324],110:[0,.44444,0,0,.71296],111:[0,.44444,0,0,.58472],112:[.19444,.44444,0,0,.60092],113:[.19444,.44444,.03704,0,.54213],114:[0,.44444,.03194,0,.5287],115:[0,.44444,0,0,.53125],116:[0,.63492,0,0,.41528],117:[0,.44444,0,0,.68102],118:[0,.44444,.03704,0,.56666],119:[0,.44444,.02778,0,.83148],120:[0,.44444,0,0,.65903],121:[.19444,.44444,.03704,0,.59028],122:[0,.44444,.04213,0,.55509],160:[0,0,0,0,.25],915:[0,.68611,.15972,0,.65694],916:[0,.68611,0,0,.95833],920:[0,.68611,.03194,0,.86722],923:[0,.68611,0,0,.80555],926:[0,.68611,.07458,0,.84125],928:[0,.68611,.08229,0,.98229],931:[0,.68611,.05451,0,.88507],933:[0,.68611,.15972,0,.67083],934:[0,.68611,0,0,.76666],936:[0,.68611,.11653,0,.71402],937:[0,.68611,.04835,0,.8789],945:[0,.44444,0,0,.76064],946:[.19444,.69444,.03403,0,.65972],947:[.19444,.44444,.06389,0,.59003],948:[0,.69444,.03819,0,.52222],949:[0,.44444,0,0,.52882],950:[.19444,.69444,.06215,0,.50833],951:[.19444,.44444,.03704,0,.6],952:[0,.69444,.03194,0,.5618],953:[0,.44444,0,0,.41204],954:[0,.44444,0,0,.66759],955:[0,.69444,0,0,.67083],956:[.19444,.44444,0,0,.70787],957:[0,.44444,.06898,0,.57685],958:[.19444,.69444,.03021,0,.50833],959:[0,.44444,0,0,.58472],960:[0,.44444,.03704,0,.68241],961:[.19444,.44444,0,0,.6118],962:[.09722,.44444,.07917,0,.42361],963:[0,.44444,.03704,0,.68588],964:[0,.44444,.13472,0,.52083],965:[0,.44444,.03704,0,.63055],966:[.19444,.44444,0,0,.74722],967:[.19444,.44444,0,0,.71805],968:[.19444,.69444,.03704,0,.75833],969:[0,.44444,.03704,0,.71782],977:[0,.69444,0,0,.69155],981:[.19444,.69444,0,0,.7125],982:[0,.44444,.03194,0,.975],1009:[.19444,.44444,0,0,.6118],1013:[0,.44444,0,0,.48333],57649:[0,.44444,0,0,.39352],57911:[.19444,.44444,0,0,.43889]},"Math-Italic":{32:[0,0,0,0,.25],48:[0,.43056,0,0,.5],49:[0,.43056,0,0,.5],50:[0,.43056,0,0,.5],51:[.19444,.43056,0,0,.5],52:[.19444,.43056,0,0,.5],53:[.19444,.43056,0,0,.5],54:[0,.64444,0,0,.5],55:[.19444,.43056,0,0,.5],56:[0,.64444,0,0,.5],57:[.19444,.43056,0,0,.5],65:[0,.68333,0,.13889,.75],66:[0,.68333,.05017,.08334,.75851],67:[0,.68333,.07153,.08334,.71472],68:[0,.68333,.02778,.05556,.82792],69:[0,.68333,.05764,.08334,.7382],70:[0,.68333,.13889,.08334,.64306],71:[0,.68333,0,.08334,.78625],72:[0,.68333,.08125,.05556,.83125],73:[0,.68333,.07847,.11111,.43958],74:[0,.68333,.09618,.16667,.55451],75:[0,.68333,.07153,.05556,.84931],76:[0,.68333,0,.02778,.68056],77:[0,.68333,.10903,.08334,.97014],78:[0,.68333,.10903,.08334,.80347],79:[0,.68333,.02778,.08334,.76278],80:[0,.68333,.13889,.08334,.64201],81:[.19444,.68333,0,.08334,.79056],82:[0,.68333,.00773,.08334,.75929],83:[0,.68333,.05764,.08334,.6132],84:[0,.68333,.13889,.08334,.58438],85:[0,.68333,.10903,.02778,.68278],86:[0,.68333,.22222,0,.58333],87:[0,.68333,.13889,0,.94445],88:[0,.68333,.07847,.08334,.82847],89:[0,.68333,.22222,0,.58056],90:[0,.68333,.07153,.08334,.68264],97:[0,.43056,0,0,.52859],98:[0,.69444,0,0,.42917],99:[0,.43056,0,.05556,.43276],100:[0,.69444,0,.16667,.52049],101:[0,.43056,0,.05556,.46563],102:[.19444,.69444,.10764,.16667,.48959],103:[.19444,.43056,.03588,.02778,.47697],104:[0,.69444,0,0,.57616],105:[0,.65952,0,0,.34451],106:[.19444,.65952,.05724,0,.41181],107:[0,.69444,.03148,0,.5206],108:[0,.69444,.01968,.08334,.29838],109:[0,.43056,0,0,.87801],110:[0,.43056,0,0,.60023],111:[0,.43056,0,.05556,.48472],112:[.19444,.43056,0,.08334,.50313],113:[.19444,.43056,.03588,.08334,.44641],114:[0,.43056,.02778,.05556,.45116],115:[0,.43056,0,.05556,.46875],116:[0,.61508,0,.08334,.36111],117:[0,.43056,0,.02778,.57246],118:[0,.43056,.03588,.02778,.48472],119:[0,.43056,.02691,.08334,.71592],120:[0,.43056,0,.02778,.57153],121:[.19444,.43056,.03588,.05556,.49028],122:[0,.43056,.04398,.05556,.46505],160:[0,0,0,0,.25],915:[0,.68333,.13889,.08334,.61528],916:[0,.68333,0,.16667,.83334],920:[0,.68333,.02778,.08334,.76278],923:[0,.68333,0,.16667,.69445],926:[0,.68333,.07569,.08334,.74236],928:[0,.68333,.08125,.05556,.83125],931:[0,.68333,.05764,.08334,.77986],933:[0,.68333,.13889,.05556,.58333],934:[0,.68333,0,.08334,.66667],936:[0,.68333,.11,.05556,.61222],937:[0,.68333,.05017,.08334,.7724],945:[0,.43056,.0037,.02778,.6397],946:[.19444,.69444,.05278,.08334,.56563],947:[.19444,.43056,.05556,0,.51773],948:[0,.69444,.03785,.05556,.44444],949:[0,.43056,0,.08334,.46632],950:[.19444,.69444,.07378,.08334,.4375],951:[.19444,.43056,.03588,.05556,.49653],952:[0,.69444,.02778,.08334,.46944],953:[0,.43056,0,.05556,.35394],954:[0,.43056,0,0,.57616],955:[0,.69444,0,0,.58334],956:[.19444,.43056,0,.02778,.60255],957:[0,.43056,.06366,.02778,.49398],958:[.19444,.69444,.04601,.11111,.4375],959:[0,.43056,0,.05556,.48472],960:[0,.43056,.03588,0,.57003],961:[.19444,.43056,0,.08334,.51702],962:[.09722,.43056,.07986,.08334,.36285],963:[0,.43056,.03588,0,.57141],964:[0,.43056,.1132,.02778,.43715],965:[0,.43056,.03588,.02778,.54028],966:[.19444,.43056,0,.08334,.65417],967:[.19444,.43056,0,.05556,.62569],968:[.19444,.69444,.03588,.11111,.65139],969:[0,.43056,.03588,0,.62245],977:[0,.69444,0,.08334,.59144],981:[.19444,.69444,0,.08334,.59583],982:[0,.43056,.02778,0,.82813],1009:[.19444,.43056,0,.08334,.51702],1013:[0,.43056,0,.05556,.4059],57649:[0,.43056,0,.02778,.32246],57911:[.19444,.43056,0,.08334,.38403]},"SansSerif-Bold":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.36667],34:[0,.69444,0,0,.55834],35:[.19444,.69444,0,0,.91667],36:[.05556,.75,0,0,.55],37:[.05556,.75,0,0,1.02912],38:[0,.69444,0,0,.83056],39:[0,.69444,0,0,.30556],40:[.25,.75,0,0,.42778],41:[.25,.75,0,0,.42778],42:[0,.75,0,0,.55],43:[.11667,.61667,0,0,.85556],44:[.10556,.13056,0,0,.30556],45:[0,.45833,0,0,.36667],46:[0,.13056,0,0,.30556],47:[.25,.75,0,0,.55],48:[0,.69444,0,0,.55],49:[0,.69444,0,0,.55],50:[0,.69444,0,0,.55],51:[0,.69444,0,0,.55],52:[0,.69444,0,0,.55],53:[0,.69444,0,0,.55],54:[0,.69444,0,0,.55],55:[0,.69444,0,0,.55],56:[0,.69444,0,0,.55],57:[0,.69444,0,0,.55],58:[0,.45833,0,0,.30556],59:[.10556,.45833,0,0,.30556],61:[-.09375,.40625,0,0,.85556],63:[0,.69444,0,0,.51945],64:[0,.69444,0,0,.73334],65:[0,.69444,0,0,.73334],66:[0,.69444,0,0,.73334],67:[0,.69444,0,0,.70278],68:[0,.69444,0,0,.79445],69:[0,.69444,0,0,.64167],70:[0,.69444,0,0,.61111],71:[0,.69444,0,0,.73334],72:[0,.69444,0,0,.79445],73:[0,.69444,0,0,.33056],74:[0,.69444,0,0,.51945],75:[0,.69444,0,0,.76389],76:[0,.69444,0,0,.58056],77:[0,.69444,0,0,.97778],78:[0,.69444,0,0,.79445],79:[0,.69444,0,0,.79445],80:[0,.69444,0,0,.70278],81:[.10556,.69444,0,0,.79445],82:[0,.69444,0,0,.70278],83:[0,.69444,0,0,.61111],84:[0,.69444,0,0,.73334],85:[0,.69444,0,0,.76389],86:[0,.69444,.01528,0,.73334],87:[0,.69444,.01528,0,1.03889],88:[0,.69444,0,0,.73334],89:[0,.69444,.0275,0,.73334],90:[0,.69444,0,0,.67223],91:[.25,.75,0,0,.34306],93:[.25,.75,0,0,.34306],94:[0,.69444,0,0,.55],95:[.35,.10833,.03056,0,.55],97:[0,.45833,0,0,.525],98:[0,.69444,0,0,.56111],99:[0,.45833,0,0,.48889],100:[0,.69444,0,0,.56111],101:[0,.45833,0,0,.51111],102:[0,.69444,.07639,0,.33611],103:[.19444,.45833,.01528,0,.55],104:[0,.69444,0,0,.56111],105:[0,.69444,0,0,.25556],106:[.19444,.69444,0,0,.28611],107:[0,.69444,0,0,.53056],108:[0,.69444,0,0,.25556],109:[0,.45833,0,0,.86667],110:[0,.45833,0,0,.56111],111:[0,.45833,0,0,.55],112:[.19444,.45833,0,0,.56111],113:[.19444,.45833,0,0,.56111],114:[0,.45833,.01528,0,.37222],115:[0,.45833,0,0,.42167],116:[0,.58929,0,0,.40417],117:[0,.45833,0,0,.56111],118:[0,.45833,.01528,0,.5],119:[0,.45833,.01528,0,.74445],120:[0,.45833,0,0,.5],121:[.19444,.45833,.01528,0,.5],122:[0,.45833,0,0,.47639],126:[.35,.34444,0,0,.55],160:[0,0,0,0,.25],168:[0,.69444,0,0,.55],176:[0,.69444,0,0,.73334],180:[0,.69444,0,0,.55],184:[.17014,0,0,0,.48889],305:[0,.45833,0,0,.25556],567:[.19444,.45833,0,0,.28611],710:[0,.69444,0,0,.55],711:[0,.63542,0,0,.55],713:[0,.63778,0,0,.55],728:[0,.69444,0,0,.55],729:[0,.69444,0,0,.30556],730:[0,.69444,0,0,.73334],732:[0,.69444,0,0,.55],733:[0,.69444,0,0,.55],915:[0,.69444,0,0,.58056],916:[0,.69444,0,0,.91667],920:[0,.69444,0,0,.85556],923:[0,.69444,0,0,.67223],926:[0,.69444,0,0,.73334],928:[0,.69444,0,0,.79445],931:[0,.69444,0,0,.79445],933:[0,.69444,0,0,.85556],934:[0,.69444,0,0,.79445],936:[0,.69444,0,0,.85556],937:[0,.69444,0,0,.79445],8211:[0,.45833,.03056,0,.55],8212:[0,.45833,.03056,0,1.10001],8216:[0,.69444,0,0,.30556],8217:[0,.69444,0,0,.30556],8220:[0,.69444,0,0,.55834],8221:[0,.69444,0,0,.55834]},"SansSerif-Italic":{32:[0,0,0,0,.25],33:[0,.69444,.05733,0,.31945],34:[0,.69444,.00316,0,.5],35:[.19444,.69444,.05087,0,.83334],36:[.05556,.75,.11156,0,.5],37:[.05556,.75,.03126,0,.83334],38:[0,.69444,.03058,0,.75834],39:[0,.69444,.07816,0,.27778],40:[.25,.75,.13164,0,.38889],41:[.25,.75,.02536,0,.38889],42:[0,.75,.11775,0,.5],43:[.08333,.58333,.02536,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,.01946,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,.13164,0,.5],48:[0,.65556,.11156,0,.5],49:[0,.65556,.11156,0,.5],50:[0,.65556,.11156,0,.5],51:[0,.65556,.11156,0,.5],52:[0,.65556,.11156,0,.5],53:[0,.65556,.11156,0,.5],54:[0,.65556,.11156,0,.5],55:[0,.65556,.11156,0,.5],56:[0,.65556,.11156,0,.5],57:[0,.65556,.11156,0,.5],58:[0,.44444,.02502,0,.27778],59:[.125,.44444,.02502,0,.27778],61:[-.13,.37,.05087,0,.77778],63:[0,.69444,.11809,0,.47222],64:[0,.69444,.07555,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,.08293,0,.66667],67:[0,.69444,.11983,0,.63889],68:[0,.69444,.07555,0,.72223],69:[0,.69444,.11983,0,.59722],70:[0,.69444,.13372,0,.56945],71:[0,.69444,.11983,0,.66667],72:[0,.69444,.08094,0,.70834],73:[0,.69444,.13372,0,.27778],74:[0,.69444,.08094,0,.47222],75:[0,.69444,.11983,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,.08094,0,.875],78:[0,.69444,.08094,0,.70834],79:[0,.69444,.07555,0,.73611],80:[0,.69444,.08293,0,.63889],81:[.125,.69444,.07555,0,.73611],82:[0,.69444,.08293,0,.64584],83:[0,.69444,.09205,0,.55556],84:[0,.69444,.13372,0,.68056],85:[0,.69444,.08094,0,.6875],86:[0,.69444,.1615,0,.66667],87:[0,.69444,.1615,0,.94445],88:[0,.69444,.13372,0,.66667],89:[0,.69444,.17261,0,.66667],90:[0,.69444,.11983,0,.61111],91:[.25,.75,.15942,0,.28889],93:[.25,.75,.08719,0,.28889],94:[0,.69444,.0799,0,.5],95:[.35,.09444,.08616,0,.5],97:[0,.44444,.00981,0,.48056],98:[0,.69444,.03057,0,.51667],99:[0,.44444,.08336,0,.44445],100:[0,.69444,.09483,0,.51667],101:[0,.44444,.06778,0,.44445],102:[0,.69444,.21705,0,.30556],103:[.19444,.44444,.10836,0,.5],104:[0,.69444,.01778,0,.51667],105:[0,.67937,.09718,0,.23889],106:[.19444,.67937,.09162,0,.26667],107:[0,.69444,.08336,0,.48889],108:[0,.69444,.09483,0,.23889],109:[0,.44444,.01778,0,.79445],110:[0,.44444,.01778,0,.51667],111:[0,.44444,.06613,0,.5],112:[.19444,.44444,.0389,0,.51667],113:[.19444,.44444,.04169,0,.51667],114:[0,.44444,.10836,0,.34167],115:[0,.44444,.0778,0,.38333],116:[0,.57143,.07225,0,.36111],117:[0,.44444,.04169,0,.51667],118:[0,.44444,.10836,0,.46111],119:[0,.44444,.10836,0,.68334],120:[0,.44444,.09169,0,.46111],121:[.19444,.44444,.10836,0,.46111],122:[0,.44444,.08752,0,.43472],126:[.35,.32659,.08826,0,.5],160:[0,0,0,0,.25],168:[0,.67937,.06385,0,.5],176:[0,.69444,0,0,.73752],184:[.17014,0,0,0,.44445],305:[0,.44444,.04169,0,.23889],567:[.19444,.44444,.04169,0,.26667],710:[0,.69444,.0799,0,.5],711:[0,.63194,.08432,0,.5],713:[0,.60889,.08776,0,.5],714:[0,.69444,.09205,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,.09483,0,.5],729:[0,.67937,.07774,0,.27778],730:[0,.69444,0,0,.73752],732:[0,.67659,.08826,0,.5],733:[0,.69444,.09205,0,.5],915:[0,.69444,.13372,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,.07555,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,.12816,0,.66667],928:[0,.69444,.08094,0,.70834],931:[0,.69444,.11983,0,.72222],933:[0,.69444,.09031,0,.77778],934:[0,.69444,.04603,0,.72222],936:[0,.69444,.09031,0,.77778],937:[0,.69444,.08293,0,.72222],8211:[0,.44444,.08616,0,.5],8212:[0,.44444,.08616,0,1],8216:[0,.69444,.07816,0,.27778],8217:[0,.69444,.07816,0,.27778],8220:[0,.69444,.14205,0,.5],8221:[0,.69444,.00316,0,.5]},"SansSerif-Regular":{32:[0,0,0,0,.25],33:[0,.69444,0,0,.31945],34:[0,.69444,0,0,.5],35:[.19444,.69444,0,0,.83334],36:[.05556,.75,0,0,.5],37:[.05556,.75,0,0,.83334],38:[0,.69444,0,0,.75834],39:[0,.69444,0,0,.27778],40:[.25,.75,0,0,.38889],41:[.25,.75,0,0,.38889],42:[0,.75,0,0,.5],43:[.08333,.58333,0,0,.77778],44:[.125,.08333,0,0,.27778],45:[0,.44444,0,0,.33333],46:[0,.08333,0,0,.27778],47:[.25,.75,0,0,.5],48:[0,.65556,0,0,.5],49:[0,.65556,0,0,.5],50:[0,.65556,0,0,.5],51:[0,.65556,0,0,.5],52:[0,.65556,0,0,.5],53:[0,.65556,0,0,.5],54:[0,.65556,0,0,.5],55:[0,.65556,0,0,.5],56:[0,.65556,0,0,.5],57:[0,.65556,0,0,.5],58:[0,.44444,0,0,.27778],59:[.125,.44444,0,0,.27778],61:[-.13,.37,0,0,.77778],63:[0,.69444,0,0,.47222],64:[0,.69444,0,0,.66667],65:[0,.69444,0,0,.66667],66:[0,.69444,0,0,.66667],67:[0,.69444,0,0,.63889],68:[0,.69444,0,0,.72223],69:[0,.69444,0,0,.59722],70:[0,.69444,0,0,.56945],71:[0,.69444,0,0,.66667],72:[0,.69444,0,0,.70834],73:[0,.69444,0,0,.27778],74:[0,.69444,0,0,.47222],75:[0,.69444,0,0,.69445],76:[0,.69444,0,0,.54167],77:[0,.69444,0,0,.875],78:[0,.69444,0,0,.70834],79:[0,.69444,0,0,.73611],80:[0,.69444,0,0,.63889],81:[.125,.69444,0,0,.73611],82:[0,.69444,0,0,.64584],83:[0,.69444,0,0,.55556],84:[0,.69444,0,0,.68056],85:[0,.69444,0,0,.6875],86:[0,.69444,.01389,0,.66667],87:[0,.69444,.01389,0,.94445],88:[0,.69444,0,0,.66667],89:[0,.69444,.025,0,.66667],90:[0,.69444,0,0,.61111],91:[.25,.75,0,0,.28889],93:[.25,.75,0,0,.28889],94:[0,.69444,0,0,.5],95:[.35,.09444,.02778,0,.5],97:[0,.44444,0,0,.48056],98:[0,.69444,0,0,.51667],99:[0,.44444,0,0,.44445],100:[0,.69444,0,0,.51667],101:[0,.44444,0,0,.44445],102:[0,.69444,.06944,0,.30556],103:[.19444,.44444,.01389,0,.5],104:[0,.69444,0,0,.51667],105:[0,.67937,0,0,.23889],106:[.19444,.67937,0,0,.26667],107:[0,.69444,0,0,.48889],108:[0,.69444,0,0,.23889],109:[0,.44444,0,0,.79445],110:[0,.44444,0,0,.51667],111:[0,.44444,0,0,.5],112:[.19444,.44444,0,0,.51667],113:[.19444,.44444,0,0,.51667],114:[0,.44444,.01389,0,.34167],115:[0,.44444,0,0,.38333],116:[0,.57143,0,0,.36111],117:[0,.44444,0,0,.51667],118:[0,.44444,.01389,0,.46111],119:[0,.44444,.01389,0,.68334],120:[0,.44444,0,0,.46111],121:[.19444,.44444,.01389,0,.46111],122:[0,.44444,0,0,.43472],126:[.35,.32659,0,0,.5],160:[0,0,0,0,.25],168:[0,.67937,0,0,.5],176:[0,.69444,0,0,.66667],184:[.17014,0,0,0,.44445],305:[0,.44444,0,0,.23889],567:[.19444,.44444,0,0,.26667],710:[0,.69444,0,0,.5],711:[0,.63194,0,0,.5],713:[0,.60889,0,0,.5],714:[0,.69444,0,0,.5],715:[0,.69444,0,0,.5],728:[0,.69444,0,0,.5],729:[0,.67937,0,0,.27778],730:[0,.69444,0,0,.66667],732:[0,.67659,0,0,.5],733:[0,.69444,0,0,.5],915:[0,.69444,0,0,.54167],916:[0,.69444,0,0,.83334],920:[0,.69444,0,0,.77778],923:[0,.69444,0,0,.61111],926:[0,.69444,0,0,.66667],928:[0,.69444,0,0,.70834],931:[0,.69444,0,0,.72222],933:[0,.69444,0,0,.77778],934:[0,.69444,0,0,.72222],936:[0,.69444,0,0,.77778],937:[0,.69444,0,0,.72222],8211:[0,.44444,.02778,0,.5],8212:[0,.44444,.02778,0,1],8216:[0,.69444,0,0,.27778],8217:[0,.69444,0,0,.27778],8220:[0,.69444,0,0,.5],8221:[0,.69444,0,0,.5]},"Script-Regular":{32:[0,0,0,0,.25],65:[0,.7,.22925,0,.80253],66:[0,.7,.04087,0,.90757],67:[0,.7,.1689,0,.66619],68:[0,.7,.09371,0,.77443],69:[0,.7,.18583,0,.56162],70:[0,.7,.13634,0,.89544],71:[0,.7,.17322,0,.60961],72:[0,.7,.29694,0,.96919],73:[0,.7,.19189,0,.80907],74:[.27778,.7,.19189,0,1.05159],75:[0,.7,.31259,0,.91364],76:[0,.7,.19189,0,.87373],77:[0,.7,.15981,0,1.08031],78:[0,.7,.3525,0,.9015],79:[0,.7,.08078,0,.73787],80:[0,.7,.08078,0,1.01262],81:[0,.7,.03305,0,.88282],82:[0,.7,.06259,0,.85],83:[0,.7,.19189,0,.86767],84:[0,.7,.29087,0,.74697],85:[0,.7,.25815,0,.79996],86:[0,.7,.27523,0,.62204],87:[0,.7,.27523,0,.80532],88:[0,.7,.26006,0,.94445],89:[0,.7,.2939,0,.70961],90:[0,.7,.24037,0,.8212],160:[0,0,0,0,.25]},"Size1-Regular":{32:[0,0,0,0,.25],40:[.35001,.85,0,0,.45834],41:[.35001,.85,0,0,.45834],47:[.35001,.85,0,0,.57778],91:[.35001,.85,0,0,.41667],92:[.35001,.85,0,0,.57778],93:[.35001,.85,0,0,.41667],123:[.35001,.85,0,0,.58334],125:[.35001,.85,0,0,.58334],160:[0,0,0,0,.25],710:[0,.72222,0,0,.55556],732:[0,.72222,0,0,.55556],770:[0,.72222,0,0,.55556],771:[0,.72222,0,0,.55556],8214:[-99e-5,.601,0,0,.77778],8593:[1e-5,.6,0,0,.66667],8595:[1e-5,.6,0,0,.66667],8657:[1e-5,.6,0,0,.77778],8659:[1e-5,.6,0,0,.77778],8719:[.25001,.75,0,0,.94445],8720:[.25001,.75,0,0,.94445],8721:[.25001,.75,0,0,1.05556],8730:[.35001,.85,0,0,1],8739:[-.00599,.606,0,0,.33333],8741:[-.00599,.606,0,0,.55556],8747:[.30612,.805,.19445,0,.47222],8748:[.306,.805,.19445,0,.47222],8749:[.306,.805,.19445,0,.47222],8750:[.30612,.805,.19445,0,.47222],8896:[.25001,.75,0,0,.83334],8897:[.25001,.75,0,0,.83334],8898:[.25001,.75,0,0,.83334],8899:[.25001,.75,0,0,.83334],8968:[.35001,.85,0,0,.47222],8969:[.35001,.85,0,0,.47222],8970:[.35001,.85,0,0,.47222],8971:[.35001,.85,0,0,.47222],9168:[-99e-5,.601,0,0,.66667],10216:[.35001,.85,0,0,.47222],10217:[.35001,.85,0,0,.47222],10752:[.25001,.75,0,0,1.11111],10753:[.25001,.75,0,0,1.11111],10754:[.25001,.75,0,0,1.11111],10756:[.25001,.75,0,0,.83334],10758:[.25001,.75,0,0,.83334]},"Size2-Regular":{32:[0,0,0,0,.25],40:[.65002,1.15,0,0,.59722],41:[.65002,1.15,0,0,.59722],47:[.65002,1.15,0,0,.81111],91:[.65002,1.15,0,0,.47222],92:[.65002,1.15,0,0,.81111],93:[.65002,1.15,0,0,.47222],123:[.65002,1.15,0,0,.66667],125:[.65002,1.15,0,0,.66667],160:[0,0,0,0,.25],710:[0,.75,0,0,1],732:[0,.75,0,0,1],770:[0,.75,0,0,1],771:[0,.75,0,0,1],8719:[.55001,1.05,0,0,1.27778],8720:[.55001,1.05,0,0,1.27778],8721:[.55001,1.05,0,0,1.44445],8730:[.65002,1.15,0,0,1],8747:[.86225,1.36,.44445,0,.55556],8748:[.862,1.36,.44445,0,.55556],8749:[.862,1.36,.44445,0,.55556],8750:[.86225,1.36,.44445,0,.55556],8896:[.55001,1.05,0,0,1.11111],8897:[.55001,1.05,0,0,1.11111],8898:[.55001,1.05,0,0,1.11111],8899:[.55001,1.05,0,0,1.11111],8968:[.65002,1.15,0,0,.52778],8969:[.65002,1.15,0,0,.52778],8970:[.65002,1.15,0,0,.52778],8971:[.65002,1.15,0,0,.52778],10216:[.65002,1.15,0,0,.61111],10217:[.65002,1.15,0,0,.61111],10752:[.55001,1.05,0,0,1.51112],10753:[.55001,1.05,0,0,1.51112],10754:[.55001,1.05,0,0,1.51112],10756:[.55001,1.05,0,0,1.11111],10758:[.55001,1.05,0,0,1.11111]},"Size3-Regular":{32:[0,0,0,0,.25],40:[.95003,1.45,0,0,.73611],41:[.95003,1.45,0,0,.73611],47:[.95003,1.45,0,0,1.04445],91:[.95003,1.45,0,0,.52778],92:[.95003,1.45,0,0,1.04445],93:[.95003,1.45,0,0,.52778],123:[.95003,1.45,0,0,.75],125:[.95003,1.45,0,0,.75],160:[0,0,0,0,.25],710:[0,.75,0,0,1.44445],732:[0,.75,0,0,1.44445],770:[0,.75,0,0,1.44445],771:[0,.75,0,0,1.44445],8730:[.95003,1.45,0,0,1],8968:[.95003,1.45,0,0,.58334],8969:[.95003,1.45,0,0,.58334],8970:[.95003,1.45,0,0,.58334],8971:[.95003,1.45,0,0,.58334],10216:[.95003,1.45,0,0,.75],10217:[.95003,1.45,0,0,.75]},"Size4-Regular":{32:[0,0,0,0,.25],40:[1.25003,1.75,0,0,.79167],41:[1.25003,1.75,0,0,.79167],47:[1.25003,1.75,0,0,1.27778],91:[1.25003,1.75,0,0,.58334],92:[1.25003,1.75,0,0,1.27778],93:[1.25003,1.75,0,0,.58334],123:[1.25003,1.75,0,0,.80556],125:[1.25003,1.75,0,0,.80556],160:[0,0,0,0,.25],710:[0,.825,0,0,1.8889],732:[0,.825,0,0,1.8889],770:[0,.825,0,0,1.8889],771:[0,.825,0,0,1.8889],8730:[1.25003,1.75,0,0,1],8968:[1.25003,1.75,0,0,.63889],8969:[1.25003,1.75,0,0,.63889],8970:[1.25003,1.75,0,0,.63889],8971:[1.25003,1.75,0,0,.63889],9115:[.64502,1.155,0,0,.875],9116:[1e-5,.6,0,0,.875],9117:[.64502,1.155,0,0,.875],9118:[.64502,1.155,0,0,.875],9119:[1e-5,.6,0,0,.875],9120:[.64502,1.155,0,0,.875],9121:[.64502,1.155,0,0,.66667],9122:[-99e-5,.601,0,0,.66667],9123:[.64502,1.155,0,0,.66667],9124:[.64502,1.155,0,0,.66667],9125:[-99e-5,.601,0,0,.66667],9126:[.64502,1.155,0,0,.66667],9127:[1e-5,.9,0,0,.88889],9128:[.65002,1.15,0,0,.88889],9129:[.90001,0,0,0,.88889],9130:[0,.3,0,0,.88889],9131:[1e-5,.9,0,0,.88889],9132:[.65002,1.15,0,0,.88889],9133:[.90001,0,0,0,.88889],9143:[.88502,.915,0,0,1.05556],10216:[1.25003,1.75,0,0,.80556],10217:[1.25003,1.75,0,0,.80556],57344:[-.00499,.605,0,0,1.05556],57345:[-.00499,.605,0,0,1.05556],57680:[0,.12,0,0,.45],57681:[0,.12,0,0,.45],57682:[0,.12,0,0,.45],57683:[0,.12,0,0,.45]},"Typewriter-Regular":{32:[0,0,0,0,.525],33:[0,.61111,0,0,.525],34:[0,.61111,0,0,.525],35:[0,.61111,0,0,.525],36:[.08333,.69444,0,0,.525],37:[.08333,.69444,0,0,.525],38:[0,.61111,0,0,.525],39:[0,.61111,0,0,.525],40:[.08333,.69444,0,0,.525],41:[.08333,.69444,0,0,.525],42:[0,.52083,0,0,.525],43:[-.08056,.53055,0,0,.525],44:[.13889,.125,0,0,.525],45:[-.08056,.53055,0,0,.525],46:[0,.125,0,0,.525],47:[.08333,.69444,0,0,.525],48:[0,.61111,0,0,.525],49:[0,.61111,0,0,.525],50:[0,.61111,0,0,.525],51:[0,.61111,0,0,.525],52:[0,.61111,0,0,.525],53:[0,.61111,0,0,.525],54:[0,.61111,0,0,.525],55:[0,.61111,0,0,.525],56:[0,.61111,0,0,.525],57:[0,.61111,0,0,.525],58:[0,.43056,0,0,.525],59:[.13889,.43056,0,0,.525],60:[-.05556,.55556,0,0,.525],61:[-.19549,.41562,0,0,.525],62:[-.05556,.55556,0,0,.525],63:[0,.61111,0,0,.525],64:[0,.61111,0,0,.525],65:[0,.61111,0,0,.525],66:[0,.61111,0,0,.525],67:[0,.61111,0,0,.525],68:[0,.61111,0,0,.525],69:[0,.61111,0,0,.525],70:[0,.61111,0,0,.525],71:[0,.61111,0,0,.525],72:[0,.61111,0,0,.525],73:[0,.61111,0,0,.525],74:[0,.61111,0,0,.525],75:[0,.61111,0,0,.525],76:[0,.61111,0,0,.525],77:[0,.61111,0,0,.525],78:[0,.61111,0,0,.525],79:[0,.61111,0,0,.525],80:[0,.61111,0,0,.525],81:[.13889,.61111,0,0,.525],82:[0,.61111,0,0,.525],83:[0,.61111,0,0,.525],84:[0,.61111,0,0,.525],85:[0,.61111,0,0,.525],86:[0,.61111,0,0,.525],87:[0,.61111,0,0,.525],88:[0,.61111,0,0,.525],89:[0,.61111,0,0,.525],90:[0,.61111,0,0,.525],91:[.08333,.69444,0,0,.525],92:[.08333,.69444,0,0,.525],93:[.08333,.69444,0,0,.525],94:[0,.61111,0,0,.525],95:[.09514,0,0,0,.525],96:[0,.61111,0,0,.525],97:[0,.43056,0,0,.525],98:[0,.61111,0,0,.525],99:[0,.43056,0,0,.525],100:[0,.61111,0,0,.525],101:[0,.43056,0,0,.525],102:[0,.61111,0,0,.525],103:[.22222,.43056,0,0,.525],104:[0,.61111,0,0,.525],105:[0,.61111,0,0,.525],106:[.22222,.61111,0,0,.525],107:[0,.61111,0,0,.525],108:[0,.61111,0,0,.525],109:[0,.43056,0,0,.525],110:[0,.43056,0,0,.525],111:[0,.43056,0,0,.525],112:[.22222,.43056,0,0,.525],113:[.22222,.43056,0,0,.525],114:[0,.43056,0,0,.525],115:[0,.43056,0,0,.525],116:[0,.55358,0,0,.525],117:[0,.43056,0,0,.525],118:[0,.43056,0,0,.525],119:[0,.43056,0,0,.525],120:[0,.43056,0,0,.525],121:[.22222,.43056,0,0,.525],122:[0,.43056,0,0,.525],123:[.08333,.69444,0,0,.525],124:[.08333,.69444,0,0,.525],125:[.08333,.69444,0,0,.525],126:[0,.61111,0,0,.525],127:[0,.61111,0,0,.525],160:[0,0,0,0,.525],176:[0,.61111,0,0,.525],184:[.19445,0,0,0,.525],305:[0,.43056,0,0,.525],567:[.22222,.43056,0,0,.525],711:[0,.56597,0,0,.525],713:[0,.56555,0,0,.525],714:[0,.61111,0,0,.525],715:[0,.61111,0,0,.525],728:[0,.61111,0,0,.525],730:[0,.61111,0,0,.525],770:[0,.61111,0,0,.525],771:[0,.61111,0,0,.525],776:[0,.61111,0,0,.525],915:[0,.61111,0,0,.525],916:[0,.61111,0,0,.525],920:[0,.61111,0,0,.525],923:[0,.61111,0,0,.525],926:[0,.61111,0,0,.525],928:[0,.61111,0,0,.525],931:[0,.61111,0,0,.525],933:[0,.61111,0,0,.525],934:[0,.61111,0,0,.525],936:[0,.61111,0,0,.525],937:[0,.61111,0,0,.525],8216:[0,.61111,0,0,.525],8217:[0,.61111,0,0,.525],8242:[0,.61111,0,0,.525],9251:[.11111,.21944,0,0,.525]}},ke={slant:[.25,.25,.25],space:[0,0,0],stretch:[0,0,0],shrink:[0,0,0],xHeight:[.431,.431,.431],quad:[1,1.171,1.472],extraSpace:[0,0,0],num1:[.677,.732,.925],num2:[.394,.384,.387],num3:[.444,.471,.504],denom1:[.686,.752,1.025],denom2:[.345,.344,.532],sup1:[.413,.503,.504],sup2:[.363,.431,.404],sup3:[.289,.286,.294],sub1:[.15,.143,.2],sub2:[.247,.286,.4],supDrop:[.386,.353,.494],subDrop:[.05,.071,.1],delim1:[2.39,1.7,1.98],delim2:[1.01,1.157,1.42],axisHeight:[.25,.25,.25],defaultRuleThickness:[.04,.049,.049],bigOpSpacing1:[.111,.111,.111],bigOpSpacing2:[.166,.166,.166],bigOpSpacing3:[.2,.2,.2],bigOpSpacing4:[.6,.611,.611],bigOpSpacing5:[.1,.143,.143],sqrtRuleThickness:[.04,.04,.04],ptPerEm:[10,10,10],doubleRuleSep:[.2,.2,.2],arrayRuleWidth:[.04,.04,.04],fboxsep:[.3,.3,.3],fboxrule:[.04,.04,.04]},ar={Å:"A",Ð:"D",Þ:"o",å:"a",ð:"d",þ:"o",А:"A",Б:"B",В:"B",Г:"F",Д:"A",Е:"E",Ж:"K",З:"3",И:"N",Й:"N",К:"K",Л:"N",М:"M",Н:"H",О:"O",П:"N",Р:"P",С:"C",Т:"T",У:"y",Ф:"O",Х:"X",Ц:"U",Ч:"h",Ш:"W",Щ:"W",Ъ:"B",Ы:"X",Ь:"B",Э:"3",Ю:"X",Я:"R",а:"a",б:"b",в:"a",г:"r",д:"y",е:"e",ж:"m",з:"e",и:"n",й:"n",к:"n",л:"n",м:"m",н:"n",о:"o",п:"n",р:"p",с:"c",т:"o",у:"y",ф:"b",х:"x",ц:"n",ч:"n",ш:"w",щ:"w",ъ:"a",ы:"m",ь:"a",э:"e",ю:"m",я:"r"};function x1(r,e){z0[r]=e}function Ot(r,e,t){if(!z0[e])throw new Error("Font metrics not found for font: "+e+".");var a=r.charCodeAt(0),n=z0[e][a];if(!n&&r[0]in ar&&(a=ar[r[0]].charCodeAt(0),n=z0[e][a]),!n&&t==="text"&&Hr(a)&&(n=z0[e][77]),n)return{depth:n[0],height:n[1],italic:n[2],skew:n[3],width:n[4]}}var Ke={};function w1(r){var e;if(r>=5?e=0:r>=3?e=1:e=2,!Ke[e]){var t=Ke[e]={cssEmPerMu:ke.quad[e]/18};for(var a in ke)ke.hasOwnProperty(a)&&(t[a]=ke[a][e])}return Ke[e]}var Z={math:{},text:{}};function i(r,e,t,a,n,s){Z[r][n]={font:e,group:t,replace:a},s&&a&&(Z[r][a]=Z[r][n])}var o="math",S="text",u="main",p="ams",j="accent-token",_="bin",c0="close",oe="inner",I="mathord",a0="op-token",v0="open",ve="punct",f="rel",E0="spacing",g="textord";i(o,u,f,"≡","\\equiv",!0);i(o,u,f,"≺","\\prec",!0);i(o,u,f,"≻","\\succ",!0);i(o,u,f,"∼","\\sim",!0);i(o,u,f,"⊥","\\perp");i(o,u,f,"⪯","\\preceq",!0);i(o,u,f,"⪰","\\succeq",!0);i(o,u,f,"≃","\\simeq",!0);i(o,u,f,"∣","\\mid",!0);i(o,u,f,"≪","\\ll",!0);i(o,u,f,"≫","\\gg",!0);i(o,u,f,"≍","\\asymp",!0);i(o,u,f,"∥","\\parallel");i(o,u,f,"⋈","\\bowtie",!0);i(o,u,f,"⌣","\\smile",!0);i(o,u,f,"⊑","\\sqsubseteq",!0);i(o,u,f,"⊒","\\sqsupseteq",!0);i(o,u,f,"≐","\\doteq",!0);i(o,u,f,"⌢","\\frown",!0);i(o,u,f,"∋","\\ni",!0);i(o,u,f,"∝","\\propto",!0);i(o,u,f,"⊢","\\vdash",!0);i(o,u,f,"⊣","\\dashv",!0);i(o,u,f,"∋","\\owns");i(o,u,ve,".","\\ldotp");i(o,u,ve,"⋅","\\cdotp");i(o,u,ve,"⋅","·");i(S,u,g,"⋅","·");i(o,u,g,"#","\\#");i(S,u,g,"#","\\#");i(o,u,g,"&","\\&");i(S,u,g,"&","\\&");i(o,u,g,"ℵ","\\aleph",!0);i(o,u,g,"∀","\\forall",!0);i(o,u,g,"ℏ","\\hbar",!0);i(o,u,g,"∃","\\exists",!0);i(o,u,g,"∇","\\nabla",!0);i(o,u,g,"♭","\\flat",!0);i(o,u,g,"ℓ","\\ell",!0);i(o,u,g,"♮","\\natural",!0);i(o,u,g,"♣","\\clubsuit",!0);i(o,u,g,"℘","\\wp",!0);i(o,u,g,"♯","\\sharp",!0);i(o,u,g,"♢","\\diamondsuit",!0);i(o,u,g,"ℜ","\\Re",!0);i(o,u,g,"♡","\\heartsuit",!0);i(o,u,g,"ℑ","\\Im",!0);i(o,u,g,"♠","\\spadesuit",!0);i(o,u,g,"§","\\S",!0);i(S,u,g,"§","\\S");i(o,u,g,"¶","\\P",!0);i(S,u,g,"¶","\\P");i(o,u,g,"†","\\dag");i(S,u,g,"†","\\dag");i(S,u,g,"†","\\textdagger");i(o,u,g,"‡","\\ddag");i(S,u,g,"‡","\\ddag");i(S,u,g,"‡","\\textdaggerdbl");i(o,u,c0,"⎱","\\rmoustache",!0);i(o,u,v0,"⎰","\\lmoustache",!0);i(o,u,c0,"⟯","\\rgroup",!0);i(o,u,v0,"⟮","\\lgroup",!0);i(o,u,_,"∓","\\mp",!0);i(o,u,_,"⊖","\\ominus",!0);i(o,u,_,"⊎","\\uplus",!0);i(o,u,_,"⊓","\\sqcap",!0);i(o,u,_,"∗","\\ast");i(o,u,_,"⊔","\\sqcup",!0);i(o,u,_,"◯","\\bigcirc",!0);i(o,u,_,"∙","\\bullet",!0);i(o,u,_,"‡","\\ddagger");i(o,u,_,"≀","\\wr",!0);i(o,u,_,"⨿","\\amalg");i(o,u,_,"&","\\And");i(o,u,f,"⟵","\\longleftarrow",!0);i(o,u,f,"⇐","\\Leftarrow",!0);i(o,u,f,"⟸","\\Longleftarrow",!0);i(o,u,f,"⟶","\\longrightarrow",!0);i(o,u,f,"⇒","\\Rightarrow",!0);i(o,u,f,"⟹","\\Longrightarrow",!0);i(o,u,f,"↔","\\leftrightarrow",!0);i(o,u,f,"⟷","\\longleftrightarrow",!0);i(o,u,f,"⇔","\\Leftrightarrow",!0);i(o,u,f,"⟺","\\Longleftrightarrow",!0);i(o,u,f,"↦","\\mapsto",!0);i(o,u,f,"⟼","\\longmapsto",!0);i(o,u,f,"↗","\\nearrow",!0);i(o,u,f,"↩","\\hookleftarrow",!0);i(o,u,f,"↪","\\hookrightarrow",!0);i(o,u,f,"↘","\\searrow",!0);i(o,u,f,"↼","\\leftharpoonup",!0);i(o,u,f,"⇀","\\rightharpoonup",!0);i(o,u,f,"↙","\\swarrow",!0);i(o,u,f,"↽","\\leftharpoondown",!0);i(o,u,f,"⇁","\\rightharpoondown",!0);i(o,u,f,"↖","\\nwarrow",!0);i(o,u,f,"⇌","\\rightleftharpoons",!0);i(o,p,f,"≮","\\nless",!0);i(o,p,f,"","\\@nleqslant");i(o,p,f,"","\\@nleqq");i(o,p,f,"⪇","\\lneq",!0);i(o,p,f,"≨","\\lneqq",!0);i(o,p,f,"","\\@lvertneqq");i(o,p,f,"⋦","\\lnsim",!0);i(o,p,f,"⪉","\\lnapprox",!0);i(o,p,f,"⊀","\\nprec",!0);i(o,p,f,"⋠","\\npreceq",!0);i(o,p,f,"⋨","\\precnsim",!0);i(o,p,f,"⪹","\\precnapprox",!0);i(o,p,f,"≁","\\nsim",!0);i(o,p,f,"","\\@nshortmid");i(o,p,f,"∤","\\nmid",!0);i(o,p,f,"⊬","\\nvdash",!0);i(o,p,f,"⊭","\\nvDash",!0);i(o,p,f,"⋪","\\ntriangleleft");i(o,p,f,"⋬","\\ntrianglelefteq",!0);i(o,p,f,"⊊","\\subsetneq",!0);i(o,p,f,"","\\@varsubsetneq");i(o,p,f,"⫋","\\subsetneqq",!0);i(o,p,f,"","\\@varsubsetneqq");i(o,p,f,"≯","\\ngtr",!0);i(o,p,f,"","\\@ngeqslant");i(o,p,f,"","\\@ngeqq");i(o,p,f,"⪈","\\gneq",!0);i(o,p,f,"≩","\\gneqq",!0);i(o,p,f,"","\\@gvertneqq");i(o,p,f,"⋧","\\gnsim",!0);i(o,p,f,"⪊","\\gnapprox",!0);i(o,p,f,"⊁","\\nsucc",!0);i(o,p,f,"⋡","\\nsucceq",!0);i(o,p,f,"⋩","\\succnsim",!0);i(o,p,f,"⪺","\\succnapprox",!0);i(o,p,f,"≆","\\ncong",!0);i(o,p,f,"","\\@nshortparallel");i(o,p,f,"∦","\\nparallel",!0);i(o,p,f,"⊯","\\nVDash",!0);i(o,p,f,"⋫","\\ntriangleright");i(o,p,f,"⋭","\\ntrianglerighteq",!0);i(o,p,f,"","\\@nsupseteqq");i(o,p,f,"⊋","\\supsetneq",!0);i(o,p,f,"","\\@varsupsetneq");i(o,p,f,"⫌","\\supsetneqq",!0);i(o,p,f,"","\\@varsupsetneqq");i(o,p,f,"⊮","\\nVdash",!0);i(o,p,f,"⪵","\\precneqq",!0);i(o,p,f,"⪶","\\succneqq",!0);i(o,p,f,"","\\@nsubseteqq");i(o,p,_,"⊴","\\unlhd");i(o,p,_,"⊵","\\unrhd");i(o,p,f,"↚","\\nleftarrow",!0);i(o,p,f,"↛","\\nrightarrow",!0);i(o,p,f,"⇍","\\nLeftarrow",!0);i(o,p,f,"⇏","\\nRightarrow",!0);i(o,p,f,"↮","\\nleftrightarrow",!0);i(o,p,f,"⇎","\\nLeftrightarrow",!0);i(o,p,f,"△","\\vartriangle");i(o,p,g,"ℏ","\\hslash");i(o,p,g,"▽","\\triangledown");i(o,p,g,"◊","\\lozenge");i(o,p,g,"Ⓢ","\\circledS");i(o,p,g,"®","\\circledR");i(S,p,g,"®","\\circledR");i(o,p,g,"∡","\\measuredangle",!0);i(o,p,g,"∄","\\nexists");i(o,p,g,"℧","\\mho");i(o,p,g,"Ⅎ","\\Finv",!0);i(o,p,g,"⅁","\\Game",!0);i(o,p,g,"‵","\\backprime");i(o,p,g,"▲","\\blacktriangle");i(o,p,g,"▼","\\blacktriangledown");i(o,p,g,"■","\\blacksquare");i(o,p,g,"⧫","\\blacklozenge");i(o,p,g,"★","\\bigstar");i(o,p,g,"∢","\\sphericalangle",!0);i(o,p,g,"∁","\\complement",!0);i(o,p,g,"ð","\\eth",!0);i(S,u,g,"ð","ð");i(o,p,g,"╱","\\diagup");i(o,p,g,"╲","\\diagdown");i(o,p,g,"□","\\square");i(o,p,g,"□","\\Box");i(o,p,g,"◊","\\Diamond");i(o,p,g,"¥","\\yen",!0);i(S,p,g,"¥","\\yen",!0);i(o,p,g,"✓","\\checkmark",!0);i(S,p,g,"✓","\\checkmark");i(o,p,g,"ℶ","\\beth",!0);i(o,p,g,"ℸ","\\daleth",!0);i(o,p,g,"ℷ","\\gimel",!0);i(o,p,g,"ϝ","\\digamma",!0);i(o,p,g,"ϰ","\\varkappa");i(o,p,v0,"┌","\\@ulcorner",!0);i(o,p,c0,"┐","\\@urcorner",!0);i(o,p,v0,"└","\\@llcorner",!0);i(o,p,c0,"┘","\\@lrcorner",!0);i(o,p,f,"≦","\\leqq",!0);i(o,p,f,"⩽","\\leqslant",!0);i(o,p,f,"⪕","\\eqslantless",!0);i(o,p,f,"≲","\\lesssim",!0);i(o,p,f,"⪅","\\lessapprox",!0);i(o,p,f,"≊","\\approxeq",!0);i(o,p,_,"⋖","\\lessdot");i(o,p,f,"⋘","\\lll",!0);i(o,p,f,"≶","\\lessgtr",!0);i(o,p,f,"⋚","\\lesseqgtr",!0);i(o,p,f,"⪋","\\lesseqqgtr",!0);i(o,p,f,"≑","\\doteqdot");i(o,p,f,"≓","\\risingdotseq",!0);i(o,p,f,"≒","\\fallingdotseq",!0);i(o,p,f,"∽","\\backsim",!0);i(o,p,f,"⋍","\\backsimeq",!0);i(o,p,f,"⫅","\\subseteqq",!0);i(o,p,f,"⋐","\\Subset",!0);i(o,p,f,"⊏","\\sqsubset",!0);i(o,p,f,"≼","\\preccurlyeq",!0);i(o,p,f,"⋞","\\curlyeqprec",!0);i(o,p,f,"≾","\\precsim",!0);i(o,p,f,"⪷","\\precapprox",!0);i(o,p,f,"⊲","\\vartriangleleft");i(o,p,f,"⊴","\\trianglelefteq");i(o,p,f,"⊨","\\vDash",!0);i(o,p,f,"⊪","\\Vvdash",!0);i(o,p,f,"⌣","\\smallsmile");i(o,p,f,"⌢","\\smallfrown");i(o,p,f,"≏","\\bumpeq",!0);i(o,p,f,"≎","\\Bumpeq",!0);i(o,p,f,"≧","\\geqq",!0);i(o,p,f,"⩾","\\geqslant",!0);i(o,p,f,"⪖","\\eqslantgtr",!0);i(o,p,f,"≳","\\gtrsim",!0);i(o,p,f,"⪆","\\gtrapprox",!0);i(o,p,_,"⋗","\\gtrdot");i(o,p,f,"⋙","\\ggg",!0);i(o,p,f,"≷","\\gtrless",!0);i(o,p,f,"⋛","\\gtreqless",!0);i(o,p,f,"⪌","\\gtreqqless",!0);i(o,p,f,"≖","\\eqcirc",!0);i(o,p,f,"≗","\\circeq",!0);i(o,p,f,"≜","\\triangleq",!0);i(o,p,f,"∼","\\thicksim");i(o,p,f,"≈","\\thickapprox");i(o,p,f,"⫆","\\supseteqq",!0);i(o,p,f,"⋑","\\Supset",!0);i(o,p,f,"⊐","\\sqsupset",!0);i(o,p,f,"≽","\\succcurlyeq",!0);i(o,p,f,"⋟","\\curlyeqsucc",!0);i(o,p,f,"≿","\\succsim",!0);i(o,p,f,"⪸","\\succapprox",!0);i(o,p,f,"⊳","\\vartriangleright");i(o,p,f,"⊵","\\trianglerighteq");i(o,p,f,"⊩","\\Vdash",!0);i(o,p,f,"∣","\\shortmid");i(o,p,f,"∥","\\shortparallel");i(o,p,f,"≬","\\between",!0);i(o,p,f,"⋔","\\pitchfork",!0);i(o,p,f,"∝","\\varpropto");i(o,p,f,"◀","\\blacktriangleleft");i(o,p,f,"∴","\\therefore",!0);i(o,p,f,"∍","\\backepsilon");i(o,p,f,"▶","\\blacktriangleright");i(o,p,f,"∵","\\because",!0);i(o,p,f,"⋘","\\llless");i(o,p,f,"⋙","\\gggtr");i(o,p,_,"⊲","\\lhd");i(o,p,_,"⊳","\\rhd");i(o,p,f,"≂","\\eqsim",!0);i(o,u,f,"⋈","\\Join");i(o,p,f,"≑","\\Doteq",!0);i(o,p,_,"∔","\\dotplus",!0);i(o,p,_,"∖","\\smallsetminus");i(o,p,_,"⋒","\\Cap",!0);i(o,p,_,"⋓","\\Cup",!0);i(o,p,_,"⩞","\\doublebarwedge",!0);i(o,p,_,"⊟","\\boxminus",!0);i(o,p,_,"⊞","\\boxplus",!0);i(o,p,_,"⋇","\\divideontimes",!0);i(o,p,_,"⋉","\\ltimes",!0);i(o,p,_,"⋊","\\rtimes",!0);i(o,p,_,"⋋","\\leftthreetimes",!0);i(o,p,_,"⋌","\\rightthreetimes",!0);i(o,p,_,"⋏","\\curlywedge",!0);i(o,p,_,"⋎","\\curlyvee",!0);i(o,p,_,"⊝","\\circleddash",!0);i(o,p,_,"⊛","\\circledast",!0);i(o,p,_,"⋅","\\centerdot");i(o,p,_,"⊺","\\intercal",!0);i(o,p,_,"⋒","\\doublecap");i(o,p,_,"⋓","\\doublecup");i(o,p,_,"⊠","\\boxtimes",!0);i(o,p,f,"⇢","\\dashrightarrow",!0);i(o,p,f,"⇠","\\dashleftarrow",!0);i(o,p,f,"⇇","\\leftleftarrows",!0);i(o,p,f,"⇆","\\leftrightarrows",!0);i(o,p,f,"⇚","\\Lleftarrow",!0);i(o,p,f,"↞","\\twoheadleftarrow",!0);i(o,p,f,"↢","\\leftarrowtail",!0);i(o,p,f,"↫","\\looparrowleft",!0);i(o,p,f,"⇋","\\leftrightharpoons",!0);i(o,p,f,"↶","\\curvearrowleft",!0);i(o,p,f,"↺","\\circlearrowleft",!0);i(o,p,f,"↰","\\Lsh",!0);i(o,p,f,"⇈","\\upuparrows",!0);i(o,p,f,"↿","\\upharpoonleft",!0);i(o,p,f,"⇃","\\downharpoonleft",!0);i(o,u,f,"⊶","\\origof",!0);i(o,u,f,"⊷","\\imageof",!0);i(o,p,f,"⊸","\\multimap",!0);i(o,p,f,"↭","\\leftrightsquigarrow",!0);i(o,p,f,"⇉","\\rightrightarrows",!0);i(o,p,f,"⇄","\\rightleftarrows",!0);i(o,p,f,"↠","\\twoheadrightarrow",!0);i(o,p,f,"↣","\\rightarrowtail",!0);i(o,p,f,"↬","\\looparrowright",!0);i(o,p,f,"↷","\\curvearrowright",!0);i(o,p,f,"↻","\\circlearrowright",!0);i(o,p,f,"↱","\\Rsh",!0);i(o,p,f,"⇊","\\downdownarrows",!0);i(o,p,f,"↾","\\upharpoonright",!0);i(o,p,f,"⇂","\\downharpoonright",!0);i(o,p,f,"⇝","\\rightsquigarrow",!0);i(o,p,f,"⇝","\\leadsto");i(o,p,f,"⇛","\\Rrightarrow",!0);i(o,p,f,"↾","\\restriction");i(o,u,g,"‘","`");i(o,u,g,"$","\\$");i(S,u,g,"$","\\$");i(S,u,g,"$","\\textdollar");i(o,u,g,"%","\\%");i(S,u,g,"%","\\%");i(o,u,g,"_","\\_");i(S,u,g,"_","\\_");i(S,u,g,"_","\\textunderscore");i(o,u,g,"∠","\\angle",!0);i(o,u,g,"∞","\\infty",!0);i(o,u,g,"′","\\prime");i(o,u,g,"△","\\triangle");i(o,u,g,"Γ","\\Gamma",!0);i(o,u,g,"Δ","\\Delta",!0);i(o,u,g,"Θ","\\Theta",!0);i(o,u,g,"Λ","\\Lambda",!0);i(o,u,g,"Ξ","\\Xi",!0);i(o,u,g,"Π","\\Pi",!0);i(o,u,g,"Σ","\\Sigma",!0);i(o,u,g,"Υ","\\Upsilon",!0);i(o,u,g,"Φ","\\Phi",!0);i(o,u,g,"Ψ","\\Psi",!0);i(o,u,g,"Ω","\\Omega",!0);i(o,u,g,"A","Α");i(o,u,g,"B","Β");i(o,u,g,"E","Ε");i(o,u,g,"Z","Ζ");i(o,u,g,"H","Η");i(o,u,g,"I","Ι");i(o,u,g,"K","Κ");i(o,u,g,"M","Μ");i(o,u,g,"N","Ν");i(o,u,g,"O","Ο");i(o,u,g,"P","Ρ");i(o,u,g,"T","Τ");i(o,u,g,"X","Χ");i(o,u,g,"¬","\\neg",!0);i(o,u,g,"¬","\\lnot");i(o,u,g,"⊤","\\top");i(o,u,g,"⊥","\\bot");i(o,u,g,"∅","\\emptyset");i(o,p,g,"∅","\\varnothing");i(o,u,I,"α","\\alpha",!0);i(o,u,I,"β","\\beta",!0);i(o,u,I,"γ","\\gamma",!0);i(o,u,I,"δ","\\delta",!0);i(o,u,I,"ϵ","\\epsilon",!0);i(o,u,I,"ζ","\\zeta",!0);i(o,u,I,"η","\\eta",!0);i(o,u,I,"θ","\\theta",!0);i(o,u,I,"ι","\\iota",!0);i(o,u,I,"κ","\\kappa",!0);i(o,u,I,"λ","\\lambda",!0);i(o,u,I,"μ","\\mu",!0);i(o,u,I,"ν","\\nu",!0);i(o,u,I,"ξ","\\xi",!0);i(o,u,I,"ο","\\omicron",!0);i(o,u,I,"π","\\pi",!0);i(o,u,I,"ρ","\\rho",!0);i(o,u,I,"σ","\\sigma",!0);i(o,u,I,"τ","\\tau",!0);i(o,u,I,"υ","\\upsilon",!0);i(o,u,I,"ϕ","\\phi",!0);i(o,u,I,"χ","\\chi",!0);i(o,u,I,"ψ","\\psi",!0);i(o,u,I,"ω","\\omega",!0);i(o,u,I,"ε","\\varepsilon",!0);i(o,u,I,"ϑ","\\vartheta",!0);i(o,u,I,"ϖ","\\varpi",!0);i(o,u,I,"ϱ","\\varrho",!0);i(o,u,I,"ς","\\varsigma",!0);i(o,u,I,"φ","\\varphi",!0);i(o,u,_,"∗","*",!0);i(o,u,_,"+","+");i(o,u,_,"−","-",!0);i(o,u,_,"⋅","\\cdot",!0);i(o,u,_,"∘","\\circ",!0);i(o,u,_,"÷","\\div",!0);i(o,u,_,"±","\\pm",!0);i(o,u,_,"×","\\times",!0);i(o,u,_,"∩","\\cap",!0);i(o,u,_,"∪","\\cup",!0);i(o,u,_,"∖","\\setminus",!0);i(o,u,_,"∧","\\land");i(o,u,_,"∨","\\lor");i(o,u,_,"∧","\\wedge",!0);i(o,u,_,"∨","\\vee",!0);i(o,u,g,"√","\\surd");i(o,u,v0,"⟨","\\langle",!0);i(o,u,v0,"∣","\\lvert");i(o,u,v0,"∥","\\lVert");i(o,u,c0,"?","?");i(o,u,c0,"!","!");i(o,u,c0,"⟩","\\rangle",!0);i(o,u,c0,"∣","\\rvert");i(o,u,c0,"∥","\\rVert");i(o,u,f,"=","=");i(o,u,f,":",":");i(o,u,f,"≈","\\approx",!0);i(o,u,f,"≅","\\cong",!0);i(o,u,f,"≥","\\ge");i(o,u,f,"≥","\\geq",!0);i(o,u,f,"←","\\gets");i(o,u,f,">","\\gt",!0);i(o,u,f,"∈","\\in",!0);i(o,u,f,"","\\@not");i(o,u,f,"⊂","\\subset",!0);i(o,u,f,"⊃","\\supset",!0);i(o,u,f,"⊆","\\subseteq",!0);i(o,u,f,"⊇","\\supseteq",!0);i(o,p,f,"⊈","\\nsubseteq",!0);i(o,p,f,"⊉","\\nsupseteq",!0);i(o,u,f,"⊨","\\models");i(o,u,f,"←","\\leftarrow",!0);i(o,u,f,"≤","\\le");i(o,u,f,"≤","\\leq",!0);i(o,u,f,"<","\\lt",!0);i(o,u,f,"→","\\rightarrow",!0);i(o,u,f,"→","\\to");i(o,p,f,"≱","\\ngeq",!0);i(o,p,f,"≰","\\nleq",!0);i(o,u,E0," ","\\ ");i(o,u,E0," ","\\space");i(o,u,E0," ","\\nobreakspace");i(S,u,E0," ","\\ ");i(S,u,E0," "," ");i(S,u,E0," ","\\space");i(S,u,E0," ","\\nobreakspace");i(o,u,E0,"","\\nobreak");i(o,u,E0,"","\\allowbreak");i(o,u,ve,",",",");i(o,u,ve,";",";");i(o,p,_,"⊼","\\barwedge",!0);i(o,p,_,"⊻","\\veebar",!0);i(o,u,_,"⊙","\\odot",!0);i(o,u,_,"⊕","\\oplus",!0);i(o,u,_,"⊗","\\otimes",!0);i(o,u,g,"∂","\\partial",!0);i(o,u,_,"⊘","\\oslash",!0);i(o,p,_,"⊚","\\circledcirc",!0);i(o,p,_,"⊡","\\boxdot",!0);i(o,u,_,"△","\\bigtriangleup");i(o,u,_,"▽","\\bigtriangledown");i(o,u,_,"†","\\dagger");i(o,u,_,"⋄","\\diamond");i(o,u,_,"⋆","\\star");i(o,u,_,"◃","\\triangleleft");i(o,u,_,"▹","\\triangleright");i(o,u,v0,"{","\\{");i(S,u,g,"{","\\{");i(S,u,g,"{","\\textbraceleft");i(o,u,c0,"}","\\}");i(S,u,g,"}","\\}");i(S,u,g,"}","\\textbraceright");i(o,u,v0,"{","\\lbrace");i(o,u,c0,"}","\\rbrace");i(o,u,v0,"[","\\lbrack",!0);i(S,u,g,"[","\\lbrack",!0);i(o,u,c0,"]","\\rbrack",!0);i(S,u,g,"]","\\rbrack",!0);i(o,u,v0,"(","\\lparen",!0);i(o,u,c0,")","\\rparen",!0);i(S,u,g,"<","\\textless",!0);i(S,u,g,">","\\textgreater",!0);i(o,u,v0,"⌊","\\lfloor",!0);i(o,u,c0,"⌋","\\rfloor",!0);i(o,u,v0,"⌈","\\lceil",!0);i(o,u,c0,"⌉","\\rceil",!0);i(o,u,g,"\\","\\backslash");i(o,u,g,"∣","|");i(o,u,g,"∣","\\vert");i(S,u,g,"|","\\textbar",!0);i(o,u,g,"∥","\\|");i(o,u,g,"∥","\\Vert");i(S,u,g,"∥","\\textbardbl");i(S,u,g,"~","\\textasciitilde");i(S,u,g,"\\","\\textbackslash");i(S,u,g,"^","\\textasciicircum");i(o,u,f,"↑","\\uparrow",!0);i(o,u,f,"⇑","\\Uparrow",!0);i(o,u,f,"↓","\\downarrow",!0);i(o,u,f,"⇓","\\Downarrow",!0);i(o,u,f,"↕","\\updownarrow",!0);i(o,u,f,"⇕","\\Updownarrow",!0);i(o,u,a0,"∐","\\coprod");i(o,u,a0,"⋁","\\bigvee");i(o,u,a0,"⋀","\\bigwedge");i(o,u,a0,"⨄","\\biguplus");i(o,u,a0,"⋂","\\bigcap");i(o,u,a0,"⋃","\\bigcup");i(o,u,a0,"∫","\\int");i(o,u,a0,"∫","\\intop");i(o,u,a0,"∬","\\iint");i(o,u,a0,"∭","\\iiint");i(o,u,a0,"∏","\\prod");i(o,u,a0,"∑","\\sum");i(o,u,a0,"⨂","\\bigotimes");i(o,u,a0,"⨁","\\bigoplus");i(o,u,a0,"⨀","\\bigodot");i(o,u,a0,"∮","\\oint");i(o,u,a0,"∯","\\oiint");i(o,u,a0,"∰","\\oiiint");i(o,u,a0,"⨆","\\bigsqcup");i(o,u,a0,"∫","\\smallint");i(S,u,oe,"…","\\textellipsis");i(o,u,oe,"…","\\mathellipsis");i(S,u,oe,"…","\\ldots",!0);i(o,u,oe,"…","\\ldots",!0);i(o,u,oe,"⋯","\\@cdots",!0);i(o,u,oe,"⋱","\\ddots",!0);i(o,u,g,"⋮","\\varvdots");i(S,u,g,"⋮","\\varvdots");i(o,u,j,"ˊ","\\acute");i(o,u,j,"ˋ","\\grave");i(o,u,j,"¨","\\ddot");i(o,u,j,"~","\\tilde");i(o,u,j,"ˉ","\\bar");i(o,u,j,"˘","\\breve");i(o,u,j,"ˇ","\\check");i(o,u,j,"^","\\hat");i(o,u,j,"⃗","\\vec");i(o,u,j,"˙","\\dot");i(o,u,j,"˚","\\mathring");i(o,u,I,"","\\@imath");i(o,u,I,"","\\@jmath");i(o,u,g,"ı","ı");i(o,u,g,"ȷ","ȷ");i(S,u,g,"ı","\\i",!0);i(S,u,g,"ȷ","\\j",!0);i(S,u,g,"ß","\\ss",!0);i(S,u,g,"æ","\\ae",!0);i(S,u,g,"œ","\\oe",!0);i(S,u,g,"ø","\\o",!0);i(S,u,g,"Æ","\\AE",!0);i(S,u,g,"Œ","\\OE",!0);i(S,u,g,"Ø","\\O",!0);i(S,u,j,"ˊ","\\'");i(S,u,j,"ˋ","\\`");i(S,u,j,"ˆ","\\^");i(S,u,j,"˜","\\~");i(S,u,j,"ˉ","\\=");i(S,u,j,"˘","\\u");i(S,u,j,"˙","\\.");i(S,u,j,"¸","\\c");i(S,u,j,"˚","\\r");i(S,u,j,"ˇ","\\v");i(S,u,j,"¨",'\\"');i(S,u,j,"˝","\\H");i(S,u,j,"◯","\\textcircled");var Vr={"--":!0,"---":!0,"``":!0,"''":!0};i(S,u,g,"–","--",!0);i(S,u,g,"–","\\textendash");i(S,u,g,"—","---",!0);i(S,u,g,"—","\\textemdash");i(S,u,g,"‘","`",!0);i(S,u,g,"‘","\\textquoteleft");i(S,u,g,"’","'",!0);i(S,u,g,"’","\\textquoteright");i(S,u,g,"“","``",!0);i(S,u,g,"“","\\textquotedblleft");i(S,u,g,"”","''",!0);i(S,u,g,"”","\\textquotedblright");i(o,u,g,"°","\\degree",!0);i(S,u,g,"°","\\degree");i(S,u,g,"°","\\textdegree",!0);i(o,u,g,"£","\\pounds");i(o,u,g,"£","\\mathsterling",!0);i(S,u,g,"£","\\pounds");i(S,u,g,"£","\\textsterling",!0);i(o,p,g,"✠","\\maltese");i(S,p,g,"✠","\\maltese");var nr='0123456789/@."';for(var Je=0;Je{var e=r.charCodeAt(0),t=r.charCodeAt(1),a=(e-55296)*1024+(t-56320)+65536;if(119808<=a&&a<120484){var n=Math.floor((a-119808)/26);return pr[n]}else if(120782<=a&&a<=120831){var s=Math.floor((a-120782)/10);return k1[s]}else{if(a===120485||a===120486)return pr[0];if(120486{if(L0(r.classes)!==L0(e.classes)||r.skew!==e.skew||r.maxFontSize!==e.maxFontSize||r.italic!==0&&r.hasClass("mathnormal"))return!1;if(r.classes.length===1){var t=r.classes[0];if(t==="mbin"||t==="mord")return!1}for(var a of Object.keys(r.style))if(r.style[a]!==e.style[a])return!1;for(var n of Object.keys(e.style))if(r.style[n]!==e.style[n])return!1;return!0},Xr=r=>{for(var e=0;et&&(t=l.height),l.depth>a&&(a=l.depth),l.maxFontSize>n&&(n=l.maxFontSize)}e.height=t,e.depth=a,e.maxFontSize=n},k=function(e,t,a,n){var s=new se(e,t,a,n);return Rt(s),s},P0=(r,e,t,a)=>new se(r,e,t,a),ae=function(e,t,a){var n=k([e],[],t);return n.height=Math.max(a||t.fontMetrics().defaultRuleThickness,t.minRuleThickness),n.style.borderBottomWidth=M(n.height),n.maxFontSize=1,n},T1=function(e,t,a,n){var s=new Re(e,t,a,n);return Rt(s),s},I0=function(e){var t=new ie(e);return Rt(t),t},ne=function(e,t){return e instanceof ie?k([],[e],t):e},q1=function(e){if(e.positionType==="individualShift"){for(var t=e.children,a=[t[0]],n=-t[0].shift-t[0].elem.depth,s=n,l=1;l{var t=k(["mspace"],[],e),a=J(r,e);return t.style.marginRight=M(a),t},Me=(r,e,t)=>{var a,n;switch(r){case"amsrm":a="AMS";break;case"textrm":a="Main";break;case"textsf":a="SansSerif";break;case"texttt":a="Typewriter";break;default:a=r}return e==="textbf"&&t==="textit"?n="BoldItalic":e==="textbf"?n="Bold":t==="textit"?n="Italic":n="Regular",a+"-"+n},St={mathbf:{variant:"bold",fontName:"Main-Bold"},mathrm:{variant:"normal",fontName:"Main-Regular"},textit:{variant:"italic",fontName:"Main-Italic"},mathit:{variant:"italic",fontName:"Main-Italic"},mathnormal:{variant:"italic",fontName:"Math-Italic"},mathsfit:{variant:"sans-serif-italic",fontName:"SansSerif-Italic"},mathbb:{variant:"double-struck",fontName:"AMS-Regular"},mathcal:{variant:"script",fontName:"Caligraphic-Regular"},mathfrak:{variant:"fraktur",fontName:"Fraktur-Regular"},mathscr:{variant:"script",fontName:"Script-Regular"},mathsf:{variant:"sans-serif",fontName:"SansSerif-Regular"},mathtt:{variant:"monospace",fontName:"Typewriter-Regular"}},Yr={vec:["vec",.471,.714],oiintSize1:["oiintSize1",.957,.499],oiintSize2:["oiintSize2",1.472,.659],oiiintSize1:["oiiintSize1",1.304,.499],oiiintSize2:["oiiintSize2",1.98,.659]},Zr=function(e,t){var[a,n,s]=Yr[e],l=new G0(a),c=new B0([l],{width:M(n),height:M(s),style:"width:"+M(n),viewBox:"0 0 "+1e3*n+" "+1e3*s,preserveAspectRatio:"xMinYMin"}),m=P0(["overlay"],[c],t);return m.height=s,m.style.height=M(s),m.style.width=M(n),m},K={number:3,unit:"mu"},W0={number:4,unit:"mu"},q0={number:5,unit:"mu"},D1={mord:{mop:K,mbin:W0,mrel:q0,minner:K},mop:{mord:K,mop:K,mrel:q0,minner:K},mbin:{mord:W0,mop:W0,mopen:W0,minner:W0},mrel:{mord:q0,mop:q0,mopen:q0,minner:q0},mopen:{},mclose:{mop:K,mbin:W0,mrel:q0,minner:K},mpunct:{mord:K,mop:K,mrel:q0,mopen:K,mclose:K,mpunct:K,minner:K},minner:{mord:K,mop:K,mbin:W0,mrel:q0,mopen:K,mpunct:K,minner:K}},C1={mord:{mop:K},mop:{mord:K,mop:K},mbin:{},mrel:{},mopen:{},mclose:{mop:K},mpunct:{},minner:{mop:K}},jr={},de={},pe={};function C(r){for(var{type:e,names:t,htmlBuilder:a,mathmlBuilder:n}=r,s=0;s{var D=q.classes[0],B=T.classes[0];D==="mbin"&&_1.has(B)?q.classes[0]="mord":B==="mbin"&&B1.has(D)&&(T.classes[0]="mord")},{node:b},x,y),kt(s,(T,q)=>{var D,B,O=At(q),$=At(T),E=O&&$?T.hasClass("mtight")?(D=C1[O])==null?void 0:D[$]:(B=D1[O])==null?void 0:B[$]:null;if(E)return Wr(E,d)},{node:b},x,y),s},kt=function(e,t,a,n,s){n&&e.push(n);for(var l=0;lx=>{e.splice(b+1,0,x),l++})(l)}n&&e.pop()},Kr=function(e){return e instanceof ie||e instanceof Re||e instanceof se&&e.hasClass("enclosing")?e:null},zt=function(e,t){var a=Kr(e);if(a){var n=a.children;if(n.length){if(t==="right")return zt(n[n.length-1],"right");if(t==="left")return zt(n[0],"left")}}return e},At=function(e,t){if(!e)return null;t&&(e=zt(e,t));var a=e.classes[0];return I1[a]||null},fe=function(e,t){var a=["nulldelimiter"].concat(e.baseSizingClasses());return k(t.concat(a))},X=function(e,t,a){if(!e)return k();if(de[e.type]){var n=de[e.type](e,t);if(a&&t.size!==a.size){n=k(t.sizingClasses(a),[n],t);var s=t.sizeMultiplier/a.sizeMultiplier;n.height*=s,n.depth*=s}return n}else throw new z("Got group of unknown type: '"+e.type+"'")};function Te(r,e){var t=k(["base"],r,e),a=k(["strut"]);return a.style.height=M(t.height+t.depth),t.depth&&(a.style.verticalAlign=M(-t.depth)),t.children.unshift(a),t}function Mt(r,e){var t=null;r.length===1&&r[0].type==="tag"&&(t=r[0].tag,r=r[0].body);var a=i0(r,e,"root"),n;a.length===2&&a[1].hasClass("tag")&&(n=a.pop());for(var s=[],l=[],c=0;c0&&(s.push(Te(l,e)),l=[]),s.push(a[c]));l.length>0&&s.push(Te(l,e));var d;t?(d=Te(i0(t,e,!0),e),d.classes=["tag"],s.push(d)):n&&s.push(n);var v=k(["katex-html"],s);if(v.setAttribute("aria-hidden","true"),d){var b=d.children[0];b.style.height=M(v.height+v.depth),v.depth&&(b.style.verticalAlign=M(-v.depth))}return v}function Jr(r){return new ie(r)}class A{constructor(e,t,a){this.type=void 0,this.attributes=void 0,this.children=void 0,this.classes=void 0,this.type=e,this.attributes={},this.children=t||[],this.classes=a||[]}setAttribute(e,t){this.attributes[e]=t}getAttribute(e){return this.attributes[e]}toNode(){var e=document.createElementNS("http://www.w3.org/1998/Math/MathML",this.type);for(var t in this.attributes)Object.prototype.hasOwnProperty.call(this.attributes,t)&&e.setAttribute(t,this.attributes[t]);this.classes.length>0&&(e.className=L0(this.classes));for(var a=0;a0&&(e+=' class ="'+s0(L0(this.classes))+'"'),e+=">";for(var a=0;a",e}toText(){return this.children.map(e=>e.toText()).join("")}}class r0{constructor(e){this.text=void 0,this.text=e}toNode(){return document.createTextNode(this.text)}toMarkup(){return s0(this.toText())}toText(){return this.text}}class Qr{constructor(e){this.width=void 0,this.character=void 0,this.width=e,e>=.05555&&e<=.05556?this.character=" ":e>=.1666&&e<=.1667?this.character=" ":e>=.2222&&e<=.2223?this.character=" ":e>=.2777&&e<=.2778?this.character="  ":e>=-.05556&&e<=-.05555?this.character=" ⁣":e>=-.1667&&e<=-.1666?this.character=" ⁣":e>=-.2223&&e<=-.2222?this.character=" ⁣":e>=-.2778&&e<=-.2777?this.character=" ⁣":this.character=null}toNode(){if(this.character)return document.createTextNode(this.character);var e=document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");return e.setAttribute("width",M(this.width)),e}toMarkup(){return this.character?""+this.character+"":''}toText(){return this.character?this.character:" "}}var O1=new Set(["\\imath","\\jmath"]),$1=new Set(["mrow","mtable"]),y0=function(e,t,a){return Z[t][e]&&Z[t][e].replace&&e.charCodeAt(0)!==55349&&!(Vr.hasOwnProperty(e)&&a&&(a.fontFamily&&a.fontFamily.slice(4,6)==="tt"||a.font&&a.font.slice(4,6)==="tt"))&&(e=Z[t][e].replace),new r0(e)},Nt=function(e){return e.length===1?e[0]:new A("mrow",e)},R1={mathit:"italic",boldsymbol:r=>r.type==="textord"?"bold":"bold-italic",mathbf:"bold",mathbb:"double-struck",mathsfit:"sans-serif-italic",mathfrak:"fraktur",mathscr:"script",mathcal:"script",mathsf:"sans-serif",mathtt:"monospace"},Ft=(r,e)=>{if(r.mode==="text"){if(e.fontFamily==="texttt")return"monospace";if(e.fontFamily==="textsf")return e.fontShape==="textit"&&e.fontWeight==="textbf"?"sans-serif-bold-italic":e.fontShape==="textit"?"sans-serif-italic":e.fontWeight==="textbf"?"bold-sans-serif":"sans-serif";if(e.fontShape==="textit"&&e.fontWeight==="textbf")return"bold-italic";if(e.fontShape==="textit")return"italic";if(e.fontWeight==="textbf")return"bold"}var t=e.font;if(!t||t==="mathnormal")return null;var a=r.mode,n=R1[t];if(n)return typeof n=="function"?n(r):n;var s=r.text;if(O1.has(s))return null;if(Z[a][s]){var l=Z[a][s].replace;l&&(s=l)}var c=St[t].fontName;return Ot(s,c,a)?St[t].variant:null};function rt(r){if(!r)return!1;if(r.type==="mi"&&r.children.length===1){var e=r.children[0];return e instanceof r0&&e.text==="."}else if(r.type==="mo"&&r.children.length===1&&r.getAttribute("separator")==="true"&&r.getAttribute("lspace")==="0em"&&r.getAttribute("rspace")==="0em"){var t=r.children[0];return t instanceof r0&&t.text===","}else return!1}var g0=function(e,t,a){if(e.length===1){var n=Y(e[0],t);return a&&n instanceof A&&n.type==="mo"&&(n.setAttribute("lspace","0em"),n.setAttribute("rspace","0em")),[n]}for(var s=[],l,c=0;c=1&&(l.type==="mn"||rt(l))){var d=m.children[0];d instanceof A&&d.type==="mn"&&(d.children=[...l.children,...d.children],s.pop())}else if(l.type==="mi"&&l.children.length===1){var v=l.children[0];if(v instanceof r0&&v.text==="̸"&&(m.type==="mo"||m.type==="mi"||m.type==="mn")){var b=m.children[0];b instanceof r0&&b.text.length>0&&(b.text=b.text.slice(0,1)+"̸"+b.text.slice(1),s.pop())}}}s.push(m),l=m}return s},U0=function(e,t,a){return Nt(g0(e,t,a))},Y=function(e,t){if(!e)return new A("mrow");if(pe[e.type])return pe[e.type](e,t);throw new z("Got group of unknown type: '"+e.type+"'")};function fr(r,e,t,a,n){var s=g0(r,t),l;s.length===1&&s[0]instanceof A&&$1.has(s[0].type)?l=s[0]:l=new A("mrow",s);var c=new A("annotation",[new r0(e)]);c.setAttribute("encoding","application/x-tex");var m=new A("semantics",[l,c]),d=new A("math",[m]);d.setAttribute("xmlns","http://www.w3.org/1998/Math/MathML"),a&&d.setAttribute("display","block");var v=n?"katex":"katex-mathml";return k([v],[d])}var N1=[[1,1,1],[2,1,1],[3,1,1],[4,2,1],[5,2,1],[6,3,1],[7,4,2],[8,6,3],[9,7,6],[10,8,7],[11,10,9]],vr=[.5,.6,.7,.8,.9,1,1.2,1.44,1.728,2.074,2.488],gr=function(e,t){return t.size<2?e:N1[e-1][t.size-1]};class D0{constructor(e){this.style=void 0,this.color=void 0,this.size=void 0,this.textSize=void 0,this.phantom=void 0,this.font=void 0,this.fontFamily=void 0,this.fontWeight=void 0,this.fontShape=void 0,this.sizeMultiplier=void 0,this.maxSize=void 0,this.minRuleThickness=void 0,this._fontMetrics=void 0,this.style=e.style,this.color=e.color,this.size=e.size||D0.BASESIZE,this.textSize=e.textSize||this.size,this.phantom=!!e.phantom,this.font=e.font||"",this.fontFamily=e.fontFamily||"",this.fontWeight=e.fontWeight||"",this.fontShape=e.fontShape||"",this.sizeMultiplier=vr[this.size-1],this.maxSize=e.maxSize,this.minRuleThickness=e.minRuleThickness,this._fontMetrics=void 0}extend(e){var t={style:this.style,size:this.size,textSize:this.textSize,color:this.color,phantom:this.phantom,font:this.font,fontFamily:this.fontFamily,fontWeight:this.fontWeight,fontShape:this.fontShape,maxSize:this.maxSize,minRuleThickness:this.minRuleThickness};return Object.assign(t,e),new D0(t)}havingStyle(e){return this.style===e?this:this.extend({style:e,size:gr(this.textSize,e)})}havingCrampedStyle(){return this.havingStyle(this.style.cramp())}havingSize(e){return this.size===e&&this.textSize===e?this:this.extend({style:this.style.text(),size:e,textSize:e,sizeMultiplier:vr[e-1]})}havingBaseStyle(e){e=e||this.style.text();var t=gr(D0.BASESIZE,e);return this.size===t&&this.textSize===D0.BASESIZE&&this.style===e?this:this.extend({style:e,size:t})}havingBaseSizing(){var e;switch(this.style.id){case 4:case 5:e=3;break;case 6:case 7:e=1;break;default:e=6}return this.extend({style:this.style.text(),size:e})}withColor(e){return this.extend({color:e})}withPhantom(){return this.extend({phantom:!0})}withFont(e){return this.extend({font:e})}withTextFontFamily(e){return this.extend({fontFamily:e,font:""})}withTextFontWeight(e){return this.extend({fontWeight:e,font:""})}withTextFontShape(e){return this.extend({fontShape:e,font:""})}sizingClasses(e){return e.size!==this.size?["sizing","reset-size"+e.size,"size"+this.size]:[]}baseSizingClasses(){return this.size!==D0.BASESIZE?["sizing","reset-size"+this.size,"size"+D0.BASESIZE]:[]}fontMetrics(){return this._fontMetrics||(this._fontMetrics=w1(this.size)),this._fontMetrics}getColor(){return this.phantom?"transparent":this.color}}D0.BASESIZE=6;var ea=function(e){return new D0({style:e.displayMode?N.DISPLAY:N.TEXT,maxSize:e.maxSize,minRuleThickness:e.minRuleThickness})},ta=function(e,t){if(t.displayMode){var a=["katex-display"];t.leqno&&a.push("leqno"),t.fleqn&&a.push("fleqn"),e=k(a,[e])}return e},F1=function(e,t,a){var n=ea(a),s;if(a.output==="mathml")return fr(e,t,n,a.displayMode,!0);if(a.output==="html"){var l=Mt(e,n);s=k(["katex"],[l])}else{var c=fr(e,t,n,a.displayMode,!1),m=Mt(e,n);s=k(["katex"],[c,m])}return ta(s,a)},H1=function(e,t,a){var n=ea(a),s=Mt(e,n),l=k(["katex"],[s]);return ta(l,a)},L1={widehat:"^",widecheck:"ˇ",widetilde:"~",utilde:"~",overleftarrow:"←",underleftarrow:"←",xleftarrow:"←",overrightarrow:"→",underrightarrow:"→",xrightarrow:"→",underbrace:"⏟",overbrace:"⏞",underbracket:"⎵",overbracket:"⎴",overgroup:"⏠",undergroup:"⏡",overleftrightarrow:"↔",underleftrightarrow:"↔",xleftrightarrow:"↔",Overrightarrow:"⇒",xRightarrow:"⇒",overleftharpoon:"↼",xleftharpoonup:"↼",overrightharpoon:"⇀",xrightharpoonup:"⇀",xLeftarrow:"⇐",xLeftrightarrow:"⇔",xhookleftarrow:"↩",xhookrightarrow:"↪",xmapsto:"↦",xrightharpoondown:"⇁",xleftharpoondown:"↽",xrightleftharpoons:"⇌",xleftrightharpoons:"⇋",xtwoheadleftarrow:"↞",xtwoheadrightarrow:"↠",xlongequal:"=",xtofrom:"⇄",xrightleftarrows:"⇄",xrightequilibrium:"⇌",xleftequilibrium:"⇋","\\cdrightarrow":"→","\\cdleftarrow":"←","\\cdlongequal":"="},He=function(e){var t=new A("mo",[new r0(L1[e.replace(/^\\/,"")])]);return t.setAttribute("stretchy","true"),t},G1={overrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],overleftarrow:[["leftarrow"],.888,522,"xMinYMin"],underrightarrow:[["rightarrow"],.888,522,"xMaxYMin"],underleftarrow:[["leftarrow"],.888,522,"xMinYMin"],xrightarrow:[["rightarrow"],1.469,522,"xMaxYMin"],"\\cdrightarrow":[["rightarrow"],3,522,"xMaxYMin"],xleftarrow:[["leftarrow"],1.469,522,"xMinYMin"],"\\cdleftarrow":[["leftarrow"],3,522,"xMinYMin"],Overrightarrow:[["doublerightarrow"],.888,560,"xMaxYMin"],xRightarrow:[["doublerightarrow"],1.526,560,"xMaxYMin"],xLeftarrow:[["doubleleftarrow"],1.526,560,"xMinYMin"],overleftharpoon:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoonup:[["leftharpoon"],.888,522,"xMinYMin"],xleftharpoondown:[["leftharpoondown"],.888,522,"xMinYMin"],overrightharpoon:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoonup:[["rightharpoon"],.888,522,"xMaxYMin"],xrightharpoondown:[["rightharpoondown"],.888,522,"xMaxYMin"],xlongequal:[["longequal"],.888,334,"xMinYMin"],"\\cdlongequal":[["longequal"],3,334,"xMinYMin"],xtwoheadleftarrow:[["twoheadleftarrow"],.888,334,"xMinYMin"],xtwoheadrightarrow:[["twoheadrightarrow"],.888,334,"xMaxYMin"],overleftrightarrow:[["leftarrow","rightarrow"],.888,522],overbrace:[["leftbrace","midbrace","rightbrace"],1.6,548],underbrace:[["leftbraceunder","midbraceunder","rightbraceunder"],1.6,548],underleftrightarrow:[["leftarrow","rightarrow"],.888,522],xleftrightarrow:[["leftarrow","rightarrow"],1.75,522],xLeftrightarrow:[["doubleleftarrow","doublerightarrow"],1.75,560],xrightleftharpoons:[["leftharpoondownplus","rightharpoonplus"],1.75,716],xleftrightharpoons:[["leftharpoonplus","rightharpoondownplus"],1.75,716],xhookleftarrow:[["leftarrow","righthook"],1.08,522],xhookrightarrow:[["lefthook","rightarrow"],1.08,522],overlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],underlinesegment:[["leftlinesegment","rightlinesegment"],.888,522],overbracket:[["leftbracketover","rightbracketover"],1.6,440],underbracket:[["leftbracketunder","rightbracketunder"],1.6,410],overgroup:[["leftgroup","rightgroup"],.888,342],undergroup:[["leftgroupunder","rightgroupunder"],.888,342],xmapsto:[["leftmapsto","rightarrow"],1.5,522],xtofrom:[["leftToFrom","rightToFrom"],1.75,528],xrightleftarrows:[["baraboveleftarrow","rightarrowabovebar"],1.75,901],xrightequilibrium:[["baraboveshortleftharpoon","rightharpoonaboveshortbar"],1.75,716],xleftequilibrium:[["shortbaraboveleftharpoon","shortrightharpoonabovebar"],1.75,716]},P1=new Set(["widehat","widecheck","widetilde","utilde"]),Le=function(e,t){function a(){var c=4e5,m=e.label.slice(1);if(P1.has(m)&&"base"in e){var d=e.base.type==="ordgroup"?e.base.body.length:1,v,b,x;if(d>5)m==="widehat"||m==="widecheck"?(v=420,c=2364,x=.42,b=m+"4"):(v=312,c=2340,x=.34,b="tilde4");else{var y=[1,1,2,2,3,3][d];m==="widehat"||m==="widecheck"?(c=[0,1062,2364,2364,2364][y],v=[0,239,300,360,420][y],x=[0,.24,.3,.3,.36,.42][y],b=m+y):(c=[0,600,1033,2339,2340][y],v=[0,260,286,306,312][y],x=[0,.26,.286,.3,.306,.34][y],b="tilde"+y)}var T=new G0(b),q=new B0([T],{width:"100%",height:M(x),viewBox:"0 0 "+c+" "+v,preserveAspectRatio:"none"});return{span:P0([],[q],t),minWidth:0,height:x}}else{var D=[],B=G1[m];if(!B)throw new Error('No SVG data for "'+m+'".');var[O,$,E]=B,F=E/1e3,H=O.length,G,P;if(H===1){if(B.length!==4)throw new Error('Expected 4-tuple for single-path SVG data "'+m+'".');G=["hide-tail"],P=[B[3]]}else if(H===2)G=["halfarrow-left","halfarrow-right"],P=["xMinYMin","xMaxYMin"];else if(H===3)G=["brace-left","brace-center","brace-right"],P=["xMinYMin","xMidYMin","xMaxYMin"];else throw new Error(`Correct katexImagesData or update code here to support + `+H+" children.");for(var U=0;U0&&(n.style.minWidth=M(s)),n},U1=function(e,t,a,n,s){var l,c=e.height+e.depth+a+n;if(/fbox|color|angl/.test(t)){if(l=k(["stretchy",t],[],s),t==="fbox"){var m=s.color&&s.getColor();m&&(l.style.borderColor=m)}}else{var d=[];/^[bx]cancel$/.test(t)&&d.push(new vt({x1:"0",y1:"0",x2:"100%",y2:"100%","stroke-width":"0.046em"})),/^x?cancel$/.test(t)&&d.push(new vt({x1:"0",y1:"100%",x2:"100%",y2:"0","stroke-width":"0.046em"}));var v=new B0(d,{width:"100%",height:M(c)});l=P0([],[v],s)}return l.height=c,l.style.height=M(c),l},V1={bin:1,close:1,inner:1,open:1,punct:1,rel:1},X1={"accent-token":1,mathord:1,"op-token":1,spacing:1,textord:1};function W1(r){return r in V1}function L(r,e){if(!r||r.type!==e)throw new Error("Expected node of type "+e+", but got "+(r?"node of type "+r.type:String(r)));return r}function Ge(r){var e=Pe(r);if(!e)throw new Error("Expected node of symbol group type, but got "+(r?"node of type "+r.type:String(r)));return e}function Pe(r){return r&&(r.type==="atom"||X1.hasOwnProperty(r.type))?r:null}var ra=r=>{if(r instanceof f0)return r;if(y1(r)&&r.children.length===1)return ra(r.children[0])},aa=(r,e)=>{var t,a,n;r&&r.type==="supsub"?(a=L(r.base,"accent"),t=a.base,r.base=t,n=b1(X(r,e)),r.base=a):(a=L(r,"accent"),t=a.base);var s=X(t,e.havingCrampedStyle()),l=a.isShifty&&_0(t),c=0;if(l){var m,d;c=(m=(d=ra(s))==null?void 0:d.skew)!=null?m:0}var v=a.label==="\\c",b=v?s.height+s.depth:Math.min(s.height,e.fontMetrics().xHeight),x;if(a.isStretchy)x=Le(a,e),x=V({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"elem",elem:x,wrapperClasses:["svg-align"],wrapperStyle:c>0?{width:"calc(100% - "+M(2*c)+")",marginLeft:M(2*c)}:void 0}]});else{var y,T;a.label==="\\vec"?(y=Zr("vec",e),T=Yr.vec[1]):(y=Fe({type:"textord",mode:a.mode,text:a.label},e),y=g1(y),y.italic=0,T=y.width,v&&(b+=y.depth)),x=k(["accent-body"],[y]);var q=a.label==="\\textcircled";q&&(x.classes.push("accent-full"),b=s.height);var D=c;q||(D-=T/2),x.style.left=M(D),a.label==="\\textcircled"&&(x.style.top=".2em"),x=V({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"kern",size:-b},{type:"elem",elem:x}]})}var B=k(["mord","accent"],[x],e);return n?(n.children[0]=B,n.height=Math.max(B.height,n.height),n.classes[0]="mord",n):B},Y1=(r,e)=>{var t=r.isStretchy?He(r.label):new A("mo",[y0(r.label,r.mode)]),a=new A("mover",[Y(r.base,e),t]);return a.setAttribute("accent","true"),a},Z1=new RegExp(["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring"].map(r=>"\\"+r).join("|"));C({type:"accent",names:["\\acute","\\grave","\\ddot","\\tilde","\\bar","\\breve","\\check","\\hat","\\vec","\\dot","\\mathring","\\widecheck","\\widehat","\\widetilde","\\overrightarrow","\\overleftarrow","\\Overrightarrow","\\overleftrightarrow","\\overgroup","\\overlinesegment","\\overleftharpoon","\\overrightharpoon"],numArgs:1,handler:(r,e)=>{var t=$e(e[0]),a=!Z1.test(r.funcName),n=!a||r.funcName==="\\widehat"||r.funcName==="\\widetilde"||r.funcName==="\\widecheck";return{type:"accent",mode:r.parser.mode,label:r.funcName,isStretchy:a,isShifty:n,base:t}},htmlBuilder:aa,mathmlBuilder:Y1});C({type:"accent",names:["\\'","\\`","\\^","\\~","\\=","\\u","\\.",'\\"',"\\c","\\r","\\H","\\v","\\textcircled"],numArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["primitive"],handler:(r,e)=>{var t=e[0],a=r.parser.mode;return a==="math"&&(r.parser.settings.reportNonstrict("mathVsTextAccents","LaTeX's accent "+r.funcName+" works only in text mode"),a="text"),{type:"accent",mode:a,label:r.funcName,isStretchy:!1,isShifty:!0,base:t}}});C({type:"accentUnder",names:["\\underleftarrow","\\underrightarrow","\\underleftrightarrow","\\undergroup","\\underlinesegment","\\utilde"],numArgs:1,handler:(r,e)=>{var{parser:t,funcName:a}=r,n=e[0];return{type:"accentUnder",mode:t.mode,label:a,base:n}},htmlBuilder:(r,e)=>{var t=X(r.base,e),a=Le(r,e),n=r.label==="\\utilde"?.12:0,s=V({positionType:"top",positionData:t.height,children:[{type:"elem",elem:a,wrapperClasses:["svg-align"]},{type:"kern",size:n},{type:"elem",elem:t}]});return k(["mord","accentunder"],[s],e)},mathmlBuilder:(r,e)=>{var t=He(r.label),a=new A("munder",[Y(r.base,e),t]);return a.setAttribute("accentunder","true"),a}});var qe=r=>{var e=new A("mpadded",r?[r]:[]);return e.setAttribute("width","+0.6em"),e.setAttribute("lspace","0.3em"),e};C({type:"xArrow",names:["\\xleftarrow","\\xrightarrow","\\xLeftarrow","\\xRightarrow","\\xleftrightarrow","\\xLeftrightarrow","\\xhookleftarrow","\\xhookrightarrow","\\xmapsto","\\xrightharpoondown","\\xrightharpoonup","\\xleftharpoondown","\\xleftharpoonup","\\xrightleftharpoons","\\xleftrightharpoons","\\xlongequal","\\xtwoheadrightarrow","\\xtwoheadleftarrow","\\xtofrom","\\xrightleftarrows","\\xrightequilibrium","\\xleftequilibrium","\\\\cdrightarrow","\\\\cdleftarrow","\\\\cdlongequal"],numArgs:1,numOptionalArgs:1,handler(r,e,t){var{parser:a,funcName:n}=r;return{type:"xArrow",mode:a.mode,label:n,body:e[0],below:t[0]}},htmlBuilder(r,e){var t=e.style,a=e.havingStyle(t.sup()),n=ne(X(r.body,a,e),e),s=r.label.slice(0,2)==="\\x"?"x":"cd";n.classes.push(s+"-arrow-pad");var l;r.below&&(a=e.havingStyle(t.sub()),l=ne(X(r.below,a,e),e),l.classes.push(s+"-arrow-pad"));var c=Le(r,e),m=-e.fontMetrics().axisHeight+.5*c.height,d=-e.fontMetrics().axisHeight-.5*c.height-.111;(n.depth>.25||r.label==="\\xleftequilibrium")&&(d-=n.depth);var v;if(l){var b=-e.fontMetrics().axisHeight+l.height+.5*c.height+.111;v=V({positionType:"individualShift",children:[{type:"elem",elem:n,shift:d},{type:"elem",elem:c,shift:m,wrapperClasses:["svg-align"]},{type:"elem",elem:l,shift:b}]})}else v=V({positionType:"individualShift",children:[{type:"elem",elem:n,shift:d},{type:"elem",elem:c,shift:m,wrapperClasses:["svg-align"]}]});return k(["mrel","x-arrow"],[v],e)},mathmlBuilder(r,e){var t=He(r.label);t.setAttribute("minsize",r.label.charAt(0)==="x"?"1.75em":"3.0em");var a;if(r.body){var n=qe(Y(r.body,e));if(r.below){var s=qe(Y(r.below,e));a=new A("munderover",[t,s,n])}else a=new A("mover",[t,n])}else if(r.below){var l=qe(Y(r.below,e));a=new A("munder",[t,l])}else a=qe(),a=new A("mover",[t,a]);return a}});function j1(r,e){var t=i0(r.body,e,!0);return k([r.mclass],t,e)}function K1(r,e){var t,a=g0(r.body,e);return r.mclass==="minner"?t=new A("mpadded",a):r.mclass==="mord"?r.isCharacterBox?(t=a[0],t.type="mi"):t=new A("mi",a):(r.isCharacterBox?(t=a[0],t.type="mo"):t=new A("mo",a),r.mclass==="mbin"?(t.attributes.lspace="0.22em",t.attributes.rspace="0.22em"):r.mclass==="mpunct"?(t.attributes.lspace="0em",t.attributes.rspace="0.17em"):(r.mclass==="mopen"||r.mclass==="mclose")&&(t.attributes.lspace="0em",t.attributes.rspace="0em")),t}C({type:"mclass",names:["\\mathord","\\mathbin","\\mathrel","\\mathopen","\\mathclose","\\mathpunct","\\mathinner"],numArgs:1,primitive:!0,handler(r,e){var{parser:t,funcName:a}=r,n=e[0];return{type:"mclass",mode:t.mode,mclass:"m"+a.slice(5),body:t0(n),isCharacterBox:_0(n)}},htmlBuilder:j1,mathmlBuilder:K1});var Ue=r=>{var e=r.type==="ordgroup"&&r.body.length?r.body[0]:r;return e.type==="atom"&&(e.family==="bin"||e.family==="rel")?"m"+e.family:"mord"};C({type:"mclass",names:["\\@binrel"],numArgs:2,handler(r,e){var{parser:t}=r;return{type:"mclass",mode:t.mode,mclass:Ue(e[0]),body:t0(e[1]),isCharacterBox:_0(e[1])}}});C({type:"mclass",names:["\\stackrel","\\overset","\\underset"],numArgs:2,handler(r,e){var{parser:t,funcName:a}=r,n=e[1],s=e[0],l;a!=="\\stackrel"?l=Ue(n):l="mrel";var c={type:"op",mode:n.mode,limits:!0,alwaysHandleSupSub:!0,parentIsSupSub:!1,symbol:!1,suppressBaseShift:a!=="\\stackrel",body:t0(n)},m=a==="\\underset"?{type:"supsub",mode:s.mode,base:c,sub:s}:{type:"supsub",mode:s.mode,base:c,sup:s};return{type:"mclass",mode:t.mode,mclass:l,body:[m],isCharacterBox:_0(m)}}});C({type:"pmb",names:["\\pmb"],numArgs:1,allowedInText:!0,handler(r,e){var{parser:t}=r;return{type:"pmb",mode:t.mode,mclass:Ue(e[0]),body:t0(e[0])}},htmlBuilder(r,e){var t=i0(r.body,e,!0),a=k([r.mclass],t,e);return a.style.textShadow="0.02em 0.01em 0.04px",a},mathmlBuilder(r,e){var t=g0(r.body,e),a=new A("mstyle",t);return a.setAttribute("style","text-shadow: 0.02em 0.01em 0.04px"),a}});var J1={">":"\\\\cdrightarrow","<":"\\\\cdleftarrow","=":"\\\\cdlongequal",A:"\\uparrow",V:"\\downarrow","|":"\\Vert",".":"no arrow"},br=()=>({type:"styling",body:[],mode:"math",style:"display",resetFont:!0}),yr=r=>r.type==="textord"&&r.text==="@",Q1=(r,e)=>(r.type==="mathord"||r.type==="atom")&&r.text===e;function en(r,e,t){var a=J1[r];switch(a){case"\\\\cdrightarrow":case"\\\\cdleftarrow":return t.callFunction(a,[e[0]],[e[1]]);case"\\uparrow":case"\\downarrow":{var n=t.callFunction("\\\\cdleft",[e[0]],[]),s={type:"atom",text:a,mode:"math",family:"rel"},l=t.callFunction("\\Big",[s],[]),c=t.callFunction("\\\\cdright",[e[1]],[]),m={type:"ordgroup",mode:"math",body:[n,l,c]};return t.callFunction("\\\\cdparent",[m],[])}case"\\\\cdlongequal":return t.callFunction("\\\\cdlongequal",[],[]);case"\\Vert":{var d={type:"textord",text:"\\Vert",mode:"math"};return t.callFunction("\\Big",[d],[])}default:return{type:"textord",text:" ",mode:"math"}}}function tn(r){var e=[];for(r.gullet.beginGroup(),r.gullet.macros.set("\\cr","\\\\\\relax"),r.gullet.beginGroup();;){e.push(r.parseExpression(!1,"\\\\")),r.gullet.endGroup(),r.gullet.beginGroup();var t=r.fetch().text;if(t==="&"||t==="\\\\")r.consume();else if(t==="\\end"){e[e.length-1].length===0&&e.pop();break}else throw new z("Expected \\\\ or \\cr or \\end",r.nextToken)}for(var a=[],n=[a],s=0;sAV".includes(d))for(var b=0;b<2;b++){for(var x=!0,y=m+1;yAV=|." after @',l[m]);var T=en(d,v,r),q={type:"styling",body:[T],mode:"math",style:"display",resetFont:!0};a.push(q),c=br()}s%2===0?a.push(c):a.shift(),a=[],n.push(a)}r.gullet.endGroup(),r.gullet.endGroup();var D=new Array(n[0].length).fill({type:"align",align:"c",pregap:.25,postgap:.25});return{type:"array",mode:"math",body:n,arraystretch:1,addJot:!0,rowGaps:[null],cols:D,colSeparationType:"CD",hLinesBeforeRow:new Array(n.length+1).fill([])}}C({type:"cdlabel",names:["\\\\cdleft","\\\\cdright"],numArgs:1,handler(r,e){var{parser:t,funcName:a}=r;return{type:"cdlabel",mode:t.mode,side:a.slice(4),label:e[0]}},htmlBuilder(r,e){var t=e.havingStyle(e.style.sup()),a=ne(X(r.label,t,e),e);return a.classes.push("cd-label-"+r.side),a.style.bottom=M(.8-a.depth),a.height=0,a.depth=0,a},mathmlBuilder(r,e){var t=new A("mrow",[Y(r.label,e)]);return t=new A("mpadded",[t]),t.setAttribute("width","0"),r.side==="left"&&t.setAttribute("lspace","-1width"),t.setAttribute("voffset","0.7em"),t=new A("mstyle",[t]),t.setAttribute("displaystyle","false"),t.setAttribute("scriptlevel","1"),t}});C({type:"cdlabelparent",names:["\\\\cdparent"],numArgs:1,handler(r,e){var{parser:t}=r;return{type:"cdlabelparent",mode:t.mode,fragment:e[0]}},htmlBuilder(r,e){var t=ne(X(r.fragment,e),e);return t.classes.push("cd-vert-arrow"),t},mathmlBuilder(r,e){return new A("mrow",[Y(r.fragment,e)])}});C({type:"textord",names:["\\@char"],numArgs:1,allowedInText:!0,handler(r,e){for(var{parser:t}=r,a=L(e[0],"ordgroup"),n=a.body,s="",l=0;l=1114111)throw new z("\\@char with invalid code point "+s);return m<=65535?d=String.fromCharCode(m):(m-=65536,d=String.fromCharCode((m>>10)+55296,(m&1023)+56320)),{type:"textord",mode:t.mode,text:d}}});var rn=(r,e)=>{var t=i0(r.body,e.withColor(r.color),!1);return I0(t)},an=(r,e)=>{var t=g0(r.body,e.withColor(r.color)),a=new A("mstyle",t);return a.setAttribute("mathcolor",r.color),a};C({type:"color",names:["\\textcolor"],numArgs:2,allowedInText:!0,argTypes:["color","original"],handler(r,e){var{parser:t}=r,a=L(e[0],"color-token").color,n=e[1];return{type:"color",mode:t.mode,color:a,body:t0(n)}},htmlBuilder:rn,mathmlBuilder:an});C({type:"color",names:["\\color"],numArgs:1,allowedInText:!0,argTypes:["color"],handler(r,e){var{parser:t,breakOnTokenText:a}=r,n=L(e[0],"color-token").color;t.gullet.macros.set("\\current@color",n);var s=t.parseExpression(!0,a);return{type:"color",mode:t.mode,color:n,body:s}}});C({type:"cr",names:["\\\\"],numArgs:0,numOptionalArgs:0,allowedInText:!0,handler(r,e,t){var{parser:a}=r,n=a.gullet.future().text==="["?a.parseSizeGroup(!0):null,s=!a.settings.displayMode||!a.settings.useStrictBehavior("newLineInDisplayMode","In LaTeX, \\\\ or \\newline does nothing in display mode");return{type:"cr",mode:a.mode,newLine:s,size:n&&L(n,"size").value}},htmlBuilder(r,e){var t=k(["mspace"],[],e);return r.newLine&&(t.classes.push("newline"),r.size&&(t.style.marginTop=M(J(r.size,e)))),t},mathmlBuilder(r,e){var t=new A("mspace");return r.newLine&&(t.setAttribute("linebreak","newline"),r.size&&t.setAttribute("height",M(J(r.size,e)))),t}});var Tt={"\\global":"\\global","\\long":"\\\\globallong","\\\\globallong":"\\\\globallong","\\def":"\\gdef","\\gdef":"\\gdef","\\edef":"\\xdef","\\xdef":"\\xdef","\\let":"\\\\globallet","\\futurelet":"\\\\globalfuture"},na=r=>{var e=r.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(e))throw new z("Expected a control sequence",r);return e},nn=r=>{var e=r.gullet.popToken();return e.text==="="&&(e=r.gullet.popToken(),e.text===" "&&(e=r.gullet.popToken())),e},ia=(r,e,t,a)=>{var n=r.gullet.macros.get(t.text);n==null&&(t.noexpand=!0,n={tokens:[t],numArgs:0,unexpandable:!r.gullet.isExpandable(t.text)}),r.gullet.macros.set(e,n,a)};C({type:"internal",names:["\\global","\\long","\\\\globallong"],numArgs:0,allowedInText:!0,handler(r){var{parser:e,funcName:t}=r;e.consumeSpaces();var a=e.fetch();if(Tt[a.text])return(t==="\\global"||t==="\\\\globallong")&&(a.text=Tt[a.text]),L(e.parseFunction(),"internal");throw new z("Invalid token after macro prefix",a)}});C({type:"internal",names:["\\def","\\gdef","\\edef","\\xdef"],numArgs:0,allowedInText:!0,primitive:!0,handler(r){var{parser:e,funcName:t}=r,a=e.gullet.popToken(),n=a.text;if(/^(?:[\\{}$&#^_]|EOF)$/.test(n))throw new z("Expected a control sequence",a);for(var s=0,l,c=[[]];e.gullet.future().text!=="{";)if(a=e.gullet.popToken(),a.text==="#"){if(e.gullet.future().text==="{"){l=e.gullet.future(),c[s].push("{");break}if(a=e.gullet.popToken(),!/^[1-9]$/.test(a.text))throw new z('Invalid argument number "'+a.text+'"');if(parseInt(a.text)!==s+1)throw new z('Argument number "'+a.text+'" out of order');s++,c.push([])}else{if(a.text==="EOF")throw new z("Expected a macro definition");c[s].push(a.text)}var{tokens:m}=e.gullet.consumeArg();return l&&m.unshift(l),(t==="\\edef"||t==="\\xdef")&&(m=e.gullet.expandTokens(m),m.reverse()),e.gullet.macros.set(n,{tokens:m,numArgs:s,delimiters:c},t===Tt[t]),{type:"internal",mode:e.mode}}});C({type:"internal",names:["\\let","\\\\globallet"],numArgs:0,allowedInText:!0,primitive:!0,handler(r){var{parser:e,funcName:t}=r,a=na(e.gullet.popToken());e.gullet.consumeSpaces();var n=nn(e);return ia(e,a,n,t==="\\\\globallet"),{type:"internal",mode:e.mode}}});C({type:"internal",names:["\\futurelet","\\\\globalfuture"],numArgs:0,allowedInText:!0,primitive:!0,handler(r){var{parser:e,funcName:t}=r,a=na(e.gullet.popToken()),n=e.gullet.popToken(),s=e.gullet.popToken();return ia(e,a,s,t==="\\\\globalfuture"),e.gullet.pushToken(s),e.gullet.pushToken(n),{type:"internal",mode:e.mode}}});var ce=function(e,t,a){var n=Z.math[e]&&Z.math[e].replace,s=Ot(n||e,t,a);if(!s)throw new Error("Unsupported symbol "+e+" and font size "+t+".");return s},Ht=function(e,t,a,n){var s=a.havingBaseStyle(t),l=k(n.concat(s.sizingClasses(a)),[e],a),c=s.sizeMultiplier/a.sizeMultiplier;return l.height*=c,l.depth*=c,l.maxFontSize=s.sizeMultiplier,l},sa=function(e,t,a){var n=t.havingBaseStyle(a),s=(1-t.sizeMultiplier/n.sizeMultiplier)*t.fontMetrics().axisHeight;e.classes.push("delimcenter"),e.style.top=M(s),e.height-=s,e.depth+=s},sn=function(e,t,a,n,s,l){var c=l0(e,"Main-Regular",s,n),m=Ht(c,t,n,l);return sa(m,n,t),m},on=function(e,t,a,n){return l0(e,"Size"+t+"-Regular",a,n)},oa=function(e,t,a,n,s,l){var c=on(e,t,s,n),m=Ht(k(["delimsizing","size"+t],[c],n),N.TEXT,n,l);return a&&sa(m,n,N.TEXT),m},at=function(e,t,a){var n;t==="Size1-Regular"?n="delim-size1":n="delim-size4";var s=k(["delimsizinginner",n],[k([],[l0(e,t,a)])]);return{type:"elem",elem:s}},nt=function(e,t,a){var n=z0["Size4-Regular"][e.charCodeAt(0)]?z0["Size4-Regular"][e.charCodeAt(0)][4]:z0["Size1-Regular"][e.charCodeAt(0)][4],s=new G0("inner",c1(e,Math.round(1e3*t))),l=new B0([s],{width:M(n),height:M(t),style:"width:"+M(n),viewBox:"0 0 "+1e3*n+" "+Math.round(1e3*t),preserveAspectRatio:"xMinYMin"}),c=P0([],[l],a);return c.height=t,c.style.height=M(t),c.style.width=M(n),{type:"elem",elem:c}},qt=.008,De={type:"kern",size:-1*qt},ln=new Set(["|","\\lvert","\\rvert","\\vert"]),un=new Set(["\\|","\\lVert","\\rVert","\\Vert"]),la=function(e,t,a,n,s,l){var c,m,d,v,b="",x=0;c=d=v=e,m=null;var y="Size1-Regular";e==="\\uparrow"?d=v="⏐":e==="\\Uparrow"?d=v="‖":e==="\\downarrow"?c=d="⏐":e==="\\Downarrow"?c=d="‖":e==="\\updownarrow"?(c="\\uparrow",d="⏐",v="\\downarrow"):e==="\\Updownarrow"?(c="\\Uparrow",d="‖",v="\\Downarrow"):ln.has(e)?(d="∣",b="vert",x=333):un.has(e)?(d="∥",b="doublevert",x=556):e==="["||e==="\\lbrack"?(c="⎡",d="⎢",v="⎣",y="Size4-Regular",b="lbrack",x=667):e==="]"||e==="\\rbrack"?(c="⎤",d="⎥",v="⎦",y="Size4-Regular",b="rbrack",x=667):e==="\\lfloor"||e==="⌊"?(d=c="⎢",v="⎣",y="Size4-Regular",b="lfloor",x=667):e==="\\lceil"||e==="⌈"?(c="⎡",d=v="⎢",y="Size4-Regular",b="lceil",x=667):e==="\\rfloor"||e==="⌋"?(d=c="⎥",v="⎦",y="Size4-Regular",b="rfloor",x=667):e==="\\rceil"||e==="⌉"?(c="⎤",d=v="⎥",y="Size4-Regular",b="rceil",x=667):e==="("||e==="\\lparen"?(c="⎛",d="⎜",v="⎝",y="Size4-Regular",b="lparen",x=875):e===")"||e==="\\rparen"?(c="⎞",d="⎟",v="⎠",y="Size4-Regular",b="rparen",x=875):e==="\\{"||e==="\\lbrace"?(c="⎧",m="⎨",v="⎩",d="⎪",y="Size4-Regular"):e==="\\}"||e==="\\rbrace"?(c="⎫",m="⎬",v="⎭",d="⎪",y="Size4-Regular"):e==="\\lgroup"||e==="⟮"?(c="⎧",v="⎩",d="⎪",y="Size4-Regular"):e==="\\rgroup"||e==="⟯"?(c="⎫",v="⎭",d="⎪",y="Size4-Regular"):e==="\\lmoustache"||e==="⎰"?(c="⎧",v="⎭",d="⎪",y="Size4-Regular"):(e==="\\rmoustache"||e==="⎱")&&(c="⎫",v="⎩",d="⎪",y="Size4-Regular");var T=ce(c,y,s),q=T.height+T.depth,D=ce(d,y,s),B=D.height+D.depth,O=ce(v,y,s),$=O.height+O.depth,E=0,F=1;if(m!==null){var H=ce(m,y,s);E=H.height+H.depth,F=2}var G=q+$+E,P=Math.max(0,Math.ceil((t-G)/(F*B))),U=G+P*F*B,h0=n.fontMetrics().axisHeight;a&&(h0*=n.sizeMultiplier);var d0=U/2-h0,e0=[];if(b.length>0){var le=U-q-$,S0=Math.round(U*1e3),x0=h1(b,Math.round(le*1e3)),O0=new G0(b,x0),j0=M(x/1e3),K0=M(S0/1e3),Ze=new B0([O0],{width:j0,height:K0,viewBox:"0 0 "+x+" "+S0}),$0=P0([],[Ze],n);$0.height=S0/1e3,$0.style.width=j0,$0.style.height=K0,e0.push({type:"elem",elem:$0})}else{if(e0.push(at(v,y,s)),e0.push(De),m===null){var R0=U-q-$+2*qt;e0.push(nt(d,R0,n))}else{var ue=(U-q-$-E)/2+2*qt;e0.push(nt(d,ue,n)),e0.push(De),e0.push(at(m,y,s)),e0.push(De),e0.push(nt(d,ue,n))}e0.push(De),e0.push(at(c,y,s))}var w0=n.havingBaseStyle(N.TEXT),ge=V({positionType:"bottom",positionData:d0,children:e0});return Ht(k(["delimsizing","mult"],[ge],w0),N.TEXT,n,l)},it=80,st=.08,ot=function(e,t,a,n,s){var l=u1(e,n,a),c=new G0(e,l),m=new B0([c],{width:"400em",height:M(t),viewBox:"0 0 400000 "+a,preserveAspectRatio:"xMinYMin slice"});return P0(["hide-tail"],[m],s)},cn=function(e,t){var a=t.havingBaseSizing(),n=da("\\surd",e*a.sizeMultiplier,ma,a),s=a.sizeMultiplier,l=Math.max(0,t.minRuleThickness-t.fontMetrics().sqrtRuleThickness),c,m,d,v,b;return n.type==="small"?(v=1e3+1e3*l+it,e<1?s=1:e<1.4&&(s=.7),m=(1+l+st)/s,d=(1+l)/s,c=ot("sqrtMain",m,v,l,t),c.style.minWidth="0.853em",b=.833/s):n.type==="large"?(v=(1e3+it)*he[n.size],d=(he[n.size]+l)/s,m=(he[n.size]+l+st)/s,c=ot("sqrtSize"+n.size,m,v,l,t),c.style.minWidth="1.02em",b=1/s):(m=e+l+st,d=e+l,v=Math.floor(1e3*e+l)+it,c=ot("sqrtTall",m,v,l,t),c.style.minWidth="0.742em",b=1.056),c.height=d,c.style.height=M(m),{span:c,advanceWidth:b,ruleWidth:(t.fontMetrics().sqrtRuleThickness+l)*s}},ua=new Set(["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","\\surd"]),hn=new Set(["\\uparrow","\\downarrow","\\updownarrow","\\Uparrow","\\Downarrow","\\Updownarrow","|","\\|","\\vert","\\Vert","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱"]),ca=new Set(["<",">","\\langle","\\rangle","/","\\backslash","\\lt","\\gt"]),he=[0,1.2,1.8,2.4,3],ha=function(e,t,a,n,s){if(e==="<"||e==="\\lt"||e==="⟨"?e="\\langle":(e===">"||e==="\\gt"||e==="⟩")&&(e="\\rangle"),ua.has(e)||ca.has(e))return oa(e,t,!1,a,n,s);if(hn.has(e))return la(e,he[t],!1,a,n,s);throw new z("Illegal delimiter: '"+e+"'")},mn=[{type:"small",style:N.SCRIPTSCRIPT},{type:"small",style:N.SCRIPT},{type:"small",style:N.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4}],dn=[{type:"small",style:N.SCRIPTSCRIPT},{type:"small",style:N.SCRIPT},{type:"small",style:N.TEXT},{type:"stack"}],ma=[{type:"small",style:N.SCRIPTSCRIPT},{type:"small",style:N.SCRIPT},{type:"small",style:N.TEXT},{type:"large",size:1},{type:"large",size:2},{type:"large",size:3},{type:"large",size:4},{type:"stack"}],pn=function(e){if(e.type==="small")return"Main-Regular";if(e.type==="large")return"Size"+e.size+"-Regular";if(e.type==="stack")return"Size4-Regular";var t=e.type;throw new Error("Add support for delim type '"+t+"' here.")},da=function(e,t,a,n){for(var s=Math.min(2,3-n.style.size),l=s;lt)return c}return a[a.length-1]},Dt=function(e,t,a,n,s,l){e==="<"||e==="\\lt"||e==="⟨"?e="\\langle":(e===">"||e==="\\gt"||e==="⟩")&&(e="\\rangle");var c;ca.has(e)?c=mn:ua.has(e)?c=ma:c=dn;var m=da(e,t,c,n);return m.type==="small"?sn(e,m.style,a,n,s,l):m.type==="large"?oa(e,m.size,a,n,s,l):la(e,t,a,n,s,l)},lt=function(e,t,a,n,s,l){var c=n.fontMetrics().axisHeight*n.sizeMultiplier,m=901,d=5/n.fontMetrics().ptPerEm,v=Math.max(t-c,a+c),b=Math.max(v/500*m,2*v-d);return Dt(e,b,!0,n,s,l)},xr={"\\bigl":{mclass:"mopen",size:1},"\\Bigl":{mclass:"mopen",size:2},"\\biggl":{mclass:"mopen",size:3},"\\Biggl":{mclass:"mopen",size:4},"\\bigr":{mclass:"mclose",size:1},"\\Bigr":{mclass:"mclose",size:2},"\\biggr":{mclass:"mclose",size:3},"\\Biggr":{mclass:"mclose",size:4},"\\bigm":{mclass:"mrel",size:1},"\\Bigm":{mclass:"mrel",size:2},"\\biggm":{mclass:"mrel",size:3},"\\Biggm":{mclass:"mrel",size:4},"\\big":{mclass:"mord",size:1},"\\Big":{mclass:"mord",size:2},"\\bigg":{mclass:"mord",size:3},"\\Bigg":{mclass:"mord",size:4}},fn=new Set(["(","\\lparen",")","\\rparen","[","\\lbrack","]","\\rbrack","\\{","\\lbrace","\\}","\\rbrace","\\lfloor","\\rfloor","⌊","⌋","\\lceil","\\rceil","⌈","⌉","<",">","\\langle","⟨","\\rangle","⟩","\\lt","\\gt","\\lvert","\\rvert","\\lVert","\\rVert","\\lgroup","\\rgroup","⟮","⟯","\\lmoustache","\\rmoustache","⎰","⎱","/","\\backslash","|","\\vert","\\|","\\Vert","\\uparrow","\\Uparrow","\\downarrow","\\Downarrow","\\updownarrow","\\Updownarrow","."]);function wr(r){return"isMiddle"in r}function Ve(r,e){var t=Pe(r);if(t&&fn.has(t.text))return t;throw t?new z("Invalid delimiter '"+t.text+"' after '"+e.funcName+"'",r):new z("Invalid delimiter type '"+r.type+"'",r)}C({type:"delimsizing",names:["\\bigl","\\Bigl","\\biggl","\\Biggl","\\bigr","\\Bigr","\\biggr","\\Biggr","\\bigm","\\Bigm","\\biggm","\\Biggm","\\big","\\Big","\\bigg","\\Bigg"],numArgs:1,argTypes:["primitive"],handler:(r,e)=>{var t=Ve(e[0],r);return{type:"delimsizing",mode:r.parser.mode,size:xr[r.funcName].size,mclass:xr[r.funcName].mclass,delim:t.text}},htmlBuilder:(r,e)=>r.delim==="."?k([r.mclass]):ha(r.delim,r.size,e,r.mode,[r.mclass]),mathmlBuilder:r=>{var e=[];r.delim!=="."&&e.push(y0(r.delim,r.mode));var t=new A("mo",e);r.mclass==="mopen"||r.mclass==="mclose"?t.setAttribute("fence","true"):t.setAttribute("fence","false"),t.setAttribute("stretchy","true");var a=M(he[r.size]);return t.setAttribute("minsize",a),t.setAttribute("maxsize",a),t}});function Sr(r){if(!r.body)throw new Error("Bug: The leftright ParseNode wasn't fully parsed.")}C({type:"leftright-right",names:["\\right"],numArgs:1,primitive:!0,handler:(r,e)=>{var t=r.parser.gullet.macros.get("\\current@color");if(t&&typeof t!="string")throw new z("\\current@color set to non-string in \\right");return{type:"leftright-right",mode:r.parser.mode,delim:Ve(e[0],r).text,color:t}}});C({type:"leftright",names:["\\left"],numArgs:1,primitive:!0,handler:(r,e)=>{var t=Ve(e[0],r),a=r.parser;++a.leftrightDepth;var n=a.parseExpression(!1);--a.leftrightDepth,a.expect("\\right",!1);var s=L(a.parseFunction(),"leftright-right");return{type:"leftright",mode:a.mode,body:n,left:t.text,right:s.delim,rightColor:s.color}},htmlBuilder:(r,e)=>{Sr(r);for(var t=i0(r.body,e,!0,["mopen","mclose"]),a=0,n=0,s=!1,l=0;l{Sr(r);var t=g0(r.body,e);if(r.left!=="."){var a=new A("mo",[y0(r.left,r.mode)]);a.setAttribute("fence","true"),t.unshift(a)}if(r.right!=="."){var n=new A("mo",[y0(r.right,r.mode)]);n.setAttribute("fence","true"),r.rightColor&&n.setAttribute("mathcolor",r.rightColor),t.push(n)}return Nt(t)}});C({type:"middle",names:["\\middle"],numArgs:1,primitive:!0,handler:(r,e)=>{var t=Ve(e[0],r);if(!r.parser.leftrightDepth)throw new z("\\middle without preceding \\left",t);return{type:"middle",mode:r.parser.mode,delim:t.text}},htmlBuilder:(r,e)=>{var t;return r.delim==="."?t=fe(e,[]):(t=ha(r.delim,1,e,r.mode,[]),t.isMiddle={delim:r.delim,options:e}),t},mathmlBuilder:(r,e)=>{var t=r.delim==="\\vert"||r.delim==="|"?y0("|","text"):y0(r.delim,r.mode),a=new A("mo",[t]);return a.setAttribute("fence","true"),a.setAttribute("lspace","0.05em"),a.setAttribute("rspace","0.05em"),a}});var vn=(r,e)=>{var t=ne(X(r.body,e),e),a=r.label.slice(1),n=e.sizeMultiplier,s,l,c=_0(r.body);if(a==="sout")s=k(["stretchy","sout"]),s.height=e.fontMetrics().defaultRuleThickness/n,l=-.5*e.fontMetrics().xHeight;else if(a==="phase"){var m=J({number:.6,unit:"pt"},e),d=J({number:.35,unit:"ex"},e),v=e.havingBaseSizing();n=n/v.sizeMultiplier;var b=t.height+t.depth+m+d;t.style.paddingLeft=M(b/2+m);var x=Math.floor(1e3*b*n),y=o1(x),T=new B0([new G0("phase",y)],{width:"400em",height:M(x/1e3),viewBox:"0 0 400000 "+x,preserveAspectRatio:"xMinYMin slice"});s=P0(["hide-tail"],[T],e),s.style.height=M(b),l=t.depth+m+d}else{/cancel/.test(a)?c||t.classes.push("cancel-pad"):a==="angl"?t.classes.push("anglpad"):t.classes.push("boxpad");var q,D,B=0;/box/.test(a)?(B=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness),q=e.fontMetrics().fboxsep+(a==="colorbox"?0:B),D=q):a==="angl"?(B=Math.max(e.fontMetrics().defaultRuleThickness,e.minRuleThickness),q=4*B,D=Math.max(0,.25-t.depth)):(q=c?.2:0,D=q),s=U1(t,a,q,D,e),/fbox|boxed|fcolorbox/.test(a)?(s.style.borderStyle="solid",s.style.borderWidth=M(B)):a==="angl"&&B!==.049&&(s.style.borderTopWidth=M(B),s.style.borderRightWidth=M(B)),l=t.depth+D,r.backgroundColor&&(s.style.backgroundColor=r.backgroundColor,r.borderColor&&(s.style.borderColor=r.borderColor))}var O;if(r.backgroundColor)O=V({positionType:"individualShift",children:[{type:"elem",elem:s,shift:l},{type:"elem",elem:t,shift:0}]});else{var $=/cancel|phase/.test(a)?["svg-align"]:[];O=V({positionType:"individualShift",children:[{type:"elem",elem:t,shift:0},{type:"elem",elem:s,shift:l,wrapperClasses:$}]})}return/cancel/.test(a)&&(O.height=t.height,O.depth=t.depth),/cancel/.test(a)&&!c?k(["mord","cancel-lap"],[O],e):k(["mord"],[O],e)},gn=(r,e)=>{var t,a=new A(r.label.includes("colorbox")?"mpadded":"menclose",[Y(r.body,e)]);switch(r.label){case"\\cancel":a.setAttribute("notation","updiagonalstrike");break;case"\\bcancel":a.setAttribute("notation","downdiagonalstrike");break;case"\\phase":a.setAttribute("notation","phasorangle");break;case"\\sout":a.setAttribute("notation","horizontalstrike");break;case"\\fbox":a.setAttribute("notation","box");break;case"\\angl":a.setAttribute("notation","actuarial");break;case"\\fcolorbox":case"\\colorbox":if(t=e.fontMetrics().fboxsep*e.fontMetrics().ptPerEm,a.setAttribute("width","+"+2*t+"pt"),a.setAttribute("height","+"+2*t+"pt"),a.setAttribute("lspace",t+"pt"),a.setAttribute("voffset",t+"pt"),r.label==="\\fcolorbox"){var n=Math.max(e.fontMetrics().fboxrule,e.minRuleThickness);a.setAttribute("style","border: "+M(n)+" solid "+r.borderColor)}break;case"\\xcancel":a.setAttribute("notation","updiagonalstrike downdiagonalstrike");break}return r.backgroundColor&&a.setAttribute("mathbackground",r.backgroundColor),a};C({type:"enclose",names:["\\colorbox"],numArgs:2,allowedInText:!0,argTypes:["color","hbox"],handler(r,e,t){var{parser:a,funcName:n}=r,s=L(e[0],"color-token").color,l=e[1];return{type:"enclose",mode:a.mode,label:n,backgroundColor:s,body:l}},htmlBuilder:vn,mathmlBuilder:gn});C({type:"enclose",names:["\\fcolorbox"],numArgs:3,allowedInText:!0,argTypes:["color","color","hbox"],handler(r,e,t){var{parser:a,funcName:n}=r,s=L(e[0],"color-token").color,l=L(e[1],"color-token").color,c=e[2];return{type:"enclose",mode:a.mode,label:n,backgroundColor:l,borderColor:s,body:c}}});C({type:"enclose",names:["\\fbox"],numArgs:1,argTypes:["hbox"],allowedInText:!0,handler(r,e){var{parser:t}=r;return{type:"enclose",mode:t.mode,label:"\\fbox",body:e[0]}}});C({type:"enclose",names:["\\cancel","\\bcancel","\\xcancel","\\phase"],numArgs:1,handler(r,e){var{parser:t,funcName:a}=r,n=e[0];return{type:"enclose",mode:t.mode,label:a,body:n}}});C({type:"enclose",names:["\\sout"],numArgs:1,allowedInText:!0,handler(r,e){var{parser:t,funcName:a}=r;t.mode==="math"&&t.settings.reportNonstrict("mathVsSout","LaTeX's \\sout works only in text mode");var n=e[0];return{type:"enclose",mode:t.mode,label:a,body:n}}});C({type:"enclose",names:["\\angl"],numArgs:1,argTypes:["hbox"],allowedInText:!1,handler(r,e){var{parser:t}=r;return{type:"enclose",mode:t.mode,label:"\\angl",body:e[0]}}});var pa={};function A0(r){for(var{type:e,names:t,props:a,handler:n,htmlBuilder:s,mathmlBuilder:l}=r,c={type:e,numArgs:a.numArgs||0,allowedInText:!1,numOptionalArgs:0,handler:n},m=0;m{var e=r.parser.settings;if(!e.displayMode)throw new z("{"+r.envName+"} can be used only in display mode.")},bn=new Set(["gather","gather*"]);function Lt(r){if(!r.includes("ed"))return!r.includes("*")}function V0(r,e,t){var{hskipBeforeAndAfter:a,addJot:n,cols:s,arraystretch:l,colSeparationType:c,autoTag:m,singleRow:d,emptySingleRow:v,maxNumCols:b,leqno:x}=e;if(r.gullet.beginGroup(),d||r.gullet.macros.set("\\cr","\\\\\\relax"),!l){var y=r.gullet.expandMacroAsText("\\arraystretch");if(y==null)l=1;else if(l=parseFloat(y),!l||l<0)throw new z("Invalid \\arraystretch: "+y)}r.gullet.beginGroup();var T=[],q=[T],D=[],B=[],O=m!=null?[]:void 0;function $(){m&&r.gullet.macros.set("\\@eqnsw","1",!0)}function E(){O&&(r.gullet.macros.get("\\df@tag")?(O.push(r.subparse([new p0("\\df@tag")])),r.gullet.macros.set("\\df@tag",void 0,!0)):O.push(!!m&&r.gullet.macros.get("\\@eqnsw")==="1"))}for($(),B.push(kr(r));;){var F=r.parseExpression(!1,d?"\\end":"\\\\");r.gullet.endGroup(),r.gullet.beginGroup();var H={type:"ordgroup",mode:r.mode,body:F};t&&(H={type:"styling",mode:r.mode,style:t,resetFont:!0,body:[H]}),T.push(H);var G=r.fetch().text;if(G==="&"){if(b&&T.length===b){if(d||c)throw new z("Too many tab characters: &",r.nextToken);r.settings.reportNonstrict("textEnv","Too few columns specified in the {array} column argument.")}r.consume()}else if(G==="\\end"){E(),T.length===1&&H.type==="styling"&&H.body.length===1&&H.body[0].type==="ordgroup"&&H.body[0].body.length===0&&(q.length>1||!v)&&q.pop(),B.length0&&($+=.25),d.push({pos:$,isDashed:we[Se]})}for(E(l[0]),a=0;a0&&(d0+=O,Gwe))for(a=0;a=c)){var Q0=void 0;if(n>0||e.hskipBeforeAndAfter){var Zt,jt;Q0=(Zt=(jt=w0)==null?void 0:jt.pregap)!=null?Zt:x,Q0!==0&&(x0=k(["arraycolsep"],[]),x0.style.width=M(Q0),S0.push(x0))}var Kt=[];for(a=0;a0){for(var $a=ae("hline",t,v),Ra=ae("hdashline",t,v),je=[{type:"elem",elem:xe,shift:0}];d.length>0;){var er=d.pop(),tr=er.pos-e0;er.isDashed?je.push({type:"elem",elem:Ra,shift:tr}):je.push({type:"elem",elem:$a,shift:tr})}xe=V({positionType:"individualShift",children:je})}if(j0.length===0)return k(["mord"],[xe],t);var Na=V({positionType:"individualShift",children:j0}),Fa=k(["tag"],[Na],t);return I0([xe,Fa])},yn={c:"center ",l:"left ",r:"right "},T0=function(e,t){for(var a=[],n=new A("mtd",[],["mtr-glue"]),s=new A("mtd",[],["mml-eqn-num"]),l=0;l0){var T=e.cols,q="",D=!1,B=0,O=T.length;T[0].type==="separator"&&(x+="top ",B=1),T[T.length-1].type==="separator"&&(x+="bottom ",O-=1);for(var $=B;$0?"left ":"",x+=U[U.length-1].length>0?"right ":"";for(var h0=1;h00&&x&&(q=1),a[y]={type:"align",align:T,pregap:q,postgap:0}}return s.colSeparationType=x?"align":"alignat",s};A0({type:"array",names:["array","darray"],props:{numArgs:1},handler(r,e){var t=Pe(e[0]),a=t?[e[0]]:L(e[0],"ordgroup").body,n=a.map(function(l){var c=Ge(l),m=c.text;if("lcr".includes(m))return{type:"align",align:m};if(m==="|")return{type:"separator",separator:"|"};if(m===":")return{type:"separator",separator:":"};throw new z("Unknown column alignment: "+m,l)}),s={cols:n,hskipBeforeAndAfter:!0,maxNumCols:n.length};return V0(r.parser,s,Gt(r.envName))},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["matrix","pmatrix","bmatrix","Bmatrix","vmatrix","Vmatrix","matrix*","pmatrix*","bmatrix*","Bmatrix*","vmatrix*","Vmatrix*"],props:{numArgs:0},handler(r){var e={matrix:null,pmatrix:["(",")"],bmatrix:["[","]"],Bmatrix:["\\{","\\}"],vmatrix:["|","|"],Vmatrix:["\\Vert","\\Vert"]}[r.envName.replace("*","")],t="c",a={hskipBeforeAndAfter:!1,cols:[{type:"align",align:t}]};if(r.envName.charAt(r.envName.length-1)==="*"){var n=r.parser;if(n.consumeSpaces(),n.fetch().text==="["){if(n.consume(),n.consumeSpaces(),t=n.fetch().text,!"lcr".includes(t))throw new z("Expected l or c or r",n.nextToken);n.consume(),n.consumeSpaces(),n.expect("]"),n.consume(),a.cols=[{type:"align",align:t}]}}var s=V0(r.parser,a,Gt(r.envName)),l=Math.max(0,...s.body.map(c=>c.length));return s.cols=new Array(l).fill({type:"align",align:t}),e?{type:"leftright",mode:r.mode,body:[s],left:e[0],right:e[1],rightColor:void 0}:s},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["smallmatrix"],props:{numArgs:0},handler(r){var e={arraystretch:.5},t=V0(r.parser,e,"script");return t.colSeparationType="small",t},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["subarray"],props:{numArgs:1},handler(r,e){var t=Pe(e[0]),a=t?[e[0]]:L(e[0],"ordgroup").body,n=a.map(function(c){var m=Ge(c),d=m.text;if("lc".includes(d))return{type:"align",align:d};throw new z("Unknown column alignment: "+d,c)});if(n.length>1)throw new z("{subarray} can contain only one column");var s={cols:n,hskipBeforeAndAfter:!1,arraystretch:.5},l=V0(r.parser,s,"script");if(l.body.length>0&&l.body[0].length>1)throw new z("{subarray} can contain only one column");return l},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["cases","dcases","rcases","drcases"],props:{numArgs:0},handler(r){var e={arraystretch:1.2,cols:[{type:"align",align:"l",pregap:0,postgap:1},{type:"align",align:"l",pregap:0,postgap:0}]},t=V0(r.parser,e,Gt(r.envName));return{type:"leftright",mode:r.mode,body:[t],left:r.envName.includes("r")?".":"\\{",right:r.envName.includes("r")?"\\}":".",rightColor:void 0}},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["align","align*","aligned","split"],props:{numArgs:0},handler:va,htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["gathered","gather","gather*"],props:{numArgs:0},handler(r){bn.has(r.envName)&&Xe(r);var e={cols:[{type:"align",align:"c"}],addJot:!0,colSeparationType:"gather",autoTag:Lt(r.envName),emptySingleRow:!0,leqno:r.parser.settings.leqno};return V0(r.parser,e,"display")},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["alignat","alignat*","alignedat"],props:{numArgs:1},handler:va,htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["equation","equation*"],props:{numArgs:0},handler(r){Xe(r);var e={autoTag:Lt(r.envName),emptySingleRow:!0,singleRow:!0,maxNumCols:1,leqno:r.parser.settings.leqno};return V0(r.parser,e,"display")},htmlBuilder:M0,mathmlBuilder:T0});A0({type:"array",names:["CD"],props:{numArgs:0},handler(r){return Xe(r),tn(r.parser)},htmlBuilder:M0,mathmlBuilder:T0});h("\\nonumber","\\gdef\\@eqnsw{0}");h("\\notag","\\nonumber");C({type:"text",names:["\\hline","\\hdashline"],numArgs:0,allowedInText:!0,allowedInMath:!0,handler(r,e){throw new z(r.funcName+" valid only within array environment")}});var zr=pa;C({type:"environment",names:["\\begin","\\end"],numArgs:1,argTypes:["text"],handler(r,e){var{parser:t,funcName:a}=r,n=e[0];if(n.type!=="ordgroup")throw new z("Invalid environment name",n);for(var s="",l=0;l{var t=r.font,a=e.withFont(t);return X(r.body,a)},wn=(r,e)=>{var t=r.font,a=e.withFont(t);return Y(r.body,a)},Ar={"\\Bbb":"\\mathbb","\\bold":"\\mathbf","\\frak":"\\mathfrak"};C({type:"font",names:["\\mathrm","\\mathit","\\mathbf","\\mathnormal","\\mathsfit","\\mathbb","\\mathcal","\\mathfrak","\\mathscr","\\mathsf","\\mathtt","\\Bbb","\\bold","\\frak"],numArgs:1,allowedInArgument:!0,handler:(r,e)=>{var{parser:t,funcName:a}=r,n=$e(e[0]),s=a in Ar?Ar[a]:a;return{type:"font",mode:t.mode,font:s.slice(1),body:n}},htmlBuilder:xn,mathmlBuilder:wn});C({type:"mclass",names:["\\boldsymbol","\\bm"],numArgs:1,handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"mclass",mode:t.mode,mclass:Ue(a),body:[{type:"font",mode:t.mode,font:"boldsymbol",body:a}],isCharacterBox:_0(a)}}});C({type:"font",names:["\\rm","\\sf","\\tt","\\bf","\\it","\\cal"],numArgs:0,allowedInText:!0,handler:(r,e)=>{var{parser:t,funcName:a,breakOnTokenText:n}=r,{mode:s}=t,l=t.parseExpression(!0,n);return{type:"font",mode:s,font:"math"+a.slice(1),body:{type:"ordgroup",mode:t.mode,body:l}}}});var Sn=(r,e)=>{var t=e.style,a=t.fracNum(),n=t.fracDen(),s;s=e.havingStyle(a);var l=X(r.numer,s,e);if(r.continued){var c=8.5/e.fontMetrics().ptPerEm,m=3.5/e.fontMetrics().ptPerEm;l.height=l.height0?T=3*x:T=7*x,q=e.fontMetrics().denom1):(b>0?(y=e.fontMetrics().num2,T=x):(y=e.fontMetrics().num3,T=3*x),q=e.fontMetrics().denom2);var D;if(v){var O=e.fontMetrics().axisHeight;y-l.depth-(O+.5*b){var t=new A("mfrac",[Y(r.numer,e),Y(r.denom,e)]);if(!r.hasBarLine)t.setAttribute("linethickness","0px");else if(r.barSize){var a=J(r.barSize,e);t.setAttribute("linethickness",M(a))}if(r.leftDelim!=null||r.rightDelim!=null){var n=[];if(r.leftDelim!=null){var s=new A("mo",[new r0(r.leftDelim.replace("\\",""))]);s.setAttribute("fence","true"),n.push(s)}if(n.push(t),r.rightDelim!=null){var l=new A("mo",[new r0(r.rightDelim.replace("\\",""))]);l.setAttribute("fence","true"),n.push(l)}return Nt(n)}return t},ga=(r,e)=>{if(!e)return r;var t={type:"styling",mode:r.mode,style:e,body:[r]};return t};C({type:"genfrac",names:["\\cfrac","\\dfrac","\\frac","\\tfrac","\\dbinom","\\binom","\\tbinom","\\\\atopfrac","\\\\bracefrac","\\\\brackfrac"],numArgs:2,allowedInArgument:!0,handler:(r,e)=>{var{parser:t,funcName:a}=r,n=e[0],s=e[1],l,c=null,m=null;switch(a){case"\\cfrac":case"\\dfrac":case"\\frac":case"\\tfrac":l=!0;break;case"\\\\atopfrac":l=!1;break;case"\\dbinom":case"\\binom":case"\\tbinom":l=!1,c="(",m=")";break;case"\\\\bracefrac":l=!1,c="\\{",m="\\}";break;case"\\\\brackfrac":l=!1,c="[",m="]";break;default:throw new Error("Unrecognized genfrac command")}var d=a==="\\cfrac",v=null;return d||a.startsWith("\\d")?v="display":a.startsWith("\\t")&&(v="text"),ga({type:"genfrac",mode:t.mode,numer:n,denom:s,continued:d,hasBarLine:l,leftDelim:c,rightDelim:m,barSize:null},v)},htmlBuilder:Sn,mathmlBuilder:kn});C({type:"infix",names:["\\over","\\choose","\\atop","\\brace","\\brack"],numArgs:0,infix:!0,handler(r){var{parser:e,funcName:t,token:a}=r,n;switch(t){case"\\over":n="\\frac";break;case"\\choose":n="\\binom";break;case"\\atop":n="\\\\atopfrac";break;case"\\brace":n="\\\\bracefrac";break;case"\\brack":n="\\\\brackfrac";break;default:throw new Error("Unrecognized infix genfrac command")}return{type:"infix",mode:e.mode,replaceWith:n,token:a}}});var Mr=["display","text","script","scriptscript"],Tr=function(e){var t=null;return e.length>0&&(t=e,t=t==="."?null:t),t};C({type:"genfrac",names:["\\genfrac"],numArgs:6,allowedInArgument:!0,argTypes:["math","math","size","text","math","math"],handler(r,e){var{parser:t}=r,a=e[4],n=e[5],s=$e(e[0]),l=s.type==="atom"&&s.family==="open"?Tr(s.text):null,c=$e(e[1]),m=c.type==="atom"&&c.family==="close"?Tr(c.text):null,d=L(e[2],"size"),v,b=null;d.isBlank?v=!0:(b=d.value,v=b.number>0);var x=null,y=e[3];if(y.type==="ordgroup"){if(y.body.length>0){var T=L(y.body[0],"textord");x=Mr[Number(T.text)]}}else y=L(y,"textord"),x=Mr[Number(y.text)];return ga({type:"genfrac",mode:t.mode,numer:a,denom:n,continued:!1,hasBarLine:v,barSize:b,leftDelim:l,rightDelim:m},x)}});C({type:"infix",names:["\\above"],numArgs:1,argTypes:["size"],infix:!0,handler(r,e){var{parser:t,funcName:a,token:n}=r;return{type:"infix",mode:t.mode,replaceWith:"\\\\abovefrac",size:L(e[0],"size").value,token:n}}});C({type:"genfrac",names:["\\\\abovefrac"],numArgs:3,argTypes:["math","size","math"],handler:(r,e)=>{var{parser:t,funcName:a}=r,n=e[0],s=L(e[1],"infix").size;if(!s)throw new Error("\\\\abovefrac expected size, but got "+String(s));var l=e[2],c=s.number>0;return{type:"genfrac",mode:t.mode,numer:n,denom:l,continued:!1,hasBarLine:c,barSize:s,leftDelim:null,rightDelim:null}}});var ba=(r,e)=>{var t=e.style,a,n;r.type==="supsub"?(a=r.sup?X(r.sup,e.havingStyle(t.sup()),e):X(r.sub,e.havingStyle(t.sub()),e),n=L(r.base,"horizBrace")):n=L(r,"horizBrace");var s=X(n.base,e.havingBaseStyle(N.DISPLAY)),l=Le(n,e),c;if(n.isOver?c=V({positionType:"firstBaseline",children:[{type:"elem",elem:s},{type:"kern",size:.1},{type:"elem",elem:l,wrapperClasses:["svg-align"]}]}):c=V({positionType:"bottom",positionData:s.depth+.1+l.height,children:[{type:"elem",elem:l,wrapperClasses:["svg-align"]},{type:"kern",size:.1},{type:"elem",elem:s}]}),a){var m=k(["minner",n.isOver?"mover":"munder"],[c],e);n.isOver?c=V({positionType:"firstBaseline",children:[{type:"elem",elem:m},{type:"kern",size:.2},{type:"elem",elem:a}]}):c=V({positionType:"bottom",positionData:m.depth+.2+a.height+a.depth,children:[{type:"elem",elem:a},{type:"kern",size:.2},{type:"elem",elem:m}]})}return k(["minner",n.isOver?"mover":"munder"],[c],e)},zn=(r,e)=>{var t=He(r.label);return new A(r.isOver?"mover":"munder",[Y(r.base,e),t])};C({type:"horizBrace",names:["\\overbrace","\\underbrace","\\overbracket","\\underbracket"],numArgs:1,handler(r,e){var{parser:t,funcName:a}=r;return{type:"horizBrace",mode:t.mode,label:a,isOver:a.includes("\\over"),base:e[0]}},htmlBuilder:ba,mathmlBuilder:zn});C({type:"href",names:["\\href"],numArgs:2,argTypes:["url","original"],allowedInText:!0,handler:(r,e)=>{var{parser:t}=r,a=e[1],n=L(e[0],"url").url;return t.settings.isTrusted({command:"\\href",url:n})?{type:"href",mode:t.mode,href:n,body:t0(a)}:t.formatUnsupportedCmd("\\href")},htmlBuilder:(r,e)=>{var t=i0(r.body,e,!1);return T1(r.href,[],t,e)},mathmlBuilder:(r,e)=>{var t=U0(r.body,e);return t instanceof A||(t=new A("mrow",[t])),t.setAttribute("href",r.href),t}});C({type:"href",names:["\\url"],numArgs:1,argTypes:["url"],allowedInText:!0,handler:(r,e)=>{var{parser:t}=r,a=L(e[0],"url").url;if(!t.settings.isTrusted({command:"\\url",url:a}))return t.formatUnsupportedCmd("\\url");for(var n=[],s=0;s{var{parser:t,funcName:a,token:n}=r,s=L(e[0],"raw").string,l=e[1];t.settings.strict&&t.settings.reportNonstrict("htmlExtension","HTML extension is disabled on strict mode");var c,m={};switch(a){case"\\htmlClass":m.class=s,c={command:"\\htmlClass",class:s};break;case"\\htmlId":m.id=s,c={command:"\\htmlId",id:s};break;case"\\htmlStyle":m.style=s,c={command:"\\htmlStyle",style:s};break;case"\\htmlData":{for(var d=s.split(","),v=0;v{var t=i0(r.body,e,!1),a=["enclosing"];r.attributes.class&&a.push(...r.attributes.class.trim().split(/\s+/));var n=k(a,t,e);for(var s in r.attributes)s!=="class"&&r.attributes.hasOwnProperty(s)&&n.setAttribute(s,r.attributes[s]);return n},mathmlBuilder:(r,e)=>U0(r.body,e)});C({type:"htmlmathml",names:["\\html@mathml"],numArgs:2,allowedInArgument:!0,allowedInText:!0,handler:(r,e)=>{var{parser:t}=r;return{type:"htmlmathml",mode:t.mode,html:t0(e[0]),mathml:t0(e[1])}},htmlBuilder:(r,e)=>{var t=i0(r.html,e,!1);return I0(t)},mathmlBuilder:(r,e)=>U0(r.mathml,e)});var ut=function(e){if(/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(e))return{number:+e,unit:"bp"};var t=/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/.exec(e);if(!t)throw new z("Invalid size: '"+e+"' in \\includegraphics");var a={number:+(t[1]+t[2]),unit:t[3]};if(!Lr(a))throw new z("Invalid unit: '"+a.unit+"' in \\includegraphics.");return a};C({type:"includegraphics",names:["\\includegraphics"],numArgs:1,numOptionalArgs:1,argTypes:["raw","url"],allowedInText:!1,handler:(r,e,t)=>{var{parser:a}=r,n={number:0,unit:"em"},s={number:.9,unit:"em"},l={number:0,unit:"em"},c="";if(t[0])for(var m=L(t[0],"raw").string,d=m.split(","),v=0;v{var t=J(r.height,e),a=0;r.totalheight.number>0&&(a=J(r.totalheight,e)-t);var n=0;r.width.number>0&&(n=J(r.width,e));var s={height:M(t+a)};n>0&&(s.width=M(n)),a>0&&(s.verticalAlign=M(-a));var l=new f1(r.src,r.alt,s);return l.height=t,l.depth=a,l},mathmlBuilder:(r,e)=>{var t=new A("mglyph",[]);t.setAttribute("alt",r.alt);var a=J(r.height,e),n=0;if(r.totalheight.number>0&&(n=J(r.totalheight,e)-a,t.setAttribute("valign",M(-n))),t.setAttribute("height",M(a+n)),r.width.number>0){var s=J(r.width,e);t.setAttribute("width",M(s))}return t.setAttribute("src",r.src),t}});C({type:"kern",names:["\\kern","\\mkern","\\hskip","\\mskip"],numArgs:1,argTypes:["size"],primitive:!0,allowedInText:!0,handler(r,e){var{parser:t,funcName:a}=r,n=L(e[0],"size");if(t.settings.strict){var s=a[1]==="m",l=n.value.unit==="mu";s?(l||t.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" supports only mu units, "+("not "+n.value.unit+" units")),t.mode!=="math"&&t.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" works only in math mode")):l&&t.settings.reportNonstrict("mathVsTextUnits","LaTeX's "+a+" doesn't support mu units")}return{type:"kern",mode:t.mode,dimension:n.value}},htmlBuilder(r,e){return Wr(r.dimension,e)},mathmlBuilder(r,e){var t=J(r.dimension,e);return new Qr(t)}});C({type:"lap",names:["\\mathllap","\\mathrlap","\\mathclap"],numArgs:1,allowedInText:!0,handler:(r,e)=>{var{parser:t,funcName:a}=r,n=e[0];return{type:"lap",mode:t.mode,alignment:a.slice(5),body:n}},htmlBuilder:(r,e)=>{var t;r.alignment==="clap"?(t=k([],[X(r.body,e)]),t=k(["inner"],[t],e)):t=k(["inner"],[X(r.body,e)]);var a=k(["fix"],[]),n=k([r.alignment],[t,a],e),s=k(["strut"]);return s.style.height=M(n.height+n.depth),n.depth&&(s.style.verticalAlign=M(-n.depth)),n.children.unshift(s),n=k(["thinbox"],[n],e),k(["mord","vbox"],[n],e)},mathmlBuilder:(r,e)=>{var t=new A("mpadded",[Y(r.body,e)]);if(r.alignment!=="rlap"){var a=r.alignment==="llap"?"-1":"-0.5";t.setAttribute("lspace",a+"width")}return t.setAttribute("width","0px"),t}});C({type:"styling",names:["\\(","$"],numArgs:0,allowedInText:!0,allowedInMath:!1,handler(r,e){var{funcName:t,parser:a}=r,n=a.mode;a.switchMode("math");var s=t==="\\("?"\\)":"$",l=a.parseExpression(!1,s);return a.expect(s),a.switchMode(n),{type:"styling",mode:a.mode,style:"text",resetFont:!0,body:l}}});C({type:"text",names:["\\)","\\]"],numArgs:0,allowedInText:!0,allowedInMath:!1,handler(r,e){throw new z("Mismatched "+r.funcName)}});var qr=(r,e)=>{switch(e.style.size){case N.DISPLAY.size:return r.display;case N.TEXT.size:return r.text;case N.SCRIPT.size:return r.script;case N.SCRIPTSCRIPT.size:return r.scriptscript;default:return r.text}};C({type:"mathchoice",names:["\\mathchoice"],numArgs:4,primitive:!0,handler:(r,e)=>{var{parser:t}=r;return{type:"mathchoice",mode:t.mode,display:t0(e[0]),text:t0(e[1]),script:t0(e[2]),scriptscript:t0(e[3])}},htmlBuilder:(r,e)=>{var t=qr(r,e),a=i0(t,e,!1);return I0(a)},mathmlBuilder:(r,e)=>{var t=qr(r,e);return U0(t,e)}});var ya=(r,e,t,a,n,s,l)=>{r=k([],[r]);var c=t&&_0(t),m,d;if(e){var v=X(e,a.havingStyle(n.sup()),a);d={elem:v,kern:Math.max(a.fontMetrics().bigOpSpacing1,a.fontMetrics().bigOpSpacing3-v.depth)}}if(t){var b=X(t,a.havingStyle(n.sub()),a);m={elem:b,kern:Math.max(a.fontMetrics().bigOpSpacing2,a.fontMetrics().bigOpSpacing4-b.height)}}var x;if(d&&m){var y=a.fontMetrics().bigOpSpacing5+m.elem.height+m.elem.depth+m.kern+r.depth+l;x=V({positionType:"bottom",positionData:y,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:m.elem,marginLeft:M(-s)},{type:"kern",size:m.kern},{type:"elem",elem:r},{type:"kern",size:d.kern},{type:"elem",elem:d.elem,marginLeft:M(s)},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]})}else if(m){var T=r.height-l;x=V({positionType:"top",positionData:T,children:[{type:"kern",size:a.fontMetrics().bigOpSpacing5},{type:"elem",elem:m.elem,marginLeft:M(-s)},{type:"kern",size:m.kern},{type:"elem",elem:r}]})}else if(d){var q=r.depth+l;x=V({positionType:"bottom",positionData:q,children:[{type:"elem",elem:r},{type:"kern",size:d.kern},{type:"elem",elem:d.elem,marginLeft:M(s)},{type:"kern",size:a.fontMetrics().bigOpSpacing5}]})}else return r;var D=[x];if(m&&s!==0&&!c){var B=k(["mspace"],[],a);B.style.marginRight=M(s),D.unshift(B)}return k(["mop","op-limits"],D,a)},xa=new Set(["\\smallint"]),wa=(r,e)=>{var t,a,n=!1,s;r.type==="supsub"?(t=r.sup,a=r.sub,s=L(r.base,"op"),n=!0):s=L(r,"op");var l=e.style,c=!1;l.size===N.DISPLAY.size&&s.symbol&&!xa.has(s.name)&&(c=!0);var m,d;if(s.symbol){var v=c?"Size2-Regular":"Size1-Regular",b="";if((s.name==="\\oiint"||s.name==="\\oiiint")&&(b=s.name.slice(1),s.name=b==="oiint"?"\\iint":"\\iiint"),m=l0(s.name,v,"math",e,["mop","op-symbol",c?"large-op":"small-op"]),d=m.italic,b.length>0){var x=Zr(b+"Size"+(c?"2":"1"),e);m=V({positionType:"individualShift",children:[{type:"elem",elem:m,shift:0},{type:"elem",elem:x,shift:c?.08:0}]}),s.name="\\"+b,m.classes.unshift("mop"),m.italic=d}}else if(s.body){var y=i0(s.body,e,!0);y.length===1&&y[0]instanceof f0?(m=y[0],m.classes[0]="mop"):m=k(["mop"],y,e)}else{for(var T=[],q=1;q{var t;if(r.symbol)t=new A("mo",[y0(r.name,r.mode)]),xa.has(r.name)&&t.setAttribute("largeop","false");else if(r.body)t=new A("mo",g0(r.body,e));else{t=new A("mi",[new r0(r.name.slice(1))]);var a=new A("mo",[y0("⁡","text")]);r.parentIsSupSub?t=new A("mrow",[t,a]):t=Jr([t,a])}return t},Mn={"∏":"\\prod","∐":"\\coprod","∑":"\\sum","⋀":"\\bigwedge","⋁":"\\bigvee","⋂":"\\bigcap","⋃":"\\bigcup","⨀":"\\bigodot","⨁":"\\bigoplus","⨂":"\\bigotimes","⨄":"\\biguplus","⨆":"\\bigsqcup"};C({type:"op",names:["\\coprod","\\bigvee","\\bigwedge","\\biguplus","\\bigcap","\\bigcup","\\intop","\\prod","\\sum","\\bigotimes","\\bigoplus","\\bigodot","\\bigsqcup","\\smallint","∏","∐","∑","⋀","⋁","⋂","⋃","⨀","⨁","⨂","⨄","⨆"],numArgs:0,handler:(r,e)=>{var{parser:t,funcName:a}=r,n=a;return n.length===1&&(n=Mn[n]),{type:"op",mode:t.mode,limits:!0,parentIsSupSub:!1,symbol:!0,name:n}},htmlBuilder:wa,mathmlBuilder:An});C({type:"op",names:["\\mathop"],numArgs:1,primitive:!0,handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"op",mode:t.mode,limits:!1,parentIsSupSub:!1,symbol:!1,body:t0(a)}}});var Tn={"∫":"\\int","∬":"\\iint","∭":"\\iiint","∮":"\\oint","∯":"\\oiint","∰":"\\oiiint"};C({type:"op",names:["\\arcsin","\\arccos","\\arctan","\\arctg","\\arcctg","\\arg","\\ch","\\cos","\\cosec","\\cosh","\\cot","\\cotg","\\coth","\\csc","\\ctg","\\cth","\\deg","\\dim","\\exp","\\hom","\\ker","\\lg","\\ln","\\log","\\sec","\\sin","\\sinh","\\sh","\\tan","\\tanh","\\tg","\\th"],numArgs:0,handler(r){var{parser:e,funcName:t}=r;return{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!1,name:t}}});C({type:"op",names:["\\det","\\gcd","\\inf","\\lim","\\max","\\min","\\Pr","\\sup"],numArgs:0,handler(r){var{parser:e,funcName:t}=r;return{type:"op",mode:e.mode,limits:!0,parentIsSupSub:!1,symbol:!1,name:t}}});C({type:"op",names:["\\int","\\iint","\\iiint","\\oint","\\oiint","\\oiiint","∫","∬","∭","∮","∯","∰"],numArgs:0,allowedInArgument:!0,handler(r){var{parser:e,funcName:t}=r,a=t;return a.length===1&&(a=Tn[a]),{type:"op",mode:e.mode,limits:!1,parentIsSupSub:!1,symbol:!0,name:a}}});var Sa=(r,e)=>{var t,a,n=!1,s;r.type==="supsub"?(t=r.sup,a=r.sub,s=L(r.base,"operatorname"),n=!0):s=L(r,"operatorname");var l;if(s.body.length>0){for(var c=s.body.map(b=>{var x="text"in b?b.text:void 0;return typeof x=="string"?{type:"textord",mode:b.mode,text:x}:b}),m=i0(c,e.withFont("mathrm"),!0),d=0;d{for(var t=g0(r.body,e.withFont("mathrm")),a=!0,n=0;nv.toText()).join("");t=[new r0(c)]}var m=new A("mi",t);m.setAttribute("mathvariant","normal");var d=new A("mo",[y0("⁡","text")]);return r.parentIsSupSub?new A("mrow",[m,d]):Jr([m,d])};C({type:"operatorname",names:["\\operatorname@","\\operatornamewithlimits"],numArgs:1,handler:(r,e)=>{var{parser:t,funcName:a}=r,n=e[0];return{type:"operatorname",mode:t.mode,body:t0(n),alwaysHandleSupSub:a==="\\operatornamewithlimits",limits:!1,parentIsSupSub:!1}},htmlBuilder:Sa,mathmlBuilder:qn});h("\\operatorname","\\@ifstar\\operatornamewithlimits\\operatorname@");Z0({type:"ordgroup",htmlBuilder(r,e){return r.semisimple?I0(i0(r.body,e,!1)):k(["mord"],i0(r.body,e,!0),e)},mathmlBuilder(r,e){return U0(r.body,e,!0)}});C({type:"overline",names:["\\overline"],numArgs:1,handler(r,e){var{parser:t}=r,a=e[0];return{type:"overline",mode:t.mode,body:a}},htmlBuilder(r,e){var t=X(r.body,e.havingCrampedStyle()),a=ae("overline-line",e),n=e.fontMetrics().defaultRuleThickness,s=V({positionType:"firstBaseline",children:[{type:"elem",elem:t},{type:"kern",size:3*n},{type:"elem",elem:a},{type:"kern",size:n}]});return k(["mord","overline"],[s],e)},mathmlBuilder(r,e){var t=new A("mo",[new r0("‾")]);t.setAttribute("stretchy","true");var a=new A("mover",[Y(r.body,e),t]);return a.setAttribute("accent","true"),a}});C({type:"phantom",names:["\\phantom"],numArgs:1,allowedInText:!0,handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"phantom",mode:t.mode,body:t0(a)}},htmlBuilder:(r,e)=>{var t=i0(r.body,e.withPhantom(),!1);return I0(t)},mathmlBuilder:(r,e)=>{var t=g0(r.body,e);return new A("mphantom",t)}});h("\\hphantom","\\smash{\\phantom{#1}}");C({type:"vphantom",names:["\\vphantom"],numArgs:1,allowedInText:!0,handler:(r,e)=>{var{parser:t}=r,a=e[0];return{type:"vphantom",mode:t.mode,body:a}},htmlBuilder:(r,e)=>{var t=k(["inner"],[X(r.body,e.withPhantom())]),a=k(["fix"],[]);return k(["mord","rlap"],[t,a],e)},mathmlBuilder:(r,e)=>{var t=g0(t0(r.body),e),a=new A("mphantom",t),n=new A("mpadded",[a]);return n.setAttribute("width","0px"),n}});C({type:"raisebox",names:["\\raisebox"],numArgs:2,argTypes:["size","hbox"],allowedInText:!0,handler(r,e){var{parser:t}=r,a=L(e[0],"size").value,n=e[1];return{type:"raisebox",mode:t.mode,dy:a,body:n}},htmlBuilder(r,e){var t=X(r.body,e),a=J(r.dy,e);return V({positionType:"shift",positionData:-a,children:[{type:"elem",elem:t}]})},mathmlBuilder(r,e){var t=new A("mpadded",[Y(r.body,e)]),a=r.dy.number+r.dy.unit;return t.setAttribute("voffset",a),t}});C({type:"internal",names:["\\relax"],numArgs:0,allowedInText:!0,allowedInArgument:!0,handler(r){var{parser:e}=r;return{type:"internal",mode:e.mode}}});C({type:"rule",names:["\\rule"],numArgs:2,numOptionalArgs:1,allowedInText:!0,allowedInMath:!0,argTypes:["size","size","size"],handler(r,e,t){var{parser:a}=r,n=t[0],s=L(e[0],"size"),l=L(e[1],"size");return{type:"rule",mode:a.mode,shift:n&&L(n,"size").value,width:s.value,height:l.value}},htmlBuilder(r,e){var t=k(["mord","rule"],[],e),a=J(r.width,e),n=J(r.height,e),s=r.shift?J(r.shift,e):0;return t.style.borderRightWidth=M(a),t.style.borderTopWidth=M(n),t.style.bottom=M(s),t.width=a,t.height=n+s,t.depth=-s,t.maxFontSize=n*1.125*e.sizeMultiplier,t},mathmlBuilder(r,e){var t=J(r.width,e),a=J(r.height,e),n=r.shift?J(r.shift,e):0,s=e.color&&e.getColor()||"black",l=new A("mspace");l.setAttribute("mathbackground",s),l.setAttribute("width",M(t)),l.setAttribute("height",M(a));var c=new A("mpadded",[l]);return n>=0?c.setAttribute("height",M(n)):(c.setAttribute("height",M(n)),c.setAttribute("depth",M(-n))),c.setAttribute("voffset",M(n)),c}});function ka(r,e,t){for(var a=i0(r,e,!1),n=e.sizeMultiplier/t.sizeMultiplier,s=0;s{var t=e.havingSize(r.size);return ka(r.body,t,e)};C({type:"sizing",names:Dr,numArgs:0,allowedInText:!0,handler:(r,e)=>{var{breakOnTokenText:t,funcName:a,parser:n}=r,s=n.parseExpression(!1,t);return{type:"sizing",mode:n.mode,size:Dr.indexOf(a)+1,body:s}},htmlBuilder:Dn,mathmlBuilder:(r,e)=>{var t=e.havingSize(r.size),a=g0(r.body,t),n=new A("mstyle",a);return n.setAttribute("mathsize",M(t.sizeMultiplier)),n}});C({type:"smash",names:["\\smash"],numArgs:1,numOptionalArgs:1,allowedInText:!0,handler:(r,e,t)=>{var{parser:a}=r,n=!1,s=!1,l=t[0]&&L(t[0],"ordgroup");if(l)for(var c,m=0;m{var t=k([],[X(r.body,e)]);if(!r.smashHeight&&!r.smashDepth)return t;if(r.smashHeight&&(t.height=0),r.smashDepth&&(t.depth=0),r.smashHeight&&r.smashDepth)return k(["mord","smash"],[t],e);if(t.children)for(var a=0;a{var t=new A("mpadded",[Y(r.body,e)]);return r.smashHeight&&t.setAttribute("height","0px"),r.smashDepth&&t.setAttribute("depth","0px"),t}});C({type:"sqrt",names:["\\sqrt"],numArgs:1,numOptionalArgs:1,handler(r,e,t){var{parser:a}=r,n=t[0],s=e[0];return{type:"sqrt",mode:a.mode,body:s,index:n}},htmlBuilder(r,e){var t=X(r.body,e.havingCrampedStyle());t.height===0&&(t.height=e.fontMetrics().xHeight),t=ne(t,e);var a=e.fontMetrics(),n=a.defaultRuleThickness,s=n;e.style.idt.height+t.depth+l&&(l=(l+b-t.height-t.depth)/2);var x=m.height-t.height-l-d;t.style.paddingLeft=M(v);var y=V({positionType:"firstBaseline",children:[{type:"elem",elem:t,wrapperClasses:["svg-align"]},{type:"kern",size:-(t.height+x)},{type:"elem",elem:m},{type:"kern",size:d}]});if(r.index){var T=e.havingStyle(N.SCRIPTSCRIPT),q=X(r.index,T,e),D=.6*(y.height-y.depth),B=V({positionType:"shift",positionData:-D,children:[{type:"elem",elem:q}]}),O=k(["root"],[B]);return k(["mord","sqrt"],[O,y],e)}else return k(["mord","sqrt"],[y],e)},mathmlBuilder(r,e){var{body:t,index:a}=r;return a?new A("mroot",[Y(t,e),Y(a,e)]):new A("msqrt",[Y(t,e)])}});var Ct={display:N.DISPLAY,text:N.TEXT,script:N.SCRIPT,scriptscript:N.SCRIPTSCRIPT};function Cn(r){return r in Ct}C({type:"styling",names:["\\displaystyle","\\textstyle","\\scriptstyle","\\scriptscriptstyle"],numArgs:0,allowedInText:!0,primitive:!0,handler(r,e){var{breakOnTokenText:t,funcName:a,parser:n}=r,s=n.parseExpression(!0,t),l=a.slice(1,a.length-5);if(!Cn(l))throw new Error("Unknown style: "+l);return{type:"styling",mode:n.mode,style:l,body:s}},htmlBuilder(r,e){var t=Ct[r.style],a=e.havingStyle(t);return r.resetFont&&(a=a.withFont("")),ka(r.body,a,e)},mathmlBuilder(r,e){var t=Ct[r.style],a=e.havingStyle(t);r.resetFont&&(a=a.withFont(""));var n=g0(r.body,a),s=new A("mstyle",n),l={display:["0","true"],text:["0","false"],script:["1","false"],scriptscript:["2","false"]},c=l[r.style];return s.setAttribute("scriptlevel",c[0]),s.setAttribute("displaystyle",c[1]),s}});var Bn=function(e,t){var a=e.base;if(a)if(a.type==="op"){var n=a.limits&&(t.style.size===N.DISPLAY.size||a.alwaysHandleSupSub);return n?wa:null}else if(a.type==="operatorname"){var s=a.alwaysHandleSupSub&&(t.style.size===N.DISPLAY.size||a.limits);return s?Sa:null}else{if(a.type==="accent")return _0(a.base)?aa:null;if(a.type==="horizBrace"){var l=!e.sub;return l===a.isOver?ba:null}else return null}else return null};Z0({type:"supsub",htmlBuilder(r,e){var t=Bn(r,e);if(t)return t(r,e);var{base:a,sup:n,sub:s}=r,l=X(a,e),c,m,d=e.fontMetrics(),v=0,b=0,x=a&&_0(a);if(n){var y=e.havingStyle(e.style.sup());c=X(n,y,e),x||(v=l.height-y.fontMetrics().supDrop*y.sizeMultiplier/e.sizeMultiplier)}if(s){var T=e.havingStyle(e.style.sub());m=X(s,T,e),x||(b=l.depth+T.fontMetrics().subDrop*T.sizeMultiplier/e.sizeMultiplier)}var q;e.style===N.DISPLAY?q=d.sup1:e.style.cramped?q=d.sup3:q=d.sup2;var D=e.sizeMultiplier,B=M(.5/d.ptPerEm/D),O=null;if(m){var $=r.base&&r.base.type==="op"&&r.base.name&&(r.base.name==="\\oiint"||r.base.name==="\\oiiint");if(l instanceof f0||$){var E;O=M(-((E=l.italic)!=null?E:0))}}var F;if(c&&m){v=Math.max(v,q,c.depth+.25*d.xHeight),b=Math.max(b,d.sub2);var H=d.defaultRuleThickness,G=4*H;if(v-c.depth-(m.height-b)0&&(v+=P,b-=P)}var U=[{type:"elem",elem:m,shift:b,marginRight:B,marginLeft:O},{type:"elem",elem:c,shift:-v,marginRight:B}];F=V({positionType:"individualShift",children:U})}else if(m){b=Math.max(b,d.sub1,m.height-.8*d.xHeight);var h0=[{type:"elem",elem:m,marginLeft:O,marginRight:B}];F=V({positionType:"shift",positionData:b,children:h0})}else if(c)v=Math.max(v,q,c.depth+.25*d.xHeight),F=V({positionType:"shift",positionData:-v,children:[{type:"elem",elem:c,marginRight:B}]});else throw new Error("supsub must have either sup or sub.");var d0=At(l,"right")||"mord";return k([d0],[l,k(["msupsub"],[F])],e)},mathmlBuilder(r,e){var t=!1,a,n;r.base&&r.base.type==="horizBrace"&&(n=!!r.sup,n===r.base.isOver&&(t=!0,a=r.base.isOver)),r.base&&(r.base.type==="op"||r.base.type==="operatorname")&&(r.base.parentIsSupSub=!0);var s=[Y(r.base,e)];r.sub&&s.push(Y(r.sub,e)),r.sup&&s.push(Y(r.sup,e));var l;if(t)l=a?"mover":"munder";else if(r.sub)if(r.sup){var d=r.base;d&&d.type==="op"&&d.limits&&e.style===N.DISPLAY||d&&d.type==="operatorname"&&d.alwaysHandleSupSub&&(e.style===N.DISPLAY||d.limits)?l="munderover":l="msubsup"}else{var m=r.base;m&&m.type==="op"&&m.limits&&(e.style===N.DISPLAY||m.alwaysHandleSupSub)||m&&m.type==="operatorname"&&m.alwaysHandleSupSub&&(m.limits||e.style===N.DISPLAY)?l="munder":l="msub"}else{var c=r.base;c&&c.type==="op"&&c.limits&&(e.style===N.DISPLAY||c.alwaysHandleSupSub)||c&&c.type==="operatorname"&&c.alwaysHandleSupSub&&(c.limits||e.style===N.DISPLAY)?l="mover":l="msup"}return new A(l,s)}});Z0({type:"atom",htmlBuilder(r,e){return $t(r.text,r.mode,e,["m"+r.family])},mathmlBuilder(r,e){var t=new A("mo",[y0(r.text,r.mode)]);if(r.family==="bin"){var a=Ft(r,e);a==="bold-italic"&&t.setAttribute("mathvariant",a)}else r.family==="punct"?t.setAttribute("separator","true"):(r.family==="open"||r.family==="close")&&t.setAttribute("stretchy","false");return t}});var za={mi:"italic",mn:"normal",mtext:"normal"};Z0({type:"mathord",htmlBuilder(r,e){return Fe(r,e)},mathmlBuilder(r,e){var t=new A("mi",[y0(r.text,r.mode,e)]),a=Ft(r,e)||"italic";return a!==za[t.type]&&t.setAttribute("mathvariant",a),t}});Z0({type:"textord",htmlBuilder(r,e){return Fe(r,e)},mathmlBuilder(r,e){var t=y0(r.text,r.mode,e),a=Ft(r,e)||"normal",n;return r.mode==="text"?n=new A("mtext",[t]):/[0-9]/.test(r.text)?n=new A("mn",[t]):r.text==="\\prime"?n=new A("mo",[t]):n=new A("mi",[t]),a!==za[n.type]&&n.setAttribute("mathvariant",a),n}});var ct={"\\nobreak":"nobreak","\\allowbreak":"allowbreak"},ht={" ":{},"\\ ":{},"~":{className:"nobreak"},"\\space":{},"\\nobreakspace":{className:"nobreak"}};Z0({type:"spacing",htmlBuilder(r,e){if(ht.hasOwnProperty(r.text)){var t=ht[r.text].className||"";if(r.mode==="text"){var a=Fe(r,e);return a.classes.push(t),a}else return k(["mspace",t],[$t(r.text,r.mode,e)],e)}else{if(ct.hasOwnProperty(r.text))return k(["mspace",ct[r.text]],[],e);throw new z('Unknown type of space "'+r.text+'"')}},mathmlBuilder(r,e){var t;if(ht.hasOwnProperty(r.text))t=new A("mtext",[new r0(" ")]);else{if(ct.hasOwnProperty(r.text))return new A("mspace");throw new z('Unknown type of space "'+r.text+'"')}return t}});var Cr=()=>{var r=new A("mtd",[]);return r.setAttribute("width","50%"),r};Z0({type:"tag",mathmlBuilder(r,e){var t=new A("mtable",[new A("mtr",[Cr(),new A("mtd",[U0(r.body,e)]),Cr(),new A("mtd",[U0(r.tag,e)])])]);return t.setAttribute("width","100%"),t}});var Br={"\\text":void 0,"\\textrm":"textrm","\\textsf":"textsf","\\texttt":"texttt","\\textnormal":"textrm"},_r={"\\textbf":"textbf","\\textmd":"textmd"},_n={"\\textit":"textit","\\textup":"textup"},Er=(r,e)=>{var t=r.font;if(t){if(Br[t])return e.withTextFontFamily(Br[t]);if(_r[t])return e.withTextFontWeight(_r[t]);if(t==="\\emph")return e.fontShape==="textit"?e.withTextFontShape("textup"):e.withTextFontShape("textit")}else return e;return e.withTextFontShape(_n[t])};C({type:"text",names:["\\text","\\textrm","\\textsf","\\texttt","\\textnormal","\\textbf","\\textmd","\\textit","\\textup","\\emph"],numArgs:1,argTypes:["text"],allowedInArgument:!0,allowedInText:!0,handler(r,e){var{parser:t,funcName:a}=r,n=e[0];return{type:"text",mode:t.mode,body:t0(n),font:a}},htmlBuilder(r,e){var t=Er(r,e),a=i0(r.body,t,!0);return k(["mord","text"],a,t)},mathmlBuilder(r,e){var t=Er(r,e);return U0(r.body,t)}});C({type:"underline",names:["\\underline"],numArgs:1,allowedInText:!0,handler(r,e){var{parser:t}=r;return{type:"underline",mode:t.mode,body:e[0]}},htmlBuilder(r,e){var t=X(r.body,e),a=ae("underline-line",e),n=e.fontMetrics().defaultRuleThickness,s=V({positionType:"top",positionData:t.height,children:[{type:"kern",size:n},{type:"elem",elem:a},{type:"kern",size:3*n},{type:"elem",elem:t}]});return k(["mord","underline"],[s],e)},mathmlBuilder(r,e){var t=new A("mo",[new r0("‾")]);t.setAttribute("stretchy","true");var a=new A("munder",[Y(r.body,e),t]);return a.setAttribute("accentunder","true"),a}});C({type:"vcenter",names:["\\vcenter"],numArgs:1,argTypes:["original"],allowedInText:!1,handler(r,e){var{parser:t}=r;return{type:"vcenter",mode:t.mode,body:e[0]}},htmlBuilder(r,e){var t=X(r.body,e),a=e.fontMetrics().axisHeight,n=.5*(t.height-a-(t.depth+a));return V({positionType:"shift",positionData:n,children:[{type:"elem",elem:t}]})},mathmlBuilder(r,e){var t=new A("mpadded",[Y(r.body,e)],["vcenter"]);return new A("mrow",[t])}});C({type:"verb",names:["\\verb"],numArgs:0,allowedInText:!0,handler(r,e,t){throw new z("\\verb ended by end of line instead of matching delimiter")},htmlBuilder(r,e){for(var t=Ir(r),a=[],n=e.havingStyle(e.style.text()),s=0;sr.body.replace(/ /g,r.star?"␣":" "),H0=jr,Aa=`[ \r + ]`,En="\\\\[a-zA-Z@]+",In="\\\\[^\uD800-\uDFFF]",On="("+En+")"+Aa+"*",$n=`\\\\( +|[ \r ]+ +?)[ \r ]*`,Bt="[̀-ͯ]",Rn=new RegExp(Bt+"+$"),Nn="("+Aa+"+)|"+($n+"|")+"([!-\\[\\]-‧‪-퟿豈-￿]"+(Bt+"*")+"|[\uD800-\uDBFF][\uDC00-\uDFFF]"+(Bt+"*")+"|\\\\verb\\*([^]).*?\\4|\\\\verb([^*a-zA-Z]).*?\\5"+("|"+On)+("|"+In+")");class Or{constructor(e,t){this.input=void 0,this.settings=void 0,this.tokenRegex=void 0,this.catcodes=void 0,this.input=e,this.settings=t,this.tokenRegex=new RegExp(Nn,"g"),this.catcodes={"%":14,"~":13}}setCatcode(e,t){this.catcodes[e]=t}lex(){var e=this.input,t=this.tokenRegex.lastIndex;if(t===e.length)return new p0("EOF",new m0(this,t,t));var a=this.tokenRegex.exec(e);if(a===null||a.index!==t)throw new z("Unexpected character: '"+e[t]+"'",new p0(e[t],new m0(this,t,t+1)));var n=a[6]||a[3]||(a[2]?"\\ ":" ");if(this.catcodes[n]===14){var s=e.indexOf(` +`,this.tokenRegex.lastIndex);return s===-1?(this.tokenRegex.lastIndex=e.length,this.settings.reportNonstrict("commentAtEnd","% comment has no terminating newline; LaTeX would fail because of commenting the end of math mode (e.g. $)")):this.tokenRegex.lastIndex=s+1,this.lex()}return new p0(n,new m0(this,t,this.tokenRegex.lastIndex))}}class Fn{constructor(e,t){e===void 0&&(e={}),t===void 0&&(t={}),this.current=void 0,this.builtins=void 0,this.undefStack=void 0,this.current=t,this.builtins=e,this.undefStack=[]}beginGroup(){this.undefStack.push({})}endGroup(){if(this.undefStack.length===0)throw new z("Unbalanced namespace destruction: attempt to pop global namespace; please report this as a bug");var e=this.undefStack.pop();for(var t in e)e.hasOwnProperty(t)&&(e[t]==null?delete this.current[t]:this.current[t]=e[t])}endGroups(){for(;this.undefStack.length>0;)this.endGroup()}has(e){return this.current.hasOwnProperty(e)||this.builtins.hasOwnProperty(e)}get(e){return this.current.hasOwnProperty(e)?this.current[e]:this.builtins[e]}set(e,t,a){if(a===void 0&&(a=!1),a){for(var n=0;n0&&(this.undefStack[this.undefStack.length-1][e]=t)}else{var s=this.undefStack[this.undefStack.length-1];s&&!s.hasOwnProperty(e)&&(s[e]=this.current[e])}t==null?delete this.current[e]:this.current[e]=t}}var Hn=fa;h("\\noexpand",function(r){var e=r.popToken();return r.isExpandable(e.text)&&(e.noexpand=!0,e.treatAsRelax=!0),{tokens:[e],numArgs:0}});h("\\expandafter",function(r){var e=r.popToken();return r.expandOnce(!0),{tokens:[e],numArgs:0}});h("\\@firstoftwo",function(r){var e=r.consumeArgs(2);return{tokens:e[0],numArgs:0}});h("\\@secondoftwo",function(r){var e=r.consumeArgs(2);return{tokens:e[1],numArgs:0}});h("\\@ifnextchar",function(r){var e=r.consumeArgs(3);r.consumeSpaces();var t=r.future();return e[0].length===1&&e[0][0].text===t.text?{tokens:e[1],numArgs:0}:{tokens:e[2],numArgs:0}});h("\\@ifstar","\\@ifnextchar *{\\@firstoftwo{#1}}");h("\\TextOrMath",function(r){var e=r.consumeArgs(2);return r.mode==="text"?{tokens:e[0],numArgs:0}:{tokens:e[1],numArgs:0}});var $r={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,A:10,b:11,B:11,c:12,C:12,d:13,D:13,e:14,E:14,f:15,F:15};h("\\char",function(r){var e=r.popToken(),t,a=0;if(e.text==="'")t=8,e=r.popToken();else if(e.text==='"')t=16,e=r.popToken();else if(e.text==="`")if(e=r.popToken(),e.text[0]==="\\")a=e.text.charCodeAt(1);else{if(e.text==="EOF")throw new z("\\char` missing argument");a=e.text.charCodeAt(0)}else t=10;if(t){if(a=$r[e.text],a==null||a>=t)throw new z("Invalid base-"+t+" digit "+e.text);for(var n;(n=$r[r.future().text])!=null&&n{var n=r.consumeArg().tokens;if(n.length!==1)throw new z("\\newcommand's first argument must be a macro name");var s=n[0].text,l=r.isDefined(s);if(l&&!e)throw new z("\\newcommand{"+s+"} attempting to redefine "+(s+"; use \\renewcommand"));if(!l&&!t)throw new z("\\renewcommand{"+s+"} when command "+s+" does not yet exist; use \\newcommand");var c=0;if(n=r.consumeArg().tokens,n.length===1&&n[0].text==="["){for(var m="",d=r.expandNextToken();d.text!=="]"&&d.text!=="EOF";)m+=d.text,d=r.expandNextToken();if(!m.match(/^\s*[0-9]+\s*$/))throw new z("Invalid number of arguments: "+m);c=parseInt(m),n=r.consumeArg().tokens}return l&&a||r.macros.set(s,{tokens:n,numArgs:c}),""};h("\\newcommand",r=>Pt(r,!1,!0,!1));h("\\renewcommand",r=>Pt(r,!0,!1,!1));h("\\providecommand",r=>Pt(r,!0,!0,!0));h("\\message",r=>{var e=r.consumeArgs(1)[0];return console.log(e.reverse().map(t=>t.text).join("")),""});h("\\errmessage",r=>{var e=r.consumeArgs(1)[0];return console.error(e.reverse().map(t=>t.text).join("")),""});h("\\show",r=>{var e=r.popToken(),t=e.text;return console.log(e,r.macros.get(t),H0[t],Z.math[t],Z.text[t]),""});h("\\bgroup","{");h("\\egroup","}");h("~","\\nobreakspace");h("\\lq","`");h("\\rq","'");h("\\aa","\\r a");h("\\AA","\\r A");h("\\textcopyright","\\html@mathml{\\textcircled{c}}{\\char`©}");h("\\copyright","\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}");h("\\textregistered","\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`®}");h("ℬ","\\mathscr{B}");h("ℰ","\\mathscr{E}");h("ℱ","\\mathscr{F}");h("ℋ","\\mathscr{H}");h("ℐ","\\mathscr{I}");h("ℒ","\\mathscr{L}");h("ℳ","\\mathscr{M}");h("ℛ","\\mathscr{R}");h("ℭ","\\mathfrak{C}");h("ℌ","\\mathfrak{H}");h("ℨ","\\mathfrak{Z}");h("\\Bbbk","\\Bbb{k}");h("\\llap","\\mathllap{\\textrm{#1}}");h("\\rlap","\\mathrlap{\\textrm{#1}}");h("\\clap","\\mathclap{\\textrm{#1}}");h("\\mathstrut","\\vphantom{(}");h("\\underbar","\\underline{\\text{#1}}");h("\\not",'\\html@mathml{\\mathrel{\\mathrlap\\@not}\\nobreak}{\\char"338}');h("\\neq","\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}");h("\\ne","\\neq");h("≠","\\neq");h("\\notin","\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}{\\mathrel{\\char`∉}}");h("∉","\\notin");h("≘","\\html@mathml{\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}}{\\mathrel{\\char`≘}}");h("≙","\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`≘}}");h("≚","\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`≚}}");h("≛","\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}{\\mathrel{\\char`≛}}");h("≝","\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}{\\mathrel{\\char`≝}}");h("≞","\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}{\\mathrel{\\char`≞}}");h("≟","\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`≟}}");h("⟂","\\perp");h("‼","\\mathclose{!\\mkern-0.8mu!}");h("∌","\\notni");h("⌜","\\ulcorner");h("⌝","\\urcorner");h("⌞","\\llcorner");h("⌟","\\lrcorner");h("©","\\copyright");h("®","\\textregistered");h("\\ulcorner",'\\html@mathml{\\@ulcorner}{\\mathop{\\char"231c}}');h("\\urcorner",'\\html@mathml{\\@urcorner}{\\mathop{\\char"231d}}');h("\\llcorner",'\\html@mathml{\\@llcorner}{\\mathop{\\char"231e}}');h("\\lrcorner",'\\html@mathml{\\@lrcorner}{\\mathop{\\char"231f}}');h("\\vdots","{\\varvdots\\rule{0pt}{15pt}}");h("⋮","\\vdots");h("\\varGamma","\\mathit{\\Gamma}");h("\\varDelta","\\mathit{\\Delta}");h("\\varTheta","\\mathit{\\Theta}");h("\\varLambda","\\mathit{\\Lambda}");h("\\varXi","\\mathit{\\Xi}");h("\\varPi","\\mathit{\\Pi}");h("\\varSigma","\\mathit{\\Sigma}");h("\\varUpsilon","\\mathit{\\Upsilon}");h("\\varPhi","\\mathit{\\Phi}");h("\\varPsi","\\mathit{\\Psi}");h("\\varOmega","\\mathit{\\Omega}");h("\\substack","\\begin{subarray}{c}#1\\end{subarray}");h("\\colon","\\nobreak\\mskip2mu\\mathpunct{}\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu\\relax");h("\\boxed","\\fbox{$\\displaystyle{#1}$}");h("\\iff","\\DOTSB\\;\\Longleftrightarrow\\;");h("\\implies","\\DOTSB\\;\\Longrightarrow\\;");h("\\impliedby","\\DOTSB\\;\\Longleftarrow\\;");h("\\dddot","{\\overset{\\raisebox{-0.1ex}{\\normalsize ...}}{#1}}");h("\\ddddot","{\\overset{\\raisebox{-0.1ex}{\\normalsize ....}}{#1}}");var Rr={",":"\\dotsc","\\not":"\\dotsb","+":"\\dotsb","=":"\\dotsb","<":"\\dotsb",">":"\\dotsb","-":"\\dotsb","*":"\\dotsb",":":"\\dotsb","\\DOTSB":"\\dotsb","\\coprod":"\\dotsb","\\bigvee":"\\dotsb","\\bigwedge":"\\dotsb","\\biguplus":"\\dotsb","\\bigcap":"\\dotsb","\\bigcup":"\\dotsb","\\prod":"\\dotsb","\\sum":"\\dotsb","\\bigotimes":"\\dotsb","\\bigoplus":"\\dotsb","\\bigodot":"\\dotsb","\\bigsqcup":"\\dotsb","\\And":"\\dotsb","\\longrightarrow":"\\dotsb","\\Longrightarrow":"\\dotsb","\\longleftarrow":"\\dotsb","\\Longleftarrow":"\\dotsb","\\longleftrightarrow":"\\dotsb","\\Longleftrightarrow":"\\dotsb","\\mapsto":"\\dotsb","\\longmapsto":"\\dotsb","\\hookrightarrow":"\\dotsb","\\doteq":"\\dotsb","\\mathbin":"\\dotsb","\\mathrel":"\\dotsb","\\relbar":"\\dotsb","\\Relbar":"\\dotsb","\\xrightarrow":"\\dotsb","\\xleftarrow":"\\dotsb","\\DOTSI":"\\dotsi","\\int":"\\dotsi","\\oint":"\\dotsi","\\iint":"\\dotsi","\\iiint":"\\dotsi","\\iiiint":"\\dotsi","\\idotsint":"\\dotsi","\\DOTSX":"\\dotsx"},Ln=new Set(["bin","rel"]);h("\\dots",function(r){var e="\\dotso",t=r.expandAfterFuture().text;return t in Rr?e=Rr[t]:(t.slice(0,4)==="\\not"||t in Z.math&&Ln.has(Z.math[t].group))&&(e="\\dotsb"),e});var Ut={")":!0,"]":!0,"\\rbrack":!0,"\\}":!0,"\\rbrace":!0,"\\rangle":!0,"\\rceil":!0,"\\rfloor":!0,"\\rgroup":!0,"\\rmoustache":!0,"\\right":!0,"\\bigr":!0,"\\biggr":!0,"\\Bigr":!0,"\\Biggr":!0,$:!0,";":!0,".":!0,",":!0};h("\\dotso",function(r){var e=r.future().text;return e in Ut?"\\ldots\\,":"\\ldots"});h("\\dotsc",function(r){var e=r.future().text;return e in Ut&&e!==","?"\\ldots\\,":"\\ldots"});h("\\cdots",function(r){var e=r.future().text;return e in Ut?"\\@cdots\\,":"\\@cdots"});h("\\dotsb","\\cdots");h("\\dotsm","\\cdots");h("\\dotsi","\\!\\cdots");h("\\dotsx","\\ldots\\,");h("\\DOTSI","\\relax");h("\\DOTSB","\\relax");h("\\DOTSX","\\relax");h("\\tmspace","\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax");h("\\,","\\tmspace+{3mu}{.1667em}");h("\\thinspace","\\,");h("\\>","\\mskip{4mu}");h("\\:","\\tmspace+{4mu}{.2222em}");h("\\medspace","\\:");h("\\;","\\tmspace+{5mu}{.2777em}");h("\\thickspace","\\;");h("\\!","\\tmspace-{3mu}{.1667em}");h("\\negthinspace","\\!");h("\\negmedspace","\\tmspace-{4mu}{.2222em}");h("\\negthickspace","\\tmspace-{5mu}{.277em}");h("\\enspace","\\kern.5em ");h("\\enskip","\\hskip.5em\\relax");h("\\quad","\\hskip1em\\relax");h("\\qquad","\\hskip2em\\relax");h("\\tag","\\@ifstar\\tag@literal\\tag@paren");h("\\tag@paren","\\tag@literal{({#1})}");h("\\tag@literal",r=>{if(r.macros.get("\\df@tag"))throw new z("Multiple \\tag");return"\\gdef\\df@tag{\\text{#1}}"});h("\\bmod","\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}\\mathbin{\\rm mod}\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}");h("\\pod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)");h("\\pmod","\\pod{{\\rm mod}\\mkern6mu#1}");h("\\mod","\\allowbreak\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}{\\rm mod}\\,\\,#1");h("\\newline","\\\\\\relax");h("\\TeX","\\textrm{\\html@mathml{T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX}{TeX}}");var Ma=M(z0["Main-Regular"][84][1]-.7*z0["Main-Regular"][65][1]);h("\\LaTeX","\\textrm{\\html@mathml{"+("L\\kern-.36em\\raisebox{"+Ma+"}{\\scriptstyle A}")+"\\kern-.15em\\TeX}{LaTeX}}");h("\\KaTeX","\\textrm{\\html@mathml{"+("K\\kern-.17em\\raisebox{"+Ma+"}{\\scriptstyle A}")+"\\kern-.15em\\TeX}{KaTeX}}");h("\\hspace","\\@ifstar\\@hspacer\\@hspace");h("\\@hspace","\\hskip #1\\relax");h("\\@hspacer","\\rule{0pt}{0pt}\\hskip #1\\relax");h("\\ordinarycolon",":");h("\\vcentcolon","\\mathrel{\\mathop\\ordinarycolon}");h("\\dblcolon",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}{\\mathop{\\char"2237}}');h("\\coloneqq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2254}}');h("\\Coloneqq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}{\\mathop{\\char"2237\\char"3d}}');h("\\coloneq",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"3a\\char"2212}}');h("\\Coloneq",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}{\\mathop{\\char"2237\\char"2212}}');h("\\eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2255}}');h("\\Eqqcolon",'\\html@mathml{\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"3d\\char"2237}}');h("\\eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}{\\mathop{\\char"2239}}');h("\\Eqcolon",'\\html@mathml{\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}{\\mathop{\\char"2212\\char"2237}}');h("\\colonapprox",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"3a\\char"2248}}');h("\\Colonapprox",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}{\\mathop{\\char"2237\\char"2248}}');h("\\colonsim",'\\html@mathml{\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"3a\\char"223c}}');h("\\Colonsim",'\\html@mathml{\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}{\\mathop{\\char"2237\\char"223c}}');h("∷","\\dblcolon");h("∹","\\eqcolon");h("≔","\\coloneqq");h("≕","\\eqqcolon");h("⩴","\\Coloneqq");h("\\ratio","\\vcentcolon");h("\\coloncolon","\\dblcolon");h("\\colonequals","\\coloneqq");h("\\coloncolonequals","\\Coloneqq");h("\\equalscolon","\\eqqcolon");h("\\equalscoloncolon","\\Eqqcolon");h("\\colonminus","\\coloneq");h("\\coloncolonminus","\\Coloneq");h("\\minuscolon","\\eqcolon");h("\\minuscoloncolon","\\Eqcolon");h("\\coloncolonapprox","\\Colonapprox");h("\\coloncolonsim","\\Colonsim");h("\\simcolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}");h("\\simcoloncolon","\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}");h("\\approxcolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}");h("\\approxcoloncolon","\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}");h("\\notni","\\html@mathml{\\not\\ni}{\\mathrel{\\char`∌}}");h("\\limsup","\\DOTSB\\operatorname*{lim\\,sup}");h("\\liminf","\\DOTSB\\operatorname*{lim\\,inf}");h("\\injlim","\\DOTSB\\operatorname*{inj\\,lim}");h("\\projlim","\\DOTSB\\operatorname*{proj\\,lim}");h("\\varlimsup","\\DOTSB\\operatorname*{\\overline{lim}}");h("\\varliminf","\\DOTSB\\operatorname*{\\underline{lim}}");h("\\varinjlim","\\DOTSB\\operatorname*{\\underrightarrow{lim}}");h("\\varprojlim","\\DOTSB\\operatorname*{\\underleftarrow{lim}}");h("\\gvertneqq","\\html@mathml{\\@gvertneqq}{≩}");h("\\lvertneqq","\\html@mathml{\\@lvertneqq}{≨}");h("\\ngeqq","\\html@mathml{\\@ngeqq}{≱}");h("\\ngeqslant","\\html@mathml{\\@ngeqslant}{≱}");h("\\nleqq","\\html@mathml{\\@nleqq}{≰}");h("\\nleqslant","\\html@mathml{\\@nleqslant}{≰}");h("\\nshortmid","\\html@mathml{\\@nshortmid}{∤}");h("\\nshortparallel","\\html@mathml{\\@nshortparallel}{∦}");h("\\nsubseteqq","\\html@mathml{\\@nsubseteqq}{⊈}");h("\\nsupseteqq","\\html@mathml{\\@nsupseteqq}{⊉}");h("\\varsubsetneq","\\html@mathml{\\@varsubsetneq}{⊊}");h("\\varsubsetneqq","\\html@mathml{\\@varsubsetneqq}{⫋}");h("\\varsupsetneq","\\html@mathml{\\@varsupsetneq}{⊋}");h("\\varsupsetneqq","\\html@mathml{\\@varsupsetneqq}{⫌}");h("\\imath","\\html@mathml{\\@imath}{ı}");h("\\jmath","\\html@mathml{\\@jmath}{ȷ}");h("\\llbracket","\\html@mathml{\\mathopen{[\\mkern-3.2mu[}}{\\mathopen{\\char`⟦}}");h("\\rrbracket","\\html@mathml{\\mathclose{]\\mkern-3.2mu]}}{\\mathclose{\\char`⟧}}");h("⟦","\\llbracket");h("⟧","\\rrbracket");h("\\lBrace","\\html@mathml{\\mathopen{\\{\\mkern-3.2mu[}}{\\mathopen{\\char`⦃}}");h("\\rBrace","\\html@mathml{\\mathclose{]\\mkern-3.2mu\\}}}{\\mathclose{\\char`⦄}}");h("⦃","\\lBrace");h("⦄","\\rBrace");h("\\minuso","\\mathbin{\\html@mathml{{\\mathrlap{\\mathchoice{\\kern{0.145em}}{\\kern{0.145em}}{\\kern{0.1015em}}{\\kern{0.0725em}}\\circ}{-}}}{\\char`⦵}}");h("⦵","\\minuso");h("\\darr","\\downarrow");h("\\dArr","\\Downarrow");h("\\Darr","\\Downarrow");h("\\lang","\\langle");h("\\rang","\\rangle");h("\\uarr","\\uparrow");h("\\uArr","\\Uparrow");h("\\Uarr","\\Uparrow");h("\\N","\\mathbb{N}");h("\\R","\\mathbb{R}");h("\\Z","\\mathbb{Z}");h("\\alef","\\aleph");h("\\alefsym","\\aleph");h("\\Alpha","\\mathrm{A}");h("\\Beta","\\mathrm{B}");h("\\bull","\\bullet");h("\\Chi","\\mathrm{X}");h("\\clubs","\\clubsuit");h("\\cnums","\\mathbb{C}");h("\\Complex","\\mathbb{C}");h("\\Dagger","\\ddagger");h("\\diamonds","\\diamondsuit");h("\\empty","\\emptyset");h("\\Epsilon","\\mathrm{E}");h("\\Eta","\\mathrm{H}");h("\\exist","\\exists");h("\\harr","\\leftrightarrow");h("\\hArr","\\Leftrightarrow");h("\\Harr","\\Leftrightarrow");h("\\hearts","\\heartsuit");h("\\image","\\Im");h("\\infin","\\infty");h("\\Iota","\\mathrm{I}");h("\\isin","\\in");h("\\Kappa","\\mathrm{K}");h("\\larr","\\leftarrow");h("\\lArr","\\Leftarrow");h("\\Larr","\\Leftarrow");h("\\lrarr","\\leftrightarrow");h("\\lrArr","\\Leftrightarrow");h("\\Lrarr","\\Leftrightarrow");h("\\Mu","\\mathrm{M}");h("\\natnums","\\mathbb{N}");h("\\Nu","\\mathrm{N}");h("\\Omicron","\\mathrm{O}");h("\\plusmn","\\pm");h("\\rarr","\\rightarrow");h("\\rArr","\\Rightarrow");h("\\Rarr","\\Rightarrow");h("\\real","\\Re");h("\\reals","\\mathbb{R}");h("\\Reals","\\mathbb{R}");h("\\Rho","\\mathrm{P}");h("\\sdot","\\cdot");h("\\sect","\\S");h("\\spades","\\spadesuit");h("\\sub","\\subset");h("\\sube","\\subseteq");h("\\supe","\\supseteq");h("\\Tau","\\mathrm{T}");h("\\thetasym","\\vartheta");h("\\weierp","\\wp");h("\\Zeta","\\mathrm{Z}");h("\\argmin","\\DOTSB\\operatorname*{arg\\,min}");h("\\argmax","\\DOTSB\\operatorname*{arg\\,max}");h("\\plim","\\DOTSB\\mathop{\\operatorname{plim}}\\limits");h("\\bra","\\mathinner{\\langle{#1}|}");h("\\ket","\\mathinner{|{#1}\\rangle}");h("\\braket","\\mathinner{\\langle{#1}\\rangle}");h("\\Bra","\\left\\langle#1\\right|");h("\\Ket","\\left|#1\\right\\rangle");var Ta=r=>e=>{var t=e.consumeArg().tokens,a=e.consumeArg().tokens,n=e.consumeArg().tokens,s=e.consumeArg().tokens,l=e.macros.get("|"),c=e.macros.get("\\|");e.macros.beginGroup();var m=b=>x=>{r&&(x.macros.set("|",l),n.length&&x.macros.set("\\|",c));var y=b;if(!b&&n.length){var T=x.future();T.text==="|"&&(x.popToken(),y=!0)}return{tokens:y?n:a,numArgs:0}};e.macros.set("|",m(!1)),n.length&&e.macros.set("\\|",m(!0));var d=e.consumeArg().tokens,v=e.expandTokens([...s,...d,...t]);return e.macros.endGroup(),{tokens:v.reverse(),numArgs:0}};h("\\bra@ket",Ta(!1));h("\\bra@set",Ta(!0));h("\\Braket","\\bra@ket{\\left\\langle}{\\,\\middle\\vert\\,}{\\,\\middle\\vert\\,}{\\right\\rangle}");h("\\Set","\\bra@set{\\left\\{\\:}{\\;\\middle\\vert\\;}{\\;\\middle\\Vert\\;}{\\:\\right\\}}");h("\\set","\\bra@set{\\{\\,}{\\mid}{}{\\,\\}}");h("\\angln","{\\angl n}");h("\\blue","\\textcolor{##6495ed}{#1}");h("\\orange","\\textcolor{##ffa500}{#1}");h("\\pink","\\textcolor{##ff00af}{#1}");h("\\red","\\textcolor{##df0030}{#1}");h("\\green","\\textcolor{##28ae7b}{#1}");h("\\gray","\\textcolor{gray}{#1}");h("\\purple","\\textcolor{##9d38bd}{#1}");h("\\blueA","\\textcolor{##ccfaff}{#1}");h("\\blueB","\\textcolor{##80f6ff}{#1}");h("\\blueC","\\textcolor{##63d9ea}{#1}");h("\\blueD","\\textcolor{##11accd}{#1}");h("\\blueE","\\textcolor{##0c7f99}{#1}");h("\\tealA","\\textcolor{##94fff5}{#1}");h("\\tealB","\\textcolor{##26edd5}{#1}");h("\\tealC","\\textcolor{##01d1c1}{#1}");h("\\tealD","\\textcolor{##01a995}{#1}");h("\\tealE","\\textcolor{##208170}{#1}");h("\\greenA","\\textcolor{##b6ffb0}{#1}");h("\\greenB","\\textcolor{##8af281}{#1}");h("\\greenC","\\textcolor{##74cf70}{#1}");h("\\greenD","\\textcolor{##1fab54}{#1}");h("\\greenE","\\textcolor{##0d923f}{#1}");h("\\goldA","\\textcolor{##ffd0a9}{#1}");h("\\goldB","\\textcolor{##ffbb71}{#1}");h("\\goldC","\\textcolor{##ff9c39}{#1}");h("\\goldD","\\textcolor{##e07d10}{#1}");h("\\goldE","\\textcolor{##a75a05}{#1}");h("\\redA","\\textcolor{##fca9a9}{#1}");h("\\redB","\\textcolor{##ff8482}{#1}");h("\\redC","\\textcolor{##f9685d}{#1}");h("\\redD","\\textcolor{##e84d39}{#1}");h("\\redE","\\textcolor{##bc2612}{#1}");h("\\maroonA","\\textcolor{##ffbde0}{#1}");h("\\maroonB","\\textcolor{##ff92c6}{#1}");h("\\maroonC","\\textcolor{##ed5fa6}{#1}");h("\\maroonD","\\textcolor{##ca337c}{#1}");h("\\maroonE","\\textcolor{##9e034e}{#1}");h("\\purpleA","\\textcolor{##ddd7ff}{#1}");h("\\purpleB","\\textcolor{##c6b9fc}{#1}");h("\\purpleC","\\textcolor{##aa87ff}{#1}");h("\\purpleD","\\textcolor{##7854ab}{#1}");h("\\purpleE","\\textcolor{##543b78}{#1}");h("\\mintA","\\textcolor{##f5f9e8}{#1}");h("\\mintB","\\textcolor{##edf2df}{#1}");h("\\mintC","\\textcolor{##e0e5cc}{#1}");h("\\grayA","\\textcolor{##f6f7f7}{#1}");h("\\grayB","\\textcolor{##f0f1f2}{#1}");h("\\grayC","\\textcolor{##e3e5e6}{#1}");h("\\grayD","\\textcolor{##d6d8da}{#1}");h("\\grayE","\\textcolor{##babec2}{#1}");h("\\grayF","\\textcolor{##888d93}{#1}");h("\\grayG","\\textcolor{##626569}{#1}");h("\\grayH","\\textcolor{##3b3e40}{#1}");h("\\grayI","\\textcolor{##21242c}{#1}");h("\\kaBlue","\\textcolor{##314453}{#1}");h("\\kaGreen","\\textcolor{##71B307}{#1}");var qa={"^":!0,_:!0,"\\limits":!0,"\\nolimits":!0};class Gn{constructor(e,t,a){this.settings=void 0,this.expansionCount=void 0,this.lexer=void 0,this.macros=void 0,this.stack=void 0,this.mode=void 0,this.settings=t,this.expansionCount=0,this.feed(e),this.macros=new Fn(Hn,t.macros),this.mode=a,this.stack=[]}feed(e){this.lexer=new Or(e,this.settings)}switchMode(e){this.mode=e}beginGroup(){this.macros.beginGroup()}endGroup(){this.macros.endGroup()}endGroups(){this.macros.endGroups()}future(){return this.stack.length===0&&this.pushToken(this.lexer.lex()),this.stack[this.stack.length-1]}popToken(){return this.future(),this.stack.pop()}pushToken(e){this.stack.push(e)}pushTokens(e){this.stack.push(...e)}scanArgument(e){var t,a,n;if(e){if(this.consumeSpaces(),this.future().text!=="[")return null;t=this.popToken(),{tokens:n,end:a}=this.consumeArg(["]"])}else({tokens:n,start:t,end:a}=this.consumeArg());return this.pushToken(new p0("EOF",a.loc)),this.pushTokens(n),new p0("",m0.range(t,a))}consumeSpaces(){for(;;){var e=this.future();if(e.text===" ")this.stack.pop();else break}}consumeArg(e){var t=[],a=e&&e.length>0;a||this.consumeSpaces();var n=this.future(),s,l=0,c=0;do{if(s=this.popToken(),t.push(s),s.text==="{")++l;else if(s.text==="}"){if(--l,l===-1)throw new z("Extra }",s)}else if(s.text==="EOF")throw new z("Unexpected end of input in a macro argument, expected '"+(e&&a?e[c]:"}")+"'",s);if(e&&a)if((l===0||l===1&&e[c]==="{")&&s.text===e[c]){if(++c,c===e.length){t.splice(-c,c);break}}else c=0}while(l!==0||a);return n.text==="{"&&t[t.length-1].text==="}"&&(t.pop(),t.shift()),t.reverse(),{tokens:t,start:n,end:s}}consumeArgs(e,t){if(t){if(t.length!==e+1)throw new z("The length of delimiters doesn't match the number of args!");for(var a=t[0],n=0;nthis.settings.maxExpand)throw new z("Too many expansions: infinite loop or need to increase maxExpand setting")}expandOnce(e){var t=this.popToken(),a=t.text,n=t.noexpand?null:this._getExpansion(a);if(n==null||e&&n.unexpandable){if(e&&n==null&&a[0]==="\\"&&!this.isDefined(a))throw new z("Undefined control sequence: "+a);return this.pushToken(t),!1}this.countExpansion(1);var s=n.tokens,l=this.consumeArgs(n.numArgs,n.delimiters);if(n.numArgs){s=s.slice();for(var c=s.length-1;c>=0;--c){var m=s[c];if(m.text==="#"){if(c===0)throw new z("Incomplete placeholder at end of macro body",m);if(m=s[--c],m.text==="#")s.splice(c+1,1);else if(/^[1-9]$/.test(m.text))s.splice(c,2,...l[+m.text-1]);else throw new z("Not a valid argument number",m)}}}return this.pushTokens(s),s.length}expandAfterFuture(){return this.expandOnce(),this.future()}expandNextToken(){for(;;)if(this.expandOnce()===!1){var e=this.stack.pop();return e.treatAsRelax&&(e.text="\\relax"),e}}expandMacro(e){return this.macros.has(e)?this.expandTokens([new p0(e)]):void 0}expandTokens(e){var t=[],a=this.stack.length;for(this.pushTokens(e);this.stack.length>a;)if(this.expandOnce(!0)===!1){var n=this.stack.pop();n.treatAsRelax&&(n.noexpand=!1,n.treatAsRelax=!1),t.push(n)}return this.countExpansion(t.length),t}expandMacroAsText(e){var t=this.expandMacro(e);return t&&t.map(a=>a.text).join("")}_getExpansion(e){var t=this.macros.get(e);if(t==null)return t;if(e.length===1){var a=this.lexer.catcodes[e];if(a!=null&&a!==13)return}var n=typeof t=="function"?t(this):t;if(typeof n=="string"){var s=0;if(n.includes("#"))for(var l=n.replace(/##/g,"");l.includes("#"+(s+1));)++s;for(var c=new Or(n,this.settings),m=[],d=c.lex();d.text!=="EOF";)m.push(d),d=c.lex();m.reverse();var v={tokens:m,numArgs:s};return v}return n}isDefined(e){return this.macros.has(e)||H0.hasOwnProperty(e)||Z.math.hasOwnProperty(e)||Z.text.hasOwnProperty(e)||qa.hasOwnProperty(e)}isExpandable(e){var t=this.macros.get(e);return t!=null?typeof t=="string"||typeof t=="function"||!t.unexpandable:H0.hasOwnProperty(e)&&!H0[e].primitive}}var Nr=/^[₊₋₌₍₎₀₁₂₃₄₅₆₇₈₉ₐₑₕᵢⱼₖₗₘₙₒₚᵣₛₜᵤᵥₓᵦᵧᵨᵩᵪ]/,Ce=Object.freeze({"₊":"+","₋":"-","₌":"=","₍":"(","₎":")","₀":"0","₁":"1","₂":"2","₃":"3","₄":"4","₅":"5","₆":"6","₇":"7","₈":"8","₉":"9","ₐ":"a","ₑ":"e","ₕ":"h","ᵢ":"i","ⱼ":"j","ₖ":"k","ₗ":"l","ₘ":"m","ₙ":"n","ₒ":"o","ₚ":"p","ᵣ":"r","ₛ":"s","ₜ":"t","ᵤ":"u","ᵥ":"v","ₓ":"x","ᵦ":"β","ᵧ":"γ","ᵨ":"ρ","ᵩ":"ϕ","ᵪ":"χ","⁺":"+","⁻":"-","⁼":"=","⁽":"(","⁾":")","⁰":"0","¹":"1","²":"2","³":"3","⁴":"4","⁵":"5","⁶":"6","⁷":"7","⁸":"8","⁹":"9","ᴬ":"A","ᴮ":"B","ᴰ":"D","ᴱ":"E","ᴳ":"G","ᴴ":"H","ᴵ":"I","ᴶ":"J","ᴷ":"K","ᴸ":"L","ᴹ":"M","ᴺ":"N","ᴼ":"O","ᴾ":"P","ᴿ":"R","ᵀ":"T","ᵁ":"U","ⱽ":"V","ᵂ":"W","ᵃ":"a","ᵇ":"b","ᶜ":"c","ᵈ":"d","ᵉ":"e","ᶠ":"f","ᵍ":"g",ʰ:"h","ⁱ":"i",ʲ:"j","ᵏ":"k",ˡ:"l","ᵐ":"m",ⁿ:"n","ᵒ":"o","ᵖ":"p",ʳ:"r",ˢ:"s","ᵗ":"t","ᵘ":"u","ᵛ":"v",ʷ:"w",ˣ:"x",ʸ:"y","ᶻ":"z","ᵝ":"β","ᵞ":"γ","ᵟ":"δ","ᵠ":"ϕ","ᵡ":"χ","ᶿ":"θ"}),mt={"́":{text:"\\'",math:"\\acute"},"̀":{text:"\\`",math:"\\grave"},"̈":{text:'\\"',math:"\\ddot"},"̃":{text:"\\~",math:"\\tilde"},"̄":{text:"\\=",math:"\\bar"},"̆":{text:"\\u",math:"\\breve"},"̌":{text:"\\v",math:"\\check"},"̂":{text:"\\^",math:"\\hat"},"̇":{text:"\\.",math:"\\dot"},"̊":{text:"\\r",math:"\\mathring"},"̋":{text:"\\H"},"̧":{text:"\\c"}},Fr={á:"á",à:"à",ä:"ä",ǟ:"ǟ",ã:"ã",ā:"ā",ă:"ă",ắ:"ắ",ằ:"ằ",ẵ:"ẵ",ǎ:"ǎ",â:"â",ấ:"ấ",ầ:"ầ",ẫ:"ẫ",ȧ:"ȧ",ǡ:"ǡ",å:"å",ǻ:"ǻ",ḃ:"ḃ",ć:"ć",ḉ:"ḉ",č:"č",ĉ:"ĉ",ċ:"ċ",ç:"ç",ď:"ď",ḋ:"ḋ",ḑ:"ḑ",é:"é",è:"è",ë:"ë",ẽ:"ẽ",ē:"ē",ḗ:"ḗ",ḕ:"ḕ",ĕ:"ĕ",ḝ:"ḝ",ě:"ě",ê:"ê",ế:"ế",ề:"ề",ễ:"ễ",ė:"ė",ȩ:"ȩ",ḟ:"ḟ",ǵ:"ǵ",ḡ:"ḡ",ğ:"ğ",ǧ:"ǧ",ĝ:"ĝ",ġ:"ġ",ģ:"ģ",ḧ:"ḧ",ȟ:"ȟ",ĥ:"ĥ",ḣ:"ḣ",ḩ:"ḩ",í:"í",ì:"ì",ï:"ï",ḯ:"ḯ",ĩ:"ĩ",ī:"ī",ĭ:"ĭ",ǐ:"ǐ",î:"î",ǰ:"ǰ",ĵ:"ĵ",ḱ:"ḱ",ǩ:"ǩ",ķ:"ķ",ĺ:"ĺ",ľ:"ľ",ļ:"ļ",ḿ:"ḿ",ṁ:"ṁ",ń:"ń",ǹ:"ǹ",ñ:"ñ",ň:"ň",ṅ:"ṅ",ņ:"ņ",ó:"ó",ò:"ò",ö:"ö",ȫ:"ȫ",õ:"õ",ṍ:"ṍ",ṏ:"ṏ",ȭ:"ȭ",ō:"ō",ṓ:"ṓ",ṑ:"ṑ",ŏ:"ŏ",ǒ:"ǒ",ô:"ô",ố:"ố",ồ:"ồ",ỗ:"ỗ",ȯ:"ȯ",ȱ:"ȱ",ő:"ő",ṕ:"ṕ",ṗ:"ṗ",ŕ:"ŕ",ř:"ř",ṙ:"ṙ",ŗ:"ŗ",ś:"ś",ṥ:"ṥ",š:"š",ṧ:"ṧ",ŝ:"ŝ",ṡ:"ṡ",ş:"ş",ẗ:"ẗ",ť:"ť",ṫ:"ṫ",ţ:"ţ",ú:"ú",ù:"ù",ü:"ü",ǘ:"ǘ",ǜ:"ǜ",ǖ:"ǖ",ǚ:"ǚ",ũ:"ũ",ṹ:"ṹ",ū:"ū",ṻ:"ṻ",ŭ:"ŭ",ǔ:"ǔ",û:"û",ů:"ů",ű:"ű",ṽ:"ṽ",ẃ:"ẃ",ẁ:"ẁ",ẅ:"ẅ",ŵ:"ŵ",ẇ:"ẇ",ẘ:"ẘ",ẍ:"ẍ",ẋ:"ẋ",ý:"ý",ỳ:"ỳ",ÿ:"ÿ",ỹ:"ỹ",ȳ:"ȳ",ŷ:"ŷ",ẏ:"ẏ",ẙ:"ẙ",ź:"ź",ž:"ž",ẑ:"ẑ",ż:"ż",Á:"Á",À:"À",Ä:"Ä",Ǟ:"Ǟ",Ã:"Ã",Ā:"Ā",Ă:"Ă",Ắ:"Ắ",Ằ:"Ằ",Ẵ:"Ẵ",Ǎ:"Ǎ",Â:"Â",Ấ:"Ấ",Ầ:"Ầ",Ẫ:"Ẫ",Ȧ:"Ȧ",Ǡ:"Ǡ",Å:"Å",Ǻ:"Ǻ",Ḃ:"Ḃ",Ć:"Ć",Ḉ:"Ḉ",Č:"Č",Ĉ:"Ĉ",Ċ:"Ċ",Ç:"Ç",Ď:"Ď",Ḋ:"Ḋ",Ḑ:"Ḑ",É:"É",È:"È",Ë:"Ë",Ẽ:"Ẽ",Ē:"Ē",Ḗ:"Ḗ",Ḕ:"Ḕ",Ĕ:"Ĕ",Ḝ:"Ḝ",Ě:"Ě",Ê:"Ê",Ế:"Ế",Ề:"Ề",Ễ:"Ễ",Ė:"Ė",Ȩ:"Ȩ",Ḟ:"Ḟ",Ǵ:"Ǵ",Ḡ:"Ḡ",Ğ:"Ğ",Ǧ:"Ǧ",Ĝ:"Ĝ",Ġ:"Ġ",Ģ:"Ģ",Ḧ:"Ḧ",Ȟ:"Ȟ",Ĥ:"Ĥ",Ḣ:"Ḣ",Ḩ:"Ḩ",Í:"Í",Ì:"Ì",Ï:"Ï",Ḯ:"Ḯ",Ĩ:"Ĩ",Ī:"Ī",Ĭ:"Ĭ",Ǐ:"Ǐ",Î:"Î",İ:"İ",Ĵ:"Ĵ",Ḱ:"Ḱ",Ǩ:"Ǩ",Ķ:"Ķ",Ĺ:"Ĺ",Ľ:"Ľ",Ļ:"Ļ",Ḿ:"Ḿ",Ṁ:"Ṁ",Ń:"Ń",Ǹ:"Ǹ",Ñ:"Ñ",Ň:"Ň",Ṅ:"Ṅ",Ņ:"Ņ",Ó:"Ó",Ò:"Ò",Ö:"Ö",Ȫ:"Ȫ",Õ:"Õ",Ṍ:"Ṍ",Ṏ:"Ṏ",Ȭ:"Ȭ",Ō:"Ō",Ṓ:"Ṓ",Ṑ:"Ṑ",Ŏ:"Ŏ",Ǒ:"Ǒ",Ô:"Ô",Ố:"Ố",Ồ:"Ồ",Ỗ:"Ỗ",Ȯ:"Ȯ",Ȱ:"Ȱ",Ő:"Ő",Ṕ:"Ṕ",Ṗ:"Ṗ",Ŕ:"Ŕ",Ř:"Ř",Ṙ:"Ṙ",Ŗ:"Ŗ",Ś:"Ś",Ṥ:"Ṥ",Š:"Š",Ṧ:"Ṧ",Ŝ:"Ŝ",Ṡ:"Ṡ",Ş:"Ş",Ť:"Ť",Ṫ:"Ṫ",Ţ:"Ţ",Ú:"Ú",Ù:"Ù",Ü:"Ü",Ǘ:"Ǘ",Ǜ:"Ǜ",Ǖ:"Ǖ",Ǚ:"Ǚ",Ũ:"Ũ",Ṹ:"Ṹ",Ū:"Ū",Ṻ:"Ṻ",Ŭ:"Ŭ",Ǔ:"Ǔ",Û:"Û",Ů:"Ů",Ű:"Ű",Ṽ:"Ṽ",Ẃ:"Ẃ",Ẁ:"Ẁ",Ẅ:"Ẅ",Ŵ:"Ŵ",Ẇ:"Ẇ",Ẍ:"Ẍ",Ẋ:"Ẋ",Ý:"Ý",Ỳ:"Ỳ",Ÿ:"Ÿ",Ỹ:"Ỹ",Ȳ:"Ȳ",Ŷ:"Ŷ",Ẏ:"Ẏ",Ź:"Ź",Ž:"Ž",Ẑ:"Ẑ",Ż:"Ż",ά:"ά",ὰ:"ὰ",ᾱ:"ᾱ",ᾰ:"ᾰ",έ:"έ",ὲ:"ὲ",ή:"ή",ὴ:"ὴ",ί:"ί",ὶ:"ὶ",ϊ:"ϊ",ΐ:"ΐ",ῒ:"ῒ",ῑ:"ῑ",ῐ:"ῐ",ό:"ό",ὸ:"ὸ",ύ:"ύ",ὺ:"ὺ",ϋ:"ϋ",ΰ:"ΰ",ῢ:"ῢ",ῡ:"ῡ",ῠ:"ῠ",ώ:"ώ",ὼ:"ὼ",Ύ:"Ύ",Ὺ:"Ὺ",Ϋ:"Ϋ",Ῡ:"Ῡ",Ῠ:"Ῠ",Ώ:"Ώ",Ὼ:"Ὼ"};class We{constructor(e,t){this.mode=void 0,this.gullet=void 0,this.settings=void 0,this.leftrightDepth=void 0,this.nextToken=void 0,this.mode="math",this.gullet=new Gn(e,t,this.mode),this.settings=t,this.leftrightDepth=0,this.nextToken=null}expect(e,t){if(t===void 0&&(t=!0),this.fetch().text!==e)throw new z("Expected '"+e+"', got '"+this.fetch().text+"'",this.fetch());t&&this.consume()}consume(){this.nextToken=null}fetch(){return this.nextToken==null&&(this.nextToken=this.gullet.expandNextToken()),this.nextToken}switchMode(e){this.mode=e,this.gullet.switchMode(e)}parse(){this.settings.globalGroup||this.gullet.beginGroup(),this.settings.colorIsTextColor&&this.gullet.macros.set("\\color","\\textcolor");try{var e=this.parseExpression(!1);return this.expect("EOF"),this.settings.globalGroup||this.gullet.endGroup(),e}finally{this.gullet.endGroups()}}subparse(e){var t=this.nextToken;this.consume(),this.gullet.pushToken(new p0("}")),this.gullet.pushTokens(e);var a=this.parseExpression(!1);return this.expect("}"),this.nextToken=t,a}parseExpression(e,t){for(var a=[];;){this.mode==="math"&&this.consumeSpaces();var n=this.fetch();if(We.endOfExpression.has(n.text)||t&&n.text===t||e&&H0[n.text]&&H0[n.text].infix)break;var s=this.parseAtom(t);if(s){if(s.type==="internal")continue}else break;a.push(s)}return this.mode==="text"&&this.formLigatures(a),this.handleInfixNodes(a)}handleInfixNodes(e){for(var t=-1,a,n=0;n=128)this.settings.strict&&(Hr(t.charCodeAt(0))?this.mode==="math"&&this.settings.reportNonstrict("unicodeTextInMathMode",'Unicode text character "'+t[0]+'" used in math mode',e):this.settings.reportNonstrict("unknownSymbol",'Unrecognized Unicode character "'+t[0]+'"'+(" ("+t.charCodeAt(0)+")"),e)),l={type:"textord",mode:"text",loc:m0.range(e),text:t};else return null;if(this.consume(),s)for(var v=0;v=0;s--)e[s].loc.start>n&&(a+=" ",n=e[s].loc.start),a+=e[s].text,n+=e[s].text.length;var l=W.go(w.go(a,t));return l},w={go:function(e,t){if(!e)return[];t===void 0&&(t="ce");var a="0",n={};n.parenthesisLevel=0,e=e.replace(/\n/g," "),e=e.replace(/[\u2212\u2013\u2014\u2010]/g,"-"),e=e.replace(/[\u2026]/g,"...");for(var s,l=10,c=[];;){s!==e?(l=10,s=e):l--;var m=w.stateMachines[t],d=m.transitions[a]||m.transitions["*"];e:for(var v=0;v0){if(x.revisit||(e=b.remainder),!x.toContinue)break e}else return c}}if(l<=0)throw["MhchemBugU","mhchem bug U. Please report."]}},concatArray:function(e,t){if(t)if(Array.isArray(t))for(var a=0;a":/^[=<>]/,"#":/^[#\u2261]/,"+":/^\+/,"-$":/^-(?=[\s_},;\]/]|$|\([a-z]+\))/,"-9":/^-(?=[0-9])/,"- orbital overlap":/^-(?=(?:[spd]|sp)(?:$|[\s,;\)\]\}]))/,"-":/^-/,"pm-operator":/^(?:\\pm|\$\\pm\$|\+-|\+\/-)/,operator:/^(?:\+|(?:[\-=<>]|<<|>>|\\approx|\$\\approx\$)(?=\s|$|-?[0-9]))/,arrowUpDown:/^(?:v|\(v\)|\^|\(\^\))(?=$|[\s,;\)\]\}])/,"\\bond{(...)}":function(e){return w.patterns.findObserveGroups(e,"\\bond{","","","}")},"->":/^(?:<->|<-->|->|<-|<=>>|<<=>|<=>|[\u2192\u27F6\u21CC])/,CMT:/^[CMT](?=\[)/,"[(...)]":function(e){return w.patterns.findObserveGroups(e,"[","","","]")},"1st-level escape":/^(&|\\\\|\\hline)\s*/,"\\,":/^(?:\\[,\ ;:])/,"\\x{}{}":function(e){return w.patterns.findObserveGroups(e,"",/^\\[a-zA-Z]+\{/,"}","","","{","}","",!0)},"\\x{}":function(e){return w.patterns.findObserveGroups(e,"",/^\\[a-zA-Z]+\{/,"}","")},"\\ca":/^\\ca(?:\s+|(?![a-zA-Z]))/,"\\x":/^(?:\\[a-zA-Z]+\s*|\\[_&{}%])/,orbital:/^(?:[0-9]{1,2}[spdfgh]|[0-9]{0,2}sp)(?=$|[^a-zA-Z])/,others:/^[\/~|]/,"\\frac{(...)}":function(e){return w.patterns.findObserveGroups(e,"\\frac{","","","}","{","","","}")},"\\overset{(...)}":function(e){return w.patterns.findObserveGroups(e,"\\overset{","","","}","{","","","}")},"\\underset{(...)}":function(e){return w.patterns.findObserveGroups(e,"\\underset{","","","}","{","","","}")},"\\underbrace{(...)}":function(e){return w.patterns.findObserveGroups(e,"\\underbrace{","","","}_","{","","","}")},"\\color{(...)}0":function(e){return w.patterns.findObserveGroups(e,"\\color{","","","}")},"\\color{(...)}{(...)}1":function(e){return w.patterns.findObserveGroups(e,"\\color{","","","}","{","","","}")},"\\color(...){(...)}2":function(e){return w.patterns.findObserveGroups(e,"\\color","\\","",/^(?=\{)/,"{","","","}")},"\\ce{(...)}":function(e){return w.patterns.findObserveGroups(e,"\\ce{","","","}")},oxidation$:/^(?:[+-][IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"d-oxidation$":/^(?:[+-]?\s?[IVX]+|\\pm\s*0|\$\\pm\$\s*0)$/,"roman numeral":/^[IVX]+/,"1/2$":/^[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+(?:\$[a-z]\$|[a-z])?$/,amount:function(e){var t;if(t=e.match(/^(?:(?:(?:\([+\-]?[0-9]+\/[0-9]+\)|[+\-]?(?:[0-9]+|\$[a-z]\$|[a-z])\/[0-9]+|[+\-]?[0-9]+[.,][0-9]+|[+\-]?\.[0-9]+|[+\-]?[0-9]+)(?:[a-z](?=\s*[A-Z]))?)|[+\-]?[a-z](?=\s*[A-Z])|\+(?!\s))/),t)return{match_:t[0],remainder:e.substr(t[0].length)};var a=w.patterns.findObserveGroups(e,"","$","$","");return a&&(t=a.match_.match(/^\$(?:\(?[+\-]?(?:[0-9]*[a-z]?[+\-])?[0-9]*[a-z](?:[+\-][0-9]*[a-z]?)?\)?|\+|-)\$$/),t)?{match_:t[0],remainder:e.substr(t[0].length)}:null},amount2:function(e){return this.amount(e)},"(KV letters),":/^(?:[A-Z][a-z]{0,2}|i)(?=,)/,formula$:function(e){if(e.match(/^\([a-z]+\)$/))return null;var t=e.match(/^(?:[a-z]|(?:[0-9\ \+\-\,\.\(\)]+[a-z])+[0-9\ \+\-\,\.\(\)]*|(?:[a-z][0-9\ \+\-\,\.\(\)]+)+[a-z]?)$/);return t?{match_:t[0],remainder:e.substr(t[0].length)}:null},uprightEntities:/^(?:pH|pOH|pC|pK|iPr|iBu)(?=$|[^a-zA-Z])/,"/":/^\s*(\/)\s*/,"//":/^\s*(\/\/)\s*/,"*":/^\s*[*.]\s*/},findObserveGroups:function(e,t,a,n,s,l,c,m,d,v){var b=function($,E){if(typeof E=="string")return $.indexOf(E)!==0?null:E;var F=$.match(E);return F?F[0]:null},x=function($,E,F){for(var H=0;E<$.length;){var G=$.charAt(E),P=b($.substr(E),F);if(P!==null&&H===0)return{endMatchBegin:E,endMatchEnd:E+P.length};if(G==="{")H++;else if(G==="}"){if(H===0)throw["ExtraCloseMissingOpen","Extra close brace or missing open brace"];H--}E++}return H>0,null},y=b(e,t);if(y===null||(e=e.substr(y.length),y=b(e,a),y===null))return null;var T=x(e,y.length,n||s);if(T===null)return null;var q=e.substring(0,n?T.endMatchEnd:T.endMatchBegin);if(l||c){var D=this.findObserveGroups(e.substr(T.endMatchEnd),l,c,m,d);if(D===null)return null;var B=[q,D.match_];return{match_:v?B.join(""):B,remainder:D.remainder}}else return{match_:q,remainder:e.substr(T.endMatchEnd)}},match_:function(e,t){var a=w.patterns.patterns[e];if(a===void 0)throw["MhchemBugP","mhchem bug P. Please report. ("+e+")"];if(typeof a=="function")return w.patterns.patterns[e](t);var n=t.match(a);if(n){var s;return n[2]?s=[n[1],n[2]]:n[1]?s=n[1]:s=n[0],{match_:s,remainder:t.substr(n[0].length)}}return null}},actions:{"a=":function(e,t){e.a=(e.a||"")+t},"b=":function(e,t){e.b=(e.b||"")+t},"p=":function(e,t){e.p=(e.p||"")+t},"o=":function(e,t){e.o=(e.o||"")+t},"q=":function(e,t){e.q=(e.q||"")+t},"d=":function(e,t){e.d=(e.d||"")+t},"rm=":function(e,t){e.rm=(e.rm||"")+t},"text=":function(e,t){e.text_=(e.text_||"")+t},insert:function(e,t,a){return{type_:a}},"insert+p1":function(e,t,a){return{type_:a,p1:t}},"insert+p1+p2":function(e,t,a){return{type_:a,p1:t[0],p2:t[1]}},copy:function(e,t){return t},rm:function(e,t){return{type_:"rm",p1:t||""}},text:function(e,t){return w.go(t,"text")},"{text}":function(e,t){var a=["{"];return w.concatArray(a,w.go(t,"text")),a.push("}"),a},"tex-math":function(e,t){return w.go(t,"tex-math")},"tex-math tight":function(e,t){return w.go(t,"tex-math tight")},bond:function(e,t,a){return{type_:"bond",kind_:a||t}},"color0-output":function(e,t){return{type_:"color0",color:t[0]}},ce:function(e,t){return w.go(t)},"1/2":function(e,t){var a=[];t.match(/^[+\-]/)&&(a.push(t.substr(0,1)),t=t.substr(1));var n=t.match(/^([0-9]+|\$[a-z]\$|[a-z])\/([0-9]+)(\$[a-z]\$|[a-z])?$/);return n[1]=n[1].replace(/\$/g,""),a.push({type_:"frac",p1:n[1],p2:n[2]}),n[3]&&(n[3]=n[3].replace(/\$/g,""),a.push({type_:"tex-math",p1:n[3]})),a},"9,9":function(e,t){return w.go(t,"9,9")}},createTransitions:function(e){var t,a,n,s,l={};for(t in e)for(a in e[t])for(n=a.split("|"),e[t][a].stateArray=n,s=0;s":{"0|1|2|3":{action_:"r=",nextState:"r"},"a|as":{action_:["output","r="],nextState:"r"},"*":{action_:["output","r="],nextState:"r"}},"+":{o:{action_:"d= kv",nextState:"d"},"d|D":{action_:"d=",nextState:"d"},q:{action_:"d=",nextState:"qd"},"qd|qD":{action_:"d=",nextState:"qd"},dq:{action_:["output","d="],nextState:"d"},3:{action_:["sb=false","output","operator"],nextState:"0"}},amount:{"0|2":{action_:"a=",nextState:"a"}},"pm-operator":{"0|1|2|a|as":{action_:["sb=false","output",{type_:"operator",option:"\\pm"}],nextState:"0"}},operator:{"0|1|2|a|as":{action_:["sb=false","output","operator"],nextState:"0"}},"-$":{"o|q":{action_:["charge or bond","output"],nextState:"qd"},d:{action_:"d=",nextState:"d"},D:{action_:["output",{type_:"bond",option:"-"}],nextState:"3"},q:{action_:"d=",nextState:"qd"},qd:{action_:"d=",nextState:"qd"},"qD|dq":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},"-9":{"3|o":{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"3"}},"- orbital overlap":{o:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},d:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"}},"-":{"0|1|2":{action_:[{type_:"output",option:1},"beginsWithBond=true",{type_:"bond",option:"-"}],nextState:"3"},3:{action_:{type_:"bond",option:"-"}},a:{action_:["output",{type_:"insert",option:"hyphen"}],nextState:"2"},as:{action_:[{type_:"output",option:2},{type_:"bond",option:"-"}],nextState:"3"},b:{action_:"b="},o:{action_:{type_:"- after o/d",option:!1},nextState:"2"},q:{action_:{type_:"- after o/d",option:!1},nextState:"2"},"d|qd|dq":{action_:{type_:"- after o/d",option:!0},nextState:"2"},"D|qD|p":{action_:["output",{type_:"bond",option:"-"}],nextState:"3"}},amount2:{"1|3":{action_:"a=",nextState:"a"}},letters:{"0|1|2|3|a|as|b|p|bp|o":{action_:"o=",nextState:"o"},"q|dq":{action_:["output","o="],nextState:"o"},"d|D|qd|qD":{action_:"o after d",nextState:"o"}},digits:{o:{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},q:{action_:["output","o="],nextState:"o"},a:{action_:"o=",nextState:"o"}},"space A":{"b|p|bp":{}},space:{a:{nextState:"as"},0:{action_:"sb=false"},"1|2":{action_:"sb=true"},"r|rt|rd|rdt|rdq":{action_:"output",nextState:"0"},"*":{action_:["output","sb=true"],nextState:"1"}},"1st-level escape":{"1|2":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}]},"*":{action_:["output",{type_:"insert+p1",option:"1st-level escape"}],nextState:"0"}},"[(...)]":{"r|rt":{action_:"rd=",nextState:"rd"},"rd|rdt":{action_:"rq=",nextState:"rdq"}},"...":{"o|d|D|dq|qd|qD":{action_:["output",{type_:"bond",option:"..."}],nextState:"3"},"*":{action_:[{type_:"output",option:1},{type_:"insert",option:"ellipsis"}],nextState:"1"}},". |* ":{"*":{action_:["output",{type_:"insert",option:"addition compound"}],nextState:"1"}},"state of aggregation $":{"*":{action_:["output","state of aggregation"],nextState:"1"}},"{[(":{"a|as|o":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"0|1|2|3":{action_:["o=","output","parenthesisLevel++"],nextState:"2"},"*":{action_:["output","o=","output","parenthesisLevel++"],nextState:"2"}},")]}":{"0|1|2|3|b|p|bp|o":{action_:["o=","parenthesisLevel--"],nextState:"o"},"a|as|d|D|q|qd|qD|dq":{action_:["output","o=","parenthesisLevel--"],nextState:"o"}},", ":{"*":{action_:["output","comma"],nextState:"0"}},"^_":{"*":{}},"^{(...)}|^($...$)":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"D"},q:{action_:"d=",nextState:"qD"},"d|D|qd|qD|dq":{action_:["output","d="],nextState:"D"}},"^a|^\\x{}{}|^\\x{}|^\\x|'":{"0|1|2|as":{action_:"b=",nextState:"b"},p:{action_:"b=",nextState:"bp"},"3|o":{action_:"d= kv",nextState:"d"},q:{action_:"d=",nextState:"qd"},"d|qd|D|qD":{action_:"d="},dq:{action_:["output","d="],nextState:"d"}},"_{(state of aggregation)}$":{"d|D|q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"_{(...)}|_($...$)|_9|_\\x{}{}|_\\x{}|_\\x":{"0|1|2|as":{action_:"p=",nextState:"p"},b:{action_:"p=",nextState:"bp"},"3|o":{action_:"q=",nextState:"q"},"d|D":{action_:"q=",nextState:"dq"},"q|qd|qD|dq":{action_:["output","q="],nextState:"q"}},"=<>":{"0|1|2|3|a|as|o|q|d|D|qd|qD|dq":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"#":{"0|1|2|3|a|as|o":{action_:[{type_:"output",option:2},{type_:"bond",option:"#"}],nextState:"3"}},"{}":{"*":{action_:{type_:"output",option:1},nextState:"1"}},"{...}":{"0|1|2|3|a|as|b|p|bp":{action_:"o=",nextState:"o"},"o|d|D|q|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"$...$":{a:{action_:"a="},"0|1|2|3|as|b|p|bp|o":{action_:"o=",nextState:"o"},"as|o":{action_:"o="},"q|d|D|qd|qD|dq":{action_:["output","o="],nextState:"o"}},"\\bond{(...)}":{"*":{action_:[{type_:"output",option:2},"bond"],nextState:"3"}},"\\frac{(...)}":{"*":{action_:[{type_:"output",option:1},"frac-output"],nextState:"3"}},"\\overset{(...)}":{"*":{action_:[{type_:"output",option:2},"overset-output"],nextState:"3"}},"\\underset{(...)}":{"*":{action_:[{type_:"output",option:2},"underset-output"],nextState:"3"}},"\\underbrace{(...)}":{"*":{action_:[{type_:"output",option:2},"underbrace-output"],nextState:"3"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:[{type_:"output",option:2},"color-output"],nextState:"3"}},"\\color{(...)}0":{"*":{action_:[{type_:"output",option:2},"color0-output"]}},"\\ce{(...)}":{"*":{action_:[{type_:"output",option:2},"ce"],nextState:"3"}},"\\,":{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"1"}},"\\x{}{}|\\x{}|\\x":{"0|1|2|3|a|as|b|p|bp|o|c0":{action_:["o=","output"],nextState:"3"},"*":{action_:["output","o=","output"],nextState:"3"}},others:{"*":{action_:[{type_:"output",option:1},"copy"],nextState:"3"}},else2:{a:{action_:"a to o",nextState:"o",revisit:!0},as:{action_:["output","sb=true"],nextState:"1",revisit:!0},"r|rt|rd|rdt|rdq":{action_:["output"],nextState:"0",revisit:!0},"*":{action_:["output","copy"],nextState:"3"}}}),actions:{"o after d":function(e,t){var a;if((e.d||"").match(/^[0-9]+$/)){var n=e.d;e.d=void 0,a=this.output(e),e.b=n}else a=this.output(e);return w.actions["o="](e,t),a},"d= kv":function(e,t){e.d=t,e.dType="kv"},"charge or bond":function(e,t){if(e.beginsWithBond){var a=[];return w.concatArray(a,this.output(e)),w.concatArray(a,w.actions.bond(e,t,"-")),a}else e.d=t},"- after o/d":function(e,t,a){var n=w.patterns.match_("orbital",e.o||""),s=w.patterns.match_("one lowercase greek letter $",e.o||""),l=w.patterns.match_("one lowercase latin letter $",e.o||""),c=w.patterns.match_("$one lowercase latin letter$ $",e.o||""),m=t==="-"&&(n&&n.remainder===""||s||l||c);m&&!e.a&&!e.b&&!e.p&&!e.d&&!e.q&&!n&&l&&(e.o="$"+e.o+"$");var d=[];return m?(w.concatArray(d,this.output(e)),d.push({type_:"hyphen"})):(n=w.patterns.match_("digits",e.d||""),a&&n&&n.remainder===""?(w.concatArray(d,w.actions["d="](e,t)),w.concatArray(d,this.output(e))):(w.concatArray(d,this.output(e)),w.concatArray(d,w.actions.bond(e,t,"-")))),d},"a to o":function(e){e.o=e.a,e.a=void 0},"sb=true":function(e){e.sb=!0},"sb=false":function(e){e.sb=!1},"beginsWithBond=true":function(e){e.beginsWithBond=!0},"beginsWithBond=false":function(e){e.beginsWithBond=!1},"parenthesisLevel++":function(e){e.parenthesisLevel++},"parenthesisLevel--":function(e){e.parenthesisLevel--},"state of aggregation":function(e,t){return{type_:"state of aggregation",p1:w.go(t,"o")}},comma:function(e,t){var a=t.replace(/\s*$/,""),n=a!==t;return n&&e.parenthesisLevel===0?{type_:"comma enumeration L",p1:a}:{type_:"comma enumeration M",p1:a}},output:function(e,t,a){var n;if(!e.r)n=[],!e.a&&!e.b&&!e.p&&!e.o&&!e.q&&!e.d&&!a||(e.sb&&n.push({type_:"entitySkip"}),!e.o&&!e.q&&!e.d&&!e.b&&!e.p&&a!==2?(e.o=e.a,e.a=void 0):!e.o&&!e.q&&!e.d&&(e.b||e.p)?(e.o=e.a,e.d=e.b,e.q=e.p,e.a=e.b=e.p=void 0):e.o&&e.dType==="kv"&&w.patterns.match_("d-oxidation$",e.d||"")?e.dType="oxidation":e.o&&e.dType==="kv"&&!e.q&&(e.dType=void 0),n.push({type_:"chemfive",a:w.go(e.a,"a"),b:w.go(e.b,"bd"),p:w.go(e.p,"pq"),o:w.go(e.o,"o"),q:w.go(e.q,"pq"),d:w.go(e.d,e.dType==="oxidation"?"oxidation":"bd"),dType:e.dType}));else{var s;e.rdt==="M"?s=w.go(e.rd,"tex-math"):e.rdt==="T"?s=[{type_:"text",p1:e.rd||""}]:s=w.go(e.rd);var l;e.rqt==="M"?l=w.go(e.rq,"tex-math"):e.rqt==="T"?l=[{type_:"text",p1:e.rq||""}]:l=w.go(e.rq),n={type_:"arrow",r:e.r,rd:s,rq:l}}for(var c in e)c!=="parenthesisLevel"&&c!=="beginsWithBond"&&delete e[c];return n},"oxidation-output":function(e,t){var a=["{"];return w.concatArray(a,w.go(t,"oxidation")),a.push("}"),a},"frac-output":function(e,t){return{type_:"frac-ce",p1:w.go(t[0]),p2:w.go(t[1])}},"overset-output":function(e,t){return{type_:"overset",p1:w.go(t[0]),p2:w.go(t[1])}},"underset-output":function(e,t){return{type_:"underset",p1:w.go(t[0]),p2:w.go(t[1])}},"underbrace-output":function(e,t){return{type_:"underbrace",p1:w.go(t[0]),p2:w.go(t[1])}},"color-output":function(e,t){return{type_:"color",color1:t[0],color2:w.go(t[1])}},"r=":function(e,t){e.r=t},"rdt=":function(e,t){e.rdt=t},"rd=":function(e,t){e.rd=t},"rqt=":function(e,t){e.rqt=t},"rq=":function(e,t){e.rq=t},operator:function(e,t,a){return{type_:"operator",kind_:a||t}}}},a:{transitions:w.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},"$(...)$":{"*":{action_:"tex-math tight",nextState:"1"}},",":{"*":{action_:{type_:"insert",option:"commaDecimal"}}},else2:{"*":{action_:"copy"}}}),actions:{}},o:{transitions:w.createTransitions({empty:{"*":{}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"1",revisit:!0}},letters:{"*":{action_:"rm"}},"\\ca":{"*":{action_:{type_:"insert",option:"circa"}}},"\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"{text}"}},else2:{"*":{action_:"copy"}}}),actions:{}},text:{transitions:w.createTransitions({empty:{"*":{action_:"output"}},"{...}":{"*":{action_:"text="}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"\\greek":{"*":{action_:["output","rm"]}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:["output","copy"]}},else:{"*":{action_:"text="}}}),actions:{output:function(e){if(e.text_){var t={type_:"text",p1:e.text_};for(var a in e)delete e[a];return t}}}},pq:{transitions:w.createTransitions({empty:{"*":{}},"state of aggregation $":{"*":{action_:"state of aggregation"}},i$:{0:{nextState:"!f",revisit:!0}},"(KV letters),":{0:{action_:"rm",nextState:"0"}},formula$:{0:{nextState:"f",revisit:!0}},"1/2$":{0:{action_:"1/2"}},else:{0:{nextState:"!f",revisit:!0}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"a-z":{f:{action_:"tex-math"}},letters:{"*":{action_:"rm"}},"-9.,9":{"*":{action_:"9,9"}},",":{"*":{action_:{type_:"insert+p1",option:"comma enumeration S"}}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"state of aggregation":function(e,t){return{type_:"state of aggregation subscript",p1:w.go(t,"o")}},"color-output":function(e,t){return{type_:"color",color1:t[0],color2:w.go(t[1],"pq")}}}},bd:{transitions:w.createTransitions({empty:{"*":{}},x$:{0:{nextState:"!f",revisit:!0}},formula$:{0:{nextState:"f",revisit:!0}},else:{0:{nextState:"!f",revisit:!0}},"-9.,9 no missing 0":{"*":{action_:"9,9"}},".":{"*":{action_:{type_:"insert",option:"electron dot"}}},"a-z":{f:{action_:"tex-math"}},x:{"*":{action_:{type_:"insert",option:"KV x"}}},letters:{"*":{action_:"rm"}},"'":{"*":{action_:{type_:"insert",option:"prime"}}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},"{(...)}":{"*":{action_:"text"}},"\\color{(...)}{(...)}1|\\color(...){(...)}2":{"*":{action_:"color-output"}},"\\color{(...)}0":{"*":{action_:"color0-output"}},"\\ce{(...)}":{"*":{action_:"ce"}},"\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"copy"}},else2:{"*":{action_:"copy"}}}),actions:{"color-output":function(e,t){return{type_:"color",color1:t[0],color2:w.go(t[1],"bd")}}}},oxidation:{transitions:w.createTransitions({empty:{"*":{}},"roman numeral":{"*":{action_:"roman-numeral"}},"${(...)}$|$(...)$":{"*":{action_:"tex-math"}},else:{"*":{action_:"copy"}}}),actions:{"roman-numeral":function(e,t){return{type_:"roman numeral",p1:t||""}}}},"tex-math":{transitions:w.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},else:{"*":{action_:"o="}}}),actions:{output:function(e){if(e.o){var t={type_:"tex-math",p1:e.o};for(var a in e)delete e[a];return t}}}},"tex-math tight":{transitions:w.createTransitions({empty:{"*":{action_:"output"}},"\\ce{(...)}":{"*":{action_:["output","ce"]}},"{...}|\\,|\\x{}{}|\\x{}|\\x":{"*":{action_:"o="}},"-|+":{"*":{action_:"tight operator"}},else:{"*":{action_:"o="}}}),actions:{"tight operator":function(e,t){e.o=(e.o||"")+"{"+t+"}"},output:function(e){if(e.o){var t={type_:"tex-math",p1:e.o};for(var a in e)delete e[a];return t}}}},"9,9":{transitions:w.createTransitions({empty:{"*":{}},",":{"*":{action_:"comma"}},else:{"*":{action_:"copy"}}}),actions:{comma:function(){return{type_:"commaDecimal"}}}},pu:{transitions:w.createTransitions({empty:{"*":{action_:"output"}},space$:{"*":{action_:["output","space"]}},"{[(|)]}":{"0|a":{action_:"copy"}},"(-)(9)^(-9)":{0:{action_:"number^",nextState:"a"}},"(-)(9.,9)(e)(99)":{0:{action_:"enumber",nextState:"a"}},space:{"0|a":{}},"pm-operator":{"0|a":{action_:{type_:"operator",option:"\\pm"},nextState:"0"}},operator:{"0|a":{action_:"copy",nextState:"0"}},"//":{d:{action_:"o=",nextState:"/"}},"/":{d:{action_:"o=",nextState:"/"}},"{...}|else":{"0|d":{action_:"d=",nextState:"d"},a:{action_:["space","d="],nextState:"d"},"/|q":{action_:"q=",nextState:"q"}}}),actions:{enumber:function(e,t){var a=[];return t[0]==="+-"||t[0]==="+/-"?a.push("\\pm "):t[0]&&a.push(t[0]),t[1]&&(w.concatArray(a,w.go(t[1],"pu-9,9")),t[2]&&(t[2].match(/[,.]/)?w.concatArray(a,w.go(t[2],"pu-9,9")):a.push(t[2])),t[3]=t[4]||t[3],t[3]&&(t[3]=t[3].trim(),t[3]==="e"||t[3].substr(0,1)==="*"?a.push({type_:"cdot"}):a.push({type_:"times"}))),t[3]&&a.push("10^{"+t[5]+"}"),a},"number^":function(e,t){var a=[];return t[0]==="+-"||t[0]==="+/-"?a.push("\\pm "):t[0]&&a.push(t[0]),w.concatArray(a,w.go(t[1],"pu-9,9")),a.push("^{"+t[2]+"}"),a},operator:function(e,t,a){return{type_:"operator",kind_:a||t}},space:function(){return{type_:"pu-space-1"}},output:function(e){var t,a=w.patterns.match_("{(...)}",e.d||"");a&&a.remainder===""&&(e.d=a.match_);var n=w.patterns.match_("{(...)}",e.q||"");if(n&&n.remainder===""&&(e.q=n.match_),e.d&&(e.d=e.d.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),e.d=e.d.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F")),e.q){e.q=e.q.replace(/\u00B0C|\^oC|\^{o}C/g,"{}^{\\circ}C"),e.q=e.q.replace(/\u00B0F|\^oF|\^{o}F/g,"{}^{\\circ}F");var s={d:w.go(e.d,"pu"),q:w.go(e.q,"pu")};e.o==="//"?t={type_:"pu-frac",p1:s.d,p2:s.q}:(t=s.d,s.d.length>1||s.q.length>1?t.push({type_:" / "}):t.push({type_:"/"}),w.concatArray(t,s.q))}else t=w.go(e.d,"pu-2");for(var l in e)delete e[l];return t}}},"pu-2":{transitions:w.createTransitions({empty:{"*":{action_:"output"}},"*":{"*":{action_:["output","cdot"],nextState:"0"}},"\\x":{"*":{action_:"rm="}},space:{"*":{action_:["output","space"],nextState:"0"}},"^{(...)}|^(-1)":{1:{action_:"^(-1)"}},"-9.,9":{0:{action_:"rm=",nextState:"0"},1:{action_:"^(-1)",nextState:"0"}},"{...}|else":{"*":{action_:"rm=",nextState:"1"}}}),actions:{cdot:function(){return{type_:"tight cdot"}},"^(-1)":function(e,t){e.rm+="^{"+t+"}"},space:function(){return{type_:"pu-space-2"}},output:function(e){var t=[];if(e.rm){var a=w.patterns.match_("{(...)}",e.rm||"");a&&a.remainder===""?t=w.go(a.match_,"pu"):t={type_:"rm",p1:e.rm}}for(var n in e)delete e[n];return t}}},"pu-9,9":{transitions:w.createTransitions({empty:{0:{action_:"output-0"},o:{action_:"output-o"}},",":{0:{action_:["output-0","comma"],nextState:"o"}},".":{0:{action_:["output-0","copy"],nextState:"o"}},else:{"*":{action_:"text="}}}),actions:{comma:function(){return{type_:"commaDecimal"}},"output-0":function(e){var t=[];if(e.text_=e.text_||"",e.text_.length>4){var a=e.text_.length%3;a===0&&(a=3);for(var n=e.text_.length-3;n>0;n-=3)t.push(e.text_.substr(n,3)),t.push({type_:"1000 separator"});t.push(e.text_.substr(0,a)),t.reverse()}else t.push(e.text_);for(var s in e)delete e[s];return t},"output-o":function(e){var t=[];if(e.text_=e.text_||"",e.text_.length>4){for(var a=e.text_.length-3,n=0;n":return"rightarrow";case"→":return"rightarrow";case"⟶":return"rightarrow";case"<-":return"leftarrow";case"<->":return"leftrightarrow";case"<-->":return"rightleftarrows";case"<=>":return"rightleftharpoons";case"⇌":return"rightleftharpoons";case"<=>>":return"rightequilibrium";case"<<=>":return"leftequilibrium";default:throw["MhchemBugT","mhchem bug T. Please report."]}},_getBond:function(e){switch(e){case"-":return"{-}";case"1":return"{-}";case"=":return"{=}";case"2":return"{=}";case"#":return"{\\equiv}";case"3":return"{\\equiv}";case"~":return"{\\tripledash}";case"~-":return"{\\mathrlap{\\raisebox{-.1em}{$-$}}\\raisebox{.1em}{$\\tripledash$}}";case"~=":return"{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case"~--":return"{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$\\tripledash$}}-}";case"-~-":return"{\\mathrlap{\\raisebox{-.2em}{$-$}}\\mathrlap{\\raisebox{.2em}{$-$}}\\tripledash}";case"...":return"{{\\cdot}{\\cdot}{\\cdot}}";case"....":return"{{\\cdot}{\\cdot}{\\cdot}{\\cdot}}";case"->":return"{\\rightarrow}";case"<-":return"{\\leftarrow}";case"<":return"{<}";case">":return"{>}";default:throw["MhchemBugT","mhchem bug T. Please report."]}},_getOperator:function(e){switch(e){case"+":return" {}+{} ";case"-":return" {}-{} ";case"=":return" {}={} ";case"<":return" {}<{} ";case">":return" {}>{} ";case"<<":return" {}\\ll{} ";case">>":return" {}\\gg{} ";case"\\pm":return" {}\\pm{} ";case"\\approx":return" {}\\approx{} ";case"$\\approx$":return" {}\\approx{} ";case"v":return" \\downarrow{} ";case"(v)":return" \\downarrow{} ";case"^":return" \\uparrow{} ";case"(^)":return" \\uparrow{} ";default:throw["MhchemBugT","mhchem bug T. Please report."]}}};let Be=!1;globalThis.addEventListener("message",r=>{var e,t,a,n;const s=r.data||{};if(s.type==="init"){Be=!!s.debug;try{Be&&console.debug("[katexRenderer.worker] debug enabled")}catch{}return}const l=(e=s.id)!=null?e:"",c=(t=s.content)!=null?t:"",m=(a=s.displayMode)==null||a;try{Be&&console.debug("[katexRenderer.worker] render start",{id:l,displayMode:m,content:c});const d={id:l,html:Ye.renderToString(c,{throwOnError:!0,displayMode:m,output:"html",strict:"ignore"}),content:c,displayMode:m};try{globalThis.postMessage(d),Be&&console.debug("[katexRenderer.worker] render success",{id:l})}catch(v){console.error("[katexRenderer.worker] failed to postMessage result",v)}}catch(d){const v={id:l,error:String((n=d?.message)!=null?n:d),content:c,displayMode:m};try{globalThis.postMessage(v)}catch(b){console.error("[katexRenderer.worker] failed to postMessage error",b)}}}),globalThis.addEventListener("error",r=>{var e;console.error("[katexRenderer.worker] uncaught error",r.message,r.error);try{globalThis.postMessage({id:"__worker_uncaught__",error:String((e=r.message)!=null?e:r.error),content:"",displayMode:!0})}catch{}}); diff --git a/apps/kimi-code/dist-web/assets/laserwave-DUszq2jm.js b/apps/kimi-code/dist-web/assets/laserwave-DUszq2jm.js new file mode 100644 index 0000000000000000000000000000000000000000..a050c7e8c29e4faa9917922cad31d33e9572351d --- /dev/null +++ b/apps/kimi-code/dist-web/assets/laserwave-DUszq2jm.js @@ -0,0 +1 @@ +const t=Object.freeze(JSON.parse('{"colors":{"activityBar.activeBorder":"#EB64B9","activityBar.background":"#27212e","activityBar.foreground":"#ddd","activityBarBadge.background":"#EB64B9","button.background":"#EB64B9","diffEditor.border":"#b4dce7","diffEditor.insertedTextBackground":"#74dfc423","diffEditor.removedTextBackground":"#eb64b940","editor.background":"#27212e","editor.findMatchBackground":"#40b4c48c","editor.findMatchHighlightBackground":"#40b4c460","editor.foreground":"#ffffff","editor.selectionBackground":"#eb64b927","editor.selectionHighlightBackground":"#eb64b927","editor.wordHighlightBackground":"#eb64b927","editorError.foreground":"#ff3e7b","editorGroupHeader.tabsBackground":"#242029","editorGutter.addedBackground":"#74dfc4","editorGutter.deletedBackground":"#eb64B9","editorGutter.modifiedBackground":"#40b4c4","editorSuggestWidget.border":"#b4dce7","focusBorder":"#EB64B9","gitDecoration.conflictingResourceForeground":"#EB64B9","gitDecoration.deletedResourceForeground":"#b381c5","gitDecoration.ignoredResourceForeground":"#92889d","gitDecoration.modifiedResourceForeground":"#74dfc4","gitDecoration.untrackedResourceForeground":"#40b4c4","input.background":"#3a3242","input.border":"#964c7b","inputOption.activeBorder":"#EB64B9","list.activeSelectionBackground":"#eb64b98f","list.activeSelectionForeground":"#eee","list.dropBackground":"#74dfc466","list.errorForeground":"#ff3e7b","list.focusBackground":"#eb64ba60","list.highlightForeground":"#eb64b9","list.hoverBackground":"#91889b80","list.hoverForeground":"#eee","list.inactiveSelectionBackground":"#eb64b98f","list.inactiveSelectionForeground":"#ddd","list.invalidItemForeground":"#fff","menu.background":"#27212e","merge.currentContentBackground":"#74dfc433","merge.currentHeaderBackground":"#74dfc4cc","merge.incomingContentBackground":"#40b4c433","merge.incomingHeaderBackground":"#40b4c4cc","notifications.background":"#3e3549","peekView.border":"#40b4c4","peekViewEditor.background":"#40b5c449","peekViewEditor.matchHighlightBackground":"#40b5c460","peekViewResult.matchHighlightBackground":"#27212e","peekViewResult.selectionBackground":"#40b4c43f","progressBar.background":"#40b4c4","sideBar.background":"#27212e","sideBar.foreground":"#ddd","sideBarSectionHeader.background":"#27212e","sideBarTitle.foreground":"#EB64B9","statusBar.background":"#EB64B9","statusBar.debuggingBackground":"#74dfc4","statusBar.foreground":"#27212e","statusBar.noFolderBackground":"#EB64B9","tab.activeBorder":"#EB64B9","tab.inactiveBackground":"#242029","terminal.ansiBlue":"#40b4c4","terminal.ansiCyan":"#b4dce7","terminal.ansiGreen":"#74dfc4","terminal.ansiMagenta":"#b381c5","terminal.ansiRed":"#EB64B9","terminal.ansiYellow":"#ffe261","titleBar.activeBackground":"#27212e","titleBar.inactiveBackground":"#27212e","tree.indentGuidesStroke":"#ffffff33"},"displayName":"LaserWave","name":"laserwave","tokenColors":[{"scope":["keyword.other","keyword.control","storage.type.class.js","keyword.control.module.js","storage.type.extends.js","variable.language.this.js","keyword.control.switch.js","keyword.control.loop.js","keyword.control.conditional.js","keyword.control.flow.js","keyword.operator.accessor.js","keyword.other.important.css","keyword.control.at-rule.media.scss","entity.name.tag.reference.scss","meta.class.python","storage.type.function.python","keyword.control.flow.python","storage.type.function.js","keyword.control.export.ts","keyword.control.flow.ts","keyword.control.from.ts","keyword.control.import.ts","storage.type.class.ts","keyword.control.loop.ts","keyword.control.ruby","keyword.control.module.ruby","keyword.control.class.ruby","keyword.other.special-method.ruby","keyword.control.def.ruby","markup.heading","keyword.other.import.java","keyword.other.package.java","storage.modifier.java","storage.modifier.extends.java","storage.modifier.implements.java","storage.modifier.cs","storage.modifier.js","storage.modifier.dart","keyword.declaration.dart","keyword.package.go","keyword.import.go","keyword.fsharp","variable.parameter.function-call.python"],"settings":{"foreground":"#40b4c4"}},{"scope":["binding.fsharp","support.function","meta.function-call","entity.name.function","support.function.misc.scss","meta.method.declaration.ts","entity.name.function.method.js"],"settings":{"foreground":"#EB64B9"}},{"scope":["string","string.quoted","string.unquoted","string.other.link.title.markdown"],"settings":{"foreground":"#b4dce7"}},{"scope":["constant.numeric"],"settings":{"foreground":"#b381c5"}},{"scope":["meta.brace","punctuation","punctuation.bracket","punctuation.section","punctuation.separator","punctuation.comma.dart","punctuation.terminator","punctuation.definition","punctuation.parenthesis","meta.delimiter.comma.js","meta.brace.curly.litobj.js","punctuation.definition.tag","puncatuation.other.comma.go","punctuation.section.embedded","punctuation.definition.string","punctuation.definition.tag.jsx","punctuation.definition.tag.end","punctuation.definition.markdown","punctuation.terminator.rule.css","punctuation.definition.block.ts","punctuation.definition.tag.html","punctuation.section.class.end.js","punctuation.definition.tag.begin","punctuation.squarebracket.open.cs","punctuation.separator.dict.python","punctuation.section.function.scss","punctuation.section.class.begin.js","punctuation.section.array.end.ruby","punctuation.separator.key-value.js","meta.method-call.with-arguments.js","punctuation.section.scope.end.ruby","punctuation.squarebracket.close.cs","punctuation.separator.key-value.css","punctuation.definition.constant.css","punctuation.section.array.begin.ruby","punctuation.section.scope.begin.ruby","punctuation.definition.string.end.js","punctuation.definition.parameters.ruby","punctuation.definition.string.begin.js","punctuation.section.class.begin.python","storage.modifier.array.bracket.square.c","punctuation.separator.parameters.python","punctuation.section.group.end.powershell","punctuation.definition.parameters.end.ts","punctuation.section.braces.end.powershell","punctuation.section.function.begin.python","punctuation.definition.parameters.begin.ts","punctuation.section.bracket.end.powershell","punctuation.section.group.begin.powershell","punctuation.section.braces.begin.powershell","punctuation.definition.parameters.end.python","punctuation.definition.typeparameters.end.cs","punctuation.section.bracket.begin.powershell","punctuation.definition.arguments.begin.python","punctuation.definition.parameters.begin.python","punctuation.definition.typeparameters.begin.cs","punctuation.section.block.begin.bracket.curly.c","punctuation.definition.map.begin.bracket.round.scss","punctuation.section.property-list.end.bracket.curly.css","punctuation.definition.parameters.end.bracket.round.java","punctuation.section.property-list.begin.bracket.curly.css","punctuation.definition.parameters.begin.bracket.round.java"],"settings":{"foreground":"#7b6995"}},{"scope":["keyword.operator","meta.decorator.ts","entity.name.type.ts","punctuation.dot.dart","keyword.symbol.fsharp","punctuation.accessor.ts","punctuation.accessor.cs","keyword.operator.logical","meta.tag.inline.any.html","punctuation.separator.java","keyword.operator.comparison","keyword.operator.arithmetic","keyword.operator.assignment","keyword.operator.ternary.js","keyword.operator.other.ruby","keyword.operator.logical.js","punctuation.other.period.go","keyword.operator.increment.ts","keyword.operator.increment.js","storage.type.function.arrow.js","storage.type.function.arrow.ts","keyword.operator.relational.js","keyword.operator.relational.ts","keyword.operator.arithmetic.js","keyword.operator.assignment.js","storage.type.function.arrow.tsx","keyword.operator.logical.python","punctuation.separator.period.java","punctuation.separator.method.ruby","keyword.operator.assignment.python","keyword.operator.arithmetic.python","keyword.operator.increment-decrement.java"],"settings":{"foreground":"#74dfc4"}},{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"#91889b"}},{"scope":["meta.tag.sgml","entity.name.tag","entity.name.tag.open.jsx","entity.name.tag.close.jsx","entity.name.tag.inline.any.html","entity.name.tag.structure.any.html"],"settings":{"foreground":"#74dfc4"}},{"scope":["variable.other.enummember","entity.other.attribute-name","entity.other.attribute-name.jsx","entity.other.attribute-name.html","entity.other.attribute-name.id.css","entity.other.attribute-name.id.html","entity.other.attribute-name.class.css"],"settings":{"foreground":"#EB64B9"}},{"scope":["variable.other.property","variable.parameter.fsharp","support.variable.property.js","support.type.property-name.css","support.type.property-name.json","support.variable.property.dom.js"],"settings":{"foreground":"#40b4c4"}},{"scope":["constant.language","constant.other.elm","constant.language.c","variable.language.dart","variable.language.this","support.class.builtin.js","support.constant.json.ts","support.class.console.ts","support.class.console.js","variable.language.this.js","variable.language.this.ts","entity.name.section.fsharp","support.type.object.dom.js","variable.other.constant.js","variable.language.self.ruby","variable.other.constant.ruby","support.type.object.console.js","constant.language.undefined.js","support.function.builtin.python","constant.language.boolean.true.js","constant.language.boolean.false.js","variable.language.special.self.python","support.constant.automatic.powershell"],"settings":{"foreground":"#ffe261"}},{"scope":["variable.other","variable.scss","meta.function-call.c","variable.parameter.ts","variable.parameter.dart","variable.other.class.js","variable.other.object.js","variable.other.object.ts","support.function.json.ts","variable.name.source.dart","variable.other.source.dart","variable.other.readwrite.js","variable.other.readwrite.ts","support.function.console.ts","entity.name.type.instance.js","meta.function-call.arguments","variable.other.property.dom.ts","support.variable.property.dom.ts","variable.other.readwrite.powershell"],"settings":{"foreground":"#fff"}},{"scope":["storage.type.annotation","punctuation.definition.annotation","support.function.attribute.fsharp"],"settings":{"foreground":"#74dfc4"}},{"scope":["entity.name.type","storage.type","keyword.var.go","keyword.type.go","keyword.type.js","storage.type.js","storage.type.ts","keyword.type.cs","keyword.const.go","keyword.struct.go","support.class.dart","storage.modifier.c","storage.modifier.ts","keyword.function.go","keyword.operator.new.ts","meta.type.annotation.ts","entity.name.type.fsharp","meta.type.annotation.tsx","storage.modifier.async.js","punctuation.definition.variable.ruby","punctuation.definition.constant.ruby"],"settings":{"foreground":"#a96bc0"}},{"scope":["markup.bold","markup.italic"],"settings":{"foreground":"#EB64B9"}},{"scope":["meta.object-literal.key.js","constant.other.object.key.js"],"settings":{"foreground":"#40b4c4"}},{"scope":[],"settings":{"foreground":"#ffb85b"}},{"scope":["meta.diff","meta.diff.header"],"settings":{"foreground":"#40b4c4"}},{"scope":["meta.diff.range.unified"],"settings":{"foreground":"#b381c5"}},{"scope":["markup.deleted","punctuation.definition.deleted.diff","punctuation.definition.from-file.diff","meta.diff.header.from-file"],"settings":{"foreground":"#eb64b9"}},{"scope":["markup.inserted","punctuation.definition.inserted.diff","punctuation.definition.to-file.diff","meta.diff.header.to-file"],"settings":{"foreground":"#74dfc4"}}],"type":"dark"}'));export{t as default}; diff --git a/apps/kimi-code/dist-web/assets/latex-CaSxy8MP.js b/apps/kimi-code/dist-web/assets/latex-CaSxy8MP.js new file mode 100644 index 0000000000000000000000000000000000000000..8c472dce5a303ba836f56ddb65c543885a422541 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/latex-CaSxy8MP.js @@ -0,0 +1 @@ +import e from"./tex-idrVyKtj.js";import"./r-Dspwwk_N.js";const n=Object.freeze(JSON.parse('{"displayName":"LaTeX","name":"latex","patterns":[{"match":"(?<=\\\\\\\\(?:[@\\\\w]|[@\\\\w]{2}|[@\\\\w]{3}|[@\\\\w]{4}|[@\\\\w]{5}|[@\\\\w]{6}))\\\\s","name":"meta.space-after-command.latex"},{"include":"#songs-env"},{"include":"#embedded-code-env"},{"include":"#verbatim-env"},{"include":"#document-env"},{"include":"#all-balanced-env"},{"include":"#documentclass-usepackage-macro"},{"include":"#input-macro"},{"include":"#sections-macro"},{"include":"#hyperref-macro"},{"include":"#newcommand-macro"},{"include":"#text-font-macro"},{"include":"#citation-macro"},{"include":"#references-macro"},{"include":"#label-macro"},{"include":"#verb-macro"},{"include":"#inline-code-macro"},{"include":"#all-other-macro"},{"include":"#display-math"},{"include":"#inline-math"},{"include":"#column-specials"},{"include":"text.tex"}],"repository":{"all-balanced-env":{"patterns":[{"begin":"\\\\s*((\\\\\\\\)begin)(\\\\{)((?:\\\\+?array|equation|(?:IEEE|sub)?eqnarray|multline|align|aligned|alignat|alignedat|flalign|flaligned|flalignat|split|gather|gathered|(?:[+dr]|dr)?cases|(?:display)?math|\\\\+?[A-Za-z]*matrix|[BVbpv]?NiceMatrix|[BVbpv]?NiceArray|(?:arg)?m(?:ini|axi))[!*]?)(})(\\\\s*\\\\n)?","captures":{"1":{"name":"support.function.be.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"},"4":{"name":"variable.parameter.function.latex"},"5":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"meta.math.block.latex support.class.math.block.environment.latex","end":"\\\\s*((\\\\\\\\)end)(\\\\{)(\\\\4)(})(?:\\\\s*\\\\n)?","name":"meta.function.environment.math.latex","patterns":[{"match":"(?]*>)?((?:\\\\[[^]]*])*)(\\\\{)","captures":{"1":{"name":"keyword.control.cite.latex"},"2":{"name":"punctuation.definition.keyword.latex"},"3":{"patterns":[{"include":"#autocites-arg"}]},"4":{"patterns":[{"include":"#optional-arg-angle-no-highlight"}]},"5":{"patterns":[{"include":"#optional-arg-bracket-no-highlight"}]},"6":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"name":"meta.citation.latex","patterns":[{"captures":{"1":{"name":"comment.line.percentage.tex"},"2":{"name":"punctuation.definition.comment.tex"}},"match":"((%).*)$"},{"match":"[-.:\\\\p{Alphabetic}\\\\p{N}]+","name":"constant.other.reference.citation.latex"}]},"column-specials":{"captures":{"1":{"name":"punctuation.definition.column-specials.begin.latex"},"2":{"name":"punctuation.definition.column-specials.end.latex"}},"match":"[<>](\\\\{)\\\\$(})","name":"meta.column-specials.latex"},"display-math":{"patterns":[{"begin":"\\\\\\\\\\\\[","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.latex"}},"end":"\\\\\\\\]","endCaptures":{"0":{"name":"punctuation.definition.string.end.latex"}},"name":"meta.math.block.latex support.class.math.block.environment.latex","patterns":[{"include":"text.tex#math-content"},{"include":"$self"}]},{"begin":"\\\\$\\\\$","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.latex"}},"end":"\\\\$\\\\$","endCaptures":{"0":{"name":"punctuation.definition.string.end.latex"}},"name":"meta.math.block.latex support.class.math.block.environment.latex","patterns":[{"match":"\\\\\\\\\\\\$","name":"constant.character.escape.latex"},{"include":"text.tex#math-content"},{"include":"$self"}]}]},"document-env":{"patterns":[{"captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"match":"(\\\\s*\\\\\\\\begin\\\\{document})","name":"meta.function.begin-document.latex"},{"captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"match":"(\\\\s*\\\\\\\\end\\\\{document})","name":"meta.function.end-document.latex"}]},"documentclass-usepackage-macro":{"begin":"((\\\\\\\\)(?:usepackage|documentclass))\\\\b(?=[\\\\[{])","beginCaptures":{"1":{"name":"keyword.control.preamble.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"name":"meta.preamble.latex","patterns":[{"include":"#multiline-optional-arg"},{"begin":"((?:\\\\G|(?<=]))\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"support.class.latex","end":"(})","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"$self"}]}]},"embedded-code-env":{"patterns":[{"begin":"(?:^\\\\s*)?\\\\\\\\begin\\\\{(lstlisting|minted|pyglist)}(?=[\\\\[{])","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\\\\\end\\\\{\\\\1}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(asy(?:|mptote))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.asy","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.asy"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(bash)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.shell","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.shell"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(c(?:|pp))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.cpp.embedded.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.cpp.embedded.latex"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(css)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.css","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.css"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(gnuplot)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.gnuplot","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.gnuplot"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(h(?:s|askell))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.haskell","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.haskell"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(html)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"text.html","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"text.html.basic"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(java)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.java","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.java"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(j(?:l|ulia))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.julia","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.julia"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(j(?:s|avascript))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.js","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.js"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(lua)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.lua","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.lua"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(py|python|sage)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.python","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.python"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(r(?:b|uby))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.ruby","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.ruby"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(rust)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.rust","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.rust"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(t(?:s|ypescript))(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.ts","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.ts"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(xml)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"text.xml","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"text.xml"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)(yaml)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"source.yaml","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:minted|lstlisting|pyglist)})","patterns":[{"include":"source.yaml"}]},{"begin":"(?:\\\\G|(?<=]))(\\\\{)([A-Za-z]*)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"meta.function.embedded.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:lstlisting|minted|pyglist)})","name":"meta.embedded.block.generic.latex"}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{asy(?:|code)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{asy(?:|code)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.asymptote","end":"^\\\\s*(?=\\\\\\\\end\\\\{asy(?:|code)\\\\*?})","patterns":[{"include":"source.asymptote"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{cppcode\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{cppcode\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.cpp.embedded.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{cppcode\\\\*?})","patterns":[{"include":"source.cpp.embedded.latex"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{dot(?:2tex|code)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{dot(?:2tex|code)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.dot","end":"^\\\\s*(?=\\\\\\\\end\\\\{dot(?:2tex|code)\\\\*?})","patterns":[{"include":"source.dot"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{gnuplot\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{gnuplot\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.gnuplot","end":"^\\\\s*(?=\\\\\\\\end\\\\{gnuplot\\\\*?})","patterns":[{"include":"source.gnuplot"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{hscode\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{hscode\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.haskell","end":"^\\\\s*(?=\\\\\\\\end\\\\{hscode\\\\*?})","patterns":[{"include":"source.haskell"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{java(?:code|verbatim|block|concode|console|converbatim)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{java(?:code|verbatim|block|concode|console|converbatim)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.java","end":"^\\\\s*(?=\\\\\\\\end\\\\{java(?:code|verbatim|block|concode|console|converbatim)\\\\*?})","patterns":[{"include":"source.java"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{jl(?:code|verbatim|block|concode|console|converbatim)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{jl(?:code|verbatim|block|concode|console|converbatim)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.julia","end":"^\\\\s*(?=\\\\\\\\end\\\\{jl(?:code|verbatim|block|concode|console|converbatim)\\\\*?})","patterns":[{"include":"source.julia"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{julia(?:code|verbatim|block|concode|console|converbatim)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{julia(?:code|verbatim|block|concode|console|converbatim)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.julia","end":"^\\\\s*(?=\\\\\\\\end\\\\{julia(?:code|verbatim|block|concode|console|converbatim)\\\\*?})","patterns":[{"include":"source.julia"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{lua(?:code|draw)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{lua(?:code|draw)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.lua","end":"^\\\\s*(?=\\\\\\\\end\\\\{lua(?:code|draw)\\\\*?})","patterns":[{"include":"source.lua"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{py(?:code|verbatim|block|concode|console|converbatim)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{py(?:code|verbatim|block|concode|console|converbatim)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.python","end":"^\\\\s*(?=\\\\\\\\end\\\\{py(?:code|verbatim|block|concode|console|converbatim)\\\\*?})","patterns":[{"include":"source.python"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{pylab(?:code|verbatim|block|concode|console|converbatim)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{pylab(?:code|verbatim|block|concode|console|converbatim)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.python","end":"^\\\\s*(?=\\\\\\\\end\\\\{pylab(?:code|verbatim|block|concode|console|converbatim)\\\\*?})","patterns":[{"include":"source.python"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{(?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|pythonq??|pythonrepl)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{(?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|pythonq??|pythonrepl)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.python","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|pythonq??|pythonrepl)\\\\*?})","patterns":[{"include":"source.python"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{scalacode\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{scalacode\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.scala","end":"^\\\\s*(?=\\\\\\\\end\\\\{scalacode\\\\*?})","patterns":[{"include":"source.scala"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{sympy(?:code|verbatim|block|concode|console|converbatim)\\\\*?}(?:\\\\[[-0-9A-Z_a-z]*])?(?=[\\\\[{]|\\\\s*$)","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\s*\\\\\\\\end\\\\{sympy(?:code|verbatim|block|concode|console|converbatim)\\\\*?}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"variable.parameter.function.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}}},{"begin":"^(?=\\\\s*)","contentName":"source.python","end":"^\\\\s*(?=\\\\\\\\end\\\\{sympy(?:code|verbatim|block|concode|console|converbatim)\\\\*?})","patterns":[{"include":"source.python"}]}]},{"begin":"\\\\s*\\\\\\\\begin\\\\{((?:[A-Za-z]*code|lstlisting|minted|pyglist)\\\\*?)}(?:\\\\[.*])?(?:\\\\{.*})?","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"contentName":"meta.function.embedded.latex","end":"\\\\\\\\end\\\\{\\\\1}(?:\\\\s*\\\\n)?","name":"meta.embedded.block.generic.latex"},{"begin":"((?:^\\\\s*)?\\\\\\\\begin\\\\{((?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?))})(?:\\\\[[^]]*]){0,2}(?=\\\\{)","captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"(\\\\\\\\end\\\\{\\\\2})","patterns":[{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:asy(?:|mptote))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.asy","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.asy"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:bash)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.shell","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.shell"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:c(?:|pp))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.cpp.embedded.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.cpp.embedded.latex"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:css)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.css","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.css"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:gnuplot)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.gnuplot","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.gnuplot"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:h(?:s|askell))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.haskell","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.haskell"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:html)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"text.html","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"text.html.basic"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:java)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.java","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.java"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:j(?:l|ulia))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.julia","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.julia"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:j(?:s|avascript))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.js","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.js"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:lua)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.lua","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.lua"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:py|python|sage)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.python","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.python"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:r(?:b|uby))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.ruby","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.ruby"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:rust)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.rust","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.rust"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:t(?:s|ypescript))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.ts","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.ts"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:xml)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"text.xml","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"text.xml"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:yaml)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"source.yaml","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"source.yaml"}]}]},{"begin":"\\\\G(\\\\{)(?:__|[a-z\\\\s]*)(?i:tikz(?:|picture))","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"text.tex.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"include":"text.tex.latex"}]}]},{"begin":"\\\\G(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","patterns":[{"begin":"\\\\G","end":"(})\\\\s*$","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"},{"include":"$self"}]},{"begin":"^(\\\\s*)","contentName":"meta.function.embedded.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{(?:RobExt)?(?:CacheMeCode|PlaceholderPathFromCode\\\\*?|PlaceholderFromCode\\\\*?|SetPlaceholderCode\\\\*?)})","name":"meta.embedded.block.generic.latex"}]}]},{"begin":"(?:^\\\\s*)?\\\\\\\\begin\\\\{(terminal\\\\*?)}(?=[\\\\[{])","captures":{"0":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"end":"\\\\\\\\end\\\\{\\\\1}","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)([A-Za-z]*)(})","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"}},"contentName":"meta.function.embedded.latex","end":"^\\\\s*(?=\\\\\\\\end\\\\{terminal\\\\*?})","name":"meta.embedded.block.generic.latex"}]}]},"hyperref-macro":{"patterns":[{"begin":"\\\\s*((\\\\\\\\)h(?:ref|yperref|yperimage))(?=[\\\\[{])","beginCaptures":{"1":{"name":"support.function.url.latex"}},"end":"(})","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.latex"}},"name":"meta.function.hyperlink.latex","patterns":[{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=]))(\\\\{)([^}]*)(})(?:\\\\{[^}]*}){2}?(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"markup.underline.link.latex"},"3":{"name":"punctuation.definition.arguments.end.latex"},"4":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"meta.variable.parameter.function.latex","end":"(?=})","patterns":[{"include":"$self"}]},{"begin":"(?:\\\\G|(?<=]))(?:(\\\\{)[^}]*(}))?(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.latex"},"2":{"name":"punctuation.definition.arguments.end.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"meta.variable.parameter.function.latex","end":"(?=})","patterns":[{"include":"$self"}]}]},{"captures":{"1":{"name":"support.function.url.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"},"4":{"name":"markup.underline.link.latex"},"5":{"name":"punctuation.definition.arguments.end.latex"}},"match":"\\\\s*((\\\\\\\\)(?:url|path))(\\\\{)([^}]*)(})","name":"meta.function.link.url.latex"}]},"inline-code-macro":{"patterns":[{"begin":"((\\\\\\\\)addplot)\\\\+?(\\\\[[^\\\\[]*])*\\\\s*(gnuplot)\\\\s*(\\\\[[^\\\\[]*])*\\\\s*(\\\\{)","captures":{"1":{"name":"support.function.be.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"patterns":[{"include":"#optional-arg-bracket"}]},"4":{"name":"variable.parameter.function.latex"},"5":{"patterns":[{"include":"#optional-arg-bracket"}]},"6":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"\\\\s*(};)","patterns":[{"begin":"%","beginCaptures":{"0":{"name":"punctuation.definition.comment.latex"}},"end":"$\\\\n?","name":"comment.line.percentage.latex"},{"include":"source.gnuplot"}]},{"captures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"patterns":[{"include":"#optional-arg-bracket"}]},"4":{"name":"punctuation.definition.arguments.begin.latex"},"5":{"name":"punctuation.definition.arguments.end.latex"},"6":{"name":"punctuation.definition.verb.latex"},"7":{"name":"markup.raw.verb.latex"},"8":{"name":"punctuation.definition.verb.latex"},"9":{"name":"punctuation.definition.verb.latex"},"10":{"name":"markup.raw.verb.latex"},"11":{"name":"punctuation.definition.verb.latex"}},"match":"((\\\\\\\\)mint(?:|inline))((?:\\\\[[^\\\\[]*?])?)(\\\\{)[A-Za-z]*(})(?:([^A-Za-{])(.*?)(\\\\6)|(\\\\{)(.*?)(}))","name":"meta.function.verb.latex"},{"captures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"patterns":[{"include":"#optional-arg-bracket"}]},"4":{"name":"punctuation.definition.verb.latex"},"5":{"name":"markup.raw.verb.latex"},"6":{"name":"punctuation.definition.verb.latex"},"7":{"name":"punctuation.definition.verb.latex"},"8":{"name":"markup.raw.verb.latex"},"9":{"name":"punctuation.definition.verb.latex"}},"match":"((\\\\\\\\)[a-z]+inline)((?:\\\\[[^\\\\[]*?])?)(?:([^A-Za-{])(.*?)(\\\\4)|(\\\\{)(.*?)(}))","name":"meta.function.verb.latex"},{"captures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"patterns":[{"include":"#optional-arg-bracket"}]},"4":{"name":"punctuation.definition.verb.latex"},"5":{"name":"source.python","patterns":[{"include":"source.python"}]},"6":{"name":"punctuation.definition.verb.latex"},"7":{"name":"punctuation.definition.verb.latex"},"8":{"name":"source.python","patterns":[{"include":"source.python"}]},"9":{"name":"punctuation.definition.verb.latex"}},"match":"((\\\\\\\\)(?:(?:py|pycon|pylab|pylabcon|sympy|sympycon)[cv]?|pyq|pycq|pyif))((?:\\\\[[^\\\\[]*?])?)(?:([^](),;A-\\\\[a-{}\\\\s])(.*?)(\\\\4)|(\\\\{)(.*?)(}))","name":"meta.function.verb.latex"},{"captures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"patterns":[{"include":"#optional-arg-bracket"}]},"4":{"name":"punctuation.definition.verb.latex"},"5":{"name":"source.julia","patterns":[{"include":"source.julia"}]},"6":{"name":"punctuation.definition.verb.latex"},"7":{"name":"punctuation.definition.verb.latex"},"8":{"name":"source.julia","patterns":[{"include":"source.julia"}]},"9":{"name":"punctuation.definition.verb.latex"}},"match":"((\\\\\\\\)j(?:l|ulia)[cv]?)((?:\\\\[[^\\\\[]*?])?)(?:([^A-Za-{])(.*?)(\\\\4)|(\\\\{)(.*?)(}))","name":"meta.function.verb.latex"},{"begin":"((\\\\\\\\)(?:directlua|luadirect|luaexec))(\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.lua","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.lua"},{"include":"text.tex#braces"}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:asy(?:|mptote))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.asy","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.asy"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:bash)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.shell","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.shell"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:c(?:|pp))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.cpp.embedded.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.cpp.embedded.latex"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:css)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.css","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.css"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:gnuplot)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.gnuplot","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.gnuplot"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:h(?:s|askell))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.haskell","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.haskell"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:html)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"text.html","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.html.basic"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:java)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.java","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.java"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:j(?:l|ulia))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.julia","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.julia"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:j(?:s|avascript))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.js","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.js"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:lua)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.lua","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.lua"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:py|python|sage)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.python","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.python"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:r(?:b|uby))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.ruby","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.ruby"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:rust)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.rust","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.rust"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:t(?:s|ypescript))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.ts","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.ts"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:xml)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"text.xml","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.xml"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:yaml)\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"source.yaml","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"source.yaml"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=\\\\[(?i:tikz(?:|picture))\\\\b|\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"text.tex.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex.latex"}]}]},{"begin":"((\\\\\\\\)cacheMeCode)(?=[\\\\[{])","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"}},"end":"(?<=})","patterns":[{"include":"text.tex.latex#multiline-optional-arg-no-highlight"},{"begin":"(?<=])(\\\\{)","beginCaptures":{"0":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"meta.embedded.block.generic.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"patterns":[{"include":"text.tex#braces"}]}]}]},"inline-math":{"patterns":[{"begin":"\\\\\\\\\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.latex"}},"end":"\\\\\\\\\\\\)","endCaptures":{"0":{"name":"punctuation.definition.string.end.latex"}},"name":"meta.math.block.latex support.class.math.block.environment.latex","patterns":[{"include":"text.tex#math-content"},{"include":"$self"}]},{"begin":"\\\\$(?!\\\\$)","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.tex"}},"end":"(?)","name":"meta.parameter.optional.latex"}]},"optional-arg-bracket":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.arguments.optional.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.optional.end.latex"}},"match":"(\\\\[)([^\\\\[]*?)(])","name":"meta.parameter.optional.latex"}]},"optional-arg-bracket-no-highlight":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.arguments.optional.begin.latex"},"2":{"name":"punctuation.definition.arguments.optional.end.latex"}},"match":"(\\\\[)[^\\\\[]*?(])","name":"meta.parameter.optional.latex"}]},"optional-arg-parenthesis":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.arguments.optional.begin.latex"},"2":{"name":"variable.parameter.function.latex"},"3":{"name":"punctuation.definition.arguments.optional.end.latex"}},"match":"(\\\\()([^(]*?)(\\\\))","name":"meta.parameter.optional.latex"}]},"optional-arg-parenthesis-no-highlight":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.arguments.optional.begin.latex"},"2":{"name":"punctuation.definition.arguments.optional.end.latex"}},"match":"(\\\\()[^(]*?(\\\\))","name":"meta.parameter.optional.latex"}]},"references-macro":{"patterns":[{"begin":"((\\\\\\\\)\\\\w*[Rr]ef\\\\*?)(?:\\\\[[^]]*])?(\\\\{)","beginCaptures":{"1":{"name":"keyword.control.ref.latex"},"2":{"name":"punctuation.definition.keyword.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"name":"meta.reference.label.latex","patterns":[{"match":"[!*,-/:^_\\\\p{Alphabetic}\\\\p{N}]+","name":"constant.other.reference.label.latex"}]},{"captures":{"1":{"name":"keyword.control.ref.latex"},"2":{"name":"punctuation.definition.keyword.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"},"4":{"name":"constant.other.reference.label.latex"},"5":{"name":"punctuation.definition.arguments.end.latex"},"6":{"name":"punctuation.definition.arguments.begin.latex"},"7":{"name":"constant.other.reference.label.latex"},"8":{"name":"punctuation.definition.arguments.end.latex"}},"match":"((\\\\\\\\)\\\\w*[Rr]efrange\\\\*?)(?:\\\\[[^]]*])?(\\\\{)([!*,-/:^_\\\\p{Alphabetic}\\\\p{N}]+)(})(\\\\{)([!*,-/:^_\\\\p{Alphabetic}\\\\p{N}]+)(})"},{"begin":"((\\\\\\\\)bibentry)(\\\\{)","captures":{"1":{"name":"keyword.control.cite.latex"},"2":{"name":"punctuation.definition.keyword.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"name":"meta.citation.latex","patterns":[{"match":"[.:\\\\p{Alphabetic}\\\\p{N}]+","name":"constant.other.reference.citation.latex"}]}]},"sections-macro":{"begin":"((\\\\\\\\)((?:sub){0,2}section|(?:sub)?paragraph|chapter|part|addpart|addchap|addsec|minisec|frametitle)\\\\*?)((?:\\\\[[^\\\\[]*?]){0,2})(\\\\{)","beginCaptures":{"1":{"name":"support.function.section.latex"},"2":{"name":"punctuation.definition.function.latex"},"4":{"patterns":[{"include":"#optional-arg-bracket"}]},"5":{"name":"punctuation.definition.arguments.begin.latex"}},"contentName":"entity.name.section.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.arguments.end.latex"}},"name":"meta.function.section.$3.latex","patterns":[{"include":"#braces"},{"include":"$self"}]},"songs-chords":{"patterns":[{"begin":"\\\\\\\\\\\\[","end":"]","name":"meta.chord.block.latex support.class.chord.block.environment.latex","patterns":[{"include":"$self"}]},{"match":"\\\\^","name":"meta.chord.block.latex support.class.chord.block.environment.latex"},{"include":"$self"}]},"songs-env":{"patterns":[{"begin":"(\\\\s*\\\\\\\\begin\\\\{songs}\\\\{.*})","captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"contentName":"meta.data.environment.songs.latex","end":"(\\\\\\\\end\\\\{songs}(?:\\\\s*\\\\n)?)","name":"meta.function.environment.songs.latex","patterns":[{"include":"text.tex.latex#songs-chords"}]},{"begin":"\\\\s*((\\\\\\\\)beginsong)(?=\\\\{)","captures":{"1":{"name":"support.function.be.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.arguments.begin.latex"},"4":{"name":"punctuation.definition.arguments.end.latex"}},"end":"((\\\\\\\\)endsong)(?:\\\\s*\\\\n)?","name":"meta.function.environment.song.latex","patterns":[{"include":"#multiline-arg-no-highlight"},{"include":"#multiline-optional-arg-no-highlight"},{"begin":"(?:\\\\G|(?<=[]}]))\\\\s*","contentName":"meta.data.environment.song.latex","end":"\\\\s*(?=\\\\\\\\endsong)","patterns":[{"include":"text.tex.latex#songs-chords"}]}]}]},"text-font-macro":{"patterns":[{"begin":"((\\\\\\\\)emph)(\\\\{)","beginCaptures":{"1":{"name":"support.function.emph.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.emph.begin.latex"}},"contentName":"markup.italic.emph.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.emph.end.latex"}},"name":"meta.function.emph.latex","patterns":[{"include":"#braces"},{"include":"$self"}]},{"begin":"((\\\\\\\\)textit)(\\\\{)","captures":{"1":{"name":"support.function.textit.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.textit.begin.latex"}},"contentName":"markup.italic.textit.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.textit.end.latex"}},"name":"meta.function.textit.latex","patterns":[{"include":"#braces"},{"include":"$self"}]},{"begin":"((\\\\\\\\)textbf)(\\\\{)","captures":{"1":{"name":"support.function.textbf.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.textbf.begin.latex"}},"contentName":"markup.bold.textbf.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.textbf.end.latex"}},"name":"meta.function.textbf.latex","patterns":[{"include":"#braces"},{"include":"$self"}]},{"begin":"((\\\\\\\\)texttt)(\\\\{)","captures":{"1":{"name":"support.function.texttt.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.texttt.begin.latex"}},"contentName":"markup.raw.texttt.latex","end":"}","endCaptures":{"0":{"name":"punctuation.definition.texttt.end.latex"}},"name":"meta.function.texttt.latex","patterns":[{"include":"#braces"},{"include":"$self"}]}]},"unbalanced-env":{"patterns":[{"captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"match":"(\\\\s*\\\\\\\\(?:begin|end)\\\\{(\\\\p{Alphabetic}+\\\\*?)})","name":"meta.function.environment.general.latex"}]},"verb-macro":{"patterns":[{"begin":"((\\\\\\\\)(?:[Vv]|spv)erb\\\\*?)\\\\s*((\\\\\\\\)scantokens)(\\\\{)","beginCaptures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"support.function.verb.latex"},"4":{"name":"punctuation.definition.verb.latex"},"5":{"name":"punctuation.definition.begin.latex"}},"contentName":"markup.raw.verb.latex","end":"(})","endCaptures":{"1":{"name":"punctuation.definition.end.latex"}},"name":"meta.function.verb.latex","patterns":[{"include":"$self"}]},{"captures":{"1":{"name":"support.function.verb.latex"},"2":{"name":"punctuation.definition.function.latex"},"3":{"name":"punctuation.definition.verb.latex"},"4":{"name":"markup.raw.verb.latex"},"5":{"name":"punctuation.definition.verb.latex"}},"match":"((\\\\\\\\)(?:[Vv]|spv)erb\\\\*?)\\\\s*((?<=\\\\s)\\\\S|[^A-Za-z])(.*?)(\\\\3|$)","name":"meta.function.verb.latex"}]},"verbatim-env":{"patterns":[{"begin":"(\\\\s*\\\\\\\\begin\\\\{((?:fboxv|boxedv|[Vv]|spv)erbatim\\\\*?)})","captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"contentName":"markup.raw.verbatim.latex","end":"(\\\\\\\\end\\\\{\\\\2})","name":"meta.function.verbatim.latex"},{"begin":"(\\\\s*\\\\\\\\begin\\\\{VerbatimOut}\\\\{[^}]*})","captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"contentName":"markup.raw.verbatim.latex","end":"(\\\\\\\\end\\\\{VerbatimOut})","name":"meta.function.verbatim.latex"},{"begin":"(\\\\s*\\\\\\\\begin\\\\{alltt})","captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"contentName":"markup.raw.verbatim.latex","end":"(\\\\\\\\end\\\\{alltt})","name":"meta.function.alltt.latex","patterns":[{"captures":{"1":{"name":"punctuation.definition.function.latex"}},"match":"(\\\\\\\\)[A-Za-z]+","name":"support.function.general.latex"}]},{"begin":"(\\\\s*\\\\\\\\begin\\\\{([Cc]omment)})","captures":{"1":{"patterns":[{"include":"#macro-with-args-tokenizer"}]}},"contentName":"comment.line.percentage.latex","end":"(\\\\\\\\end\\\\{\\\\2})","name":"meta.function.verbatim.latex"}]}},"scopeName":"text.tex.latex","embeddedLangs":["tex"],"embeddedLangsLazy":["shellscript","css","gnuplot","haskell","html","java","julia","javascript","lua","python","ruby","rust","typescript","xml","yaml","scala"]}')),i=[...e,n];export{i as default}; diff --git a/apps/kimi-code/dist-web/assets/layout-D-LzfAck.js b/apps/kimi-code/dist-web/assets/layout-D-LzfAck.js new file mode 100644 index 0000000000000000000000000000000000000000..e1eef47088b567cb1546a6b3f74a2c0466b290e4 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/layout-D-LzfAck.js @@ -0,0 +1 @@ +import{A as F,a as y,c as kn,B as Pn,e as Q,C as nn,D as Nn,E as Qn,F as ne,l as ee,H as re,q as te,I as ie,v as A,J as ae,K as cn,L as oe,M as Ln,t as ue,y as R,k as de,N as fe,O as _n,P as Cn,Q as se,R as en,T as In,V as ce,W as Rn,z as D,n as le,X as he,Y as ve,G as g,Z as c,_ as pe,i as m,$ as T,a0 as O,a1 as G}from"./graph-DOmOIIwC.js";import{g as we,b as be,k as V,a as Tn,c as me,d as ge,e as ye,f as xe,i as Ee,h as Mn,j as Oe,m as w}from"./map-DxJ2ADlA.js";var ke=/\s/;function Pe(n){for(var e=n.length;e--&&ke.test(n.charAt(e)););return e}var Ne=/^\s+/;function Le(n){return n&&n.slice(0,Pe(n)+1).replace(Ne,"")}var ln=NaN,_e=/^[-+]0x[0-9a-f]+$/i,Ce=/^0b[01]+$/i,Ie=/^0o[0-7]+$/i,Re=parseInt;function Te(n){if(typeof n=="number")return n;if(F(n))return ln;if(y(n)){var e=typeof n.valueOf=="function"?n.valueOf():n;n=y(e)?e+"":e}if(typeof n!="string")return n===0?n:+n;n=Le(n);var r=Ce.test(n);return r||Ie.test(n)?Re(n.slice(2),r?2:8):_e.test(n)?ln:+n}var hn=1/0,Me=17976931348623157e292;function S(n){if(!n)return n===0?n:0;if(n=Te(n),n===hn||n===-hn){var e=n<0?-1:1;return e*Me}return n===n?n:0}function Se(n){var e=S(n),r=e%1;return e===e?r?e-r:e:0}function _(n,e,r){if(!y(r))return!1;var t=typeof e;return(t=="number"?kn(r)&&Pn(e,r.length):t=="string"&&e in r)?Q(r[e],n):!1}function Fe(n){return nn(function(e,r){var t=-1,i=r.length,o=i>1?r[i-1]:void 0,a=i>2?r[2]:void 0;for(o=n.length>3&&typeof o=="function"?(i--,o):void 0,a&&_(r[0],r[1],a)&&(o=i<3?void 0:o,i=1),e=Object(e);++t2?e[2]:void 0;for(i&&_(e[0],e[1],i)&&(t=1);++r-1?i[o?e[a]:a]:void 0}}var Ke=Math.max;function Ze(n,e,r){var t=n==null?0:n.length;if(!t)return-1;var i=r==null?0:Se(r);return i<0&&(i=Ke(t+i,0)),fe(n,R(e),i)}var rn=Je(Ze);function Qe(n,e){return n==null?n:Ln(n,_n(e),V)}function nr(n,e){return n&&Cn(n,_n(e))}function er(n,e){return n>e}var rr=Object.prototype,tr=rr.hasOwnProperty;function ir(n,e){return n!=null&&tr.call(n,e)}function Bn(n,e){return n!=null&&se(n,e,ir)}function jn(n,e){return ne||o&&a&&d&&!u&&!f||t&&a&&d||!r&&d||!i)return 1;if(!t&&!o&&!f&&n=u)return d;var f=r[t];return d*(f=="desc"?-1:1)}}return n.index-e.index}function sr(n,e,r){e.length?e=D(e,function(o){return A(o)?function(a){return Rn(a,o.length===1?o[0]:o)}:o}):e=[en];var t=-1;e=D(e,le(R));var i=Oe(n,function(o,a,u){var d=D(e,function(f){return f(o)});return{criteria:d,index:++t,value:o}});return ur(i,function(o,a){return fr(o,a,r)})}function cr(n,e){return or(n,e,function(r,t){return he(n,t)})}var j=Ae(function(n,e){return n==null?{}:cr(n,e)}),lr=Math.ceil,hr=Math.max;function vr(n,e,r,t){for(var i=-1,o=hr(lr((e-n)/(r||1)),0),a=Array(o);o--;)a[++i]=n,n+=r;return a}function pr(n){return function(e,r,t){return t&&typeof t!="number"&&_(e,r,t)&&(r=t=void 0),e=S(e),r===void 0?(r=e,e=0):r=S(r),t=t===void 0?e1&&_(n,e[0],e[1])?e=[]:r>2&&_(e[0],e[1],e[2])&&(e=[e[0]]),sr(n,Nn(e),[])}),wr=0;function on(n){var e=++wr;return ve(n)+e}function br(n,e,r){for(var t=-1,i=n.length,o=e.length,a={};++t0;--u)if(a=e[u].dequeue(),a){t=t.concat(q(n,e,r,a,!0));break}}}return t}function q(n,e,r,t,i){var o=i?[]:void 0;return c(n.inEdges(t.v),function(a){var u=n.edge(a),d=n.node(a.v);i&&o.push({v:a.v,w:a.w}),d.out-=u,Z(e,r,d)}),c(n.outEdges(t.v),function(a){var u=n.edge(a),d=a.w,f=n.node(d);f.in-=u,Z(e,r,f)}),n.removeNode(t.v),o}function kr(n,e){var r=new g,t=0,i=0;c(n.nodes(),function(u){r.setNode(u,{v:u,in:0,out:0})}),c(n.edges(),function(u){var d=r.edge(u.v,u.w)||0,f=e(u),s=d+f;r.setEdge(u.v,u.w,s),i=Math.max(i,r.node(u.v).out+=f),t=Math.max(t,r.node(u.w).in+=f)});var o=k(i+t+3).map(function(){return new gr}),a=t+1;return c(r.nodes(),function(u){Z(o,a,r.node(u))}),{graph:r,buckets:o,zeroIdx:a}}function Z(n,e,r){r.out?r.in?n[r.out-r.in+e].enqueue(r):n[n.length-1].enqueue(r):n[0].enqueue(r)}function Pr(n){var e=n.graph().acyclicer==="greedy"?Er(n,r(n)):Nr(n);c(e,function(t){var i=n.edge(t);n.removeEdge(t),i.forwardName=t.name,i.reversed=!0,n.setEdge(t.w,t.v,i,on("rev"))});function r(t){return function(i){return t.edge(i).weight}}}function Nr(n){var e=[],r={},t={};function i(o){Object.prototype.hasOwnProperty.call(t,o)||(t[o]=!0,r[o]=!0,c(n.outEdges(o),function(a){Object.prototype.hasOwnProperty.call(r,a.w)?e.push(a):i(a.w)}),delete r[o])}return c(n.nodes(),i),e}function Lr(n){c(n.edges(),function(e){var r=n.edge(e);if(r.reversed){n.removeEdge(e);var t=r.forwardName;delete r.reversed,delete r.forwardName,n.setEdge(e.w,e.v,r,t)}})}function N(n,e,r,t){var i;do i=on(t);while(n.hasNode(i));return r.dummy=e,n.setNode(i,r),i}function _r(n){var e=new g().setGraph(n.graph());return c(n.nodes(),function(r){e.setNode(r,n.node(r))}),c(n.edges(),function(r){var t=e.edge(r.v,r.w)||{weight:0,minlen:1},i=n.edge(r);e.setEdge(r.v,r.w,{weight:t.weight+i.weight,minlen:Math.max(t.minlen,i.minlen)})}),e}function Gn(n){var e=new g({multigraph:n.isMultigraph()}).setGraph(n.graph());return c(n.nodes(),function(r){n.children(r).length||e.setNode(r,n.node(r))}),c(n.edges(),function(r){e.setEdge(r,n.edge(r))}),e}function pn(n,e){var r=n.x,t=n.y,i=e.x-r,o=e.y-t,a=n.width/2,u=n.height/2;if(!i&&!o)throw new Error("Not possible to find intersection inside of the rectangle");var d,f;return Math.abs(o)*a>Math.abs(i)*u?(o<0&&(u=-u),d=u*i/o,f=u):(i<0&&(a=-a),d=a,f=a*o/i),{x:r+d,y:t+f}}function $(n){var e=w(k(Vn(n)+1),function(){return[]});return c(n.nodes(),function(r){var t=n.node(r),i=t.rank;m(i)||(e[i][t.order]=r)}),e}function Cr(n){var e=C(w(n.nodes(),function(r){return n.node(r).rank}));c(n.nodes(),function(r){var t=n.node(r);Bn(t,"rank")&&(t.rank-=e)})}function Ir(n){var e=C(w(n.nodes(),function(o){return n.node(o).rank})),r=[];c(n.nodes(),function(o){var a=n.node(o).rank-e;r[a]||(r[a]=[]),r[a].push(o)});var t=0,i=n.graph().nodeRankFactor;c(r,function(o,a){m(o)&&a%i!==0?--t:t&&c(o,function(u){n.node(u).rank+=t})})}function wn(n,e,r,t){var i={width:0,height:0};return arguments.length>=4&&(i.rank=r,i.order=t),N(n,"border",i,e)}function Vn(n){return x(w(n.nodes(),function(e){var r=n.node(e).rank;if(!m(r))return r}))}function Rr(n,e){var r={lhs:[],rhs:[]};return c(n,function(t){e(t)?r.lhs.push(t):r.rhs.push(t)}),r}function Tr(n,e){return e()}function Mr(n){function e(r){var t=n.children(r),i=n.node(r);if(t.length&&c(t,e),Object.prototype.hasOwnProperty.call(i,"minRank")){i.borderLeft=[],i.borderRight=[];for(var o=i.minRank,a=i.maxRank+1;oa.lim&&(u=a,d=!0);var f=T(e.edges(),function(s){return d===gn(n,n.node(s.v),u)&&d!==gn(n,n.node(s.w),u)});return an(f,function(s){return I(e,s)})}function Un(n,e,r,t){var i=r.v,o=r.w;n.removeEdge(i,o),n.setEdge(t.v,t.w,{}),fn(n),dn(n,e),zr(n,e)}function zr(n,e){var r=rn(n.nodes(),function(i){return!e.node(i).parent}),t=Xr(n,r);t=t.slice(1),c(t,function(i){var o=n.node(i).parent,a=e.edge(i,o),u=!1;a||(a=e.edge(o,i),u=!0),e.node(i).rank=e.node(o).rank+(u?a.minlen:-a.minlen)})}function Ur(n,e,r){return n.hasEdge(e,r)}function gn(n,e,r){return r.low<=e.lim&&e.lim<=r.lim}function Jr(n){switch(n.graph().ranker){case"network-simplex":yn(n);break;case"tight-tree":Zr(n);break;case"longest-path":Kr(n);break;default:yn(n)}}var Kr=un;function Zr(n){un(n),$n(n)}function yn(n){E(n)}function Qr(n){var e=N(n,"root",{},"_root"),r=nt(n),t=x(O(r))-1,i=2*t+1;n.graph().nestingRoot=e,c(n.edges(),function(a){n.edge(a).minlen*=i});var o=et(n)+1;c(n.children(),function(a){Jn(n,e,i,o,t,r,a)}),n.graph().nodeRankFactor=i}function Jn(n,e,r,t,i,o,a){var u=n.children(a);if(!u.length){a!==e&&n.setEdge(e,a,{weight:0,minlen:r});return}var d=wn(n,"_bt"),f=wn(n,"_bb"),s=n.node(a);n.setParent(d,a),s.borderTop=d,n.setParent(f,a),s.borderBottom=f,c(u,function(l){Jn(n,e,r,t,i,o,l);var h=n.node(l),v=h.borderTop?h.borderTop:l,p=h.borderBottom?h.borderBottom:l,b=h.borderTop?t:2*t,L=v!==p?1:i-o[a]+1;n.setEdge(d,v,{weight:b,minlen:L,nestingEdge:!0}),n.setEdge(p,f,{weight:b,minlen:L,nestingEdge:!0})}),n.parent(a)||n.setEdge(e,d,{weight:0,minlen:i+o[a]})}function nt(n){var e={};function r(t,i){var o=n.children(t);o&&o.length&&c(o,function(a){r(a,i+1)}),e[t]=i}return c(n.children(),function(t){r(t,1)}),e}function et(n){return G(n.edges(),function(e,r){return e+n.edge(r).weight},0)}function rt(n){var e=n.graph();n.removeNode(e.nestingRoot),delete e.nestingRoot,c(n.edges(),function(r){var t=n.edge(r);t.nestingEdge&&n.removeEdge(r)})}function tt(n,e,r){var t={},i;c(r,function(o){for(var a=n.parent(o),u,d;a;){if(u=n.parent(a),u?(d=t[u],t[u]=a):(d=i,i=a),d&&d!==a){e.setEdge(d,a);return}a=u}})}function it(n,e,r){var t=at(n),i=new g({compound:!0}).setGraph({root:t}).setDefaultNodeLabel(function(o){return n.node(o)});return c(n.nodes(),function(o){var a=n.node(o),u=n.parent(o);(a.rank===e||a.minRank<=e&&e<=a.maxRank)&&(i.setNode(o),i.setParent(o,u||t),c(n[r](o),function(d){var f=d.v===o?d.w:d.v,s=i.edge(f,o),l=m(s)?0:s.weight;i.setEdge(f,o,{weight:n.edge(d).weight+l})}),Object.prototype.hasOwnProperty.call(a,"minRank")&&i.setNode(o,{borderLeft:a.borderLeft[e],borderRight:a.borderRight[e]}))}),i}function at(n){for(var e;n.hasNode(e=on("_root")););return e}function ot(n,e){for(var r=0,t=1;t0;)s%2&&(l+=u[s+1]),s=s-1>>1,u[s]+=f.weight;d+=f.weight*l})),d}function dt(n){var e={},r=T(n.nodes(),function(u){return!n.children(u).length}),t=x(w(r,function(u){return n.node(u).rank})),i=w(k(t+1),function(){return[]});function o(u){if(!Bn(e,u)){e[u]=!0;var d=n.node(u);i[d.rank].push(u),c(n.successors(u),o)}}var a=M(r,function(u){return n.node(u).rank});return c(a,o),i}function ft(n,e){return w(e,function(r){var t=n.inEdges(r);if(t.length){var i=G(t,function(o,a){var u=n.edge(a),d=n.node(a.v);return{sum:o.sum+u.weight*d.order,weight:o.weight+u.weight}},{sum:0,weight:0});return{v:r,barycenter:i.sum/i.weight,weight:i.weight}}else return{v:r}})}function st(n,e){var r={};c(n,function(i,o){var a=r[i.v]={indegree:0,in:[],out:[],vs:[i.v],i:o};m(i.barycenter)||(a.barycenter=i.barycenter,a.weight=i.weight)}),c(e.edges(),function(i){var o=r[i.v],a=r[i.w];!m(o)&&!m(a)&&(a.indegree++,o.out.push(r[i.w]))});var t=T(r,function(i){return!i.indegree});return ct(t)}function ct(n){var e=[];function r(o){return function(a){a.merged||(m(a.barycenter)||m(o.barycenter)||a.barycenter>=o.barycenter)&<(o,a)}}function t(o){return function(a){a.in.push(o),--a.indegree===0&&n.push(a)}}for(;n.length;){var i=n.pop();e.push(i),c(i.in.reverse(),r(i)),c(i.out,t(i))}return w(T(e,function(o){return!o.merged}),function(o){return j(o,["vs","i","barycenter","weight"])})}function lt(n,e){var r=0,t=0;n.weight&&(r+=n.barycenter*n.weight,t+=n.weight),e.weight&&(r+=e.barycenter*e.weight,t+=e.weight),n.vs=e.vs.concat(n.vs),n.barycenter=r/t,n.weight=t,n.i=Math.min(e.i,n.i),e.merged=!0}function ht(n,e){var r=Rr(n,function(s){return Object.prototype.hasOwnProperty.call(s,"barycenter")}),t=r.lhs,i=M(r.rhs,function(s){return-s.i}),o=[],a=0,u=0,d=0;t.sort(vt(!!e)),d=xn(o,i,d),c(t,function(s){d+=s.vs.length,o.push(s.vs),a+=s.barycenter*s.weight,u+=s.weight,d=xn(o,i,d)});var f={vs:P(o)};return u&&(f.barycenter=a/u,f.weight=u),f}function xn(n,e,r){for(var t;e.length&&(t=B(e)).i<=r;)e.pop(),n.push(t.vs),r++;return r}function vt(n){return function(e,r){return e.barycenterr.barycenter?1:n?r.i-e.i:e.i-r.i}}function Kn(n,e,r,t){var i=n.children(e),o=n.node(e),a=o?o.borderLeft:void 0,u=o?o.borderRight:void 0,d={};a&&(i=T(i,function(p){return p!==a&&p!==u}));var f=ft(n,i);c(f,function(p){if(n.children(p.v).length){var b=Kn(n,p.v,r,t);d[p.v]=b,Object.prototype.hasOwnProperty.call(b,"barycenter")&&wt(p,b)}});var s=st(f,r);pt(s,d);var l=ht(s,t);if(a&&(l.vs=P([a,l.vs,u]),n.predecessors(a).length)){var h=n.node(n.predecessors(a)[0]),v=n.node(n.predecessors(u)[0]);Object.prototype.hasOwnProperty.call(l,"barycenter")||(l.barycenter=0,l.weight=0),l.barycenter=(l.barycenter*l.weight+h.order+v.order)/(l.weight+2),l.weight+=2}return l}function pt(n,e){c(n,function(r){r.vs=P(r.vs.map(function(t){return e[t]?e[t].vs:t}))})}function wt(n,e){m(n.barycenter)?(n.barycenter=e.barycenter,n.weight=e.weight):(n.barycenter=(n.barycenter*n.weight+e.barycenter*e.weight)/(n.weight+e.weight),n.weight+=e.weight)}function bt(n){var e=Vn(n),r=En(n,k(1,e+1),"inEdges"),t=En(n,k(e-1,-1,-1),"outEdges"),i=dt(n);On(n,i);for(var o=Number.POSITIVE_INFINITY,a,u=0,d=0;d<4;++u,++d){mt(u%2?r:t,u%4>=2),i=$(n);var f=ot(n,i);fa||u>e[d].lim));for(f=d,d=t;(d=n.parent(d))!==f;)o.push(d);return{path:i.concat(o.reverse()),lca:f}}function xt(n){var e={},r=0;function t(i){var o=r;c(n.children(i),t),e[i]={low:o,lim:r++}}return c(n.children(),t),e}function Et(n,e){var r={};function t(i,o){var a=0,u=0,d=i.length,f=B(o);return c(o,function(s,l){var h=kt(n,s),v=h?n.node(h).order:d;(h||s===f)&&(c(o.slice(u,l+1),function(p){c(n.predecessors(p),function(b){var L=n.node(b),sn=L.order;(snf)&&Zn(r,h,s)})})}function i(o,a){var u=-1,d,f=0;return c(a,function(s,l){if(n.node(s).dummy==="border"){var h=n.predecessors(s);h.length&&(d=n.node(h[0]).order,t(a,f,l,u,d),f=l,u=d)}t(a,f,a.length,d,o.length)}),a}return G(e,i),r}function kt(n,e){if(n.node(e).dummy)return rn(n.predecessors(e),function(r){return n.node(r).dummy})}function Zn(n,e,r){if(e>r){var t=e;e=r,r=t}Object.prototype.hasOwnProperty.call(n,e)||Object.defineProperty(n,e,{enumerable:!0,configurable:!0,value:{},writable:!0});var i=n[e];Object.defineProperty(i,r,{enumerable:!0,configurable:!0,value:!0,writable:!0})}function Pt(n,e,r){if(e>r){var t=e;e=r,r=t}return!!n[e]&&Object.prototype.hasOwnProperty.call(n[e],r)}function Nt(n,e,r,t){var i={},o={},a={};return c(e,function(u){c(u,function(d,f){i[d]=d,o[d]=d,a[d]=f})}),c(e,function(u){var d=-1;c(u,function(f){var s=t(f);if(s.length){s=M(s,function(b){return a[b]});for(var l=(s.length-1)/2,h=Math.floor(l),v=Math.ceil(l);h<=v;++h){var p=s[h];o[f]===f&&d{var t=r(" buildLayoutGraph",()=>Ht(n));r(" runLayout",()=>Bt(t,r)),r(" updateInputGraph",()=>jt(n,t))})}function Bt(n,e){e(" makeSpaceForEdgeLabels",()=>zt(n)),e(" removeSelfEdges",()=>ti(n)),e(" acyclic",()=>Pr(n)),e(" nestingGraph.run",()=>Qr(n)),e(" rank",()=>Jr(Gn(n))),e(" injectEdgeLabelProxies",()=>Ut(n)),e(" removeEmptyRanks",()=>Ir(n)),e(" nestingGraph.cleanup",()=>rt(n)),e(" normalizeRanks",()=>Cr(n)),e(" assignRankMinMax",()=>Jt(n)),e(" removeEdgeLabelProxies",()=>Kt(n)),e(" normalize.run",()=>jr(n)),e(" parentDummyChains",()=>gt(n)),e(" addBorderSegments",()=>Mr(n)),e(" order",()=>bt(n)),e(" insertSelfEdges",()=>ii(n)),e(" adjustCoordinateSystem",()=>Sr(n)),e(" position",()=>Ft(n)),e(" positionSelfEdges",()=>ai(n)),e(" removeBorderNodes",()=>ri(n)),e(" normalize.undo",()=>Vr(n)),e(" fixupEdgeLabelCoords",()=>ni(n)),e(" undoCoordinateSystem",()=>Fr(n)),e(" translateGraph",()=>Zt(n)),e(" assignNodeIntersects",()=>Qt(n)),e(" reversePoints",()=>ei(n)),e(" acyclic.undo",()=>Lr(n))}function jt(n,e){c(n.nodes(),function(r){var t=n.node(r),i=e.node(r);t&&(t.x=i.x,t.y=i.y,e.children(r).length&&(t.width=i.width,t.height=i.height))}),c(n.edges(),function(r){var t=n.edge(r),i=e.edge(r);t.points=i.points,Object.prototype.hasOwnProperty.call(i,"x")&&(t.x=i.x,t.y=i.y)}),n.graph().width=e.graph().width,n.graph().height=e.graph().height}var Gt=["nodesep","edgesep","ranksep","marginx","marginy"],Vt={ranksep:50,edgesep:20,nodesep:50,rankdir:"tb"},Yt=["acyclicer","ranker","rankdir","align"],$t=["width","height"],Dt={width:0,height:0},qt=["minlen","weight","width","height","labeloffset"],Wt={minlen:1,weight:1,width:0,height:0,labeloffset:10,labelpos:"r"},Xt=["labelpos"];function Ht(n){var e=new g({multigraph:!0,compound:!0}),r=z(n.graph());return e.setGraph(K({},Vt,H(r,Gt),j(r,Yt))),c(n.nodes(),function(t){var i=z(n.node(t));e.setNode(t,He(H(i,$t),Dt)),e.setParent(t,n.parent(t))}),c(n.edges(),function(t){var i=z(n.edge(t));e.setEdge(t,K({},Wt,H(i,qt),j(i,Xt)))}),e}function zt(n){var e=n.graph();e.ranksep/=2,c(n.edges(),function(r){var t=n.edge(r);t.minlen*=2,t.labelpos.toLowerCase()!=="c"&&(e.rankdir==="TB"||e.rankdir==="BT"?t.width+=t.labeloffset:t.height+=t.labeloffset)})}function Ut(n){c(n.edges(),function(e){var r=n.edge(e);if(r.width&&r.height){var t=n.node(e.v),i=n.node(e.w),o={rank:(i.rank-t.rank)/2+t.rank,e};N(n,"edge-proxy",o,"_ep")}})}function Jt(n){var e=0;c(n.nodes(),function(r){var t=n.node(r);t.borderTop&&(t.minRank=n.node(t.borderTop).rank,t.maxRank=n.node(t.borderBottom).rank,e=x(e,t.maxRank))}),n.graph().maxRank=e}function Kt(n){c(n.nodes(),function(e){var r=n.node(e);r.dummy==="edge-proxy"&&(n.edge(r.e).labelRank=r.rank,n.removeNode(e))})}function Zt(n){var e=Number.POSITIVE_INFINITY,r=0,t=Number.POSITIVE_INFINITY,i=0,o=n.graph(),a=o.marginx||0,u=o.marginy||0;function d(f){var s=f.x,l=f.y,h=f.width,v=f.height;e=Math.min(e,s-h/2),r=Math.max(r,s+h/2),t=Math.min(t,l-v/2),i=Math.max(i,l+v/2)}c(n.nodes(),function(f){d(n.node(f))}),c(n.edges(),function(f){var s=n.edge(f);Object.prototype.hasOwnProperty.call(s,"x")&&d(s)}),e-=a,t-=u,c(n.nodes(),function(f){var s=n.node(f);s.x-=e,s.y-=t}),c(n.edges(),function(f){var s=n.edge(f);c(s.points,function(l){l.x-=e,l.y-=t}),Object.prototype.hasOwnProperty.call(s,"x")&&(s.x-=e),Object.prototype.hasOwnProperty.call(s,"y")&&(s.y-=t)}),o.width=r-e+a,o.height=i-t+u}function Qt(n){c(n.edges(),function(e){var r=n.edge(e),t=n.node(e.v),i=n.node(e.w),o,a;r.points?(o=r.points[0],a=r.points[r.points.length-1]):(r.points=[],o=i,a=t),r.points.unshift(pn(t,o)),r.points.push(pn(i,a))})}function ni(n){c(n.edges(),function(e){var r=n.edge(e);if(Object.prototype.hasOwnProperty.call(r,"x"))switch((r.labelpos==="l"||r.labelpos==="r")&&(r.width-=r.labeloffset),r.labelpos){case"l":r.x-=r.width/2+r.labeloffset;break;case"r":r.x+=r.width/2+r.labeloffset;break}})}function ei(n){c(n.edges(),function(e){var r=n.edge(e);r.reversed&&r.points.reverse()})}function ri(n){c(n.nodes(),function(e){if(n.children(e).length){var r=n.node(e),t=n.node(r.borderTop),i=n.node(r.borderBottom),o=n.node(B(r.borderLeft)),a=n.node(B(r.borderRight));r.width=Math.abs(a.x-o.x),r.height=Math.abs(i.y-t.y),r.x=o.x+r.width/2,r.y=t.y+r.height/2}}),c(n.nodes(),function(e){n.node(e).dummy==="border"&&n.removeNode(e)})}function ti(n){c(n.edges(),function(e){if(e.v===e.w){var r=n.node(e.v);r.selfEdges||(r.selfEdges=[]),r.selfEdges.push({e,label:n.edge(e)}),n.removeEdge(e)}})}function ii(n){var e=$(n);c(e,function(r){var t=0;c(r,function(i,o){var a=n.node(i);a.order=o+t,c(a.selfEdges,function(u){N(n,"selfedge",{width:u.label.width,height:u.label.height,rank:a.rank,order:o+ ++t,e:u.e,label:u.label},"_se")}),delete a.selfEdges})})}function ai(n){c(n.nodes(),function(e){var r=n.node(e);if(r.dummy==="selfedge"){var t=n.node(r.e.v),i=t.x+t.width/2,o=t.y,a=r.x-i,u=t.height/2;n.setEdge(r.e,r.label),n.removeNode(e),r.label.points=[{x:i+2*a/3,y:o-u},{x:i+5*a/6,y:o-u},{x:i+a,y:o},{x:i+5*a/6,y:o+u},{x:i+2*a/3,y:o+u}],r.label.x=r.x,r.label.y=r.y}})}function H(n,e){return Y(j(n,e),Number)}function z(n){var e={};return c(n,function(r,t){e[t.toLowerCase()]=r}),e}export{di as l}; diff --git a/apps/kimi-code/dist-web/assets/less-B1dDrJ26.js b/apps/kimi-code/dist-web/assets/less-B1dDrJ26.js new file mode 100644 index 0000000000000000000000000000000000000000..8d018465703fa41d19fea23f7691cbe4bedb1d73 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/less-B1dDrJ26.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"Less","name":"less","patterns":[{"include":"#comment-block"},{"include":"#less-namespace-accessors"},{"include":"#less-extend"},{"include":"#at-rules"},{"include":"#less-variable-assignment"},{"include":"#property-list"},{"include":"#selector"}],"repository":{"angle-type":{"captures":{"1":{"name":"keyword.other.unit.less"}},"match":"(?i:[-+]?(?:\\\\d*\\\\.\\\\d+(?:[Ee][-+]?\\\\d+)*|[-+]?\\\\d+)(deg|grad|rad|turn))\\\\b","name":"constant.numeric.less"},"arbitrary-repetition":{"captures":{"1":{"name":"punctuation.definition.arbitrary-repetition.less"}},"match":"\\\\s*(,)"},"at-charset":{"begin":"\\\\s*((@)charset)\\\\b\\\\s*","beginCaptures":{"1":{"name":"keyword.control.at-rule.charset.less"},"2":{"name":"punctuation.definition.keyword.less"}},"end":"\\\\s*((?=;|$))","name":"meta.at-rule.charset.less","patterns":[{"include":"#literal-string"}]},"at-container":{"begin":"(?=\\\\s*@container)","end":"\\\\s*(})","endCaptures":{"1":{"name":"punctuation.definition.block.end.less"}},"patterns":[{"begin":"((@)container)","beginCaptures":{"1":{"name":"keyword.control.at-rule.container.less"},"2":{"name":"punctuation.definition.keyword.less"},"3":{"name":"support.constant.container.less"}},"end":"(?=\\\\{)","name":"meta.at-rule.container.less","patterns":[{"begin":"\\\\s*(?=[^;{])","end":"\\\\s*(?=[;{])","patterns":[{"match":"\\\\b(not|and|or)\\\\b","name":"keyword.operator.comparison.less"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.at-rule.container-query.less","patterns":[{"captures":{"1":{"name":"support.type.property-name.less"}},"match":"\\\\b(aspect-ratio|block-size|height|inline-size|orientation|width)\\\\b","name":"support.constant.size-feature.less"},{"match":"(([<>])=?)|[/=]","name":"keyword.operator.comparison.less"},{"match":":","name":"punctuation.separator.key-value.less"},{"match":"portrait|landscape","name":"support.constant.property-value.less"},{"include":"#numeric-values"},{"match":"/","name":"keyword.operator.arithmetic.less"},{"include":"#var-function"},{"include":"#less-variables"},{"include":"#less-variable-interpolation"}]},{"include":"#style-function"},{"match":"--|-?(?:[A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))(?:[-A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}\\\\d]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))*","name":"variable.parameter.container-name.css"},{"include":"#arbitrary-repetition"},{"include":"#less-variables"}]}]},{"begin":"\\\\s*(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.block.begin.less"}},"end":"(?=})","patterns":[{"include":"#rule-list-body"},{"include":"$self"}]}]},"at-counter-style":{"begin":"\\\\s*((@)counter-style)\\\\b\\\\s+(?:(?i:\\\\b(decimal|none)\\\\b)|(-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*))\\\\s*(?=\\\\{|$)","beginCaptures":{"1":{"name":"keyword.control.at-rule.counter-style.less"},"2":{"name":"punctuation.definition.keyword.less"},"3":{"name":"invalid.illegal.counter-style-name.less"},"4":{"name":"entity.other.counter-style-name.css"}},"end":"\\\\s*(})","endCaptures":{"1":{"name":"punctuation.definition.block.begin.less"}},"name":"meta.at-rule.counter-style.less","patterns":[{"include":"#comment-block"},{"include":"#rule-list"}]},"at-custom-media":{"begin":"(?=\\\\s*@custom-media\\\\b)","end":"\\\\s*(?=;)","name":"meta.at-rule.custom-media.less","patterns":[{"captures":{"0":{"name":"punctuation.section.property-list.less"}},"match":"\\\\s*;"},{"captures":{"1":{"name":"keyword.control.at-rule.custom-media.less"},"2":{"name":"punctuation.definition.keyword.less"},"3":{"name":"support.constant.custom-media.less"}},"match":"\\\\s*((@)custom-media)(?=.*?)"},{"include":"#media-query-list"}]},"at-font-face":{"begin":"\\\\s*((@)font-face)\\\\s*(?=\\\\{|$)","beginCaptures":{"1":{"name":"keyword.control.at-rule.font-face.less"},"2":{"name":"punctuation.definition.keyword.less"}},"end":"\\\\s*(})","endCaptures":{"1":{"name":"punctuation.definition.block.end.less"}},"name":"meta.at-rule.font-face.less","patterns":[{"include":"#comment-block"},{"include":"#rule-list"}]},"at-import":{"begin":"\\\\s*((@)import)\\\\b\\\\s*","beginCaptures":{"1":{"name":"keyword.control.at-rule.import.less"},"2":{"name":"punctuation.definition.keyword.less"}},"end":";","endCaptures":{"0":{"name":"punctuation.terminator.rule.less"}},"name":"meta.at-rule.import.less","patterns":[{"include":"#url-function"},{"include":"#less-variables"},{"begin":"(?<=([\\"'])|([\\"']\\\\)))\\\\s*","end":"\\\\s*(?=;)","patterns":[{"include":"#media-query"}]},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.group.less","patterns":[{"match":"reference|inline|less|css|once|multiple|optional","name":"constant.language.import-directive.less"},{"include":"#comma-delimiter"}]},{"include":"#literal-string"}]},"at-keyframes":{"begin":"\\\\s*((@)keyframes)(?=.*?\\\\{)","beginCaptures":{"1":{"name":"keyword.control.at-rule.keyframe.less"},"2":{"name":"punctuation.definition.keyword.less"},"4":{"name":"support.constant.keyframe.less"}},"end":"\\\\s*(})","endCaptures":{"1":{"name":"punctuation.definition.block.end.less"}},"patterns":[{"begin":"\\\\s*(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.block.begin.less"}},"end":"(?=})","patterns":[{"captures":{"1":{"name":"keyword.other.keyframe-selector.less"},"2":{"name":"constant.numeric.less"},"3":{"name":"keyword.other.unit.less"}},"match":"\\\\s*(?:(from|to)|((?:\\\\.[0-9]+|[0-9]+(?:\\\\.[0-9]*)?)(%)))\\\\s*,?\\\\s*"},{"include":"$self"}]},{"begin":"\\\\s*(?=[^;{])","end":"\\\\s*(?=\\\\{)","name":"meta.at-rule.keyframe.less","patterns":[{"include":"#keyframe-name"},{"include":"#arbitrary-repetition"}]}]},"at-media":{"begin":"(?=\\\\s*@media\\\\b)","end":"\\\\s*(})","endCaptures":{"1":{"name":"punctuation.definition.block.end.less"}},"patterns":[{"begin":"\\\\s*((@)media)","beginCaptures":{"1":{"name":"keyword.control.at-rule.media.less"},"2":{"name":"punctuation.definition.keyword.less"},"3":{"name":"support.constant.media.less"}},"end":"\\\\s*(?=\\\\{)","name":"meta.at-rule.media.less","patterns":[{"include":"#media-query-list"}]},{"begin":"\\\\s*(\\\\{)","beginCaptures":{"1":{"name":"punctuation.definition.block.begin.less"}},"end":"(?=})","patterns":[{"include":"#rule-list-body"},{"include":"$self"}]}]},"at-namespace":{"begin":"\\\\s*((@)namespace)\\\\s+","beginCaptures":{"1":{"name":"keyword.control.at-rule.namespace.less"},"2":{"name":"punctuation.definition.keyword.less"}},"end":";","endCaptures":{"0":{"name":"punctuation.terminator.rule.less"}},"name":"meta.at-rule.namespace.less","patterns":[{"include":"#url-function"},{"include":"#literal-string"},{"match":"(-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)","name":"entity.name.constant.namespace-prefix.less"}]},"at-page":{"captures":{"1":{"name":"keyword.control.at-rule.page.less"},"2":{"name":"punctuation.definition.keyword.less"},"3":{"name":"punctuation.definition.entity.less"},"4":{"name":"entity.other.attribute-name.pseudo-class.less"}},"match":"\\\\s*((@)page)\\\\s*(?:(:)(first|left|right))?\\\\s*(?=\\\\{|$)","name":"meta.at-rule.page.less","patterns":[{"include":"#comment-block"},{"include":"#rule-list"}]},"at-rules":{"patterns":[{"include":"#at-charset"},{"include":"#at-container"},{"include":"#at-counter-style"},{"include":"#at-custom-media"},{"include":"#at-font-face"},{"include":"#at-media"},{"include":"#at-import"},{"include":"#at-keyframes"},{"include":"#at-namespace"},{"include":"#at-page"},{"include":"#at-supports"},{"include":"#at-viewport"}]},"at-supports":{"begin":"(?=\\\\s*@supports\\\\b)","end":"(?=\\\\s*)(})","endCaptures":{"1":{"name":"punctuation.definition.block.end.less"}},"patterns":[{"begin":"\\\\s*((@)supports)","beginCaptures":{"1":{"name":"keyword.control.at-rule.supports.less"},"2":{"name":"punctuation.definition.keyword.less"},"3":{"name":"support.constant.supports.less"}},"end":"\\\\s*(?=\\\\{)","name":"meta.at-rule.supports.less","patterns":[{"include":"#at-supports-operators"},{"include":"#at-supports-parens"}]},{"begin":"\\\\s*(\\\\{)","beginCaptures":{"1":{"name":"punctuation.section.property-list.begin.less"}},"end":"(?=})","patterns":[{"include":"#rule-list-body"},{"include":"$self"}]}]},"at-supports-operators":{"match":"\\\\b(?:and|or|not)\\\\b","name":"keyword.operator.logic.less"},"at-supports-parens":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.group.less","patterns":[{"include":"#at-supports-operators"},{"include":"#at-supports-parens"},{"include":"#rule-list-body"}]},"attr-function":{"begin":"\\\\b(attr)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#qualified-name"},{"include":"#literal-string"},{"begin":"(-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)","end":"(?=\\\\))","name":"entity.other.attribute-name.less","patterns":[{"match":"\\\\b((?i:em|ex|ch|rem)|(?i:v(?:[hw]|min|max))|(?i:cm|mm|q|in|pt|pc|px|fr)|(?i:deg|grad|rad|turn)|(?i:m??s)|(?i:k??Hz)|(?i:dp(?:i|cm|px)))\\\\b","name":"keyword.other.unit.less"},{"include":"#comma-delimiter"},{"include":"#property-value-constants"},{"include":"#numeric-values"}]},{"include":"#color-values"}]}]},"builtin-functions":{"patterns":[{"include":"#attr-function"},{"include":"#calc-function"},{"include":"#color-functions"},{"include":"#counter-functions"},{"include":"#cross-fade-function"},{"include":"#cubic-bezier-function"},{"include":"#filter-function"},{"include":"#fit-content-function"},{"include":"#format-function"},{"include":"#gradient-functions"},{"include":"#grid-repeat-function"},{"include":"#image-function"},{"include":"#less-functions"},{"include":"#local-function"},{"include":"#minmax-function"},{"include":"#regexp-function"},{"include":"#shape-functions"},{"include":"#steps-function"},{"include":"#symbols-function"},{"include":"#transform-functions"},{"include":"#url-function"},{"include":"#var-function"}]},"calc-function":{"begin":"\\\\b(calc)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.calc.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-strings"},{"include":"#var-function"},{"include":"#calc-function"},{"include":"#attr-function"},{"include":"#less-math"},{"include":"#relative-color"}]}]},"color-adjuster-operators":{"match":"[-*+](?=\\\\s+)","name":"keyword.operator.less"},"color-functions":{"patterns":[{"begin":"\\\\b(rgba?)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-strings"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#comma-delimiter"},{"include":"#value-separator"},{"include":"#percentage-type"},{"include":"#number-type"}]}]},{"begin":"\\\\b(hsla?|hwb|oklab|oklch|lab|lch)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#less-strings"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#comma-delimiter"},{"include":"#angle-type"},{"include":"#percentage-type"},{"include":"#number-type"},{"include":"#calc-function"},{"include":"#value-separator"}]}]},{"begin":"\\\\b(light-dark)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#comma-delimiter"}]}]},{"include":"#less-color-functions"}]},"color-values":{"patterns":[{"include":"#color-functions"},{"include":"#less-functions"},{"include":"#less-variables"},{"include":"#var-function"},{"match":"\\\\b(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)\\\\b","name":"support.constant.color.w3c-standard-color-name.less"},{"match":"\\\\b(aliceblue|antiquewhite|aquamarine|azure|beige|bisque|blanchedalmond|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkgrey|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|firebrick|floralwhite|forestgreen|gainsboro|ghostwhite|gold|goldenrod|greenyellow|grey|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightgrey|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|limegreen|linen|magenta|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|oldlace|olivedrab|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|rebeccapurple|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|tan|thistle|tomato|turquoise|violet|wheat|whitesmoke|yellowgreen)\\\\b","name":"support.constant.color.w3c-extended-color-keywords.less"},{"match":"\\\\b((?i)currentColor|transparent)\\\\b","name":"support.constant.color.w3c-special-color-keyword.less"},{"captures":{"1":{"name":"punctuation.definition.constant.less"}},"match":"(#)(\\\\h{3}|\\\\h{4}|\\\\h{6}|\\\\h{8})\\\\b","name":"constant.other.color.rgb-value.less"},{"include":"#relative-color"}]},"comma-delimiter":{"captures":{"1":{"name":"punctuation.separator.less"}},"match":"\\\\s*(,)\\\\s*"},"comment-block":{"patterns":[{"begin":"/\\\\*","beginCaptures":{"0":{"name":"punctuation.definition.comment.less"}},"end":"\\\\*/","endCaptures":{"0":{"name":"punctuation.definition.comment.less"}},"name":"comment.block.less"},{"include":"#comment-line"}]},"comment-line":{"captures":{"1":{"name":"punctuation.definition.comment.less"}},"match":"(//).*$\\\\n?","name":"comment.line.double-slash.less"},"counter-functions":{"patterns":[{"begin":"\\\\b(counter)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-strings"},{"include":"#less-variables"},{"include":"#var-function"},{"match":"--(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))+|-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*","name":"entity.other.counter-name.less"},{"begin":"(?=,)","end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"match":"\\\\b((?i:arabic-indic|armenian|bengali|cambodian|circle|cjk-decimal|cjk-earthly-branch|cjk-heavenly-stem|decimal-leading-zero|decimal|devanagari|disclosure-closed|disclosure-open|disc|ethiopic-numeric|georgian|gujarati|gurmukhi|hebrew|hiragana-iroha|hiragana|japanese-formal|japanese-informal|kannada|katakana-iroha|katakana|khmer|korean-hangul-formal|korean-hanja-formal|korean-hanja-informal|lao|lower-alpha|lower-armenian|lower-greek|lower-latin|lower-roman|malayalam|mongolian|myanmar|oriya|persian|simp-chinese-formal|simp-chinese-informal|square|tamil|telugu|thai|tibetan|trad-chinese-formal|trad-chinese-informal|upper-alpha|upper-armenian|upper-latin|upper-roman)|none)\\\\b","name":"support.constant.property-value.counter-style.less"}]}]}]},{"begin":"\\\\b(counters)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"(-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)","name":"entity.other.counter-name.less string.unquoted.less"},{"begin":"(?=,)","end":"(?=\\\\))","patterns":[{"include":"#less-strings"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#literal-string"},{"include":"#comma-delimiter"},{"match":"\\\\b((?i:arabic-indic|armenian|bengali|cambodian|circle|cjk-decimal|cjk-earthly-branch|cjk-heavenly-stem|decimal-leading-zero|decimal|devanagari|disclosure-closed|disclosure-open|disc|ethiopic-numeric|georgian|gujarati|gurmukhi|hebrew|hiragana-iroha|hiragana|japanese-formal|japanese-informal|kannada|katakana-iroha|katakana|khmer|korean-hangul-formal|korean-hanja-formal|korean-hanja-informal|lao|lower-alpha|lower-armenian|lower-greek|lower-latin|lower-roman|malayalam|mongolian|myanmar|oriya|persian|simp-chinese-formal|simp-chinese-informal|square|tamil|telugu|thai|tibetan|trad-chinese-formal|trad-chinese-informal|upper-alpha|upper-armenian|upper-latin|upper-roman)|none)\\\\b","name":"support.constant.property-value.counter-style.less"}]}]}]}]},"cross-fade-function":{"patterns":[{"begin":"\\\\b(cross-fade)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.image.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#percentage-type"},{"include":"#color-values"},{"include":"#image-type"},{"include":"#literal-string"},{"include":"#unquoted-string"}]}]}]},"cubic-bezier-function":{"begin":"\\\\b(cubic-bezier)(\\\\()","beginCaptures":{"1":{"name":"support.function.timing.less"},"2":{"name":"punctuation.definition.group.begin.less"}},"contentName":"meta.group.less","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"include":"#less-functions"},{"include":"#calc-function"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#comma-delimiter"},{"include":"#number-type"}]},"custom-property-name":{"captures":{"1":{"name":"punctuation.definition.custom-property.less"},"2":{"name":"support.type.custom-property.name.less"}},"match":"\\\\s*(--)((?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))+)","name":"support.type.custom-property.less"},"dimensions":{"patterns":[{"include":"#angle-type"},{"include":"#frequency-type"},{"include":"#time-type"},{"include":"#percentage-type"},{"include":"#length-type"}]},"filter-function":{"begin":"\\\\b(filter)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","name":"meta.group.less","patterns":[{"include":"#comma-delimiter"},{"include":"#image-type"},{"include":"#literal-string"},{"include":"#filter-functions"}]}]},"filter-functions":{"patterns":[{"include":"#less-functions"},{"begin":"\\\\b(blur)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#length-type"}]}]},{"begin":"\\\\b(brightness|contrast|grayscale|invert|opacity|saturate|sepia)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#percentage-type"},{"include":"#number-type"},{"include":"#less-functions"}]}]},{"begin":"\\\\b(drop-shadow)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#length-type"},{"include":"#color-values"}]}]},{"begin":"\\\\b(hue-rotate)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.filter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#angle-type"}]}]}]},"fit-content-function":{"begin":"\\\\b(fit-content)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.grid.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#var-function"},{"include":"#calc-function"},{"include":"#percentage-type"},{"include":"#length-type"}]}]},"format-function":{"patterns":[{"begin":"\\\\b(format)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.format.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#literal-string"}]}]}]},"frequency-type":{"captures":{"1":{"name":"keyword.other.unit.less"}},"match":"(?i:[-+]?(?:\\\\d*\\\\.\\\\d+(?:[Ee][-+]?\\\\d+)*|[-+]?\\\\d+)(k??Hz))\\\\b","name":"constant.numeric.less"},"global-property-values":{"match":"\\\\b(?:initial|inherit|unset|revert-layer|revert)\\\\b","name":"support.constant.property-value.less"},"gradient-functions":{"patterns":[{"begin":"\\\\b((?:repeating-)?linear-gradient)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.gradient.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#var-function"},{"include":"#angle-type"},{"include":"#color-values"},{"include":"#percentage-type"},{"include":"#length-type"},{"include":"#comma-delimiter"},{"match":"\\\\bto\\\\b","name":"keyword.other.less"},{"match":"\\\\b(top|right|bottom|left)\\\\b","name":"support.constant.property-value.less"}]}]},{"begin":"\\\\b((?:repeating-)?radial-gradient)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.gradient.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#var-function"},{"include":"#color-values"},{"include":"#percentage-type"},{"include":"#length-type"},{"include":"#comma-delimiter"},{"match":"\\\\b(at|circle|ellipse)\\\\b","name":"keyword.other.less"},{"match":"\\\\b(top|right|bottom|left|center|((?:farth|clos)est)-(corner|side))\\\\b","name":"support.constant.property-value.less"}]}]}]},"grid-repeat-function":{"begin":"\\\\b(repeat)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.grid.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#var-function"},{"include":"#length-type"},{"include":"#percentage-type"},{"include":"#minmax-function"},{"include":"#integer-type"},{"match":"\\\\b(auto-(fi(?:ll|t)))\\\\b","name":"support.keyword.repetitions.less"},{"match":"\\\\b(((m(?:ax|in))-content)|auto)\\\\b","name":"support.constant.property-value.less"}]}]},"image-function":{"begin":"\\\\b(image)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.image.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#image-type"},{"include":"#literal-string"},{"include":"#color-values"},{"include":"#comma-delimiter"},{"include":"#unquoted-string"}]}]},"image-type":{"patterns":[{"include":"#cross-fade-function"},{"include":"#gradient-functions"},{"include":"#image-function"},{"include":"#url-function"}]},"important":{"captures":{"1":{"name":"punctuation.separator.less"}},"match":"(!)\\\\s*important","name":"keyword.other.important.less"},"integer-type":{"match":"[-+]?\\\\d+","name":"constant.numeric.less"},"keyframe-name":{"begin":"\\\\s*(-?(?:[_a-z[^\\\\x00-\\\\x7F]]|(?:(:?\\\\\\\\[0-9a-f]{1,6}(\\\\r\\\\n|[\\\\t\\\\n\\\\f\\\\r\\\\s])?)|\\\\\\\\[^\\\\n\\\\f\\\\r0-9a-f]))(?:[-0-9_a-z[^\\\\x00-\\\\x7F]]|(?:(:?\\\\\\\\[0-9a-f]{1,6}(\\\\r\\\\n|[\\\\t\\\\n\\\\f\\\\r])?)|\\\\\\\\[^\\\\n\\\\f\\\\r0-9a-f]))*)?","beginCaptures":{"1":{"name":"variable.other.constant.animation-name.less"}},"end":"\\\\s*(?:(,)|(?=[;{]))","endCaptures":{"1":{"name":"punctuation.definition.arbitrary-repetition.less"}}},"length-type":{"patterns":[{"captures":{"1":{"name":"keyword.other.unit.less"}},"match":"[-+]?(?:\\\\d+\\\\.\\\\d+|\\\\.?\\\\d+)(?:[Ee][-+]?\\\\d+)?(em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|[mq]|in|pt|pc|px|fr|dpi|dpcm|dppx|x)","name":"constant.numeric.less"},{"match":"\\\\b[-+]?0\\\\b","name":"constant.numeric.less"}]},"less-boolean-function":{"begin":"\\\\b(boolean)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.boolean.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-logical-comparisons"}]}]},"less-color-blend-functions":{"patterns":[{"begin":"\\\\b(multiply|screen|overlay|(soft|hard)light|difference|exclusion|negation|average)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-blend.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#var-function"},{"include":"#comma-delimiter"},{"include":"#color-values"}]}]}]},"less-color-channel-functions":{"patterns":[{"begin":"\\\\b(hue|saturation|lightness|hsv(hue|saturation|value)|red|green|blue|alpha|luma|luminance)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-definition.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"}]}]}]},"less-color-definition-functions":{"patterns":[{"begin":"\\\\b(argb)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-definition.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#var-function"},{"include":"#color-values"}]}]},{"begin":"\\\\b(hsva?)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#integer-type"},{"include":"#percentage-type"},{"include":"#number-type"},{"include":"#less-strings"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#calc-function"},{"include":"#comma-delimiter"}]}]}]},"less-color-functions":{"patterns":[{"include":"#less-color-blend-functions"},{"include":"#less-color-channel-functions"},{"include":"#less-color-definition-functions"},{"include":"#less-color-operation-functions"}]},"less-color-operation-functions":{"patterns":[{"begin":"\\\\b(fade|shade|tint)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-operation.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#comma-delimiter"},{"include":"#percentage-type"}]}]},{"begin":"\\\\b(spin)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-operation.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#comma-delimiter"},{"include":"#number-type"}]}]},{"begin":"\\\\b(((de)?saturate)|((light|dark)en)|(fade(in|out)))(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-operation.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#comma-delimiter"},{"include":"#percentage-type"},{"match":"\\\\brelative\\\\b","name":"constant.language.relative.less"}]}]},{"begin":"\\\\b(contrast)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-operation.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#comma-delimiter"},{"include":"#percentage-type"}]}]},{"begin":"\\\\b(greyscale)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-operation.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"}]}]},{"begin":"\\\\b(mix)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color-operation.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#color-values"},{"include":"#comma-delimiter"},{"include":"#less-math"},{"include":"#percentage-type"}]}]}]},"less-extend":{"begin":"(:)(extend)(?=\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"},"2":{"name":"entity.other.attribute-name.pseudo-class.extend.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"\\\\ball\\\\b","name":"constant.language.all.less"},{"include":"#selectors"}]}]},"less-functions":{"patterns":[{"include":"#less-boolean-function"},{"include":"#less-color-functions"},{"include":"#less-if-function"},{"include":"#less-list-functions"},{"include":"#less-math-functions"},{"include":"#less-misc-functions"},{"include":"#less-string-functions"},{"include":"#less-type-functions"}]},"less-if-function":{"begin":"\\\\b(if)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.if.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-mixin-guards"},{"include":"#comma-delimiter"},{"include":"#property-values"}]}]},"less-list-functions":{"patterns":[{"begin":"\\\\b(length)(?=\\\\()\\\\b","beginCaptures":{"1":{"name":"support.function.length.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#property-values"},{"include":"#comma-delimiter"}]}]},{"begin":"\\\\b(extract)(?=\\\\()\\\\b","beginCaptures":{"1":{"name":"support.function.extract.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#property-values"},{"include":"#comma-delimiter"},{"include":"#integer-type"}]}]},{"begin":"\\\\b(range)(?=\\\\()\\\\b","beginCaptures":{"1":{"name":"support.function.range.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#property-values"},{"include":"#comma-delimiter"},{"include":"#integer-type"}]}]}]},"less-logical-comparisons":{"patterns":[{"captures":{"1":{"name":"keyword.operator.logical.less"}},"match":"\\\\s*(=|(([<>])=?))\\\\s*"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.group.less","patterns":[{"include":"#less-logical-comparisons"}]},{"match":"\\\\btrue|false\\\\b","name":"constant.language.less"},{"match":",","name":"punctuation.separator.less"},{"include":"#property-values"},{"include":"#selectors"},{"include":"#unquoted-string"}]},"less-math":{"patterns":[{"match":"[-*+/]","name":"keyword.operator.arithmetic.less"},{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.group.less","patterns":[{"include":"#less-math"}]},{"include":"#numeric-values"},{"include":"#less-variables"}]},"less-math-functions":{"patterns":[{"begin":"\\\\b(ceil|floor|percentage|round|sqrt|abs|a?(sin|cos|tan))(?=\\\\()","beginCaptures":{"1":{"name":"support.function.math.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#numeric-values"}]}]},{"captures":{"2":{"name":"support.function.math.less"},"3":{"name":"punctuation.definition.group.begin.less"},"4":{"name":"punctuation.definition.group.end.less"}},"match":"((pi)(\\\\()(\\\\)))","name":"meta.function-call.less"},{"begin":"\\\\b(pow|m(od|in|ax))(?=\\\\()","beginCaptures":{"1":{"name":"support.function.math.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#numeric-values"},{"include":"#comma-delimiter"}]}]}]},"less-misc-functions":{"patterns":[{"begin":"\\\\b(color)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.color.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#literal-string"}]}]},{"begin":"\\\\b(image-(size|width|height))(?=\\\\()","beginCaptures":{"1":{"name":"support.function.image.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#literal-string"},{"include":"#unquoted-string"}]}]},{"begin":"\\\\b(convert|unit)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.convert.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#numeric-values"},{"include":"#literal-string"},{"include":"#comma-delimiter"},{"match":"(([cm])?m|in|p([ctx])|m?s|g?rad|deg|turn|%|r?em|ex|ch)","name":"keyword.other.unit.less"}]}]},{"begin":"\\\\b(data-uri)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.data-uri.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#literal-string"},{"captures":{"1":{"name":"punctuation.separator.less"}},"match":"\\\\s*(,)"}]}]},{"captures":{"2":{"name":"punctuation.definition.group.begin.less"},"3":{"name":"punctuation.definition.group.end.less"}},"match":"\\\\b(default(\\\\()(\\\\)))\\\\b","name":"support.function.default.less"},{"begin":"\\\\b(get-unit)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.get-unit.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#dimensions"}]}]},{"begin":"\\\\b(svg-gradient)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.svg-gradient.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#angle-type"},{"include":"#comma-delimiter"},{"include":"#color-values"},{"include":"#percentage-type"},{"include":"#length-type"},{"match":"\\\\bto\\\\b","name":"keyword.other.less"},{"match":"\\\\b(top|right|bottom|left|center)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(at|circle|ellipse)\\\\b","name":"keyword.other.less"}]}]}]},"less-mixin-guards":{"patterns":[{"begin":"\\\\s*(and|not|or)?\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"keyword.operator.logical.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","name":"meta.group.less","patterns":[{"include":"#less-variable-comparison"},{"captures":{"1":{"name":"meta.group.less"},"2":{"name":"punctuation.definition.group.begin.less"},"3":{"name":"punctuation.definition.group.end.less"}},"match":"default((\\\\()(\\\\)))","name":"support.function.default.less"},{"include":"#property-values"},{"include":"#less-logical-comparisons"},{"include":"$self"}]}]}]},"less-namespace-accessors":{"patterns":[{"begin":"(?=\\\\s*when\\\\b)","end":"\\\\s*(?:(,)|(?=[;{]))","endCaptures":{"1":{"name":"punctuation.definition.block.end.less"}},"name":"meta.conditional.guarded-namespace.less","patterns":[{"captures":{"1":{"name":"keyword.control.conditional.less"},"2":{"name":"punctuation.definition.keyword.less"}},"match":"\\\\s*(when)(?=.*?)"},{"include":"#less-mixin-guards"},{"include":"#comma-delimiter"},{"begin":"\\\\s*(\\\\{)","beginCaptures":{"1":{"name":"punctuation.section.property-list.begin.less"}},"end":"(?=})","name":"meta.block.less","patterns":[{"include":"#rule-list-body"}]},{"include":"#selectors"}]},{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.group.begin.less"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.group.end.less"},"2":{"name":"punctuation.terminator.rule.less"}},"name":"meta.group.less","patterns":[{"include":"#less-variable-assignment"},{"include":"#comma-delimiter"},{"include":"#property-values"},{"include":"#rule-list-body"}]},{"captures":{"1":{"name":"punctuation.terminator.rule.less"}},"match":"(;)|(?=[)}])"}]},"less-string-functions":{"patterns":[{"begin":"\\\\b(e(scape)?)(?=\\\\()\\\\b","beginCaptures":{"1":{"name":"support.function.escape.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#comma-delimiter"},{"include":"#literal-string"},{"include":"#unquoted-string"}]}]},{"begin":"\\\\s*(%)(?=\\\\()\\\\s*","beginCaptures":{"1":{"name":"support.function.format.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#comma-delimiter"},{"include":"#literal-string"},{"include":"#property-values"}]}]},{"begin":"\\\\b(replace)(?=\\\\()\\\\b","beginCaptures":{"1":{"name":"support.function.replace.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#comma-delimiter"},{"include":"#literal-string"},{"include":"#property-values"}]}]}]},"less-strings":{"patterns":[{"begin":"(~)([\\"'])","beginCaptures":{"1":{"name":"constant.character.escape.less"},"2":{"name":"punctuation.definition.string.begin.less"}},"contentName":"markup.raw.inline.less","end":"([\\"'])|(\\\\n)","endCaptures":{"1":{"name":"punctuation.definition.string.end.less"},"2":{"name":"invalid.illegal.newline.less"}},"name":"string.quoted.other.less","patterns":[{"include":"#string-content"}]}]},"less-type-functions":{"patterns":[{"begin":"\\\\b(is(number|string|color|keyword|url|pixel|em|percentage|ruleset))(?=\\\\()","beginCaptures":{"1":{"name":"support.function.type.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#property-values"}]}]},{"begin":"\\\\b(isunit)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.type.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#property-values"},{"include":"#comma-delimiter"},{"match":"\\\\b((?i:em|ex|ch|rem)|(?i:v(?:[hw]|min|max))|(?i:cm|mm|q|in|pt|pc|px|fr)|(?i:deg|grad|rad|turn)|(?i:m??s)|(?i:k??Hz)|(?i:dp(?:i|cm|px)))\\\\b","name":"keyword.other.unit.less"}]}]},{"begin":"\\\\b(isdefined)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.type.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"}]}]}]},"less-variable-assignment":{"patterns":[{"begin":"(@)(-?(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)","beginCaptures":{"0":{"name":"variable.other.readwrite.less"},"1":{"name":"punctuation.definition.variable.less"},"2":{"name":"support.other.variable.less"}},"end":"\\\\s*(;|(\\\\.{3})|(?=\\\\)))","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"},"2":{"name":"keyword.operator.spread.less"}},"name":"meta.property-value.less","patterns":[{"captures":{"1":{"name":"punctuation.separator.key-value.less"},"4":{"name":"meta.property-value.less"}},"match":"(((\\\\+_?)?):)([\\\\t\\\\s]*)"},{"include":"#property-values"},{"include":"#comma-delimiter"},{"include":"#property-list"},{"include":"#unquoted-string"}]}]},"less-variable-comparison":{"patterns":[{"begin":"(@{1,2})(-?([_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)","beginCaptures":{"0":{"name":"variable.other.readwrite.less"},"1":{"name":"punctuation.definition.variable.less"},"2":{"name":"support.other.variable.less"}},"end":"\\\\s*(?=\\\\))","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"captures":{"1":{"name":"keyword.operator.logical.less"}},"match":"\\\\s*(=|(([<>])=?))\\\\s*"},{"match":"\\\\btrue\\\\b","name":"constant.language.less"},{"include":"#property-values"},{"include":"#selectors"},{"include":"#unquoted-string"},{"match":",","name":"punctuation.separator.less"}]}]},"less-variable-interpolation":{"captures":{"1":{"name":"punctuation.definition.variable.less"},"2":{"name":"punctuation.definition.expression.less"},"3":{"name":"support.other.variable.less"},"4":{"name":"punctuation.definition.expression.less"}},"match":"(@)(\\\\{)([-\\\\w]+)(})","name":"variable.other.readwrite.less"},"less-variables":{"patterns":[{"captures":{"1":{"name":"punctuation.definition.variable.less"},"2":{"name":"support.other.variable.less"}},"match":"\\\\s*(@@?)([-\\\\w]+)","name":"variable.other.readwrite.less"},{"include":"#less-variable-interpolation"}]},"literal-string":{"patterns":[{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.less"}},"end":"(')|(\\\\n)","endCaptures":{"1":{"name":"punctuation.definition.string.end.less"},"2":{"name":"invalid.illegal.newline.less"}},"name":"string.quoted.single.less","patterns":[{"include":"#string-content"}]},{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.less"}},"end":"(\\")|(\\\\n)","endCaptures":{"1":{"name":"punctuation.definition.string.end.less"},"2":{"name":"invalid.illegal.newline.less"}},"name":"string.quoted.double.less","patterns":[{"include":"#string-content"}]},{"include":"#less-strings"}]},"local-function":{"begin":"\\\\b(local)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.font-face.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#unquoted-string"}]}]},"media-query":{"begin":"\\\\s*(only|not)?\\\\s*(all|aural|braille|embossed|handheld|print|projection|screen|tty|tv)?","beginCaptures":{"1":{"name":"keyword.operator.logic.media.less"},"2":{"name":"support.constant.media.less"}},"end":"\\\\s*(?:(,)|(?=[;{]))","endCaptures":{"1":{"name":"punctuation.definition.arbitrary-repetition.less"}},"patterns":[{"include":"#less-variables"},{"include":"#custom-property-name"},{"begin":"\\\\s*(and)?\\\\s*(\\\\()\\\\s*","beginCaptures":{"1":{"name":"keyword.operator.logic.media.less"},"2":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.group.less","patterns":[{"begin":"(--|-?(?:[A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))(?:[-A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}\\\\d]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))*)\\\\s*(?=[):])","beginCaptures":{"0":{"name":"support.type.property-name.media.less"}},"end":"(((\\\\+_?)?):)|(?=\\\\))","endCaptures":{"1":{"name":"punctuation.separator.key-value.less"}}},{"match":"\\\\b(portrait|landscape|progressive|interlace)","name":"support.constant.property-value.less"},{"captures":{"1":{"name":"constant.numeric.less"},"2":{"name":"keyword.operator.arithmetic.less"},"3":{"name":"constant.numeric.less"}},"match":"\\\\s*(\\\\d+)(/)(\\\\d+)"},{"include":"#less-math"}]}]},"media-query-list":{"begin":"\\\\s*(?=[^;{])","end":"\\\\s*(?=[;{])","patterns":[{"include":"#media-query"}]},"minmax-function":{"begin":"\\\\b(minmax)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.grid.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#var-function"},{"include":"#length-type"},{"include":"#comma-delimiter"},{"match":"\\\\b(m(?:ax|in)-content)\\\\b","name":"support.constant.property-value.less"}]}]},"number-type":{"match":"[-+]?(?:\\\\d+\\\\.\\\\d+|\\\\.?\\\\d+)(?:[Ee][-+]?\\\\d+)?","name":"constant.numeric.less"},"numeric-values":{"patterns":[{"include":"#dimensions"},{"include":"#percentage-type"},{"include":"#number-type"}]},"percentage-type":{"captures":{"1":{"name":"keyword.other.unit.less"}},"match":"[-+]?(?:\\\\d+\\\\.\\\\d+|\\\\.?\\\\d+)(?:[Ee][-+]?\\\\d+)?(%)","name":"constant.numeric.less"},"property-list":{"patterns":[{"begin":"(?=(?=[^;]*)\\\\{)","end":"}","endCaptures":{"0":{"name":"punctuation.definition.block.end.less"}},"patterns":[{"include":"#rule-list"}]}]},"property-value-constants":{"patterns":[{"match":"\\\\b(flex-start|flex-end|start|end|space-between|space-around|space-evenly|stretch|baseline|safe|unsafe|legacy|anchor-center|first|last|self-start|self-end)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(text-before-edge|before-edge|middle|central|text-after-edge|after-edge|ideographic|alphabetic|hanging|mathematical|top|center|bottom)\\\\b","name":"support.constant.property-value.less"},{"include":"#global-property-values"},{"include":"#cubic-bezier-function"},{"include":"#steps-function"},{"match":"\\\\b(?:replace|add|accumulate)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(?:normal|alternate-reverse|alternate|reverse)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(?:forwards|backwards|both)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\binfinite\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(?:running|paused)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\be(?:ntry|xit)(?:-crossing|)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(linear|ease-in-out|ease-in|ease-out|ease|step-start|step-end)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(absolute|active|add|all-petite-caps|all-small-caps|all-scroll|all|alphabetic|alpha|alternate-reverse|alternate|always|annotation|antialiased|at|autohiding-scrollbar|auto|avoid-column|avoid-page|avoid-region|avoid|background-color|background-image|background-position|background-size|background-repeat|background|backwards|balance|baseline|below|bevel|bicubic|bidi-override|blink|block-line-height|block-start|block-end|block|blur|bolder|bold|border-top-left-radius|border-top-right-radius|border-bottom-left-radius|border-bottom-right-radius|border-end-end-radius|border-end-start-radius|border-start-end-radius|border-start-start-radius|border-block-start-color|border-block-start-style|border-block-start-width|border-block-start|border-block-end-color|border-block-end-style|border-block-end-width|border-block-end|border-block-color|border-block-style|border-block-width|border-block|border-inline-start-color|border-inline-start-style|border-inline-start-width|border-inline-start|border-inline-end-color|border-inline-end-style|border-inline-end-width|border-inline-end|border-inline-color|border-inline-style|border-inline-width|border-inline|border-top-color|border-top-style|border-top-width|border-top|border-right-color|border-right-style|border-right-width|border-right|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-left-color|border-left-style|border-left-width|border-left|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-image|border-color|border-style|border-width|border-radius|border-collapse|border-spacing|border|both|bottom|box-shadow|box|break-all|break-word|break-spaces|brightness|butt(on)?|capitalize|central|center|char(acter-variant)?|cjk-ideographic|clip|clone|close-quote|closest-corner|closest-side|col-resize|collapse|color-stop|color-burn|color-dodge|color|column-count|column-gap|column-reverse|column-rule-color|column-rule-width|column-rule|column-width|columns?|common-ligatures|condensed|consider-shifts|contain|content-box|contents?|contextual|contrast|cover|crisp-edges|crispEdges|crop|crosshair|cross|darken|dashed|default|dense|device-width|diagonal-fractions|difference|disabled|discard|discretionary-ligatures|disregard-shifts|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|drop-shadow|[ensw]{1,4}-resize|ease-in-out|ease-in|ease-out|ease|element|ellipsis|embed|end|EndColorStr|evenodd|exclude-ruby|exclusion|expanded|extra-condensed|extra-expanded|farthest-corner|farthest-side|farthest|fill-box|fill-opacity|fill|filter|fit-content|fixed|flat|flex-basis|flex-end|flex-grow|flex-shrink|flex-start|flexbox|flex|flip|flood-color|font-size-adjust|font-size|font-stretch|font-weight|font|forwards|from-image|from|full-width|gap|geometricPrecision|glyphs|gradient|grayscale|grid-column-gap|grid-column|grid-row-gap|grid-row|grid-gap|grid-height|grid|groove|hand|hanging|hard-light|height|help|hidden|hide|historical-forms|historical-ligatures|horizontal-tb|horizontal|hue|ideographic|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|inactive|include-ruby|infinite|inherit|initial|inline-end|inline-size|inline-start|inline-table|inline-line-height|inline-flexbox|inline-flex|inline-box|inline-block|inline|inset|inside|inter-ideograph|inter-word|intersect|invert|isolate|isolation|italic|jis(04|78|83|90)|justify-all|justify|keep-all|larger?|last|layout|left|letter-spacing|lighten|lighter|lighting-color|linear-gradient|linearRGB|linear|line-edge|line-height|line-through|line|lining-nums|list-item|local|loose|lowercase|lr-tb|ltr|luminosity|luminance|manual|manipulation|margin-bottom|margin-box|margin-left|margin-right|margin-top|margin|marker(-offset|s)?|match-parent|mathematical|max-(content|height|lines|size|width)|medium|middle|min-(content|height|width)|miter|mixed|move|multiply|newspaper|no-change|no-clip|no-close-quote|no-open-quote|no-common-ligatures|no-discretionary-ligatures|no-historical-ligatures|no-contextual|no-drop|no-repeat|none|nonzero|normal|not-allowed|nowrap|oblique|offset-after|offset-before|offset-end|offset-start|offset|oldstyle-nums|opacity|open-quote|optimize(Legibility|Precision|Quality|Speed)|order|ordinal|ornaments|outline-color|outline-offset|outline-width|outline|outset|outside|overline|over-edge|overlay|padding(-(?:bottom|box|left|right|top|box))?|page|paint(ed)?|paused|pan-(x|left|right|y|up|down)|perspective-origin|petite-caps|pixelated|pointer|pinch-zoom|pretty|pre(-(?:line|wrap))?|preserve-3d|preserve-breaks|preserve-spaces|preserve|progid:DXImageTransform\\\\.Microsoft\\\\.(Alpha|Blur|dropshadow|gradient|Shadow)|progress|proportional-nums|proportional-width|radial-gradient|recto|region|relative|repeating-linear-gradient|repeating-radial-gradient|repeat-x|repeat-y|repeat|replaced|reset-size|reverse|revert-layer|revert|ridge|right|round|row-gap|row-resize|row-reverse|row|rtl|ruby|running|saturate|saturation|screen|scrollbar|scroll-position|scroll|separate|sepia|scale-down|semi-condensed|semi-expanded|shape-image-threshold|shape-margin|shape-outside|show|sideways-lr|sideways-rl|sideways|simplified|size|slashed-zero|slice|small-caps|smaller|small|smooth|snap|solid|soft-light|space-around|space-between|space|span|sRGB|stable|stacked-fractions|stack|startColorStr|start|static|step-end|step-start|sticky|stop-color|stop-opacity|stretch|strict|stroke-box|stroke-dasharray|stroke-dashoffset|stroke-miterlimit|stroke-opacity|stroke-width|stroke|styleset|style|stylistic|subgrid|subpixel-antialiased|subtract|super|swash|table-caption|table-cell|table-column-group|table-footer-group|table-header-group|table-row-group|table-column|table-row|table|tabular-nums|tb-rl|text((-(?:bottom|(decoration|emphasis)-color|indent|(over|under)-edge|shadow|size(-adjust)?|top))|field)?|thick|thin|titling-caps|titling-case|top|touch|to|traditional|transform-origin|transform-style|transform|ultra-condensed|ultra-expanded|under-edge|underline|unicase|unset|uppercase|upright|use-glyph-orientation|use-script|verso|vertical(-(?:align|ideographic|lr|rl|text))?|view-box|viewport-fill-opacity|viewport-fill|visibility|visibleFill|visiblePainted|visibleStroke|visible|wait|wavy|weight|whitespace|width|word-spacing|wrap-reverse|wrap|xx?-(large|small)|z-index|zero|zoom-in|zoom-out|zoom|arabic-indic|armenian|bengali|cambodian|circle|cjk-decimal|cjk-earthly-branch|cjk-heavenly-stem|decimal-leading-zero|decimal|devanagari|disclosure-closed|disclosure-open|disc|ethiopic-numeric|georgian|gujarati|gurmukhi|hebrew|hiragana-iroha|hiragana|japanese-formal|japanese-informal|kannada|katakana-iroha|katakana|khmer|korean-hangul-formal|korean-hanja-formal|korean-hanja-informal|lao|lower-alpha|lower-armenian|lower-greek|lower-latin|lower-roman|malayalam|mongolian|myanmar|oriya|persian|simp-chinese-formal|simp-chinese-informal|square|tamil|telugu|thai|tibetan|trad-chinese-formal|trad-chinese-informal|upper-alpha|upper-armenian|upper-latin|upper-roman)\\\\b","name":"support.constant.property-value.less"},{"match":"\\\\b(sans-serif|serif|monospace|fantasy|cursive)\\\\b(?=\\\\s*[\\\\n,;}])","name":"support.constant.font-name.less"}]},"property-values":{"patterns":[{"include":"#comment-block"},{"include":"#builtin-functions"},{"include":"#color-functions"},{"include":"#less-functions"},{"include":"#less-variables"},{"include":"#unicode-range"},{"include":"#numeric-values"},{"include":"#color-values"},{"include":"#property-value-constants"},{"include":"#less-math"},{"include":"#literal-string"},{"include":"#comma-delimiter"},{"include":"#important"}]},"pseudo-selectors":{"patterns":[{"begin":"(:)(dir)(?=\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-class.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"ltr|rtl","name":"variable.parameter.dir.less"},{"include":"#less-variables"}]}]},{"begin":"(:)(lang)(?=\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-class.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#literal-string"},{"include":"#unquoted-string"}]}]},{"begin":"(:)(not)(?=\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-class.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#selectors"}]}]},{"begin":"(:)(nth(-last)?-(child|of-type))(?=\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"},"2":{"name":"entity.other.attribute-name.pseudo-class.less"}},"contentName":"meta.function-call.less","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-class.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","name":"meta.group.less","patterns":[{"match":"\\\\b(even|odd)\\\\b","name":"keyword.other.pseudo-class.less"},{"captures":{"1":{"name":"keyword.operator.arithmetic.less"},"2":{"name":"keyword.other.unit.less"},"4":{"name":"keyword.operator.arithmetic.less"}},"match":"([-+])?\\\\d+{0,1}(n)(\\\\s*([-+])\\\\s*\\\\d+)?|[-+]?\\\\s*\\\\d+","name":"constant.numeric.less"},{"include":"#less-math"},{"include":"#less-strings"},{"include":"#less-variable-interpolation"}]}]},{"begin":"(:)(host-context|host|has|is|not|where)(?=\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-class.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#selectors"}]}]},{"captures":{"1":{"name":"punctuation.definition.entity.less"},"2":{"name":"entity.other.attribute-name.pseudo-class.less"}},"match":"(:)(active|any-link|autofill|blank|buffering|checked|current|default|defined|disabled|empty|enabled|first-child|first-of-type|first|focus-visible|focus-within|focus|fullscreen|future|host|hover|in-range|indeterminate|invalid|last-child|last-of-type|left|local-link|link|modal|muted|only-child|only-of-type|optional|out-of-range|past|paused|picture-in-picture|placeholder-shown|playing|popover-open|read-only|read-write|required|right|root|scope|seeking|stalled|target-within|target|user-invalid|user-valid|valid|visited|volume-locked)\\\\b","name":"meta.function-call.less"},{"begin":"(::?)(highlight|part|state)(?=\\\\s*(\\\\())","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-element.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"--|-?(?:[A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))(?:[-A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}\\\\d]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))*","name":"variable.parameter.less"},{"include":"#less-variables"}]}]},{"begin":"(::?)slotted(?=\\\\s*(\\\\())","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"contentName":"meta.function-call.less","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"entity.other.attribute-name.pseudo-element.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","name":"meta.group.less","patterns":[{"include":"#selectors"}]}]},{"captures":{"1":{"name":"punctuation.definition.entity.less"}},"match":"(::?)(after|backdrop|before|cue|file-selector-button|first-letter|first-line|grammar-error|marker|placeholder|selection|spelling-error|target-text|view-transition-group|view-transition-image-pair|view-transition-new|view-transition-old|view-transition)\\\\b","name":"entity.other.attribute-name.pseudo-element.less"},{"captures":{"1":{"name":"punctuation.definition.entity.less"},"2":{"name":"meta.namespace.vendor-prefix.less"}},"match":"(::?)(-\\\\w+-)(--|-?(?:[A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))(?:[-A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}\\\\d]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))*)\\\\b","name":"entity.other.attribute-name.pseudo-element.less"}]},"qualified-name":{"captures":{"1":{"name":"entity.name.constant.less"},"2":{"name":"entity.name.namespace.wildcard.less"},"3":{"name":"punctuation.separator.namespace.less"}},"match":"(?:(-?(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)|(\\\\*))?(\\\\|)(?!=)"},"regexp-function":{"begin":"\\\\b(regexp)(?=\\\\()","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"support.function.regexp.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","name":"meta.function-call.less","patterns":[{"include":"#literal-string"}]}]},"relative-color":{"patterns":[{"match":"from","name":"keyword.other.less"},{"match":"\\\\b[abchlsw]\\\\b","name":"keyword.other.less"}]},"rule-list":{"patterns":[{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.block.begin.less"}},"end":"(?=\\\\s*})","name":"meta.property-list.less","patterns":[{"captures":{"1":{"name":"punctuation.terminator.rule.less"}},"match":"\\\\s*(;)|(?=[)}])"},{"include":"#rule-list-body"},{"include":"#less-extend"}]}]},"rule-list-body":{"patterns":[{"include":"#comment-block"},{"include":"#comment-line"},{"include":"#at-rules"},{"include":"#less-variable-assignment"},{"begin":"(?=[-\\\\w]*?@\\\\{.*}[-\\\\w]*?\\\\s*:[^(;{]*(?=[);}]))","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"begin":"(?=[^:\\\\s])","end":"(?=(((\\\\+_?)?):)[\\\\t\\\\s]*)","name":"support.type.property-name.less","patterns":[{"include":"#less-variable-interpolation"}]},{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"support.type.property-name.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"include":"#property-values"}]}]},{"begin":"(?=[-a-z])","end":"$|(?![-a-z])","patterns":[{"include":"#custom-property-name"},{"begin":"(-[-\\\\w]+?-)((?:[A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))(?:[-A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}\\\\d]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))*)\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"},"1":{"name":"meta.namespace.vendor-prefix.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"meta.property-value.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"include":"#property-values"},{"match":"[-\\\\w]+","name":"support.constant.property-value.less"}]}]},{"include":"#filter-function"},{"begin":"\\\\b(border((-(bottom|top)-(left|right))|((-(start|end)){2}))?-radius|(border-image(?!-)))\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"meta.property-value.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"include":"#value-separator"},{"include":"#property-values"}]}]},{"captures":{"1":{"name":"keyword.other.custom-property.prefix.less"},"2":{"name":"support.type.custom-property.name.less"}},"match":"\\\\b(var-)(-?(?:[-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[A-Z_a-z[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)(?=\\\\s)","name":"invalid.deprecated.custom-property.less"},{"begin":"\\\\bfont(-family)?(?!-)\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"name":"meta.property-name.less","patterns":[{"captures":{"1":{"name":"punctuation.separator.key-value.less"},"4":{"name":"meta.property-value.less"}},"match":"(((\\\\+_?)?):)([\\\\t\\\\s]*)"},{"include":"#property-values"},{"match":"-?(?:[A-Z_a-z[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*(\\\\s+-?(?:[A-Z_a-z[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)*","name":"string.unquoted.less"},{"match":",","name":"punctuation.separator.less"}]},{"begin":"\\\\banimation-timeline\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"meta.property-value.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"include":"#comment-block"},{"include":"#custom-property-name"},{"include":"#scroll-function"},{"include":"#view-function"},{"include":"#property-values"},{"include":"#less-variables"},{"include":"#arbitrary-repetition"},{"include":"#important"}]}]},{"begin":"\\\\banimation(?:-name)?(?=(?:\\\\+_?)?:)\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"meta.property-value.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"include":"#comment-block"},{"include":"#builtin-functions"},{"include":"#less-functions"},{"include":"#less-variables"},{"include":"#numeric-values"},{"include":"#property-value-constants"},{"match":"-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|(?:(:?\\\\\\\\[0-9a-f]{1,6}(\\\\r\\\\n|[\\\\t\\\\n\\\\f\\\\r\\\\s])?)|\\\\\\\\[^\\\\n\\\\f\\\\r0-9a-f]))(?:[-0-9A-Z_a-z[^\\\\x00-\\\\x7F]]|(?:(:?\\\\\\\\[0-9a-f]{1,6}(\\\\r\\\\n|[\\\\t\\\\n\\\\f\\\\r])?)|\\\\\\\\[^\\\\n\\\\f\\\\r0-9a-f]))*","name":"variable.other.constant.animation-name.less string.unquoted.less"},{"include":"#less-math"},{"include":"#arbitrary-repetition"},{"include":"#important"}]}]},{"begin":"\\\\b(transition(-(property|duration|delay|timing-function))?)\\\\b","beginCaptures":{"1":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"meta.property-value.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"include":"#time-type"},{"include":"#property-values"},{"include":"#cubic-bezier-function"},{"include":"#steps-function"},{"include":"#arbitrary-repetition"}]}]},{"begin":"\\\\b(?:backdrop-)?filter\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"name":"meta.property-name.less","patterns":[{"captures":{"1":{"name":"punctuation.separator.key-value.less"},"4":{"name":"meta.property-value.less"}},"match":"(((\\\\+_?)?):)([\\\\t\\\\s]*)"},{"match":"\\\\b(inherit|initial|unset|none)\\\\b","name":"meta.property-value.less"},{"include":"#filter-functions"}]},{"begin":"\\\\bwill-change\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"name":"meta.property-name.less","patterns":[{"captures":{"1":{"name":"punctuation.separator.key-value.less"},"4":{"name":"meta.property-value.less"}},"match":"(((\\\\+_?)?):)([\\\\t\\\\s]*)"},{"match":"unset|initial|inherit|will-change|auto|scroll-position|contents","name":"invalid.illegal.property-value.less"},{"match":"-?(?:[-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[A-Z_a-z[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*","name":"support.constant.property-value.less"},{"include":"#arbitrary-repetition"}]},{"begin":"\\\\bcounter-(increment|(re)?set)\\\\b","beginCaptures":{"0":{"name":"support.type.property-name.less"}},"end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"name":"meta.property-name.less","patterns":[{"captures":{"1":{"name":"punctuation.separator.key-value.less"},"4":{"name":"meta.property-value.less"}},"match":"(((\\\\+_?)?):)([\\\\t\\\\s]*)"},{"match":"-?(?:[-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[A-Z_a-z[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*","name":"entity.name.constant.counter-name.less"},{"include":"#integer-type"},{"match":"unset|initial|inherit|auto","name":"invalid.illegal.property-value.less"}]},{"begin":"\\\\bcontainer(?:-name)?(?=\\\\s*?:)","end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"name":"support.type.property-name.less","patterns":[{"begin":"(((\\\\+_?)?):)(?=[\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"}},"contentName":"meta.property-value.less","end":"(?=\\\\s*(;)|(?=[)}]))","patterns":[{"match":"\\\\bdefault\\\\b","name":"invalid.illegal.property-value.less"},{"include":"#global-property-values"},{"include":"#custom-property-name"},{"contentName":"variable.other.constant.container-name.less","match":"--|-?(?:[A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))(?:[-A-Z_a-z·À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}\\\\d]|\\\\\\\\(?:\\\\N|\\\\H|\\\\h{1,6}[R\\\\s]))*","name":"support.constant.property-value.less"},{"include":"#property-values"}]}]},{"match":"\\\\b(accent-height|align-content|align-items|align-self|alignment-baseline|all|animation-timing-function|animation-range-start|animation-range-end|animation-range|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation-composition|animation|appearance|ascent|aspect-ratio|azimuth|backface-visibility|background-size|background-repeat-y|background-repeat-x|background-repeat|background-position-y|background-position-x|background-position|background-origin|background-image|background-color|background-clip|background-blend-mode|background-attachment|background|baseline-shift|begin|bias|blend-mode|border-top-left-radius|border-top-right-radius|border-bottom-left-radius|border-bottom-right-radius|border-end-end-radius|border-end-start-radius|border-start-end-radius|border-start-start-radius|border-block-start-color|border-block-start-style|border-block-start-width|border-block-start|border-block-end-color|border-block-end-style|border-block-end-width|border-block-end|border-block-color|border-block-style|border-block-width|border-block|border-inline-start-color|border-inline-start-style|border-inline-start-width|border-inline-start|border-inline-end-color|border-inline-end-style|border-inline-end-width|border-inline-end|border-inline-color|border-inline-style|border-inline-width|border-inline|border-top-color|border-top-style|border-top-width|border-top|border-right-color|border-right-style|border-right-width|border-right|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-left-color|border-left-style|border-left-width|border-left|border-image-outset|border-image-repeat|border-image-slice|border-image-source|border-image-width|border-image|border-color|border-style|border-width|border-radius|border-collapse|border-spacing|border|bottom|box-(align|decoration-break|direction|flex|ordinal-group|orient|pack|shadow|sizing)|break-(after|before|inside)|caption-side|clear|clip-path|clip-rule|clip|color(-(interpolation(-filters)?|profile|rendering))?|columns|column-(break-before|count|fill|gap|(rule(-(color|style|width))?)|span|width)|container-name|container-type|container|contain-intrinsic-block-size|contain-intrinsic-inline-size|contain-intrinsic-height|contain-intrinsic-size|contain-intrinsic-width|contain|content|counter-(increment|reset)|cursor|[cdf][xy]|direction|display|divisor|dominant-baseline|dur|elevation|empty-cells|enable-background|end|fallback|fill(-(opacity|rule))?|filter|flex(-(align|basis|direction|flow|grow|item-align|line-pack|negative|order|pack|positive|preferred-size|shrink|wrap))?|float|flood-(color|opacity)|font-display|font-family|font-feature-settings|font-kerning|font-language-override|font-size(-adjust)?|font-smoothing|font-stretch|font-style|font-synthesis|font-variant(-(alternates|caps|east-asian|ligatures|numeric|position))?|font-weight|font|fr|((column|row)-)?gap|glyph-orientation-(horizontal|vertical)|grid-(area|gap)|grid-auto-(columns|flow|rows)|grid-(column|row)(-(end|gap|start))?|grid-template(-(areas|columns|rows))?|grid|height|hyphens|image-(orientation|rendering|resolution)|inset(-(block|inline))?(-(start|end))?|isolation|justify-content|justify-items|justify-self|kerning|left|letter-spacing|lighting-color|line-(box-contain|break|clamp|height)|list-style(-(image|position|type))?|(margin|padding)(-(bottom|left|right|top)|(-(block|inline)?(-(end|start))?))?|marker(-(end|mid|start))?|mask(-(clip||composite|image|origin|position|repeat|size|type))?|(m(?:ax|in))-(height|width)|mix-blend-mode|nbsp-mode|negative|object-(fit|position)|opacity|operator|order|orphans|outline(-(color|offset|style|width))?|overflow(-((inline|block)|scrolling|wrap|[xy]))?|overscroll-behavior(-(?:block|(inline|[xy])))?|pad(ding(-(bottom|left|right|top))?)?|page(-break-(after|before|inside))?|paint-order|pause(-(after|before))?|perspective(-origin(-([xy]))?)?|pitch(-range)?|place-content|place-self|pointer-events|position|prefix|quotes|range|resize|right|rotate|scale|scroll-behavior|shape-(image-threshold|margin|outside|rendering)|size|speak(-as)?|src|stop-(color|opacity)|stroke(-(dash(array|offset)|line(cap|join)|miterlimit|opacity|width))?|suffix|symbols|system|tab-size|table-layout|tap-highlight-color|text-align(-last)?|text-decoration(-(color|line|style))?|text-emphasis(-(color|position|style))?|text-(anchor|fill-color|height|indent|justify|orientation|overflow|rendering|size-adjust|shadow|transform|underline-position|wrap)|top|touch-action|transform(-origin(-([xy]))?)|transform(-style)?|transition(-(delay|duration|property|timing-function))?|translate|unicode-(bidi|range)|user-(drag|select)|vertical-align|visibility|white-space(-collapse)?|widows|width|will-change|word-(break|spacing|wrap)|writing-mode|z-index|zoom)\\\\b","name":"support.type.property-name.less"},{"match":"\\\\b(((contain-intrinsic|max|min)-)?(block|inline)?-size)\\\\b","name":"support.type.property-name.less"},{"include":"$self"}]},{"begin":"\\\\b((?:\\\\+_?)?:)([\\\\t\\\\s]*)","beginCaptures":{"1":{"name":"punctuation.separator.key-value.less"},"2":{"name":"meta.property-value.less"}},"captures":{"1":{"name":"punctuation.separator.key-value.less"},"4":{"name":"meta.property-value.less"}},"contentName":"meta.property-value.less","end":"\\\\s*(;)|(?=[)}])","endCaptures":{"1":{"name":"punctuation.terminator.rule.less"}},"patterns":[{"include":"#property-values"}]},{"include":"$self"}]},"scroll-function":{"begin":"\\\\b(scroll)(\\\\()","beginCaptures":{"1":{"name":"support.function.scroll.less"},"2":{"name":"punctuation.definition.group.begin.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"match":"root|nearest|self","name":"support.constant.scroller.less"},{"match":"block|inline|[xy]","name":"support.constant.axis.less"},{"include":"#less-variables"},{"include":"#var-function"}]},"selector":{"patterns":[{"begin":"(?=[#\\\\&*+./>A-\\\\[a-z~]|(:{1,2}\\\\S)|@\\\\{)","contentName":"meta.selector.less","end":"(?=@(?!\\\\{)|[;{])","patterns":[{"include":"#comment-line"},{"include":"#selectors"},{"include":"#less-namespace-accessors"},{"include":"#less-variable-interpolation"},{"include":"#important"}]}]},"selectors":{"patterns":[{"match":"\\\\b([a-z](?:[-0-9_a-z·]|\\\\\\\\\\\\.|[À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}])*-(?:[-0-9_a-z·]|\\\\\\\\\\\\.|[À-ÖØ-öø-ͽͿ-῿‌‍‿⁀⁰-↏Ⰰ-⿯、-퟿豈-﷏ﷰ-�𐀀-\\\\x{EFFFF}])*)\\\\b","name":"entity.name.tag.custom.less"},{"match":"\\\\b(a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdi|bdo|big|blockquote|body|br|button|canvas|caption|circle|cite|clipPath|code|col|colgroup|content|data|dataList|dd|defs|del|details|dfn|dialog|dir|div|dl|dt|element|ellipse|em|embed|eventsource|fieldset|figcaption|figure|filter|footer|foreignObject|form|frame|frameset|g|glyph|glyphRef|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|image|img|input|ins|isindex|kbd|keygen|label|legend|li|line|linearGradient|link|main|map|mark|marker|mask|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|path|pattern|picture|polygon|polyline|pre|progress|q|radialGradient|rect|rp|ruby|rtc??|s|samp|script|section|select|shadow|small|source|span|stop|strike|strong|style|sub|summary|sup|svg|switch|symbol|table|tbody|td|template|textarea|textPath|tfoot|th|thead|time|title|tr|track|tref|tspan|tt|ul??|use|var|video|wbr|xmp)\\\\b","name":"entity.name.tag.less"},{"begin":"(\\\\.)","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"(?![-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(\\\\h{1,6} ?|\\\\H)|(@(?=\\\\{)))","name":"entity.other.attribute-name.class.less","patterns":[{"include":"#less-variable-interpolation"}]},{"begin":"(#)","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"end":"(?![-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(\\\\h{1,6} ?|\\\\H)|(@(?=\\\\{)))","name":"entity.other.attribute-name.id.less","patterns":[{"include":"#less-variable-interpolation"}]},{"begin":"(&)","beginCaptures":{"1":{"name":"punctuation.definition.entity.less"}},"contentName":"entity.other.attribute-name.parent.less","end":"(?![-\\\\w[^\\\\x00-\\\\x{9F}]]|\\\\\\\\(\\\\h{1,6} ?|\\\\H)|(@(?=\\\\{)))","name":"entity.other.attribute-name.parent.less","patterns":[{"include":"#less-variable-interpolation"},{"include":"#selectors"}]},{"include":"#pseudo-selectors"},{"include":"#less-extend"},{"match":"(?!\\\\+_?:)(?:>{1,3}|[+~])(?![+;>}~])","name":"punctuation.separator.combinator.less"},{"match":"(>{1,3}|[+~]){2,}","name":"invalid.illegal.combinator.less"},{"match":"/deep/","name":"invalid.illegal.combinator.less"},{"begin":"\\\\[","beginCaptures":{"0":{"name":"punctuation.section.braces.begin.less"}},"end":"]","endCaptures":{"0":{"name":"punctuation.section.braces.end.less"}},"name":"meta.attribute-selector.less","patterns":[{"include":"#less-variable-interpolation"},{"include":"#qualified-name"},{"match":"(-?(?:[A-Z_a-z[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))(?:[-\\\\w[^\\\\x00-\\\\x7F]]|\\\\\\\\(?:\\\\h{1,6}[\\\\t\\\\n\\\\f\\\\s]?|[^\\\\n\\\\f\\\\h]))*)","name":"entity.other.attribute-name.less"},{"begin":"\\\\s*([$*^|~]?=)\\\\s*","beginCaptures":{"1":{"name":"keyword.operator.attribute-selector.less"}},"end":"(?=([]\\\\s]))","patterns":[{"include":"#less-variable-interpolation"},{"match":"[^]\\"'\\\\[\\\\s]","name":"string.unquoted.less"},{"include":"#literal-string"},{"captures":{"1":{"name":"keyword.other.less"}},"match":"(?:\\\\s+([Ii]))?"},{"match":"]","name":"punctuation.definition.entity.less"}]}]},{"include":"#arbitrary-repetition"},{"match":"\\\\*","name":"entity.name.tag.wildcard.less"}]},"shape-functions":{"patterns":[{"begin":"\\\\b(rect)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.shape.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"\\\\bauto\\\\b","name":"support.constant.property-value.less"},{"include":"#length-type"},{"include":"#comma-delimiter"}]}]},{"begin":"\\\\b(inset)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.shape.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"\\\\bround\\\\b","name":"keyword.other.less"},{"include":"#length-type"},{"include":"#percentage-type"}]}]},{"begin":"\\\\b(circle|ellipse)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.shape.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"\\\\bat\\\\b","name":"keyword.other.less"},{"match":"\\\\b(top|right|bottom|left|center|closest-side|farthest-side)\\\\b","name":"support.constant.property-value.less"},{"include":"#length-type"},{"include":"#percentage-type"}]}]},{"begin":"\\\\b(polygon)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.shape.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"\\\\b(nonzero|evenodd)\\\\b","name":"support.constant.property-value.less"},{"include":"#length-type"},{"include":"#percentage-type"}]}]}]},"steps-function":{"begin":"\\\\b(steps)(\\\\()","beginCaptures":{"1":{"name":"support.function.timing.less"},"2":{"name":"punctuation.definition.group.begin.less"}},"contentName":"meta.group.less","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"match":"jump-start|jump-end|jump-none|jump-both|start|end","name":"support.constant.step-position.less"},{"include":"#comma-delimiter"},{"include":"#integer-type"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#calc-function"}]},"string-content":{"patterns":[{"include":"#less-variable-interpolation"},{"match":"\\\\\\\\\\\\s*\\\\n","name":"constant.character.escape.newline.less"},{"match":"\\\\\\\\(\\\\h{1,6}|.)","name":"constant.character.escape.less"}]},"style-function":{"begin":"\\\\b(style)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.style.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#rule-list-body"}]}]},"symbols-function":{"begin":"\\\\b(symbols)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.counter.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"\\\\b(cyclic|numeric|alphabetic|symbolic|fixed)\\\\b","name":"support.constant.symbol-type.less"},{"include":"#comma-delimiter"},{"include":"#literal-string"},{"include":"#image-type"}]}]},"time-type":{"captures":{"1":{"name":"keyword.other.unit.less"}},"match":"(?i:[-+]?(?:\\\\d*\\\\.\\\\d+(?:[Ee][-+]?\\\\d+)*|[-+]?\\\\d+)(m??s))\\\\b","name":"constant.numeric.less"},"transform-functions":{"patterns":[{"begin":"\\\\b((?:matrix|scale)(?:3d|))(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#number-type"},{"include":"#less-variables"},{"include":"#var-function"}]}]},{"begin":"\\\\b(translate(3d)?)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#percentage-type"},{"include":"#length-type"},{"include":"#number-type"},{"include":"#less-variables"},{"include":"#var-function"}]}]},{"begin":"\\\\b(translate[XY])(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#percentage-type"},{"include":"#length-type"},{"include":"#number-type"},{"include":"#less-variables"},{"include":"#var-function"}]}]},{"begin":"\\\\b(rotate[XYZ]?|skew[XY])(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#angle-type"},{"include":"#less-variables"},{"include":"#calc-function"},{"include":"#var-function"}]}]},{"begin":"\\\\b(skew)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#angle-type"},{"include":"#less-variables"},{"include":"#calc-function"},{"include":"#var-function"}]}]},{"begin":"\\\\b(translateZ|perspective)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#length-type"},{"include":"#less-variables"},{"include":"#calc-function"},{"include":"#var-function"}]}]},{"begin":"\\\\b(rotate3d)(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#angle-type"},{"include":"#number-type"},{"include":"#less-variables"},{"include":"#calc-function"},{"include":"#var-function"}]}]},{"begin":"\\\\b(scale[XYZ])(?=\\\\()","beginCaptures":{"0":{"name":"support.function.transform.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#number-type"},{"include":"#less-variables"},{"include":"#calc-function"},{"include":"#var-function"}]}]}]},"unicode-range":{"captures":{"1":{"name":"support.constant.unicode-range.prefix.less"},"2":{"name":"constant.codepoint-range.less"},"3":{"name":"punctuation.section.range.less"}},"match":"(?i)(u\\\\+)([0-9?a-f]{1,6}(?:(-)[0-9a-f]{1,6})?)","name":"support.unicode-range.less"},"unquoted-string":{"match":"[^\\"'\\\\s]","name":"string.unquoted.less"},"url-function":{"begin":"\\\\b(url)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.url.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#less-variables"},{"include":"#literal-string"},{"include":"#unquoted-string"},{"include":"#var-function"}]}]},"value-separator":{"captures":{"1":{"name":"punctuation.separator.less"}},"match":"\\\\s*(/)\\\\s*"},"var-function":{"begin":"\\\\b(var)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.var.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"include":"#comma-delimiter"},{"include":"#custom-property-name"},{"include":"#less-variables"},{"include":"#property-values"}]}]},"view-function":{"begin":"\\\\b(view)(?=\\\\()","beginCaptures":{"1":{"name":"support.function.view.less"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.group.end.less"}},"name":"meta.function-call.less","patterns":[{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.group.begin.less"}},"end":"(?=\\\\))","patterns":[{"match":"block|inline|[xy]|auto","name":"support.constant.property-value.less"},{"include":"#percentage-type"},{"include":"#length-type"},{"include":"#less-variables"},{"include":"#var-function"},{"include":"#calc-function"},{"include":"#arbitrary-repetition"}]}]}},"scopeName":"source.css.less"}`)),n=[e];export{n as default}; diff --git a/apps/kimi-code/dist-web/assets/liquid-C0sCDyMI.js b/apps/kimi-code/dist-web/assets/liquid-C0sCDyMI.js new file mode 100644 index 0000000000000000000000000000000000000000..d0beb1b67ae62895fff8fe7b4393ae62bc5df909 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/liquid-C0sCDyMI.js @@ -0,0 +1 @@ +import e from"./html-pp8916En.js";import n from"./css-CLj8gQPS.js";import i from"./json-Cp-IABpG.js";import t from"./javascript-wDzz0qaB.js";const a=Object.freeze(JSON.parse(`{"displayName":"Liquid","fileTypes":["liquid"],"foldingStartMarker":"\\\\{%-?\\\\s*(capture|case|comment|form??|if|javascript|paginate|schema|style)[^%()}]+%}","foldingStopMarker":"\\\\{%\\\\s*(end(?:capture|case|comment|form??|if|javascript|paginate|schema|style))[^%()}]+%}","injections":{"L:meta.embedded.block.js, L:meta.embedded.block.css, L:meta.embedded.block.html, L:string.quoted":{"patterns":[{"include":"#injection"}]}},"name":"liquid","patterns":[{"include":"#core"}],"repository":{"attribute":{"begin":"\\\\w+:","beginCaptures":{"0":{"name":"entity.other.attribute-name.liquid"}},"end":"(?=,|%}|}}|\\\\|)","patterns":[{"include":"#value_expression"}]},"attribute_liquid":{"begin":"\\\\w+:","beginCaptures":{"0":{"name":"entity.other.attribute-name.liquid"}},"end":"(?=[,|])|$","patterns":[{"include":"#value_expression"}]},"comment_block":{"begin":"\\\\{%-?\\\\s*comment\\\\s*-?%}","end":"\\\\{%-?\\\\s*endcomment\\\\s*-?%}","name":"comment.block.liquid","patterns":[{"include":"#comment_block"},{"match":"(.(?!\\\\{%-?\\\\s*((?:|end)comment)\\\\s*-?%}))*."}]},"core":{"patterns":[{"include":"#raw_tag"},{"include":"#doc_tag"},{"include":"#comment_block"},{"include":"#style_codefence"},{"include":"#stylesheet_codefence"},{"include":"#json_codefence"},{"include":"#javascript_codefence"},{"include":"#object"},{"include":"#tag"},{"include":"text.html.basic"}]},"doc_tag":{"begin":"\\\\{%-?\\\\s*(doc)\\\\s*-?%}","beginCaptures":{"0":{"name":"meta.tag.liquid"},"1":{"name":"entity.name.tag.doc.liquid"}},"contentName":"comment.block.documentation.liquid","end":"\\\\{%-?\\\\s*(enddoc)\\\\s*-?%}","endCaptures":{"0":{"name":"meta.tag.liquid"},"1":{"name":"entity.name.tag.doc.liquid"}},"name":"meta.block.doc.liquid","patterns":[{"include":"#liquid_doc_description_tag"},{"include":"#liquid_doc_param_tag"},{"include":"#liquid_doc_example_tag"},{"include":"#liquid_doc_prompt_tag"},{"include":"#liquid_doc_fallback_tag"}]},"filter":{"captures":{"1":{"name":"support.function.liquid"}},"match":"\\\\|\\\\s*((?![.0-9])[-0-9A-Z_a-z]+:?)\\\\s*"},"injection":{"patterns":[{"include":"#raw_tag"},{"include":"#comment_block"},{"include":"#object"},{"include":"#tag_injection"}]},"invalid_range":{"match":"\\\\((.(?!\\\\.\\\\.))+\\\\)","name":"invalid.illegal.range.liquid"},"javascript_codefence":{"begin":"(\\\\{%-?)\\\\s*(javascript)\\\\s*(-?%})","beginCaptures":{"0":{"name":"meta.tag.metadata.javascript.start.liquid"},"1":{"name":"punctuation.definition.tag.begin.liquid"},"2":{"name":"entity.name.tag.javascript.liquid"},"3":{"name":"punctuation.definition.tag.begin.liquid"}},"contentName":"meta.embedded.block.js","end":"(\\\\{%-?)\\\\s*(endjavascript)\\\\s*(-?%})","endCaptures":{"0":{"name":"meta.tag.metadata.javascript.end.liquid"},"1":{"name":"punctuation.definition.tag.end.liquid"},"2":{"name":"entity.name.tag.javascript.liquid"},"3":{"name":"punctuation.definition.tag.end.liquid"}},"name":"meta.block.javascript.liquid","patterns":[{"include":"source.js"}]},"json_codefence":{"begin":"(\\\\{%-?)\\\\s*(schema)\\\\s*(-?%})","beginCaptures":{"0":{"name":"meta.tag.metadata.schema.start.liquid"},"1":{"name":"punctuation.definition.tag.begin.liquid"},"2":{"name":"entity.name.tag.schema.liquid"},"3":{"name":"punctuation.definition.tag.begin.liquid"}},"contentName":"meta.embedded.block.json","end":"(\\\\{%-?)\\\\s*(endschema)\\\\s*(-?%})","endCaptures":{"0":{"name":"meta.tag.metadata.schema.end.liquid"},"1":{"name":"punctuation.definition.tag.end.liquid"},"2":{"name":"entity.name.tag.schema.liquid"},"3":{"name":"punctuation.definition.tag.end.liquid"}},"name":"meta.block.schema.liquid","patterns":[{"include":"source.json"}]},"language_constant":{"match":"\\\\b(false|true|nil|blank)\\\\b|empty(?!\\\\?)","name":"constant.language.liquid"},"liquid_doc_description_tag":{"begin":"(@description)\\\\b\\\\s*","beginCaptures":{"0":{"name":"comment.block.documentation.liquid"},"1":{"name":"storage.type.class.liquid"}},"contentName":"string.quoted.single.liquid","end":"(?=@prompt|@example|@param|@description|\\\\{%-?\\\\s*enddoc\\\\s*-?%})"},"liquid_doc_example_tag":{"begin":"(@example)\\\\b\\\\s*","beginCaptures":{"0":{"name":"comment.block.documentation.liquid"},"1":{"name":"storage.type.class.liquid"}},"contentName":"meta.embedded.block.liquid","end":"(?=@prompt|@example|@param|@description|\\\\{%-?\\\\s*enddoc\\\\s*-?%})","patterns":[{"include":"#core"}]},"liquid_doc_fallback_tag":{"captures":{"1":{"name":"comment.block.liquid"}},"match":"(@\\\\w+)\\\\b"},"liquid_doc_param_tag":{"captures":{"1":{"name":"storage.type.class.liquid"},"2":{"name":"entity.name.type.instance.liquid"},"3":{"name":"variable.other.liquid"},"4":{"name":"string.quoted.single.liquid"}},"match":"(@param)\\\\s+(?:(\\\\{[^}]*}?)\\\\s+)?(\\\\[?[A-Z_a-z][-\\\\w]*]?)?(?:\\\\s+(.*))?"},"liquid_doc_prompt_tag":{"begin":"(@prompt)\\\\b\\\\s*","beginCaptures":{"0":{"name":"comment.block.documentation.liquid"},"1":{"name":"storage.type.class.liquid"}},"contentName":"string.quoted.single.liquid","end":"(?=@prompt|@example|@param|@description|\\\\{%-?\\\\s*enddoc\\\\s*-?%})"},"number":{"match":"(([-+])\\\\s*)?[0-9]+(\\\\.[0-9]+)?","name":"constant.numeric.liquid"},"object":{"begin":"(?]|>=|<=|or|and|contains)(?:(?=\\\\s)|\\\\b)"},"range":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.section.parens.begin.liquid"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.section.parens.end.liquid"}},"name":"meta.range.liquid","patterns":[{"match":"\\\\.\\\\.","name":"punctuation.range.liquid"},{"include":"#variable_lookup"},{"include":"#number"}]},"raw_tag":{"begin":"\\\\{%-?\\\\s*(raw)\\\\s*-?%}","beginCaptures":{"1":{"name":"entity.name.tag.liquid"}},"contentName":"string.unquoted.liquid","end":"\\\\{%-?\\\\s*(endraw)\\\\s*-?%}","endCaptures":{"1":{"name":"entity.name.tag.liquid"}},"name":"meta.entity.tag.raw.liquid","patterns":[{"match":"(.(?!\\\\{%-?\\\\s*endraw\\\\s*-?%}))*."}]},"string":{"patterns":[{"include":"#string_single"},{"include":"#string_double"}]},"string_double":{"begin":"\\"","end":"\\"","name":"string.quoted.double.liquid"},"string_single":{"begin":"'","end":"'","name":"string.quoted.single.liquid"},"style_codefence":{"begin":"(\\\\{%-?)\\\\s*(style)\\\\s*(-?%})","beginCaptures":{"0":{"name":"meta.tag.metadata.style.start.liquid"},"1":{"name":"punctuation.definition.tag.begin.liquid"},"2":{"name":"entity.name.tag.style.liquid"},"3":{"name":"punctuation.definition.tag.begin.liquid"}},"contentName":"meta.embedded.block.css","end":"(\\\\{%-?)\\\\s*(endstyle)\\\\s*(-?%})","endCaptures":{"0":{"name":"meta.tag.metadata.style.end.liquid"},"1":{"name":"punctuation.definition.tag.end.liquid"},"2":{"name":"entity.name.tag.style.liquid"},"3":{"name":"punctuation.definition.tag.end.liquid"}},"name":"meta.block.style.liquid","patterns":[{"include":"source.css"}]},"stylesheet_codefence":{"begin":"(\\\\{%-?)\\\\s*(stylesheet)\\\\s*(-?%})","beginCaptures":{"0":{"name":"meta.tag.metadata.style.start.liquid"},"1":{"name":"punctuation.definition.tag.begin.liquid"},"2":{"name":"entity.name.tag.style.liquid"},"3":{"name":"punctuation.definition.tag.begin.liquid"}},"contentName":"meta.embedded.block.css","end":"(\\\\{%-?)\\\\s*(endstylesheet)\\\\s*(-?%})","endCaptures":{"0":{"name":"meta.tag.metadata.style.end.liquid"},"1":{"name":"punctuation.definition.tag.end.liquid"},"2":{"name":"entity.name.tag.style.liquid"},"3":{"name":"punctuation.definition.tag.end.liquid"}},"name":"meta.block.style.liquid","patterns":[{"include":"source.css"}]},"tag":{"begin":"(?|(?<=[^=>])>|(?]>|[^.]\\\\.|[^-]-|[^+]\\\\+|[]%).0-9]=|[=>]>|\\\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\\\s+[^,/:;=>]))","name":"meta.embedded.ts","patterns":[{"include":"#javascript-expression"}]},"attrs":{"patterns":[{"include":"#javascript-comments"},{"applyEndPatternLast":1,"begin":"(?:(key|on[-$0-9A-Z_a-z]+|[$0-9A-Z_a-z]+Change|no-update(?:-body)?(?:-if)?)|([$0-9A-Z_a-z][-$0-9A-Z_a-z]*)|(#[$0-9A-Z_a-z][-$0-9A-Z_a-z]*))(:[$0-9A-Z_a-z][-$0-9A-Z_a-z]*)?","beginCaptures":{"1":{"name":"support.type.attribute-name.marko"},"2":{"name":"entity.other.attribute-name.marko"},"3":{"name":"support.function.attribute-name.marko"},"4":{"name":"support.function.attribute-name.marko"}},"end":"(?=.|$)","name":"meta.marko-attribute","patterns":[{"include":"#html-args-or-method"},{"include":"#attr-value"}]},{"begin":"(\\\\.\\\\.\\\\.)","beginCaptures":{"1":{"name":"keyword.operator.spread.marko"}},"contentName":"source.ts","end":"(?=[],;]|/>|(?<=[^=>])>|(?]>|[^.]\\\\.|[^-]-|[^+]\\\\+|[]%).0-9]=|[=>]>|\\\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\\\s+[^,/:;=>]))","name":"meta.marko-spread-attribute","patterns":[{"include":"#javascript-expression"}]},{"begin":"\\\\s*(,(?!,))","captures":{"1":{"name":"punctuation.separator.comma.marko"}},"end":"(?=\\\\S)"},{"include":"#invalid"}]},"cdata":{"begin":"\\\\s*","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"name":"meta.tag.metadata.cdata.marko"},"concise-attr-group":{"begin":"\\\\s*(\\\\[)","beginCaptures":{"1":{"name":"punctuation.section.scope.begin.marko"}},"end":"]","endCaptures":{"0":{"name":"punctuation.section.scope.end.marko"}},"patterns":[{"include":"#concise-attr-group"},{"begin":"\\\\s+","end":"(?=\\\\S)"},{"include":"#attrs"},{"include":"#invalid"}]},"concise-comment-block":{"begin":"\\\\s*(--+)\\\\s*$","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"end":"\\\\1","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-comment-block","patterns":[{"include":"#content-embedded-comment"}]},"concise-comment-line":{"applyEndPatternLast":1,"begin":"\\\\s*(--+)","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"end":"$","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-comment-line","patterns":[{"include":"#content-embedded-comment"}]},"concise-html-block":{"begin":"\\\\s*(--+)\\\\s*$","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"end":"\\\\1","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-html-block","patterns":[{"include":"#content-html-mode"}]},"concise-html-line":{"captures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"},"2":{"patterns":[{"include":"#cdata"},{"include":"#doctype"},{"include":"#declaration"},{"include":"#javascript-comments-after-whitespace"},{"include":"#html-comment"},{"include":"#tag-html"},{"match":"\\\\\\\\.","name":"text.marko"},{"include":"#placeholder"},{"match":".+?","name":"text.marko"}]},"3":{"name":"punctuation.section.embedded.scope.end.marko"}},"match":"\\\\s*(--+)(?=\\\\s+\\\\S)(.*)$()","name":"meta.section.marko-html-line"},"concise-open-tag-content":{"patterns":[{"include":"#invalid-close-tag"},{"include":"#tag-before-attrs"},{"include":"#concise-semi-eol"},{"begin":"(?!^)[\\\\t ,]","end":"(?=--)|(?=\\\\n)","patterns":[{"include":"#concise-semi-eol"},{"include":"#concise-attr-group"},{"begin":"[\\\\t ]+","end":"(?=[\\\\n\\\\S])"},{"include":"#attrs"},{"include":"#invalid"}]}]},"concise-script-block":{"begin":"\\\\s*(--+)\\\\s*$","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"end":"\\\\1","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-script-block","patterns":[{"include":"#content-embedded-script"}]},"concise-script-line":{"applyEndPatternLast":1,"begin":"\\\\s*(--+)","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"end":"$","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-script-line","patterns":[{"include":"#content-embedded-script"}]},"concise-semi-eol":{"begin":"\\\\s*(;)","beginCaptures":{"1":{"name":"punctuation.terminator.marko"}},"end":"$","patterns":[{"include":"#javascript-comments"},{"include":"#html-comment"},{"include":"#invalid"}]},"concise-style-block":{"begin":"\\\\s*(--+)\\\\s*$","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"contentName":"source.css","end":"\\\\1","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-style-block","patterns":[{"include":"#content-embedded-style"}]},"concise-style-block-less":{"begin":"\\\\s*(--+)\\\\s*$","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"contentName":"source.less","end":"\\\\1","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-style-block","patterns":[{"include":"#content-embedded-style-less"}]},"concise-style-block-scss":{"begin":"\\\\s*(--+)\\\\s*$","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"contentName":"source.scss","end":"\\\\1","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-style-block","patterns":[{"include":"#content-embedded-style-scss"}]},"concise-style-line":{"applyEndPatternLast":1,"begin":"\\\\s*(--+)","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"contentName":"source.css","end":"$","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-style-line","patterns":[{"include":"#content-embedded-style"}]},"concise-style-line-less":{"applyEndPatternLast":1,"begin":"\\\\s*(--+)","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"contentName":"source.less","end":"$","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-style-line","patterns":[{"include":"#content-embedded-style-less"}]},"concise-style-line-scss":{"applyEndPatternLast":1,"begin":"\\\\s*(--+)","beginCaptures":{"1":{"name":"punctuation.section.embedded.scope.begin.marko"}},"contentName":"source.scss","end":"$","endCaptures":{"0":{"name":"punctuation.section.embedded.scope.end.marko"}},"name":"meta.section.marko-style-line","patterns":[{"include":"#content-embedded-style-scss"}]},"content-concise-mode":{"name":"meta.marko-concise-content","patterns":[{"include":"#scriptlet"},{"include":"#javascript-comments"},{"include":"#cdata"},{"include":"#doctype"},{"include":"#declaration"},{"include":"#html-comment"},{"include":"#concise-html-block"},{"include":"#concise-html-line"},{"include":"#invalid-close-tag"},{"include":"#tag-html"},{"patterns":[{"begin":"^(\\\\s*)(?=html-comment[^-$0-9@-Z_a-z])","patterns":[{"include":"#concise-open-tag-content"},{"include":"#concise-comment-block"},{"include":"#concise-comment-line"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"},{"begin":"^(\\\\s*)(?=style\\\\b\\\\S*\\\\.less\\\\b)","patterns":[{"include":"#concise-open-tag-content"},{"include":"#concise-style-block-less"},{"include":"#concise-style-line-less"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"},{"begin":"^(\\\\s*)(?=style\\\\b\\\\S*\\\\.scss\\\\b)","patterns":[{"include":"#concise-open-tag-content"},{"include":"#concise-style-block-scss"},{"include":"#concise-style-line-scss"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"},{"begin":"^(\\\\s*)(?=style\\\\b\\\\S*\\\\.[jt]s\\\\b)","patterns":[{"include":"#concise-open-tag-content"},{"include":"#concise-script-block"},{"include":"#concise-script-line"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"},{"begin":"^(\\\\s*)(?=(?:html-)?style[^-$0-9@-Z_a-z])","patterns":[{"include":"#concise-open-tag-content"},{"include":"#concise-style-block"},{"include":"#concise-style-line"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"},{"begin":"^(\\\\s*)(?=(?:html-)?script[^-$0-9@-Z_a-z])","patterns":[{"include":"#concise-open-tag-content"},{"include":"#concise-script-block"},{"include":"#concise-script-line"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"},{"begin":"^([\\\\t ]*)(?=[#$.0-9@-Z_a-z])","patterns":[{"include":"#concise-open-tag-content"},{"include":"#content-concise-mode"}],"while":"(?=^(?:\\\\s*[])`}]|\\\\*/|\\\\s*$|\\\\1\\\\s+(\\\\S|$)))"}]}]},"content-embedded-comment":{"patterns":[{"include":"#placeholder"},{"match":".","name":"comment.block.marko"}]},"content-embedded-script":{"name":"meta.embedded.ts","patterns":[{"include":"#placeholder"},{"include":"source.ts"}]},"content-embedded-style":{"name":"meta.embedded.css","patterns":[{"include":"#placeholder"},{"include":"source.css"}]},"content-embedded-style-less":{"name":"meta.embedded.css.less","patterns":[{"include":"#placeholder"},{"include":"source.css.less"}]},"content-embedded-style-scss":{"name":"meta.embedded.css.scss","patterns":[{"include":"#placeholder"},{"include":"source.css.scss"}]},"content-html-mode":{"patterns":[{"include":"#scriptlet"},{"include":"#cdata"},{"include":"#doctype"},{"include":"#declaration"},{"include":"#javascript-comments-after-whitespace"},{"include":"#html-comment"},{"include":"#invalid-close-tag"},{"include":"#tag-html"},{"match":"\\\\\\\\.","name":"text.marko"},{"include":"#placeholder"},{"match":".+?","name":"text.marko"}]},"declaration":{"begin":"(<\\\\?)\\\\s*([-$0-9A-Z_a-z]*)","captures":{"1":{"name":"punctuation.definition.tag.marko"},"2":{"name":"entity.name.tag.marko"}},"end":"(\\\\??>)","name":"meta.tag.metadata.processing.xml.marko","patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.marko"},"2":{"name":"punctuation.separator.key-value.html"},"3":{"name":"string.quoted.double.marko"},"4":{"name":"string.quoted.single.marko"},"5":{"name":"string.unquoted.marko"}},"match":"((?:[^=>?\\\\s]|\\\\?(?!>))+)(=)(?:(\\"(?:[^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(\'(?:[^\'\\\\\\\\]|\\\\\\\\.)*\')|((?:[^>?\\\\s]|\\\\?(?!>))+))"}]},"doctype":{"begin":"\\\\s*","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"name":"meta.tag.metadata.doctype.marko","patterns":[{"match":"\\\\G(?i:DOCTYPE)","name":"entity.name.tag.marko"},{"begin":"\\"","end":"\\"","name":"string.quoted.double.marko"},{"match":"[^>\\\\s]+","name":"entity.other.attribute-name.marko"}]},"html-args-or-method":{"patterns":[{"include":"#tag-type-params"},{"begin":"\\\\s*(?=\\\\()","contentName":"source.ts","end":"(?<=\\\\))","name":"meta.embedded.ts","patterns":[{"include":"source.ts#paren-expression"}]},{"begin":"(?<=\\\\))\\\\s*(?=\\\\{)","contentName":"source.ts","end":"(?<=})","name":"meta.embedded.ts","patterns":[{"include":"source.ts"}]}]},"html-comment":{"begin":"\\\\s*(","endCaptures":{"0":{"name":"punctuation.definition.comment.marko"}},"name":"comment.block.marko"},"invalid":{"match":"\\\\S","name":"invalid.illegal.character-not-allowed-here.marko"},"invalid-close-tag":{"begin":"\\\\s*]*","end":">","name":"invalid.illegal.character-not-allowed-here.marko"},"javascript-comments":{"patterns":[{"begin":"\\\\s*(?=/\\\\*)","contentName":"source.ts","end":"(?<=\\\\*/)","patterns":[{"include":"source.ts"}]},{"captures":{"0":{"patterns":[{"include":"source.ts"}]}},"contentName":"source.ts","match":"\\\\s*//.*$"}]},"javascript-comments-after-whitespace":{"patterns":[{"begin":"(?:^|\\\\s+)(?=/\\\\*)","contentName":"source.ts","end":"(?<=\\\\*/)","patterns":[{"include":"source.ts"}]},{"captures":{"0":{"patterns":[{"include":"source.ts"}]}},"contentName":"source.ts","match":"(?:^|\\\\s+)//.*$"}]},"javascript-expression":{"patterns":[{"include":"#javascript-comments"},{"captures":{"0":{"patterns":[{"include":"source.ts"}]}},"contentName":"source.ts","match":"(?:\\\\s*\\\\b(?:as|await|extends|in|instanceof|satisfies|keyof|new|typeof|void))+\\\\s+(?![,/:;=>])[#$0-9@-Z_a-z]*"},{"applyEndPatternLast":1,"captures":{"0":{"name":"string.regexp.ts","patterns":[{"include":"source.ts#regexp"},{"include":"source.ts"}]}},"contentName":"source.ts","match":"(?)","end":"(?=/?>)","patterns":[{"include":"#attrs"}]}]},"placeholder":{"begin":"\\\\$!?\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.template-expression.begin.ts"}},"contentName":"source.ts","end":"}","endCaptures":{"0":{"name":"punctuation.definition.template-expression.end.ts"}},"patterns":[{"include":"source.ts"}]},"scriptlet":{"begin":"^\\\\s*(\\\\$)\\\\s+","beginCaptures":{"1":{"name":"keyword.control.scriptlet.marko"}},"contentName":"source.ts","end":"$","name":"meta.embedded.ts","patterns":[{"include":"source.ts"}]},"tag-before-attrs":{"patterns":[{"include":"#tag-name"},{"include":"#tag-shorthand-class-or-id"},{"begin":"/(?![*/])","beginCaptures":{"0":{"name":"punctuation.separator.tag-variable.marko"}},"contentName":"source.ts","end":"(?=[(,/;<>|]|:?=|\\\\s+[^:]|$)","name":"meta.embedded.ts","patterns":[{"match":"[$A-Z_a-z][$0-9A-Z_a-z]*","name":"variable.other.constant.object.ts"},{"begin":"\\\\{","captures":{"0":{"name":"punctuation.definition.binding-pattern.object.ts"}},"end":"}","patterns":[{"include":"source.ts#object-binding-element"},{"include":"#javascript-expression"}]},{"begin":"\\\\[","captures":{"0":{"name":"punctuation.definition.binding-pattern.array.ts"}},"end":"]","patterns":[{"include":"source.ts#array-binding-element"},{"include":"#javascript-expression"}]},{"begin":"\\\\s*(:)(?!=)","beginCaptures":{"1":{"name":"keyword.operator.type.annotation.ts"}},"end":"(?=[](,;]|/>|(?<=[^=>])>|(?]>|[^.]\\\\.|[^-]-|[^+]\\\\+|[]%).0-9]=|[=>]>|\\\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\\\s+[^,/:;=>]))","patterns":[{"include":"source.ts#type"},{"include":"#javascript-expression"}]},{"include":"#javascript-expression"}]},{"begin":"\\\\s*\\\\|","beginCaptures":{"0":{"name":"punctuation.section.scope.begin.marko"}},"contentName":"source.ts","end":"\\\\|","endCaptures":{"0":{"name":"punctuation.section.scope.end.marko"}},"patterns":[{"include":"source.ts#comment"},{"include":"source.ts#string"},{"include":"source.ts#decorator"},{"include":"source.ts#destructuring-parameter"},{"include":"source.ts#parameter-name"},{"begin":"(:)","beginCaptures":{"1":{"name":"keyword.operator.type.annotation.ts"}},"end":"(?=[,|])|(?==[^>])","name":"meta.type.annotation.ts","patterns":[{"include":"source.ts#type"}]},{"include":"source.ts#variable-initializer"},{"match":",","name":"punctuation.separator.parameter.ts"},{"include":"source.ts"}]},{"include":"#html-args-or-method"},{"include":"#attr-value"}]},"tag-html":{"patterns":[{"begin":"\\\\s*(<)(?=(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr|const|debug|id|let|lifecycle|log|return)[^-$0-9@-Z_a-z])","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/?>","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"}]},{"begin":"\\\\s*(<)(?=html-comment[^-$0-9@-Z_a-z])","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=|html-comment>))","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"end":"\\\\s*|html-comment>)","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"}]},"3":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-embedded-comment"}]}]},{"begin":"\\\\s*(<)(?=style\\\\S*\\\\.less\\\\b)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=)|(?<=)","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"contentName":"source.less","end":"\\\\s*()","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"}]},"3":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-embedded-style-less"}]}]},{"begin":"\\\\s*(<)(?=style\\\\S*\\\\.scss\\\\b)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=)|(?<=)","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"contentName":"source.scss","end":"\\\\s*()","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"}]},"3":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-embedded-style-scss"}]}]},{"begin":"\\\\s*(<)(?=style\\\\S*\\\\.[jt]s\\\\b)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=)|(?<=)","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"contentName":"source.ts","end":"\\\\s*()","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"}]},"3":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-embedded-script"}]}]},{"begin":"\\\\s*(<)(?=((?:html-)?style)[^-$0-9@-Z_a-z])","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=)|(?<=)","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"contentName":"source.css","end":"\\\\s*()","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"}]},"3":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-embedded-style"}]}]},{"begin":"\\\\s*(<)(?=((?:html-)?script)[^-$0-9@-Z_a-z])","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=)|(?<=)","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"contentName":"source.ts","end":"\\\\s*()","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"}]},"3":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-embedded-script"}]}]},{"begin":"\\\\s*(<)(?=[#$.]|([-$0-9@-Z_a-z]+))","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"}},"end":"/>|(?<=)|(?<=)","endCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#open-tag-content"},{"begin":">","beginCaptures":{"0":{"name":"punctuation.definition.tag.end.marko"}},"end":"\\\\s*(]*)(>)","endCaptures":{"1":{"name":"punctuation.definition.tag.begin.marko"},"2":{"patterns":[{"include":"#tag-name"},{"include":"#tag-shorthand-class-or-id"}]},"3":{"patterns":[{"include":"#invalid"}]},"4":{"name":"punctuation.definition.tag.end.marko"}},"patterns":[{"include":"#content-html-mode"}]}]}]},"tag-name":{"patterns":[{"applyEndPatternLast":1,"begin":"\\\\G(style)\\\\b(\\\\.[-$0-9A-Z_a-z]+(?:\\\\.[-$0-9A-Z_a-z]+)*)|([0-9@-Z_a-z](?:[-0-9@-Z_a-z]|:(?!=))*)","beginCaptures":{"1":{"name":"support.type.builtin.marko"},"2":{"name":"storage.type.marko.css"},"3":{"patterns":[{"match":"(script|style|html-script|html-style|html-comment)(?![-$0-9@-Z_a-z])","name":"support.type.builtin.marko"},{"match":"(for|if|while|else-if|else|try|await|return)(?![-$0-9@-Z_a-z])","name":"keyword.control.flow.marko"},{"match":"(const|context|debug|define|id|let|log|lifecycle)(?![-$0-9@-Z_a-z])","name":"support.function.marko"},{"match":"@.+","name":"entity.other.attribute-name.marko"},{"match":".+","name":"entity.name.tag.marko"}]}},"end":"(?=.)","patterns":[{"include":"#tag-type-args"}]},{"begin":"(?=[$0-9A-Z_a-z]|-[^-])","end":"(?=[^-$0-9A-Z_a-z]|$)","patterns":[{"include":"#javascript-placeholder"},{"match":"(?:[-0-9A-Z_a-z]|\\\\$(?!\\\\{))+","name":"entity.name.tag.marko"}]}]},"tag-shorthand-class-or-id":{"begin":"(?=[#.])","end":"$|(?=--|[^-#$.0-9A-Z_a-z])","patterns":[{"include":"#javascript-placeholder"},{"match":"(?:[-#.0-9A-Z_a-z]|\\\\$(?!\\\\{))+","name":"entity.other.attribute-name.marko"}]},"tag-type-args":{"applyEndPatternLast":1,"begin":"(?=<)","contentName":"source.ts","end":"(?<=>)","name":"meta.embedded.ts","patterns":[{"applyEndPatternLast":1,"begin":"(?<=>)(?=[\\\\t ]*<)","end":"(?=.)","patterns":[{"include":"#tag-type-params"}]},{"include":"source.ts#type-arguments"}]},"tag-type-params":{"applyEndPatternLast":1,"begin":"(?!^)[\\\\t ]*(?=<)","contentName":"source.ts","end":"(?<=>)","name":"meta.embedded.ts","patterns":[{"include":"source.ts#type-parameters"}]}},"scopeName":"text.marko","embeddedLangs":["css","less","scss","typescript"]}')),d=[...e,...n,...t,...a,s];export{d as default}; diff --git a/apps/kimi-code/dist-web/assets/material-theme-darker-BfHTSMKl.js b/apps/kimi-code/dist-web/assets/material-theme-darker-BfHTSMKl.js new file mode 100644 index 0000000000000000000000000000000000000000..7417c3157579379b80aff0b45245eeb94d66b310 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/material-theme-darker-BfHTSMKl.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"colors":{"activityBar.activeBorder":"#80CBC4","activityBar.background":"#212121","activityBar.border":"#21212160","activityBar.dropBackground":"#f0717880","activityBar.foreground":"#EEFFFF","activityBarBadge.background":"#80CBC4","activityBarBadge.foreground":"#000000","badge.background":"#00000030","badge.foreground":"#545454","breadcrumb.activeSelectionForeground":"#80CBC4","breadcrumb.background":"#212121","breadcrumb.focusForeground":"#EEFFFF","breadcrumb.foreground":"#676767","breadcrumbPicker.background":"#212121","button.background":"#61616150","button.foreground":"#ffffff","debugConsole.errorForeground":"#f07178","debugConsole.infoForeground":"#89DDFF","debugConsole.warningForeground":"#FFCB6B","debugToolBar.background":"#212121","diffEditor.insertedTextBackground":"#89DDFF20","diffEditor.removedTextBackground":"#ff9cac20","dropdown.background":"#212121","dropdown.border":"#FFFFFF10","editor.background":"#212121","editor.findMatchBackground":"#000000","editor.findMatchBorder":"#80CBC4","editor.findMatchHighlight":"#EEFFFF","editor.findMatchHighlightBackground":"#00000050","editor.findMatchHighlightBorder":"#ffffff30","editor.findRangeHighlightBackground":"#FFCB6B30","editor.foreground":"#EEFFFF","editor.lineHighlightBackground":"#00000050","editor.lineHighlightBorder":"#00000000","editor.rangeHighlightBackground":"#FFFFFF0d","editor.selectionBackground":"#61616150","editor.selectionHighlightBackground":"#FFCC0020","editor.wordHighlightBackground":"#ff9cac30","editor.wordHighlightStrongBackground":"#C3E88D30","editorBracketMatch.background":"#212121","editorBracketMatch.border":"#FFCC0050","editorCursor.foreground":"#FFCC00","editorError.foreground":"#f0717870","editorGroup.border":"#00000030","editorGroup.dropBackground":"#f0717880","editorGroup.focusedEmptyBorder":"#f07178","editorGroupHeader.tabsBackground":"#212121","editorGutter.addedBackground":"#C3E88D60","editorGutter.deletedBackground":"#f0717860","editorGutter.modifiedBackground":"#82AAFF60","editorHoverWidget.background":"#212121","editorHoverWidget.border":"#FFFFFF10","editorIndentGuide.activeBackground":"#424242","editorIndentGuide.background":"#42424270","editorInfo.foreground":"#82AAFF70","editorLineNumber.activeForeground":"#676767","editorLineNumber.foreground":"#424242","editorLink.activeForeground":"#EEFFFF","editorMarkerNavigation.background":"#EEFFFF05","editorOverviewRuler.border":"#212121","editorOverviewRuler.errorForeground":"#f0717840","editorOverviewRuler.findMatchForeground":"#80CBC4","editorOverviewRuler.infoForeground":"#82AAFF40","editorOverviewRuler.warningForeground":"#FFCB6B40","editorRuler.foreground":"#424242","editorSuggestWidget.background":"#212121","editorSuggestWidget.border":"#FFFFFF10","editorSuggestWidget.foreground":"#EEFFFF","editorSuggestWidget.highlightForeground":"#80CBC4","editorSuggestWidget.selectedBackground":"#00000050","editorWarning.foreground":"#FFCB6B70","editorWhitespace.foreground":"#EEFFFF40","editorWidget.background":"#212121","editorWidget.border":"#80CBC4","editorWidget.resizeBorder":"#80CBC4","extensionBadge.remoteForeground":"#EEFFFF","extensionButton.prominentBackground":"#C3E88D90","extensionButton.prominentForeground":"#EEFFFF","extensionButton.prominentHoverBackground":"#C3E88D","focusBorder":"#FFFFFF00","foreground":"#EEFFFF","gitDecoration.conflictingResourceForeground":"#FFCB6B90","gitDecoration.deletedResourceForeground":"#f0717890","gitDecoration.ignoredResourceForeground":"#67676790","gitDecoration.modifiedResourceForeground":"#82AAFF90","gitDecoration.untrackedResourceForeground":"#C3E88D90","input.background":"#2B2B2B","input.border":"#FFFFFF10","input.foreground":"#EEFFFF","input.placeholderForeground":"#EEFFFF60","inputOption.activeBackground":"#EEFFFF30","inputOption.activeBorder":"#EEFFFF30","inputValidation.errorBorder":"#f07178","inputValidation.infoBorder":"#82AAFF","inputValidation.warningBorder":"#FFCB6B","list.activeSelectionBackground":"#212121","list.activeSelectionForeground":"#80CBC4","list.dropBackground":"#f0717880","list.focusBackground":"#EEFFFF20","list.focusForeground":"#EEFFFF","list.highlightForeground":"#80CBC4","list.hoverBackground":"#212121","list.hoverForeground":"#FFFFFF","list.inactiveSelectionBackground":"#00000030","list.inactiveSelectionForeground":"#80CBC4","listFilterWidget.background":"#00000030","listFilterWidget.noMatchesOutline":"#00000030","listFilterWidget.outline":"#00000030","menu.background":"#212121","menu.foreground":"#EEFFFF","menu.selectionBackground":"#00000050","menu.selectionBorder":"#00000030","menu.selectionForeground":"#80CBC4","menu.separatorBackground":"#EEFFFF","menubar.selectionBackground":"#00000030","menubar.selectionBorder":"#00000030","menubar.selectionForeground":"#80CBC4","notebook.focusedCellBorder":"#80CBC4","notebook.inactiveFocusedCellBorder":"#80CBC450","notificationLink.foreground":"#80CBC4","notifications.background":"#212121","notifications.foreground":"#EEFFFF","panel.background":"#212121","panel.border":"#21212160","panel.dropBackground":"#EEFFFF","panelTitle.activeBorder":"#80CBC4","panelTitle.activeForeground":"#FFFFFF","panelTitle.inactiveForeground":"#EEFFFF","peekView.border":"#00000030","peekViewEditor.background":"#2B2B2B","peekViewEditor.matchHighlightBackground":"#61616150","peekViewEditorGutter.background":"#2B2B2B","peekViewResult.background":"#2B2B2B","peekViewResult.matchHighlightBackground":"#61616150","peekViewResult.selectionBackground":"#67676770","peekViewTitle.background":"#2B2B2B","peekViewTitleDescription.foreground":"#EEFFFF60","pickerGroup.border":"#FFFFFF1a","pickerGroup.foreground":"#80CBC4","progressBar.background":"#80CBC4","quickInput.background":"#212121","quickInput.foreground":"#676767","quickInput.list.focusBackground":"#EEFFFF20","sash.hoverBorder":"#80CBC450","scrollbar.shadow":"#00000030","scrollbarSlider.activeBackground":"#80CBC4","scrollbarSlider.background":"#EEFFFF20","scrollbarSlider.hoverBackground":"#EEFFFF10","selection.background":"#00000080","settings.checkboxBackground":"#212121","settings.checkboxForeground":"#EEFFFF","settings.dropdownBackground":"#212121","settings.dropdownForeground":"#EEFFFF","settings.headerForeground":"#80CBC4","settings.modifiedItemIndicator":"#80CBC4","settings.numberInputBackground":"#212121","settings.numberInputForeground":"#EEFFFF","settings.textInputBackground":"#212121","settings.textInputForeground":"#EEFFFF","sideBar.background":"#212121","sideBar.border":"#21212160","sideBar.foreground":"#676767","sideBarSectionHeader.background":"#212121","sideBarSectionHeader.border":"#21212160","sideBarTitle.foreground":"#EEFFFF","statusBar.background":"#212121","statusBar.border":"#21212160","statusBar.debuggingBackground":"#C792EA","statusBar.debuggingForeground":"#ffffff","statusBar.foreground":"#616161","statusBar.noFolderBackground":"#212121","statusBarItem.activeBackground":"#f0717880","statusBarItem.hoverBackground":"#54545420","statusBarItem.remoteBackground":"#80CBC4","statusBarItem.remoteForeground":"#000000","tab.activeBackground":"#212121","tab.activeBorder":"#80CBC4","tab.activeForeground":"#FFFFFF","tab.activeModifiedBorder":"#676767","tab.border":"#212121","tab.inactiveBackground":"#212121","tab.inactiveForeground":"#676767","tab.inactiveModifiedBorder":"#904348","tab.unfocusedActiveBorder":"#545454","tab.unfocusedActiveForeground":"#EEFFFF","tab.unfocusedActiveModifiedBorder":"#c05a60","tab.unfocusedInactiveModifiedBorder":"#904348","terminal.ansiBlack":"#000000","terminal.ansiBlue":"#82AAFF","terminal.ansiBrightBlack":"#545454","terminal.ansiBrightBlue":"#82AAFF","terminal.ansiBrightCyan":"#89DDFF","terminal.ansiBrightGreen":"#C3E88D","terminal.ansiBrightMagenta":"#C792EA","terminal.ansiBrightRed":"#f07178","terminal.ansiBrightWhite":"#ffffff","terminal.ansiBrightYellow":"#FFCB6B","terminal.ansiCyan":"#89DDFF","terminal.ansiGreen":"#C3E88D","terminal.ansiMagenta":"#C792EA","terminal.ansiRed":"#f07178","terminal.ansiWhite":"#ffffff","terminal.ansiYellow":"#FFCB6B","terminalCursor.background":"#000000","terminalCursor.foreground":"#FFCB6B","textLink.activeForeground":"#EEFFFF","textLink.foreground":"#80CBC4","titleBar.activeBackground":"#212121","titleBar.activeForeground":"#EEFFFF","titleBar.border":"#21212160","titleBar.inactiveBackground":"#212121","titleBar.inactiveForeground":"#676767","tree.indentGuidesStroke":"#424242","widget.shadow":"#00000030"},"displayName":"Material Theme Darker","name":"material-theme-darker","semanticHighlighting":true,"tokenColors":[{"settings":{"background":"#212121","foreground":"#EEFFFF"}},{"scope":"string","settings":{"foreground":"#C3E88D"}},{"scope":"punctuation, constant.other.symbol","settings":{"foreground":"#89DDFF"}},{"scope":"constant.character.escape, text.html constant.character.entity.named","settings":{"foreground":"#EEFFFF"}},{"scope":"constant.language.boolean","settings":{"foreground":"#ff9cac"}},{"scope":"constant.numeric","settings":{"foreground":"#F78C6C"}},{"scope":"variable, variable.parameter, support.variable, variable.language, support.constant, meta.definition.variable entity.name.function, meta.function-call.arguments","settings":{"foreground":"#EEFFFF"}},{"scope":"keyword.other","settings":{"foreground":"#F78C6C"}},{"scope":"keyword, modifier, variable.language.this, support.type.object, constant.language","settings":{"foreground":"#89DDFF"}},{"scope":"entity.name.function, support.function","settings":{"foreground":"#82AAFF"}},{"scope":"storage.type, storage.modifier, storage.control","settings":{"foreground":"#C792EA"}},{"scope":"support.module, support.node","settings":{"fontStyle":"italic","foreground":"#f07178"}},{"scope":"support.type, constant.other.key","settings":{"foreground":"#FFCB6B"}},{"scope":"entity.name.type, entity.other.inherited-class, entity.other","settings":{"foreground":"#FFCB6B"}},{"scope":"comment","settings":{"fontStyle":"italic","foreground":"#545454"}},{"scope":"comment punctuation.definition.comment, string.quoted.docstring","settings":{"fontStyle":"italic","foreground":"#545454"}},{"scope":"punctuation","settings":{"foreground":"#89DDFF"}},{"scope":"entity.name, entity.name.type.class, support.type, support.class, meta.use","settings":{"foreground":"#FFCB6B"}},{"scope":"variable.object.property, meta.field.declaration entity.name.function","settings":{"foreground":"#f07178"}},{"scope":"meta.definition.method entity.name.function","settings":{"foreground":"#f07178"}},{"scope":"meta.function entity.name.function","settings":{"foreground":"#82AAFF"}},{"scope":"template.expression.begin, template.expression.end, punctuation.definition.template-expression.begin, punctuation.definition.template-expression.end","settings":{"foreground":"#89DDFF"}},{"scope":"meta.embedded, source.groovy.embedded, meta.template.expression","settings":{"foreground":"#EEFFFF"}},{"scope":"entity.name.tag.yaml","settings":{"foreground":"#f07178"}},{"scope":"meta.object-literal.key, meta.object-literal.key string, support.type.property-name.json","settings":{"foreground":"#f07178"}},{"scope":"constant.language.json","settings":{"foreground":"#89DDFF"}},{"scope":"entity.other.attribute-name.class","settings":{"foreground":"#FFCB6B"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"#F78C6C"}},{"scope":"source.css entity.name.tag","settings":{"foreground":"#FFCB6B"}},{"scope":"support.type.property-name.css","settings":{"foreground":"#B2CCD6"}},{"scope":"meta.tag, punctuation.definition.tag","settings":{"foreground":"#89DDFF"}},{"scope":"entity.name.tag","settings":{"foreground":"#f07178"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#C792EA"}},{"scope":"punctuation.definition.entity.html","settings":{"foreground":"#EEFFFF"}},{"scope":"markup.heading","settings":{"foreground":"#89DDFF"}},{"scope":"text.html.markdown meta.link.inline, meta.link.reference","settings":{"foreground":"#f07178"}},{"scope":"text.html.markdown beginning.punctuation.definition.list","settings":{"foreground":"#89DDFF"}},{"scope":"markup.italic","settings":{"fontStyle":"italic","foreground":"#f07178"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#f07178"}},{"scope":"markup.bold markup.italic, markup.italic markup.bold","settings":{"fontStyle":"italic bold","foreground":"#f07178"}},{"scope":"markup.fenced_code.block.markdown punctuation.definition.markdown","settings":{"foreground":"#C3E88D"}},{"scope":"markup.inline.raw.string.markdown","settings":{"foreground":"#C3E88D"}},{"scope":"keyword.other.definition.ini","settings":{"foreground":"#f07178"}},{"scope":"entity.name.section.group-title.ini","settings":{"foreground":"#89DDFF"}},{"scope":"source.cs meta.class.identifier storage.type","settings":{"foreground":"#FFCB6B"}},{"scope":"source.cs meta.method.identifier entity.name.function","settings":{"foreground":"#f07178"}},{"scope":"source.cs meta.method-call meta.method, source.cs entity.name.function","settings":{"foreground":"#82AAFF"}},{"scope":"source.cs storage.type","settings":{"foreground":"#FFCB6B"}},{"scope":"source.cs meta.method.return-type","settings":{"foreground":"#FFCB6B"}},{"scope":"source.cs meta.preprocessor","settings":{"foreground":"#545454"}},{"scope":"source.cs entity.name.type.namespace","settings":{"foreground":"#EEFFFF"}},{"scope":"meta.jsx.children, SXNested","settings":{"foreground":"#EEFFFF"}},{"scope":"support.class.component","settings":{"foreground":"#FFCB6B"}},{"scope":"source.cpp meta.block variable.other","settings":{"foreground":"#EEFFFF"}},{"scope":"source.python meta.member.access.python","settings":{"foreground":"#f07178"}},{"scope":"source.python meta.function-call.python, meta.function-call.arguments","settings":{"foreground":"#82AAFF"}},{"scope":"meta.block","settings":{"foreground":"#f07178"}},{"scope":"entity.name.function.call","settings":{"foreground":"#82AAFF"}},{"scope":"source.php support.other.namespace, source.php meta.use support.class","settings":{"foreground":"#EEFFFF"}},{"scope":"constant.keyword","settings":{"fontStyle":"italic","foreground":"#89DDFF"}},{"scope":"entity.name.function","settings":{"foreground":"#82AAFF"}},{"settings":{"background":"#212121","foreground":"#EEFFFF"}},{"scope":["constant.other.placeholder"],"settings":{"foreground":"#f07178"}},{"scope":["markup.deleted"],"settings":{"foreground":"#f07178"}},{"scope":["markup.inserted"],"settings":{"foreground":"#C3E88D"}},{"scope":["markup.underline"],"settings":{"fontStyle":"underline"}},{"scope":["keyword.control"],"settings":{"fontStyle":"italic","foreground":"#89DDFF"}},{"scope":["variable.parameter"],"settings":{"fontStyle":"italic"}},{"scope":["variable.parameter.function.language.special.self.python"],"settings":{"fontStyle":"italic","foreground":"#f07178"}},{"scope":["constant.character.format.placeholder.other.python"],"settings":{"foreground":"#F78C6C"}},{"scope":["markup.quote"],"settings":{"fontStyle":"italic","foreground":"#89DDFF"}},{"scope":["markup.fenced_code.block"],"settings":{"foreground":"#EEFFFF90"}},{"scope":["punctuation.definition.quote"],"settings":{"foreground":"#ff9cac"}},{"scope":["meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#C792EA"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#FFCB6B"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#F78C6C"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#f07178"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#916b53"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#82AAFF"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#ff9cac"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#C792EA"}},{"scope":["meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json support.type.property-name.json"],"settings":{"foreground":"#C3E88D"}}],"type":"dark"}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/matlab-D7o27uSR.js b/apps/kimi-code/dist-web/assets/matlab-D7o27uSR.js new file mode 100644 index 0000000000000000000000000000000000000000..ea8bbf7e1fde869ee389d28c0ec58f9d49078d4a --- /dev/null +++ b/apps/kimi-code/dist-web/assets/matlab-D7o27uSR.js @@ -0,0 +1 @@ +const a=Object.freeze(JSON.parse(`{"displayName":"MATLAB","fileTypes":["m"],"name":"matlab","patterns":[{"include":"#all_before_command_dual"},{"include":"#command_dual"},{"include":"#all_after_command_dual"}],"repository":{"all_after_command_dual":{"patterns":[{"include":"#string"},{"include":"#line_continuation"},{"include":"#comments"},{"include":"#conjugate_transpose"},{"include":"#transpose"},{"include":"#constants"},{"include":"#variables"},{"include":"#numbers"},{"include":"#operators"}]},"all_before_command_dual":{"patterns":[{"include":"#classdef"},{"include":"#function"},{"include":"#blocks"},{"include":"#control_statements"},{"include":"#global_persistent"},{"include":"#parens"},{"include":"#square_brackets"},{"include":"#indexing_curly_brackets"},{"include":"#curly_brackets"}]},"blocks":{"patterns":[{"begin":"\\\\s*(?:^|[,;\\\\s])(for)\\\\b","beginCaptures":{"1":{"name":"keyword.control.for.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.for.matlab"}},"name":"meta.for.matlab","patterns":[{"include":"$self"}]},{"begin":"\\\\s*(?:^|[,;\\\\s])(if)\\\\b","beginCaptures":{"1":{"name":"keyword.control.if.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.if.matlab"},"2":{"patterns":[{"include":"$self"}]}},"name":"meta.if.matlab","patterns":[{"captures":{"2":{"name":"keyword.control.elseif.matlab"},"3":{"patterns":[{"include":"$self"}]}},"end":"^","match":"(\\\\s*)(?:^|[,;\\\\s])(elseif)\\\\b(.*)$\\\\n?","name":"meta.elseif.matlab"},{"captures":{"2":{"name":"keyword.control.else.matlab"},"3":{"patterns":[{"include":"$self"}]}},"end":"^","match":"(\\\\s*)(?:^|[,;\\\\s])(else)\\\\b(.*)?$\\\\n?","name":"meta.else.matlab"},{"include":"$self"}]},{"begin":"\\\\s*(?:^|[,;\\\\s])(parfor)\\\\b","beginCaptures":{"1":{"name":"keyword.control.for.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.for.matlab"}},"name":"meta.parfor.matlab","patterns":[{"begin":"\\\\G(?!$)","end":"$\\\\n?","name":"meta.parfor-quantity.matlab","patterns":[{"include":"$self"}]},{"include":"$self"}]},{"begin":"\\\\s*(?:^|[,;\\\\s])(spmd)\\\\b","beginCaptures":{"1":{"name":"keyword.control.spmd.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.spmd.matlab"}},"name":"meta.spmd.matlab","patterns":[{"begin":"\\\\G(?!$)","end":"$\\\\n?","name":"meta.spmd-statement.matlab","patterns":[{"include":"$self"}]},{"include":"$self"}]},{"begin":"\\\\s*(?:^|[,;\\\\s])(switch)\\\\b","beginCaptures":{"1":{"name":"keyword.control.switch.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.switch.matlab"}},"name":"meta.switch.matlab","patterns":[{"captures":{"2":{"name":"keyword.control.case.matlab"},"3":{"patterns":[{"include":"$self"}]}},"end":"^","match":"(\\\\s*)(?:^|[,;\\\\s])(case)\\\\b(.*)$\\\\n?","name":"meta.case.matlab"},{"captures":{"2":{"name":"keyword.control.otherwise.matlab"},"3":{"patterns":[{"include":"$self"}]}},"end":"^","match":"(\\\\s*)(?:^|[,;\\\\s])(otherwise)\\\\b(.*)?$\\\\n?","name":"meta.otherwise.matlab"},{"include":"$self"}]},{"begin":"\\\\s*(?:^|[,;\\\\s])(try)\\\\b","beginCaptures":{"1":{"name":"keyword.control.try.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.try.matlab"}},"name":"meta.try.matlab","patterns":[{"captures":{"2":{"name":"keyword.control.catch.matlab"},"3":{"patterns":[{"include":"$self"}]}},"end":"^","match":"(\\\\s*)(?:^|[,;\\\\s])(catch)\\\\b(.*)?$\\\\n?","name":"meta.catch.matlab"},{"include":"$self"}]},{"begin":"\\\\s*(?:^|[,;\\\\s])(while)\\\\b","beginCaptures":{"1":{"name":"keyword.control.while.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.while.matlab"}},"name":"meta.while.matlab","patterns":[{"include":"$self"}]}]},"braced_validator_list":{"begin":"\\\\s*(\\\\{)\\\\s*","beginCaptures":{"1":{"name":"storage.type.matlab"}},"end":"(})","endCaptures":{"1":{"name":"storage.type.matlab"}},"patterns":[{"include":"#braced_validator_list"},{"include":"#validator_strings"},{"include":"#line_continuation"},{"captures":{"1":{"name":"storage.type.matlab"}},"match":"([^\\"'.{}]+)"},{"match":"\\\\.","name":"storage.type.matlab"}]},"classdef":{"patterns":[{"begin":"^(\\\\s*)(classdef)\\\\b\\\\s*(.*)","beginCaptures":{"2":{"name":"storage.type.class.matlab"},"3":{"patterns":[{"captures":{"1":{"patterns":[{"match":"[A-Za-z][0-9A-Z_a-z]*","name":"variable.parameter.class.matlab"},{"begin":"=\\\\s*","end":",|(?=\\\\))","patterns":[{"match":"true|false","name":"constant.language.boolean.matlab"},{"include":"#string"}]}]},"2":{"name":"meta.class-declaration.matlab"},"3":{"name":"entity.name.section.class.matlab"},"4":{"name":"keyword.operator.other.matlab"},"5":{"patterns":[{"match":"[A-Za-z][0-9A-Z_a-z]*(\\\\.[A-Za-z][0-9A-Z_a-z]*)*","name":"entity.other.inherited-class.matlab"},{"match":"&","name":"keyword.operator.other.matlab"}]},"6":{"patterns":[{"include":"$self"}]}},"match":"(\\\\([^)]*\\\\))?\\\\s*(([A-Za-z][0-9A-Z_a-z]*)(?:\\\\s*(<)\\\\s*([^%]*))?)\\\\s*($|(?=(%|...)).*)"}]}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.class.matlab"}},"name":"meta.class.matlab","patterns":[{"begin":"^(\\\\s*)(properties)\\\\b([^%]*)\\\\s*(\\\\([^)]*\\\\))?\\\\s*($|(?=%))","beginCaptures":{"2":{"name":"keyword.control.properties.matlab"},"3":{"patterns":[{"match":"[A-Za-z][0-9A-Z_a-z]*","name":"variable.parameter.properties.matlab"},{"begin":"=\\\\s*","end":",|(?=\\\\))","patterns":[{"match":"true|false","name":"constant.language.boolean.matlab"},{"match":"p(?:ublic|rotected|rivate)","name":"constant.language.access.matlab"}]}]}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.properties.matlab"}},"name":"meta.properties.matlab","patterns":[{"include":"#validators"},{"include":"$self"}]},{"begin":"^(\\\\s*)(methods)\\\\b([^%]*)\\\\s*(\\\\([^)]*\\\\))?\\\\s*($|(?=%))","beginCaptures":{"2":{"name":"keyword.control.methods.matlab"},"3":{"patterns":[{"match":"[A-Za-z][0-9A-Z_a-z]*","name":"variable.parameter.methods.matlab"},{"begin":"=\\\\s*","end":",|(?=\\\\))","patterns":[{"match":"true|false","name":"constant.language.boolean.matlab"},{"match":"p(?:ublic|rotected|rivate)","name":"constant.language.access.matlab"}]}]}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.methods.matlab"}},"name":"meta.methods.matlab","patterns":[{"include":"$self"}]},{"begin":"^(\\\\s*)(events)\\\\b([^%]*)\\\\s*(\\\\([^)]*\\\\))?\\\\s*($|(?=%))","beginCaptures":{"2":{"name":"keyword.control.events.matlab"},"3":{"patterns":[{"match":"[A-Za-z][0-9A-Z_a-z]*","name":"variable.parameter.events.matlab"},{"begin":"=\\\\s*","end":",|(?=\\\\))","patterns":[{"match":"true|false","name":"constant.language.boolean.matlab"},{"match":"p(?:ublic|rotected|rivate)","name":"constant.language.access.matlab"}]}]}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.events.matlab"}},"name":"meta.events.matlab","patterns":[{"include":"$self"}]},{"begin":"^(\\\\s*)(enumeration)\\\\b([^%]*)\\\\s*($|(?=%))","beginCaptures":{"2":{"name":"keyword.control.enumeration.matlab"}},"end":"\\\\s*(?:^|[,;\\\\s])(end)\\\\b","endCaptures":{"1":{"name":"keyword.control.end.enumeration.matlab"}},"name":"meta.enumeration.matlab","patterns":[{"include":"$self"}]},{"include":"$self"}]}]},"command_dual":{"captures":{"1":{"name":"string.interpolated.matlab"},"2":{"name":"variable.other.command.matlab"},"28":{"name":"comment.line.percentage.matlab"}},"match":"^\\\\s*(([A-HJ-MO-Zbcdfghklmoq-z]\\\\w*|an??|a([0-9A-Z_a-mo-z]\\\\w*|n[0-9A-Z_a-rt-z]\\\\w*|ns\\\\w+)|ep??|e([0-9A-Z_a-oq-z]\\\\w*|p[0-9A-Z_a-rt-z]\\\\w*|ps\\\\w+)|in|i([0-9A-Z_a-mo-z]\\\\w*|n[0-9A-Z_a-eg-z]\\\\w*|nf\\\\w+)|In??|I([0-9A-Z_a-mo-z]\\\\w*|n[0-9A-Z_a-eg-z]\\\\w*|nf\\\\w+)|j\\\\w+|Na??|N([0-9A-Z_b-z]\\\\w*|a[0-9A-MO-Z_a-z]\\\\w*|aN\\\\w+)|na??|narg??|nargi|nargou??|n([0-9A-Z_b-z]\\\\w*|a([0-9A-Z_a-mopqs-z]\\\\w*|n\\\\w+|r([0-9A-Z_a-fh-z]\\\\w*|g([0-9A-Z_a-hj-nq-z]\\\\w*|i([0-9A-Z_a-mo-z]\\\\w*|n\\\\w+)|o([0-9A-Z_a-tv-z]\\\\w*|u([A-Za-su-z]\\\\w*|t\\\\w+))))))|p|p[0-9A-Z_a-hj-z]\\\\w*|pi\\\\w+)\\\\s+((([^\\"%-/:->@\\\\\\\\^{|~\\\\s]|(?=')|(?=\\"))|(\\\\.\\\\^|\\\\.\\\\*|\\\\./|\\\\.\\\\\\\\|\\\\.'|\\\\.\\\\(|&&|==|\\\\|\\\\||&(?=[^\\\\&])|\\\\|(?=[^|])|~=|<=|>=|~(?!=)|<(?!=)|>(?!=)|[-*+/:@\\\\\\\\^])(\\\\S|\\\\s*(?=%)|\\\\s+$|\\\\s+([]\\\\&)*,/:->@\\\\\\\\^|}]|(\\\\.(?:[^.\\\\d]|\\\\.[^.]))))|(\\\\.[^'(*/A-Z\\\\\\\\^a-z\\\\s]))([^%]|'[^']*'|\\"[^\\"]*\\")*|(\\\\.(?=\\\\s)|\\\\.[A-Za-z]|(?=\\\\{))([^\\"%'(=]|==|'[^']*'|\\"[^\\"]*\\"|\\\\(|\\\\([^%)]*\\\\)|\\\\[|\\\\[[^]%]*]|\\\\{|\\\\{[^%}]*})*(\\\\.\\\\.\\\\.[^%]*)?((?=%)|$)))(%.*)?$"},"comment_block":{"begin":"^(\\\\s*)%\\\\{[^\\\\n\\\\S]*+\\\\n","beginCaptures":{"1":{"name":"punctuation.definition.comment.matlab"}},"end":"^\\\\s*%}[^\\\\n\\\\S]*+(?:\\\\n|$)","name":"comment.block.percentage.matlab","patterns":[{"include":"#comment_block"},{"match":"^[^\\\\n]*\\\\n"}]},"comments":{"patterns":[{"begin":"(^[\\\\t ]+)?(?=%%\\\\s)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.matlab"}},"end":"(?!\\\\G)","patterns":[{"begin":"%%","beginCaptures":{"0":{"name":"punctuation.definition.comment.matlab"}},"end":"\\\\n","name":"comment.line.double-percentage.matlab","patterns":[{"begin":"\\\\G[^\\\\n\\\\S]*(?![\\\\n\\\\s])","contentName":"meta.cell.matlab","end":"(?=\\\\n)"}]}]},{"include":"#comment_block"},{"begin":"(^[\\\\t ]+)?(?=%)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.matlab"}},"end":"(?!\\\\G)","patterns":[{"begin":"%","beginCaptures":{"0":{"name":"punctuation.definition.comment.matlab"}},"end":"\\\\n","name":"comment.line.percentage.matlab"}]}]},"conjugate_transpose":{"match":"((?<=\\\\S)|(?<=])|(?<=\\\\))|(?<=}))'","name":"keyword.operator.transpose.matlab"},"constants":{"match":"(?=??|<=??|&&??|[:|]|\\\\|\\\\||[-*+]|\\\\.\\\\*|/|\\\\./|\\\\\\\\|\\\\.\\\\\\\\|\\\\^|\\\\.\\\\^)(?=\\\\s)","name":"keyword.operator.symbols.matlab"},"parens":{"begin":"\\\\(","end":"(\\\\)|(?\\\\[\\\\\\\\^{|~\\\\s]))|^)'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.matlab"}},"end":"'(?=([\\\\&(-/:->\\\\[-^{-~\\\\s]))","endCaptures":{"0":{"name":"punctuation.definition.string.end.matlab"}},"name":"string.quoted.single.matlab","patterns":[{"match":"''","name":"constant.character.escape.matlab"},{"match":"'(?=.)","name":"invalid.illegal.unescaped-quote.matlab"},{"match":"((%([-+0]?\\\\d{0,3}(\\\\.\\\\d{1,3})?)([EGc-gs]|(([bt])?([Xoux]))))|%%|\\\\\\\\([\\\\\\\\bfnrt]))","name":"constant.character.escape.matlab"}]},{"begin":"((?<=([\\\\&(*-/:->\\\\[\\\\\\\\^{|~\\\\s]))|^)\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.matlab"}},"end":"\\"(?=([\\\\&(-/:->\\\\[-^{-~\\\\s]))","endCaptures":{"0":{"name":"punctuation.definition.string.end.matlab"}},"name":"string.quoted.double.matlab","patterns":[{"match":"\\"\\"","name":"constant.character.escape.matlab"},{"match":"\\"(?=.)","name":"invalid.illegal.unescaped-quote.matlab"}]}]},"transpose":{"match":"\\\\.'","name":"keyword.operator.transpose.matlab"},"validator_strings":{"patterns":[{"patterns":[{"begin":"((?<=([\\\\&(*-/:->\\\\[\\\\\\\\^{|~\\\\s]))|^)'","end":"'(?=([\\\\&(-/:->\\\\[-^{-~\\\\s]))","name":"storage.type.matlab","patterns":[{"match":"''"},{"match":"'(?=.)"},{"match":"([^']+)"}]},{"begin":"((?<=([\\\\&(*-/:->\\\\[\\\\\\\\^{|~\\\\s]))|^)\\"","end":"\\"(?=([\\\\&(-/:->\\\\[-^{-~\\\\s]))","name":"storage.type.matlab","patterns":[{"match":"\\"\\""},{"match":"\\"(?=.)"},{"match":"[^\\"]+"}]}]}]},"validators":{"begin":"\\\\s*;?\\\\s*([A-Za-z][.0-9?A-Z_a-z]*)","end":"([\\\\n%;=].*)","endCaptures":{"1":{"patterns":[{"captures":{"1":{"patterns":[{"include":"$self"}]}},"match":"(%.*)"},{"captures":{"1":{"patterns":[{"include":"$self"}]}},"match":"(=[^;]*)"},{"captures":{"1":{"patterns":[{"include":"#validators"}]}},"match":"([\\\\n;]\\\\s*[A-Za-z].*)"},{"include":"$self"}]}},"patterns":[{"include":"#line_continuation"},{"match":"\\\\s*(\\\\([^)]*\\\\))","name":"storage.type.matlab"},{"match":"([A-Za-z][.0-9A-Z_a-z]*)","name":"storage.type.matlab"},{"include":"#braced_validator_list"}]},"variables":{"match":"(?>=|//=|\\\\*\\\\*=|\\\\+=|-=|/=|@=|\\\\*=|%=|~=|\\\\^=|&=|\\\\|=|=(?!=)","name":"keyword.operator.assignment.python"},"backticks":{"begin":"\`","end":"\`|(?))","name":"comment.typehint.punctuation.notation.python"},{"match":"([_[:alpha:]]\\\\w*)","name":"comment.typehint.variable.notation.python"}]},{"include":"#comments-base"}]},"comments-base":{"begin":"(#)","beginCaptures":{"1":{"name":"punctuation.definition.comment.python"}},"end":"$()","name":"comment.line.number-sign.python","patterns":[{"include":"#codetags"}]},"comments-string-double-three":{"begin":"(#)","beginCaptures":{"1":{"name":"punctuation.definition.comment.python"}},"end":"($|(?=\\"\\"\\"))","name":"comment.line.number-sign.python","patterns":[{"include":"#codetags"}]},"comments-string-single-three":{"begin":"(#)","beginCaptures":{"1":{"name":"punctuation.definition.comment.python"}},"end":"($|(?='''))","name":"comment.line.number-sign.python","patterns":[{"include":"#codetags"}]},"curly-braces":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.dict.begin.python"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.dict.end.python"}},"patterns":[{"match":":","name":"punctuation.separator.dict.python"},{"include":"#expression"}]},"decorator":{"begin":"^\\\\s*((@))\\\\s*(?=[_[:alpha:]]\\\\w*)","beginCaptures":{"1":{"name":"entity.name.function.decorator.python"},"2":{"name":"punctuation.definition.decorator.python"}},"end":"(\\\\))(.*?)(?=\\\\s*(?:#|$))|(?=[\\\\n#])","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.python"},"2":{"name":"invalid.illegal.decorator.python"}},"name":"meta.function.decorator.python","patterns":[{"include":"#decorator-name"},{"include":"#function-arguments"}]},"decorator-name":{"patterns":[{"include":"#builtin-callables"},{"include":"#illegal-object-name"},{"captures":{"2":{"name":"punctuation.separator.period.python"}},"match":"([_[:alpha:]]\\\\w*)|(\\\\.)","name":"entity.name.function.decorator.python"},{"include":"#line-continuation"},{"captures":{"1":{"name":"invalid.illegal.decorator.python"}},"match":"\\\\s*([^#(.\\\\\\\\_[:alpha:]\\\\s].*?)(?=#|$)","name":"invalid.illegal.decorator.python"}]},"double-one-regexp-character-set":{"patterns":[{"match":"\\\\[\\\\^?](?!.*?])"},{"begin":"(\\\\[)(\\\\^)?(])?","beginCaptures":{"1":{"name":"punctuation.character.set.begin.regexp constant.other.set.regexp"},"2":{"name":"keyword.operator.negation.regexp"},"3":{"name":"constant.character.set.regexp"}},"end":"(]|(?=\\"))|((?=(?)","beginCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp"},"2":{"name":"entity.name.tag.named.group.regexp"}},"end":"(\\\\)|(?=\\"))|((?=(?)","beginCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp"},"2":{"name":"entity.name.tag.named.group.regexp"}},"end":"(\\\\)|(?=\\"\\"\\"))","endCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp"},"2":{"name":"invalid.illegal.newline.python"}},"name":"meta.named.regexp","patterns":[{"include":"#double-three-regexp-expression"},{"include":"#comments-string-double-three"}]},"double-three-regexp-parentheses":{"begin":"\\\\(","beginCaptures":{"0":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp"}},"end":"(\\\\)|(?=\\"\\"\\"))","endCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.end.regexp"},"2":{"name":"invalid.illegal.newline.python"}},"patterns":[{"include":"#double-three-regexp-expression"},{"include":"#comments-string-double-three"}]},"double-three-regexp-parentheses-non-capturing":{"begin":"\\\\(\\\\?:","beginCaptures":{"0":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp"}},"end":"(\\\\)|(?=\\"\\"\\"))","endCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp"},"2":{"name":"invalid.illegal.newline.python"}},"patterns":[{"include":"#double-three-regexp-expression"},{"include":"#comments-string-double-three"}]},"ellipsis":{"match":"\\\\.\\\\.\\\\.","name":"constant.other.ellipsis.python"},"escape-sequence":{"match":"\\\\\\\\(x\\\\h{2}|[0-7]{1,3}|[\\"'\\\\\\\\abfnrtv])","name":"constant.character.escape.python"},"escape-sequence-unicode":{"patterns":[{"match":"\\\\\\\\(u\\\\h{4}|U\\\\h{8}|N\\\\{[\\\\w\\\\s]+?})","name":"constant.character.escape.python"}]},"expression":{"patterns":[{"include":"#expression-base"},{"include":"#member-access"},{"match":"\\\\b([_[:alpha:]]\\\\w*)\\\\b"}]},"expression-bare":{"patterns":[{"include":"#backticks"},{"include":"#literal"},{"include":"#regexp"},{"include":"#string"},{"include":"#lambda"},{"include":"#generator"},{"include":"#illegal-operator"},{"include":"#operator"},{"include":"#curly-braces"},{"include":"#item-access"},{"include":"#list"},{"include":"#odd-function-call"},{"include":"#round-braces"},{"include":"#function-call"},{"include":"#builtin-functions"},{"include":"#builtin-types"},{"include":"#builtin-exceptions"},{"include":"#magic-names"},{"include":"#special-names"},{"include":"#illegal-names"},{"include":"#special-variables"},{"include":"#ellipsis"},{"include":"#punctuation"},{"include":"#line-continuation"}]},"expression-base":{"patterns":[{"include":"#comments"},{"include":"#expression-bare"},{"include":"#line-continuation"}]},"f-expression":{"patterns":[{"include":"#expression-bare"},{"include":"#member-access"},{"match":"\\\\b([_[:alpha:]]\\\\w*)\\\\b"}]},"fregexp-base-expression":{"patterns":[{"include":"#fregexp-quantifier"},{"include":"#fstring-formatting-braces"},{"match":"\\\\{.*?}"},{"include":"#regexp-base-common"}]},"fregexp-quantifier":{"match":"\\\\{\\\\{(\\\\d+|\\\\d+,(\\\\d+)?|,\\\\d+)}}","name":"keyword.operator.quantifier.regexp"},"fstring-fnorm-quoted-multi-line":{"begin":"\\\\b([Ff])([BUbu])?('''|\\"\\"\\")","beginCaptures":{"1":{"name":"string.interpolated.python string.quoted.multi.python storage.type.string.python"},"2":{"name":"invalid.illegal.prefix.python"},"3":{"name":"punctuation.definition.string.begin.python string.interpolated.python string.quoted.multi.python"}},"end":"(\\\\3)","endCaptures":{"1":{"name":"punctuation.definition.string.end.python string.interpolated.python string.quoted.multi.python"},"2":{"name":"invalid.illegal.newline.python"}},"name":"meta.fstring.python","patterns":[{"include":"#fstring-guts"},{"include":"#fstring-illegal-multi-brace"},{"include":"#fstring-multi-brace"},{"include":"#fstring-multi-core"}]},"fstring-fnorm-quoted-single-line":{"begin":"\\\\b([Ff])([BUbu])?(([\\"']))","beginCaptures":{"1":{"name":"string.interpolated.python string.quoted.single.python storage.type.string.python"},"2":{"name":"invalid.illegal.prefix.python"},"3":{"name":"punctuation.definition.string.begin.python string.interpolated.python string.quoted.single.python"}},"end":"(\\\\3)|((?^]?[- +]?#?\\\\d*,?(\\\\.\\\\d+)?[%EFGXb-gnosx]?)(?=})"},{"include":"#fstring-terminator-multi-tail"}]},"fstring-terminator-multi-tail":{"begin":"(=?(?:![ars])?)(:)(?=.*?\\\\{)","beginCaptures":{"1":{"name":"storage.type.format.python"},"2":{"name":"storage.type.format.python"}},"end":"(?=})","patterns":[{"include":"#fstring-illegal-multi-brace"},{"include":"#fstring-multi-brace"},{"match":"([%EFGXb-gnosx])(?=})","name":"storage.type.format.python"},{"match":"(\\\\.\\\\d+)","name":"storage.type.format.python"},{"match":"(,)","name":"storage.type.format.python"},{"match":"(\\\\d+)","name":"storage.type.format.python"},{"match":"(#)","name":"storage.type.format.python"},{"match":"([- +])","name":"storage.type.format.python"},{"match":"([<=>^])","name":"storage.type.format.python"},{"match":"(\\\\w)","name":"storage.type.format.python"}]},"fstring-terminator-single":{"patterns":[{"match":"(=(![ars])?)(?=})","name":"storage.type.format.python"},{"match":"(=?![ars])(?=})","name":"storage.type.format.python"},{"captures":{"1":{"name":"storage.type.format.python"},"2":{"name":"storage.type.format.python"}},"match":"(=?(?:![ars])?)(:\\\\w?[<=>^]?[- +]?#?\\\\d*,?(\\\\.\\\\d+)?[%EFGXb-gnosx]?)(?=})"},{"include":"#fstring-terminator-single-tail"}]},"fstring-terminator-single-tail":{"begin":"(=?(?:![ars])?)(:)(?=.*?\\\\{)","beginCaptures":{"1":{"name":"storage.type.format.python"},"2":{"name":"storage.type.format.python"}},"end":"(?=})|(?=\\\\n)","patterns":[{"include":"#fstring-illegal-single-brace"},{"include":"#fstring-single-brace"},{"match":"([%EFGXb-gnosx])(?=})","name":"storage.type.format.python"},{"match":"(\\\\.\\\\d+)","name":"storage.type.format.python"},{"match":"(,)","name":"storage.type.format.python"},{"match":"(\\\\d+)","name":"storage.type.format.python"},{"match":"(#)","name":"storage.type.format.python"},{"match":"([- +])","name":"storage.type.format.python"},{"match":"([<=>^])","name":"storage.type.format.python"},{"match":"(\\\\w)","name":"storage.type.format.python"}]},"function-arguments":{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.arguments.begin.python"}},"contentName":"meta.function-call.arguments.python","end":"(?=\\\\))(?!\\\\)\\\\s*\\\\()","patterns":[{"match":"(,)","name":"punctuation.separator.arguments.python"},{"captures":{"1":{"name":"keyword.operator.unpacking.arguments.python"}},"match":"(?:(?<=[(,])|^)\\\\s*(\\\\*{1,2})"},{"include":"#lambda-incomplete"},{"include":"#illegal-names"},{"captures":{"1":{"name":"variable.parameter.function-call.python"},"2":{"name":"keyword.operator.assignment.python"}},"match":"\\\\b([_[:alpha:]]\\\\w*)\\\\s*(=)(?!=)"},{"match":"=(?!=)","name":"keyword.operator.assignment.python"},{"include":"#expression"},{"captures":{"1":{"name":"punctuation.definition.arguments.end.python"},"2":{"name":"punctuation.definition.arguments.begin.python"}},"match":"\\\\s*(\\\\))\\\\s*(\\\\()"}]},"function-call":{"begin":"\\\\b(?=([_[:alpha:]]\\\\w*)\\\\s*(\\\\())","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.arguments.end.python"}},"name":"meta.function-call.python","patterns":[{"include":"#special-variables"},{"include":"#function-name"},{"include":"#function-arguments"}]},"function-declaration":{"begin":"\\\\s*(?:\\\\b(async)\\\\s+)?\\\\b(def|fn)\\\\s+(?=[_[:alpha:]]\\\\p{word}*\\\\s*[(\\\\[])","beginCaptures":{"1":{"name":"storage.type.function.async.python"},"2":{"name":"storage.type.function.python"}},"end":"(:|(?=[\\\\n\\"#']))","endCaptures":{"1":{"name":"punctuation.section.function.begin.python"}},"name":"meta.function.python","patterns":[{"include":"#function-modifier"},{"include":"#function-def-name"},{"include":"#parameters"},{"include":"#meta_parameters"},{"include":"#line-continuation"},{"include":"#return-annotation"}]},"function-def-name":{"patterns":[{"include":"#illegal-object-name"},{"include":"#builtin-possible-callables"},{"match":"\\\\b([_[:alpha:]]\\\\w*)\\\\b","name":"entity.name.function.python"}]},"function-modifier":{"match":"(raises|capturing)","name":"storage.modifier"},"function-name":{"patterns":[{"include":"#builtin-possible-callables"},{"match":"\\\\b([_[:alpha:]]\\\\w*)\\\\b","name":"meta.function-call.generic.python"}]},"generator":{"begin":"(?:\\\\b(comptime)\\\\s+)?\\\\bfor\\\\b","beginCaptures":{"0":{"name":"keyword.control.flow.python"},"1":{"name":"storage.modifier.declaration.python"}},"end":"\\\\bin\\\\b","endCaptures":{"0":{"name":"keyword.control.flow.python"}},"patterns":[{"include":"#expression"}]},"illegal-names":{"captures":{"1":{"name":"keyword.control.flow.python"},"2":{"name":"storage.type.function.python"},"3":{"name":"keyword.control.import.python"}},"match":"\\\\b(?:(and|assert|async|await|break|class|struct|trait|continue|del|elif|else|except|finally|for|from|global|if|in|is|(?<=\\\\.)lambda|lambda(?=\\\\s*[.=])|nonlocal|not|or|pass|raise|return|try|while|with|yield)|(def|fn|capturing|raises|comptime)|(as|import))\\\\b"},"illegal-object-name":{"match":"\\\\b(True|False|None)\\\\b","name":"keyword.illegal.name.python"},"illegal-operator":{"patterns":[{"match":"&&|\\\\|\\\\||--|\\\\+\\\\+","name":"invalid.illegal.operator.python"},{"match":"[$?]","name":"invalid.illegal.operator.python"},{"match":"!\\\\b","name":"invalid.illegal.operator.python"}]},"import":{"patterns":[{"begin":"\\\\b(?>|[\\\\&^|~])|(\\\\*\\\\*|[-%*+]|//|[/@])|(!=|==|>=|<=|[<>])|(:=)"},"parameter-special":{"captures":{"1":{"name":"variable.parameter.function.language.python"},"2":{"name":"variable.parameter.function.language.special.self.python"},"3":{"name":"variable.parameter.function.language.special.cls.python"},"4":{"name":"punctuation.separator.parameters.python"}},"match":"\\\\b((self)|(cls))\\\\b\\\\s*(?:(,)|(?=\\\\)))"},"parameters":{"begin":"(\\\\()","beginCaptures":{"1":{"name":"punctuation.definition.parameters.begin.python"}},"end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.parameters.end.python"}},"name":"meta.function.parameters.python","patterns":[{"match":"\\\\b(owned|borrowed|inout)\\\\b","name":"storage.modifier"},{"match":"/","name":"keyword.operator.positional.parameter.python"},{"match":"(\\\\*\\\\*?)","name":"keyword.operator.unpacking.parameter.python"},{"include":"#lambda-incomplete"},{"include":"#illegal-names"},{"include":"#illegal-object-name"},{"include":"#parameter-special"},{"captures":{"1":{"name":"variable.parameter.function.language.python"},"2":{"name":"punctuation.separator.parameters.python"}},"match":"([_[:alpha:]]\\\\w*)\\\\s*(?:(,)|(?=[\\\\n#)=]))"},{"include":"#comments"},{"include":"#loose-default"},{"include":"#annotated-parameter"}]},"punctuation":{"patterns":[{"match":":","name":"punctuation.separator.colon.python"},{"match":",","name":"punctuation.separator.element.python"}]},"regexp":{"patterns":[{"include":"#regexp-single-three-line"},{"include":"#regexp-double-three-line"},{"include":"#regexp-single-one-line"},{"include":"#regexp-double-one-line"}]},"regexp-backreference":{"captures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.backreference.named.begin.regexp"},"2":{"name":"entity.name.tag.named.backreference.regexp"},"3":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.backreference.named.end.regexp"}},"match":"(\\\\()(\\\\?P=\\\\w+(?:\\\\s+\\\\p{alnum}+)?)(\\\\))","name":"meta.backreference.named.regexp"},"regexp-backreference-number":{"captures":{"1":{"name":"entity.name.tag.backreference.regexp"}},"match":"(\\\\\\\\[1-9]\\\\d?)","name":"meta.backreference.regexp"},"regexp-base-common":{"patterns":[{"match":"\\\\.","name":"support.other.match.any.regexp"},{"match":"\\\\^","name":"support.other.match.begin.regexp"},{"match":"\\\\$","name":"support.other.match.end.regexp"},{"match":"[*+?]\\\\??","name":"keyword.operator.quantifier.regexp"},{"match":"\\\\|","name":"keyword.operator.disjunction.regexp"},{"include":"#regexp-escape-sequence"}]},"regexp-base-expression":{"patterns":[{"include":"#regexp-quantifier"},{"include":"#regexp-base-common"}]},"regexp-charecter-set-escapes":{"patterns":[{"match":"\\\\\\\\[\\\\\\\\abfnrtv]","name":"constant.character.escape.regexp"},{"include":"#regexp-escape-special"},{"match":"\\\\\\\\([0-7]{1,3})","name":"constant.character.escape.regexp"},{"include":"#regexp-escape-character"},{"include":"#regexp-escape-unicode"},{"include":"#regexp-escape-catchall"}]},"regexp-double-one-line":{"begin":"\\\\b(([Uu]r)|([Bb]r)|(r[Bb]?))(\\")","beginCaptures":{"2":{"name":"invalid.deprecated.prefix.python"},"3":{"name":"storage.type.string.python"},"4":{"name":"storage.type.string.python"},"5":{"name":"punctuation.definition.string.begin.python"}},"end":"(\\")|(?)","beginCaptures":{"1":{"name":"punctuation.separator.annotation.result.python"}},"end":"(?=:)","patterns":[{"include":"#expression"}]},"round-braces":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.parenthesis.begin.python"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.parenthesis.end.python"}},"patterns":[{"include":"#expression"}]},"semicolon":{"patterns":[{"match":";$","name":"invalid.deprecated.semicolon.python"}]},"single-one-regexp-character-set":{"patterns":[{"match":"\\\\[\\\\^?](?!.*?])"},{"begin":"(\\\\[)(\\\\^)?(])?","beginCaptures":{"1":{"name":"punctuation.character.set.begin.regexp constant.other.set.regexp"},"2":{"name":"keyword.operator.negation.regexp"},"3":{"name":"constant.character.set.regexp"}},"end":"(]|(?='))|((?=(?)","beginCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp"},"2":{"name":"entity.name.tag.named.group.regexp"}},"end":"(\\\\)|(?='))|((?=(?)","beginCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.named.begin.regexp"},"2":{"name":"entity.name.tag.named.group.regexp"}},"end":"(\\\\)|(?='''))","endCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.named.end.regexp"},"2":{"name":"invalid.illegal.newline.python"}},"name":"meta.named.regexp","patterns":[{"include":"#single-three-regexp-expression"},{"include":"#comments-string-single-three"}]},"single-three-regexp-parentheses":{"begin":"\\\\(","beginCaptures":{"0":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.begin.regexp"}},"end":"(\\\\)|(?='''))","endCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.end.regexp"},"2":{"name":"invalid.illegal.newline.python"}},"patterns":[{"include":"#single-three-regexp-expression"},{"include":"#comments-string-single-three"}]},"single-three-regexp-parentheses-non-capturing":{"begin":"\\\\(\\\\?:","beginCaptures":{"0":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.begin.regexp"}},"end":"(\\\\)|(?='''))","endCaptures":{"1":{"name":"support.other.parenthesis.regexp punctuation.parenthesis.non-capturing.end.regexp"},"2":{"name":"invalid.illegal.newline.python"}},"patterns":[{"include":"#single-three-regexp-expression"},{"include":"#comments-string-single-three"}]},"special-names":{"match":"\\\\b(_*\\\\p{upper}[_\\\\d]*\\\\p{upper})[[:upper:]\\\\d]*(_\\\\w*)?\\\\b","name":"constant.other.caps.python"},"special-variables":{"captures":{"1":{"name":"variable.language.special.self.python"},"2":{"name":"variable.language.special.cls.python"}},"match":"\\\\b(?^]?[- +]?#?\\\\d*,?(\\\\.\\\\d+)?[%EFGXb-gnosx]?)?})","name":"meta.format.brace.python"},{"captures":{"1":{"name":"constant.character.format.placeholder.other.python"},"3":{"name":"storage.type.format.python"},"4":{"name":"storage.type.format.python"}},"match":"(\\\\{\\\\w*(\\\\.[_[:alpha:]]\\\\w*|\\\\[[^]\\"']+])*(![ars])?(:)[^\\\\n\\"'{}]*(?:\\\\{[^\\\\n\\"'}]*?}[^\\\\n\\"'{}]*)*})","name":"meta.format.brace.python"}]},"string-consume-escape":{"match":"\\\\\\\\[\\\\n\\"'\\\\\\\\]"},"string-entity":{"patterns":[{"include":"#escape-sequence"},{"include":"#string-line-continuation"},{"include":"#string-formatting"}]},"string-formatting":{"captures":{"1":{"name":"constant.character.format.placeholder.other.python"}},"match":"(%(\\\\([\\\\w\\\\s]*\\\\))?[- #+0]*(\\\\d+|\\\\*)?(\\\\.(\\\\d+|\\\\*))?([Lhl])?[%EFGXa-giorsux])","name":"meta.format.percent.python"},"string-line-continuation":{"match":"\\\\\\\\$","name":"constant.language.python"},"string-mojo-code-block":{"begin":"^(\\\\s*\`{3,})(mojo)$","beginCaptures":{"1":{"name":"string.quoted.single.python"},"2":{"name":"string.quoted.single.python"}},"contentName":"source.mojo","end":"^(\\\\1)$","endCaptures":{"1":{"name":"string.quoted.single.python"}},"name":"meta.embedded.block.mojo","patterns":[{"include":"source.mojo"}]},"string-multi-bad-brace1-formatting-raw":{"begin":"(?=\\\\{%(.*?(?!'''|\\"\\"\\"))%})","end":"(?='''|\\"\\"\\")","patterns":[{"include":"#string-consume-escape"}]},"string-multi-bad-brace1-formatting-unicode":{"begin":"(?=\\\\{%(.*?(?!'''|\\"\\"\\"))%})","end":"(?='''|\\"\\"\\")","patterns":[{"include":"#escape-sequence-unicode"},{"include":"#escape-sequence"},{"include":"#string-line-continuation"}]},"string-multi-bad-brace2-formatting-raw":{"begin":"(?!\\\\{\\\\{)(?=\\\\{(\\\\w*?(?!'''|\\"\\"\\")[^!.:\\\\[}\\\\w]).*?(?!'''|\\"\\"\\")})","end":"(?='''|\\"\\"\\")","patterns":[{"include":"#string-consume-escape"},{"include":"#string-formatting"}]},"string-multi-bad-brace2-formatting-unicode":{"begin":"(?!\\\\{\\\\{)(?=\\\\{(\\\\w*?(?!'''|\\"\\"\\")[^!.:\\\\[}\\\\w]).*?(?!'''|\\"\\"\\")})","end":"(?='''|\\"\\"\\")","patterns":[{"include":"#escape-sequence-unicode"},{"include":"#string-entity"}]},"string-quoted-multi-line":{"begin":"(?:\\\\b([Rr])(?=[Uu]))?([Uu])?('''|\\"\\"\\")","beginCaptures":{"1":{"name":"invalid.illegal.prefix.python"},"2":{"name":"storage.type.string.python"},"3":{"name":"punctuation.definition.string.begin.python"}},"end":"(\\\\3)","endCaptures":{"1":{"name":"punctuation.definition.string.end.python"},"2":{"name":"invalid.illegal.newline.python"}},"name":"string.quoted.multi.python","patterns":[{"include":"#string-multi-bad-brace1-formatting-unicode"},{"include":"#string-multi-bad-brace2-formatting-unicode"},{"include":"#string-unicode-guts"}]},"string-quoted-single-line":{"begin":"(?:\\\\b([Rr])(?=[Uu]))?([Uu])?(([\\"']))","beginCaptures":{"1":{"name":"invalid.illegal.prefix.python"},"2":{"name":"storage.type.string.python"},"3":{"name":"punctuation.definition.string.begin.python"}},"end":"(\\\\3)|((?","name":"keyword.operator.nushell"},{"include":"#function-multiple-inout"}]},"function-multiple-inout":{"begin":"(?<=]\\\\s*)(:)\\\\s+(\\\\[)","beginCaptures":{"1":{"name":"punctuation.definition.in-out.nushell"},"2":{"name":"meta.brace.square.begin.nushell"}},"end":"]","endCaptures":{"0":{"name":"meta.brace.square.end.nushell"}},"patterns":[{"include":"#types"},{"captures":{"1":{"name":"punctuation.separator.nushell"}},"match":"\\\\s*(,)\\\\s*"},{"captures":{"1":{"name":"keyword.operator.nushell"}},"match":"\\\\s+(->)\\\\s+"}]},"function-parameter":{"patterns":[{"captures":{"1":{"name":"keyword.control.nushell"}},"match":"(-{0,2}|\\\\.{3})[-\\\\w]+(?:\\\\((-[?\\\\w])\\\\))?","name":"variable.parameter.nushell"},{"begin":"\\\\??:\\\\s*","end":"(?=\\\\s+(?:-{0,2}|\\\\.{3})[-\\\\w]+|\\\\s*(?:[]#,=@|]|$))","patterns":[{"include":"#types"}]},{"begin":"@(?=[\\"'])","end":"(?<=[\\"'])","patterns":[{"include":"#string"}]},{"begin":"=\\\\s*","end":"(?=\\\\s+-{0,2}[-\\\\w]+|\\\\s*(?:[]#,|]|$))","name":"default.value.nushell","patterns":[{"include":"#value"}]}]},"function-parameters":{"begin":"\\\\[","beginCaptures":{"0":{"name":"meta.brace.square.begin.nushell"}},"end":"]","endCaptures":{"0":{"name":"meta.brace.square.end.nushell"}},"name":"meta.function.parameters.nushell","patterns":[{"include":"#function-parameter"},{"include":"#comment"}]},"internal-variables":{"match":"\\\\$(?:nu|env)\\\\b","name":"variable.language.nushell"},"keyword":{"match":"def(?:-env)?","name":"keyword.other.nushell"},"module":{"begin":"((?:export\\\\s+)?module)\\\\s+([-\\\\w]+)\\\\s*\\\\{","beginCaptures":{"1":{"name":"storage.type.module.nushell"},"2":{"name":"entity.name.namespace.nushell"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.module.end.nushell"}},"name":"meta.module.nushell","patterns":[{"include":"source.nushell"}]},"numbers":{"match":"(?]=?|[!=]~|\\\\+\\\\+=?)(?= |$)","name":"keyword.control.nushell"},"operators-word":{"match":"(?<=[ (])(?:mod|in|not-(?:in|like|has)|not|and|or|xor|bit-(?:or|and|xor|shl|shr)|starts-with|ends-with|like|has)(?=[ )]|$)","name":"keyword.control.nushell"},"parameters":{"captures":{"1":{"name":"keyword.control.nushell"}},"match":"(?<=\\\\s)(-{1,2})[-\\\\w]+","name":"variable.parameter.nushell"},"paren-expression":{"begin":"\\\\(","beginCaptures":{"0":{"name":"meta.brace.round.begin.nushell"}},"end":"\\\\)","endCaptures":{"0":{"name":"meta.brace.round.end.nushell"}},"name":"meta.expression.parenthesis.nushell","patterns":[{"include":"#expression"}]},"pre-command":{"begin":"(\\\\w+)(=)","beginCaptures":{"1":{"name":"variable.other.nushell"},"2":{"patterns":[{"include":"#operators"}]}},"end":"(?=\\\\s+)","patterns":[{"include":"#value"}]},"ranges":{"match":"\\\\.\\\\.","name":"meta.list.nushell","patterns":[{"include":"#types"}]},{"begin":"\\\\b(record)\\\\s*<","beginCaptures":{"1":{"name":"entity.name.type.nushell"}},"end":">","name":"meta.record.nushell","patterns":[{"captures":{"1":{"name":"variable.parameter.nushell"}},"match":"([-\\\\w]+|\\"[- \\\\w]+\\"|'[^']+')\\\\s*:\\\\s*"},{"include":"#types"}]},{"match":"\\\\b(\\\\w+)\\\\b","name":"entity.name.type.nushell"}]},"use-module":{"patterns":[{"captures":{"1":{"name":"keyword.control.import.nushell"},"2":{"name":"entity.name.namespace.nushell"},"3":{"name":"keyword.other.nushell"}},"match":"^\\\\s*((?:export )?use)\\\\s+([-\\\\w]+|\\"[- \\\\w]+\\"|'[- \\\\w]+')(?:\\\\s+([-\\\\w]+|\\"[- \\\\w]+\\"|'[- \\\\w]+'|\\\\*))?\\\\s*;?$"},{"begin":"^\\\\s*((?:export )?use)\\\\s+([-\\\\w]+|\\"[- \\\\w]+\\"|'[- \\\\w]+')\\\\s*\\\\[","beginCaptures":{"1":{"name":"keyword.control.import.nushell"},"2":{"name":"entity.name.namespace.nushell"}},"end":"(])\\\\s*;?\\\\s*$","endCaptures":{"1":{"name":"meta.brace.square.end.nushell"}},"patterns":[{"captures":{"1":{"name":"keyword.other.nushell"}},"match":"([-\\\\w]+|\\"[- \\\\w]+\\"|'[- \\\\w]+'|\\\\*),?"},{"include":"#comment"}]},{"captures":{"2":{"name":"keyword.control.import.nushell"},"3":{"name":"string.bare.nushell","patterns":[{"captures":{"1":{"name":"entity.name.namespace.nushell"}},"match":"([- \\\\w]+)(?:\\\\.nu)?(?=$|[\\"'])"}]},"4":{"name":"keyword.other.nushell"}},"match":"(?(?:[/\\\\\\\\]|~[/\\\\\\\\]|\\\\.\\\\.?[/\\\\\\\\])?(?:[^/\\\\\\\\]+[/\\\\\\\\])*[- \\\\w]+(?:\\\\.nu)?){0}^\\\\s*((?:export )?use)\\\\s+(\\"\\\\g\\"|'\\\\g'|(?![\\"'])\\\\g)(?:\\\\s+([-\\\\w]+|\\"[- \\\\w]+\\"|'[^']+'|\\\\*))?\\\\s*;?$"},{"begin":"(?(?:[/\\\\\\\\]|~[/\\\\\\\\]|\\\\.\\\\.?[/\\\\\\\\])?(?:[^/\\\\\\\\]+[/\\\\\\\\])*[- \\\\w]+(?:\\\\.nu)?){0}^\\\\s*((?:export )?use)\\\\s+(\\"\\\\g\\"|'\\\\g'|(?![\\"'])\\\\g)\\\\s+\\\\[","beginCaptures":{"2":{"name":"keyword.control.import.nushell"},"3":{"name":"string.bare.nushell","patterns":[{"captures":{"1":{"name":"entity.name.namespace.nushell"}},"match":"([- \\\\w]+)(?:\\\\.nu)?(?=$|[\\"'])"}]}},"end":"(])\\\\s*;?\\\\s*$","endCaptures":{"1":{"name":"meta.brace.square.end.nushell"}},"patterns":[{"captures":{"0":{"name":"keyword.other.nushell"}},"match":"([-\\\\w]+|\\"[- \\\\w]+\\"|'[- \\\\w]+'|\\\\*),?"},{"include":"#comment"}]},{"captures":{"0":{"name":"keyword.control.import.nushell"}},"match":"^\\\\s*(?:export )?use\\\\b"}]},"value":{"patterns":[{"include":"#variables"},{"include":"#variable-fields"},{"include":"#control-keywords"},{"include":"#constant-value"},{"include":"#table"},{"include":"#operators"},{"include":"#paren-expression"},{"include":"#braced-expression"},{"include":"#string"},{"include":"#comment"}]},"variable-fields":{"match":"(?<=[])}])(?:\\\\.(?:[-\\\\w]+|\\"[- \\\\w]+\\"))+","name":"variable.other.nushell"},"variables":{"captures":{"1":{"patterns":[{"include":"#internal-variables"},{"match":"\\\\$.+","name":"variable.other.nushell"}]},"2":{"name":"variable.other.nushell"}},"match":"(\\\\$[0-9A-Z_a-z]+)((?:\\\\.(?:[-\\\\w]+|\\"[- \\\\w]+\\"))*)"}},"scopeName":"source.nushell","aliases":["nu"]}`)),n=[e];export{n as default}; diff --git a/apps/kimi-code/dist-web/assets/ocaml-C0hk2d4L.js b/apps/kimi-code/dist-web/assets/ocaml-C0hk2d4L.js new file mode 100644 index 0000000000000000000000000000000000000000..3c4c59bf752c99a8eeabd88c36a06afc72f8e150 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/ocaml-C0hk2d4L.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"OCaml","fileTypes":[".ml",".mli"],"name":"ocaml","patterns":[{"include":"#comment"},{"include":"#pragma"},{"include":"#decl"}],"repository":{"attribute":{"begin":"(\\\\[)\\\\s*((?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)"},"attributePayload":{"patterns":[{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)%)(?![-!#-\\\\&*+./:<-@^|~])","end":"((?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*\\\\s*,|[^%\\\\s[:lower:]])|(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*|(?=\\\\btype\\\\b)","endCaptures":{"0":{"name":"entity.name.function strong emphasis"}},"patterns":[{"include":"#attributeIdentifier"}]},{"begin":"\\\\[","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"]","patterns":[{"include":"#type"}]},{"include":"#bindTermArgs"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*\\\\s*,|[^%\\\\s[:lower:]])|(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*|(?=\\\\btype\\\\b)","endCaptures":{"0":{"name":"entity.name.function strong emphasis"}},"patterns":[{"include":"#attributeIdentifier"}]},{"begin":"\\\\[","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"]","patterns":[{"include":"#type"}]},{"include":"#bindTermArgs"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*\\\\s*,|[^%\\\\s[:lower:]])|\\\\b(rec)\\\\b|((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"2":{"name":"entity.name.function strong emphasis"}},"patterns":[{"include":"#attributeIdentifier"},{"include":"#comment"}]},{"begin":"(?<=(?:\\\\P{word}|^)rec)(?!\\\\p{word})","end":"((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)|(?=[^\\\\s[:alpha:]])","endCaptures":{"0":{"name":"entity.name.function strong emphasis"}},"patterns":[{"include":"#bindTermArgs"}]},{"include":"#bindTermArgs"}]},{"begin":"(?<=(?:\\\\P{word}|^)module)(?!\\\\p{word})","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#declModule"}]},{"begin":"(?<=(?:\\\\P{word}|^)open)(?!\\\\p{word})","end":"(?=\\\\bin\\\\b)|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#pathModuleSimple"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*|(?<=\\\\))","endCaptures":{"0":{"name":"markup.inserted constant.language support.constant.property-value entity.name.filename"}},"patterns":[{"include":"#comment"},{"begin":"\\\\((?!\\\\*)","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"\\\\)","patterns":[{"begin":"(?<=\\\\()","end":"[:=]","endCaptures":{"0":{"name":"keyword"}},"patterns":[{"match":"(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename"}]},{"begin":"(?<=:)","end":"=|(?=\\\\))","endCaptures":{"0":{"name":"keyword"}},"patterns":[{"include":"#type"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)=)(?![-!#-\\\\&*+./:<-@^|~])","end":"(?=\\\\))","patterns":[{"include":"#term"}]}]}]}]},{"include":"#pattern"}]},"bindType":{"patterns":[{"begin":"(?<=(?:\\\\P{word}|^)(?:and|type))(?!\\\\p{word})","end":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"entity.name.function strong"},{"include":"#type"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]\\\\+|^\\\\+|[^-!#-\\\\&*+./:<-@^|~]|^)=)(?![-!#-\\\\&*+./:<-@^|~])","end":"\\\\band\\\\b|(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp markup.underline"}},"patterns":[{"include":"#bindConstructor"}]}]},"comment":{"patterns":[{"include":"#attribute"},{"include":"#extension"},{"include":"#commentBlock"},{"include":"#commentDoc"}]},"commentBlock":{"begin":"\\\\(\\\\*(?!\\\\*[^)])","contentName":"emphasis","end":"\\\\*\\\\)","name":"comment constant.regexp meta.separator.markdown","patterns":[{"include":"#commentBlock"},{"include":"#commentDoc"}]},"commentDoc":{"begin":"\\\\(\\\\*\\\\*","end":"\\\\*\\\\)","name":"comment constant.regexp meta.separator.markdown","patterns":[{"match":"\\\\*"},{"include":"#comment"}]},"decl":{"patterns":[{"include":"#declClass"},{"include":"#declException"},{"include":"#declInclude"},{"include":"#declModule"},{"include":"#declOpen"},{"include":"#declTerm"},{"include":"#declType"}]},"declClass":{"begin":"\\\\bclass\\\\b","beginCaptures":{"0":{"name":"entity.name.class constant.numeric markup.underline"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#comment"},{"include":"#pragma"},{"begin":"(?<=(?:\\\\P{word}|^)class)(?!\\\\p{word})","beginCaptures":{"0":{"name":"entity.name.class constant.numeric markup.underline"}},"end":"\\\\btype\\\\b|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|val)\\\\b)","endCaptures":{"0":{"name":"keyword"}},"patterns":[{"include":"#bindClassTerm"}]},{"begin":"(?<=(?:\\\\P{word}|^)type)(?!\\\\p{word})","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#bindClassType"}]}]},"declException":{"begin":"\\\\bexception\\\\b","beginCaptures":{"0":{"name":"keyword markup.underline"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#attributeIdentifier"},{"include":"#comment"},{"include":"#pragma"},{"include":"#bindConstructor"}]},"declInclude":{"begin":"\\\\binclude\\\\b","beginCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#attributeIdentifier"},{"include":"#comment"},{"include":"#pragma"},{"include":"#signature"}]},"declModule":{"begin":"(?<=(?:\\\\P{word}|^)module)(?!\\\\p{word})|\\\\bmodule\\\\b","beginCaptures":{"0":{"name":"markup.inserted constant.language support.constant.property-value entity.name.filename markup.underline"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#comment"},{"include":"#pragma"},{"begin":"(?<=(?:\\\\P{word}|^)module)(?!\\\\p{word})","end":"\\\\b(type)\\\\b|(?=\\\\p{upper})","endCaptures":{"0":{"name":"keyword"}},"patterns":[{"include":"#attributeIdentifier"},{"include":"#comment"},{"match":"\\\\brec\\\\b","name":"variable.other.class.js message.error variable.interpolation string.regexp"}]},{"begin":"(?<=(?:\\\\P{word}|^)type)(?!\\\\p{word})","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#bindSignature"}]},{"begin":"(?=\\\\p{upper})","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#bindStructure"}]}]},"declOpen":{"begin":"\\\\bopen\\\\b","beginCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#attributeIdentifier"},{"include":"#comment"},{"include":"#pragma"},{"include":"#pathModuleExtended"}]},"declTerm":{"begin":"\\\\b(?:(external|val)|(method)|(let))\\\\b(!?)","beginCaptures":{"1":{"name":"support.type markup.underline"},"2":{"name":"storage.type markup.underline"},"3":{"name":"keyword.control markup.underline"},"4":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#comment"},{"include":"#pragma"},{"include":"#bindTerm"}]},"declType":{"begin":"(?<=(?:\\\\P{word}|^)type)(?!\\\\p{word})|\\\\btype\\\\b","beginCaptures":{"0":{"name":"keyword markup.underline"}},"end":";;|(?=[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#comment"},{"include":"#pragma"},{"include":"#bindType"}]},"extension":{"begin":"(\\\\[)((?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:\\\\P{word}|^)with)(?!\\\\p{word})","end":"(:)|(=)|(;)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp strong"},"2":{"name":"support.type strong"},"3":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"match":"(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(;)|(=)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"2":{"name":"support.type strong"}},"patterns":[{"include":"#type"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)=)(?![-!#-\\\\&*+./:<-@^|~])","end":";|(?=})","endCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"include":"#term"}]}]},"literalString":{"patterns":[{"begin":"\\"","end":"\\"","name":"string beginning.punctuation.definition.quote.markdown","patterns":[{"include":"#literalStringEscape"}]},{"begin":"(\\\\{)([_[:lower:]]*?)(\\\\|)","end":"(\\\\|)(\\\\2)(})","name":"string beginning.punctuation.definition.quote.markdown","patterns":[{"include":"#literalStringEscape"}]}]},"literalStringEscape":{"match":"\\\\\\\\(?:[\\"\\\\\\\\bnrt]|\\\\d\\\\d\\\\d|x\\\\h\\\\h|o[0-3][0-7][0-7])"},"literalUnit":{"match":"\\\\(\\\\)","name":"constant.language constant.numeric entity.other.attribute-name.id.css strong"},"pathModuleExtended":{"patterns":[{"include":"#pathModulePrefixExtended"},{"match":"\\\\b(?=\\\\p{upper})[_[:alpha:]]['[:word:]]*","name":"entity.name.class constant.numeric"}]},"pathModulePrefixExtended":{"begin":"\\\\b(?=\\\\p{upper})[_[:alpha:]]['[:word:]]*(?=\\\\s*\\\\.|$|\\\\()","beginCaptures":{"0":{"name":"entity.name.class constant.numeric"}},"end":"(?![.\\\\s]|$|\\\\()","patterns":[{"include":"#comment"},{"begin":"\\\\(","captures":{"0":{"name":"keyword.control"}},"end":"\\\\)","patterns":[{"match":"\\\\b((?=\\\\p{upper})[_[:alpha:]]['[:word:]]*(?=\\\\s*\\\\)))","name":"string.other.link variable.language variable.parameter emphasis"},{"include":"#structure"}]},{"begin":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","end":"(?=[^.\\\\s])(?!\\\\(\\\\*)","patterns":[{"include":"#comment"},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)\\\\.)(?![-!#-\\\\&*+./:<-@^|~])|(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|mutable|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)|(?<=\\\\))|(?<=])","endCaptures":{"1":{"name":"keyword strong"},"2":{"name":"markup.inserted constant.language support.constant.property-value entity.name.filename"}},"patterns":[{"include":"#comment"},{"include":"#pathModulePrefixSimple"},{"begin":"\\\\((?!\\\\*)","captures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":"\\\\)","patterns":[{"include":"#term"}]},{"begin":"\\\\[","captures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":"]","patterns":[{"include":"#pattern"}]}]}]}]},"pattern":{"patterns":[{"include":"#comment"},{"include":"#patternArray"},{"include":"#patternLazy"},{"include":"#patternList"},{"include":"#patternMisc"},{"include":"#patternModule"},{"include":"#patternRecord"},{"include":"#literal"},{"include":"#patternParens"},{"include":"#patternType"},{"include":"#variablePattern"},{"include":"#termOperator"}]},"patternArray":{"begin":"\\\\[\\\\|","captures":{"0":{"name":"constant.language constant.numeric entity.other.attribute-name.id.css strong"}},"end":"\\\\|]","patterns":[{"include":"#pattern"}]},"patternLazy":{"match":"lazy","name":"variable.other.class.js message.error variable.interpolation string.regexp"},"patternList":{"begin":"\\\\[","captures":{"0":{"name":"constant.language constant.numeric entity.other.attribute-name.id.css strong"}},"end":"]","patterns":[{"include":"#pattern"}]},"patternMisc":{"captures":{"1":{"name":"string.regexp strong"},"2":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"3":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"match":"((?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:\\\\P{word}|^)with)(?!\\\\p{word})","end":"(:)|(=)|(;)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp strong"},"2":{"name":"support.type strong"},"3":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"match":"(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(;)|(=)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"2":{"name":"support.type strong"}},"patterns":[{"include":"#type"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)=)(?![-!#-\\\\&*+./:<-@^|~])","end":";|(?=})","endCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"include":"#pattern"}]}]},"patternType":{"begin":"\\\\btype\\\\b","beginCaptures":{"0":{"name":"keyword"}},"end":"(?=\\\\))","patterns":[{"include":"#declType"}]},"pragma":{"begin":"(?(?![-!#-\\\\&*+./:<-@^|~]))","endCaptures":{"1":{"name":"punctuation.definition.tag"},"2":{"name":"support.type strong"}}},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)->)(?![-!#-\\\\&*+./:<-@^|~])","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#signature"}]}]},{"match":"(?(?![-!#-\\\\&*+./:<-@^|~])","name":"support.type strong"}]},"signatureLiteral":{"begin":"\\\\bsig\\\\b","captures":{"0":{"name":"punctuation.definition.tag emphasis"}},"end":"\\\\bend\\\\b","patterns":[{"include":"#comment"},{"include":"#pragma"},{"include":"#decl"}]},"signatureParens":{"begin":"\\\\((?!\\\\))","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"\\\\)","patterns":[{"include":"#comment"},{"begin":"(?|^->)(?![-!#-\\\\&*+./:<-@^|~])|(?<=(?:\\\\P{word}|^)(?:include|open))(?!\\\\p{word})","end":"\\\\bmodule\\\\b|(?!$|\\\\s|\\\\bmodule\\\\b)","endCaptures":{"0":{"name":"markup.inserted constant.language support.constant.property-value entity.name.filename"}}},{"begin":"(?<=(?:\\\\P{word}|^)module)(?!\\\\p{word})","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"begin":"(?<=(?:\\\\P{word}|^)module)(?!\\\\p{word})","end":"\\\\btype\\\\b","endCaptures":{"0":{"name":"keyword"}}},{"begin":"(?<=(?:\\\\P{word}|^)type)(?!\\\\p{word})","end":"\\\\bof\\\\b","endCaptures":{"0":{"name":"punctuation.definition.tag"}}},{"begin":"(?<=(?:\\\\P{word}|^)of)(?!\\\\p{word})","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#signature"}]}]}]},"structure":{"patterns":[{"include":"#comment"},{"include":"#structureLiteral"},{"include":"#structureFunctor"},{"include":"#pathModuleExtended"},{"include":"#structureParens"}]},"structureFunctor":{"patterns":[{"begin":"\\\\bfunctor\\\\b","beginCaptures":{"0":{"name":"keyword"}},"end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"begin":"(?<=(?:\\\\P{word}|^)functor)(?!\\\\p{word})","end":"(\\\\(\\\\))|(\\\\((?!\\\\)))","endCaptures":{"1":{"name":"constant.language constant.numeric entity.other.attribute-name.id.css strong"},"2":{"name":"punctuation.definition.tag"}}},{"begin":"(?<=\\\\()","end":"(:)|(\\\\))","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp strong"},"2":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#variableModule"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.tag"}},"patterns":[{"include":"#signature"}]},{"begin":"(?<=\\\\))","end":"(\\\\()|((?(?![-!#-\\\\&*+./:<-@^|~]))","endCaptures":{"1":{"name":"punctuation.definition.tag"},"2":{"name":"support.type strong"}}},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)->)(?![-!#-\\\\&*+./:<-@^|~])","end":"(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","patterns":[{"include":"#structure"}]}]},{"match":"(?(?![-!#-\\\\&*+./:<-@^|~])","name":"support.type strong"}]},"structureLiteral":{"begin":"\\\\bstruct\\\\b","captures":{"0":{"name":"punctuation.definition.tag emphasis"}},"end":"\\\\bend\\\\b","patterns":[{"include":"#comment"},{"include":"#pragma"},{"include":"#decl"}]},"structureParens":{"begin":"\\\\(","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"\\\\)","patterns":[{"include":"#structureUnpack"},{"include":"#structure"}]},"structureUnpack":{"begin":"\\\\bval\\\\b","beginCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":"(?=\\\\))"},"term":{"patterns":[{"include":"#termLet"},{"include":"#termAtomic"}]},"termAtomic":{"patterns":[{"include":"#comment"},{"include":"#termConditional"},{"include":"#termConstructor"},{"include":"#termDelim"},{"include":"#termFor"},{"include":"#termFunction"},{"include":"#literal"},{"include":"#termMatch"},{"include":"#termMatchRule"},{"include":"#termPun"},{"include":"#termOperator"},{"include":"#termTry"},{"include":"#termWhile"},{"include":"#pathRecord"}]},"termConditional":{"match":"\\\\b(?:if|then|else)\\\\b","name":"keyword.control"},"termConstructor":{"patterns":[{"include":"#pathModulePrefixSimple"},{"match":"\\\\b(?=\\\\p{upper})[_[:alpha:]]['[:word:]]*","name":"constant.language constant.numeric entity.other.attribute-name.id.css strong"}]},"termDelim":{"patterns":[{"begin":"\\\\((?!\\\\))","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"\\\\)","patterns":[{"include":"#term"}]},{"begin":"\\\\bbegin\\\\b","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"\\\\bend\\\\b","patterns":[{"include":"#attributeIdentifier"},{"include":"#term"}]}]},"termFor":{"patterns":[{"begin":"\\\\bfor\\\\b","beginCaptures":{"0":{"name":"keyword.control"}},"end":"\\\\bdone\\\\b","endCaptures":{"0":{"name":"keyword.control"}},"patterns":[{"begin":"(?<=(?:\\\\P{word}|^)for)(?!\\\\p{word})","end":"(?|^->)(?![-!#-\\\\&*+./:<-@^|~])|(?<=[(;]))(?=\\\\s|\\\\blet\\\\b)|(?<=(?:\\\\P{word}|^)(?:begin|do|else|in|struct|then|try))(?!\\\\p{word})|(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)@@)(?![-!#-\\\\&*+./:<-@^|~])\\\\s+","end":"\\\\b(?:(and)|(let))\\\\b|(?=\\\\S)(?!\\\\(\\\\*)","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp markup.underline"},"2":{"name":"storage.type markup.underline"}},"patterns":[{"include":"#comment"}]},{"begin":"(?<=(?:\\\\P{word}|^)(?:and|let))(?!\\\\p{word})|(let)","beginCaptures":{"1":{"name":"storage.type markup.underline"}},"end":"\\\\b(?:(and)|(in))\\\\b|(?=[])}]|\\\\b(?:end|class|exception|external|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp markup.underline"},"2":{"name":"storage.type markup.underline"}},"patterns":[{"include":"#bindTerm"}]}]},"termMatch":{"begin":"\\\\bmatch\\\\b","captures":{"0":{"name":"keyword.control"}},"end":"\\\\bwith\\\\b","patterns":[{"include":"#term"}]},"termMatchRule":{"patterns":[{"begin":"(?<=(?:\\\\P{word}|^)(?:fun|function|with))(?!\\\\p{word})","end":"(?)(?![-!#-\\\\&*+./:<-@^|~])","endCaptures":{"1":{"name":"support.type strong"},"2":{"name":"support.type strong"}},"patterns":[{"include":"#comment"},{"include":"#attributeIdentifier"},{"include":"#pattern"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@\\\\[^|~]|^)\\\\|)(?![-!#-\\\\&*+./:<-@^|~])|(?)(?![-!#-\\\\&*+./:<-@^|~])","endCaptures":{"1":{"name":"support.type strong"},"2":{"name":"support.type strong"}},"patterns":[{"include":"#pattern"},{"begin":"\\\\bwhen\\\\b","beginCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"end":"(?=(?(?![-!#-\\\\&*+./:<-@^|~]))","patterns":[{"include":"#term"}]}]}]},"termOperator":{"patterns":[{"begin":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","endCaptures":{"0":{"name":"entity.name.function"}}},{"captures":{"0":{"name":"keyword.control strong"}},"match":"<-"},{"captures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"2":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"match":"(,|[-!#-\\\\&*+./:<-@^|~]+)|(;)"},{"match":"\\\\b(?:and|assert|asr|land|lazy|lsr|lxor|mod|new|or)\\\\b","name":"variable.other.class.js message.error variable.interpolation string.regexp"}]},"termPun":{"applyEndPatternLast":true,"begin":"(?]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","endCaptures":{"0":{"name":"markup.inserted constant.language support.constant.property-value entity.name.filename"}}}]},"termTry":{"begin":"\\\\btry\\\\b","captures":{"0":{"name":"keyword.control"}},"end":"\\\\bwith\\\\b","patterns":[{"include":"#term"}]},"termWhile":{"patterns":[{"begin":"\\\\bwhile\\\\b","beginCaptures":{"0":{"name":"keyword.control"}},"end":"\\\\bdone\\\\b","endCaptures":{"0":{"name":"keyword.control"}},"patterns":[{"begin":"(?<=(?:\\\\P{word}|^)while)(?!\\\\p{word})","end":"\\\\bdo\\\\b","endCaptures":{"0":{"name":"keyword.control"}},"patterns":[{"include":"#term"}]},{"begin":"(?<=(?:\\\\P{word}|^)do)(?!\\\\p{word})","end":"(?=\\\\bdone\\\\b)","patterns":[{"include":"#term"}]}]}]},"type":{"patterns":[{"include":"#comment"},{"match":"\\\\bnonrec\\\\b","name":"variable.other.class.js message.error variable.interpolation string.regexp"},{"include":"#pathModulePrefixExtended"},{"include":"#typeLabel"},{"include":"#typeObject"},{"include":"#typeOperator"},{"include":"#typeParens"},{"include":"#typePolymorphicVariant"},{"include":"#typeRecord"},{"include":"#typeConstructor"}]},"typeConstructor":{"patterns":[{"begin":"(_)|((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)|(')((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)|(?<=[^*]\\\\)|])","beginCaptures":{"1":{"name":"comment constant.regexp meta.separator.markdown"},"3":{"name":"string.other.link variable.language variable.parameter emphasis strong emphasis"},"4":{"name":"keyword.control emphasis"}},"end":"(?=\\\\((?!\\\\*)|[])-.:;=>\\\\[{|}])|((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)[:aceps]*(?!\\\\(\\\\*|\\\\p{word})|(?=;;|[])}]|\\\\b(?:end|and|class|exception|external|in|include|inherit|initializer|let|method|module|open|type|val)\\\\b)","endCaptures":{"1":{"name":"entity.name.function strong"}},"patterns":[{"include":"#comment"},{"include":"#pathModulePrefixExtended"}]}]},"typeLabel":{"patterns":[{"begin":"(\\\\??)((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)\\\\s*((?(?![-!#-\\\\&*+./:<-@^|~]))","patterns":[{"include":"#type"}]}]},"typeModule":{"begin":"\\\\bmodule\\\\b","beginCaptures":{"0":{"name":"markup.inserted constant.language support.constant.property-value entity.name.filename"}},"end":"(?=\\\\))","patterns":[{"include":"#pathModuleExtended"},{"include":"#signatureConstraints"}]},"typeObject":{"begin":"<","captures":{"0":{"name":"constant.language constant.numeric entity.other.attribute-name.id.css strong strong"}},"end":">","patterns":[{"begin":"(?<=[;<])","end":"(:)|(?=>)","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp strong"},"3":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"4":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"include":"#comment"},{"include":"#pathModulePrefixSimple"},{"match":"(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(;)|(?=>)","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"2":{"name":"support.type strong"}},"patterns":[{"include":"#type"}]}]},"typeOperator":{"patterns":[{"match":"[,;]|[-!#-\\\\&*+./:<-@^|~]+","name":"variable.other.class.js message.error variable.interpolation string.regexp strong"}]},"typeParens":{"begin":"\\\\(","captures":{"0":{"name":"punctuation.definition.tag"}},"end":"\\\\)","patterns":[{"match":",","name":"variable.other.class.js message.error variable.interpolation string.regexp"},{"include":"#typeModule"},{"include":"#type"}]},"typePolymorphicVariant":{"begin":"\\\\[","end":"]","patterns":[]},"typeRecord":{"begin":"\\\\{","captures":{"0":{"name":"constant.language constant.numeric entity.other.attribute-name.id.css strong strong"}},"end":"}","patterns":[{"begin":"(?<=[;{])","end":"(:)|(=)|(;)|(with)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp strong"},"2":{"name":"support.type strong"},"3":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"4":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"include":"#comment"},{"include":"#pathModulePrefixSimple"},{"match":"(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:\\\\P{word}|^)with)(?!\\\\p{word})","end":"(:)|(=)|(;)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp strong"},"2":{"name":"support.type strong"},"3":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"match":"(?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*","name":"markup.inserted constant.language support.constant.property-value entity.name.filename emphasis"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^):)(?![-!#-\\\\&*+./:<-@^|~])","end":"(;)|(=)|(?=})","endCaptures":{"1":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"},"2":{"name":"support.type strong"}},"patterns":[{"include":"#type"}]},{"begin":"(?<=(?:[^-!#-\\\\&*+./:<-@^|~]|^)=)(?![-!#-\\\\&*+./:<-@^|~])","end":";|(?=})","endCaptures":{"0":{"name":"variable.other.class.js message.error variable.interpolation string.regexp"}},"patterns":[{"include":"#type"}]}]},"variableModule":{"captures":{"0":{"name":"string.other.link variable.language variable.parameter emphasis"}},"match":"\\\\b(?=\\\\p{upper})[_[:alpha:]]['[:word:]]*"},"variablePattern":{"captures":{"1":{"name":"comment constant.regexp meta.separator.markdown"},"2":{"name":"string.other.link variable.language variable.parameter emphasis"}},"match":"\\\\b(_)\\\\b|((?!\\\\b(?:and|'|asr??|assert|\\\\*|begin|class|[,:@]|constraint|do|done|downto|else|end|=|exception|external|false|for|\\\\.|fun|function|functor|[->]|if|in|include|inherit|initializer|land|lazy|[(<\\\\[{]|let|lor|lsl|lsr|lxor|match|method|mod|module|mutable|new|nonrec|#|object|of|open|or|[%+]|private|[\\"?]|rec|[]);\\\\\\\\}]|sig|/|struct|then|~|to|true|try|type|val|\\\\||virtual|when|while|with)\\\\b(?:[^']|$))\\\\b(?=[_[:lower:]])[_[:alpha:]]['[:word:]]*)"}},"scopeName":"source.ocaml"}`)),n=[e];export{n as default}; diff --git a/apps/kimi-code/dist-web/assets/pascal-D93ZcfNL.js b/apps/kimi-code/dist-web/assets/pascal-D93ZcfNL.js new file mode 100644 index 0000000000000000000000000000000000000000..4daf7321a7058ff995aa88262b9bb49adf3c03c9 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pascal-D93ZcfNL.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"Pascal","fileTypes":["pas","p","pp","dfm","fmx","dpr","dpk","lfm","lpr","ppr"],"name":"pascal","patterns":[{"match":"\\\\b(?i:(absolute|abstract|add|all|and_then|array|asc??|asm|assembler|async|attribute|autoreleasepool|await|begin|bindable|block|by|case|cdecl|class|concat|const|constref|copy|cppdecl|contains|default|delegate|deprecated|desc|distinct|div|each|else|empty|end|ensure|enum|equals|event|except|exports??|extension|external|far|file|finalization|finalizer|finally|flags|forward|from|future|generic|goto|group|has|helper|if|implements|implies|import|in|index|inherited|initialization|inline|interrupt|into|invariants|is|iterator|label|library|join|lazy|lifetimestrategy|locked|locking|loop|mapped|matching|message|method|mod|module|name|namespace|near|nested|new|nostackframe|not|notify|nullable|object|of|old|oldfpccall|on|only|operator|optional|or_else|order|otherwise|out|override|package|packed|parallel|params|partial|pascal|pinned|platform|pow|private|program|protected|public|published|interface|implementation|qualified|queryable|raises|read|readonly|record|reference|register|remove|resident|requires??|resourcestring|restricted|result|reverse|safecall|sealed|segment|select|selector|sequence|set|shl|shr|skip|specialize|soft|static|stored|stdcall|step|strict|strong|take|then|threadvar|to|try|tuple|type|unconstrained|unit|unmanaged|unretained|unsafe|uses|using|var|view|virtual|volatile|weak|dynamic|overload|reintroduce|where|with|write|xor|yield))\\\\b","name":"keyword.pascal"},{"captures":{"1":{"name":"storage.type.prototype.pascal"},"2":{"name":"entity.name.function.prototype.pascal"}},"match":"\\\\b(?i:(function|procedure|constructor|destructor))\\\\b\\\\s+(\\\\w+(\\\\.\\\\w+)?)(\\\\(.*?\\\\))?;\\\\s*(?=(?i:attribute|forward|external))","name":"meta.function.prototype.pascal"},{"captures":{"1":{"name":"storage.type.function.pascal"},"2":{"name":"entity.name.function.pascal"}},"match":"\\\\b(?i:(function|procedure|constructor|destructor|property|read|write))\\\\b\\\\s+(\\\\w+(\\\\.\\\\w+)?)","name":"meta.function.pascal"},{"match":"\\\\b(?i:(self|result))\\\\b","name":"token.variable"},{"match":"\\\\b(?i:(and|or))\\\\b","name":"keyword.operator.pascal"},{"match":"\\\\b(?i:(break|continue|exit|abort|while|do|downto|for|raise|repeat|until))\\\\b","name":"keyword.control.pascal"},{"begin":"\\\\{\\\\$","captures":{"0":{"name":"string.regexp"}},"end":"}","name":"string.regexp"},{"match":"\\\\b(?i:(ansichar|ansistring|boolean|byte|cardinal|char|comp|currency|double|dword|extended|file|integer|int8|int16|int32|int64|longint|longword|nativeint|nativeuint|olevariant|pansichar|pchar|pwidechar|pointer|real|shortint|shortstring|single|smallint|string|uint8|uint16|uint32|uint64|variant|widechar|widestring|word|wordbool|uintptr|intptr))\\\\b","name":"storage.support.type.pascal"},{"match":"\\\\b(\\\\d+)|(\\\\d*\\\\.\\\\d+([Ee][-+]?\\\\d+)?)\\\\b","name":"constant.numeric.pascal"},{"match":"\\\\$\\\\h{1,16}\\\\b","name":"constant.numeric.hex.pascal"},{"match":"\\\\b(?i:(true|false|nil))\\\\b","name":"constant.language.pascal"},{"match":"\\\\b(?i:(Assert))\\\\b","name":"keyword.control"},{"begin":"(^[\\\\t ]+)?(?=//)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.pascal"}},"end":"(?!\\\\G)","patterns":[{"begin":"//","beginCaptures":{"0":{"name":"punctuation.definition.comment.pascal"}},"end":"\\\\n","name":"comment.line.double-slash.pascal.two"}]},{"begin":"\\\\(\\\\*","captures":{"0":{"name":"punctuation.definition.comment.pascal"}},"end":"\\\\*\\\\)","name":"comment.block.pascal.one"},{"begin":"\\\\{(?!\\\\$)","captures":{"0":{"name":"punctuation.definition.comment.pascal"}},"end":"}","name":"comment.block.pascal.two"},{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.pascal"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.pascal"}},"name":"string.quoted.single.pascal","patterns":[{"match":"''","name":"constant.character.escape.apostrophe.pascal"}]},{"match":"#\\\\d+","name":"string.other.pascal"}],"scopeName":"source.pascal"}`)),a=[e];export{a as default}; diff --git a/apps/kimi-code/dist-web/assets/pieDiagram-ENE6RG2P-Cj4sb9K4.js b/apps/kimi-code/dist-web/assets/pieDiagram-ENE6RG2P-Cj4sb9K4.js new file mode 100644 index 0000000000000000000000000000000000000000..aab2c200995fa6ca334690aff3cecc8ed45d709e --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pieDiagram-ENE6RG2P-Cj4sb9K4.js @@ -0,0 +1,39 @@ +import{p as at}from"./chunk-JWPE2WC7-K16PVern.js";import{a9 as T,a1 as B,b5 as rt,g as nt,s as it,a as ot,b as st,o as lt,n as ct,_ as g,l as G,c as ut,A as dt,D as gt,K as pt,e as ht,p as ft,B as mt}from"./mermaidParser.worker-BFSlSHEW.js";import{p as vt}from"./cynefin-VYW2F7L2-C-EfYT07.js";import{d as Z}from"./arc-Bh_RIraT.js";import{o as xt}from"./ordinal-Cboi1Yqb.js";import"./init-Gi6I4Gst.js";function St(t,n){return nt?1:n>=t?0:NaN}function yt(t){return t}function wt(){var t=yt,n=St,y=null,b=T(0),l=T(B),p=T(0);function i(e){var r,s=(e=rt(e)).length,h,w,$=0,f=new Array(s),o=new Array(s),D=+b.apply(this,arguments),E=Math.min(B,Math.max(-B,l.apply(this,arguments)-D)),k,L=Math.min(Math.abs(E)/s,p.apply(this,arguments)),u=L*(E<0?-1:1),A;for(r=0;r0&&($+=A);for(n!=null?f.sort(function(M,m){return n(o[M],o[m])}):y!=null&&f.sort(function(M,m){return y(e[M],e[m])}),r=0,w=$?(E-s*u)/$:0;r0?A*w:0)+u,o[h]={data:e[h],index:r,value:A,startAngle:D,endAngle:k,padAngle:L};return o}return i.value=function(e){return arguments.length?(t=typeof e=="function"?e:T(+e),i):t},i.sortValues=function(e){return arguments.length?(n=e,y=null,i):n},i.sort=function(e){return arguments.length?(y=e,n=null,i):y},i.startAngle=function(e){return arguments.length?(b=typeof e=="function"?e:T(+e),i):b},i.endAngle=function(e){return arguments.length?(l=typeof e=="function"?e:T(+e),i):l},i.padAngle=function(e){return arguments.length?(p=typeof e=="function"?e:T(+e),i):p},i}var At=mt.pie,I={sections:new Map,showData:!1},F=I.sections,V=I.showData,Ct=structuredClone(At),$t=g(()=>structuredClone(Ct),"getConfig"),Dt=g(()=>{F=new Map,V=I.showData,ft()},"clear"),Tt=g(({label:t,value:n})=>{if(n<0)throw new Error(`"${t}" has invalid value: ${n}. Negative values are not allowed in pie charts. All slice values must be >= 0.`);F.has(t)||(F.set(t,n),G.debug(`added new section: ${t}, with value: ${n}`))},"addSection"),bt=g(()=>F,"getSections"),kt=g(t=>{V=t},"setShowData"),zt=g(()=>V,"getShowData"),q={getConfig:$t,clear:Dt,setDiagramTitle:ct,getDiagramTitle:lt,setAccTitle:st,getAccTitle:ot,setAccDescription:it,getAccDescription:nt,addSection:Tt,getSections:bt,setShowData:kt,getShowData:zt},Et=g((t,n)=>{at(t,n),n.setShowData(t.showData),t.sections.map(n.addSection)},"populateDb"),Mt={parse:g(async t=>{const n=await vt("pie",t);G.debug(n),Et(n,q)},"parse")},Rt=g(t=>` + .pieCircle{ + stroke: ${t.pieStrokeColor}; + stroke-width : ${t.pieStrokeWidth}; + opacity : ${t.pieOpacity}; + } + .pieCircle.highlighted{ + scale: 1.05; + opacity: 1; + } + .pieCircle.highlightedOnHover:hover{ + transition-duration: 250ms; + scale: 1.05; + opacity: 1; + } + .pieOuterCircle{ + stroke: ${t.pieOuterStrokeColor}; + stroke-width: ${t.pieOuterStrokeWidth}; + fill: none; + } + .pieTitleText { + text-anchor: middle; + font-size: ${t.pieTitleTextSize}; + fill: ${t.pieTitleTextColor}; + font-family: ${t.fontFamily}; + } + .slice { + font-family: ${t.fontFamily}; + fill: ${t.pieSectionTextColor}; + font-size:${t.pieSectionTextSize}; + // fill: white; + } + .legend text { + fill: ${t.pieLegendTextColor}; + font-family: ${t.fontFamily}; + font-size: ${t.pieLegendTextSize}; + } +`,"getStyles"),Lt=Rt,Wt=g(t=>{const n=[...t.values()].reduce((l,p)=>l+p,0),y=[...t.entries()].map(([l,p])=>({label:l,value:p})).filter(l=>l.value/n*100>=1);return wt().value(l=>l.value).sort(null)(y)},"createPieArcs"),_t=g((t,n,y,b)=>{G.debug(`rendering pie chart +`+t);const l=b.db,p=ut(),i=dt(l.getConfig(),p.pie),e=40,r=18,s=4,h=450,w=h,$=gt(n),f=$.append("g");f.attr("transform","translate("+w/2+","+h/2+")");const{themeVariables:o}=p;let[D]=pt(o.pieOuterStrokeWidth);D??=2;const E=i.legendPosition,k=i.textPosition,L=i.donutHole>0&&i.donutHole<=.9?i.donutHole:0,u=Math.min(w,h)/2-e,A=Z().innerRadius(L*u).outerRadius(u),M=Z().innerRadius(u*k).outerRadius(u*k),m=f.append("g");m.append("circle").attr("cx",0).attr("cy",0).attr("r",u+D/2).attr("class","pieOuterCircle");const W=l.getSections(),J=Wt(W),Q=[o.pie1,o.pie2,o.pie3,o.pie4,o.pie5,o.pie6,o.pie7,o.pie8,o.pie9,o.pie10,o.pie11,o.pie12];let H=0;W.forEach(a=>{H+=a});const U=J.filter(a=>(a.data.value/H*100).toFixed(0)!=="0"),N=xt(Q).domain([...W.keys()]);m.selectAll("mySlices").data(U).enter().append("path").attr("d",A).attr("fill",a=>N(a.data.label)).attr("class",a=>{let c="pieCircle";return i.highlightSlice==="hover"?c+=" highlightedOnHover":i.highlightSlice===a.data.label&&(c+=" highlighted"),c}),m.selectAll("mySlices").data(U).enter().append("text").text(a=>(a.data.value/H*100).toFixed(0)+"%").attr("transform",a=>"translate("+M.centroid(a)+")").style("text-anchor","middle").attr("class","slice");const Y=f.append("text").text(l.getDiagramTitle()).attr("x",0).attr("y",-400/2).attr("class","pieTitleText"),R=[...W.entries()].map(([a,c])=>({label:a,value:c})),C=f.selectAll(".legend").data(R).enter().append("g").attr("class","legend");C.append("rect").attr("width",r).attr("height",r).style("fill",a=>N(a.label)).style("stroke",a=>N(a.label)),C.append("text").attr("x",r+s).attr("y",r-s).text(a=>l.getShowData()?`${a.label} [${a.value}]`:a.label);const z=Math.max(...C.selectAll("text").nodes().map(a=>a?.getBoundingClientRect().width??0));let _=h,O=w+e;const d=r+s,P=R.length*d;switch(E){case"center":C.attr("transform",(a,c)=>{const v=d*R.length/2,x=-z/2-(r+s),S=c*d-v;return"translate("+x+","+S+")"});break;case"top":_+=P,C.attr("transform",(a,c)=>{const v=u,x=-z/2-(r+s),S=c*d-v;return`translate(${x}, ${S})`}),m.attr("transform",()=>`translate(0, ${P+d})`);break;case"bottom":_+=P,C.attr("transform",(a,c)=>{const v=-u-d,x=-z/2-(r+s),S=c*d-v;return"translate("+x+","+S+")"});break;case"left":O+=r+s+z,C.attr("transform",(a,c)=>{const v=d*R.length/2,x=-u-(r+s),S=c*d-v;return"translate("+x+","+S+")"}),m.attr("transform",()=>`translate(${z+r+s}, 0)`);break;case"right":default:O+=r+s+z,C.attr("transform",(a,c)=>{const v=d*R.length/2,x=12*r,S=c*d-v;return"translate("+x+","+S+")"});break}const j=Y.node()?.getBoundingClientRect().width??0,tt=w/2-j/2,et=w/2+j/2,K=Math.min(0,tt),X=Math.max(O,et)-K;$.attr("viewBox",`${K} 0 ${X} ${_}`),ht($,_,X,i.useMaxWidth)},"draw"),Ft={draw:_t},Vt={parser:Mt,db:q,renderer:Ft,styles:Lt};export{Vt as diagram}; diff --git a/apps/kimi-code/dist-web/assets/pierre-dark-soft-BHGpRqa4.js b/apps/kimi-code/dist-web/assets/pierre-dark-soft-BHGpRqa4.js new file mode 100644 index 0000000000000000000000000000000000000000..647cc829efec7d9123e0e1c2c1cb906b0e8d3e1d --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pierre-dark-soft-BHGpRqa4.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"name":"pierre-dark-soft","displayName":"Pierre Dark Soft","type":"dark","colors":{"editor.background":"#171717","editor.foreground":"#d4d4d4","foreground":"#d4d4d4","focusBorder":"#69b1ff","selection.background":"#1f3e5e","editor.selectionBackground":"#69b1ff4d","editor.lineHighlightBackground":"#1f3e5e8c","editorCursor.foreground":"#69b1ff","editorLineNumber.foreground":"#636363","editorLineNumber.activeForeground":"#8a8a8a","editorIndentGuide.background":"#262626","editorIndentGuide.activeBackground":"#2c2c2c","diffEditor.insertedTextBackground":"#60d1991a","diffEditor.deletedTextBackground":"#ff67621a","sideBar.background":"#101010","sideBar.foreground":"#8a8a8a","sideBar.border":"#1d1d1d","sideBarTitle.foreground":"#d4d4d4","sideBarSectionHeader.background":"#101010","sideBarSectionHeader.foreground":"#8a8a8a","sideBarSectionHeader.border":"#1d1d1d","activityBar.background":"#101010","activityBar.foreground":"#d4d4d4","activityBar.border":"#1d1d1d","activityBar.activeBorder":"#69b1ff","activityBarBadge.background":"#69b1ff","activityBarBadge.foreground":"#171717","titleBar.activeBackground":"#101010","titleBar.activeForeground":"#d4d4d4","titleBar.inactiveBackground":"#101010","titleBar.inactiveForeground":"#636363","titleBar.border":"#1d1d1d","list.activeSelectionBackground":"#1f3e5e99","list.activeSelectionForeground":"#d4d4d4","list.inactiveSelectionBackground":"#1f3e5e73","list.hoverBackground":"#1f3e5e59","list.focusOutline":"#69b1ff","tab.activeBackground":"#171717","tab.activeForeground":"#d4d4d4","tab.activeBorderTop":"#69b1ff","tab.inactiveBackground":"#101010","tab.inactiveForeground":"#636363","tab.border":"#1d1d1d","editorGroupHeader.tabsBackground":"#101010","editorGroupHeader.tabsBorder":"#1d1d1d","panel.background":"#101010","panel.border":"#1d1d1d","panelTitle.activeBorder":"#69b1ff","panelTitle.activeForeground":"#d4d4d4","panelTitle.inactiveForeground":"#636363","statusBar.background":"#101010","statusBar.foreground":"#8a8a8a","statusBar.border":"#1d1d1d","statusBar.noFolderBackground":"#101010","statusBar.debuggingBackground":"#ffd452","statusBar.debuggingForeground":"#171717","statusBarItem.remoteBackground":"#101010","statusBarItem.remoteForeground":"#8a8a8a","input.background":"#262626","input.border":"#2c2c2c","input.foreground":"#d4d4d4","input.placeholderForeground":"#525252","dropdown.background":"#262626","dropdown.border":"#2c2c2c","dropdown.foreground":"#d4d4d4","button.background":"#69b1ff","button.foreground":"#171717","button.hoverBackground":"#61a2e8","textLink.foreground":"#69b1ff","textLink.activeForeground":"#69b1ff","notifications.background":"#1d1d1d","notifications.foreground":"#d4d4d4","notifications.border":"#262626","notificationToast.border":"#262626","notificationCenter.border":"#262626","notificationCenterHeader.background":"#1d1d1d","notificationCenterHeader.foreground":"#8a8a8a","notificationLink.foreground":"#69b1ff","notificationsErrorIcon.foreground":"#ff6762","notificationsWarningIcon.foreground":"#ffd452","notificationsInfoIcon.foreground":"#68cdf2","quickInput.background":"#1d1d1d","quickInput.foreground":"#d4d4d4","quickInputTitle.background":"#1d1d1d","widget.border":"#262626","gitDecoration.addedResourceForeground":"#60d199","gitDecoration.conflictingResourceForeground":"#9d6afb","gitDecoration.modifiedResourceForeground":"#69b1ff","gitDecoration.deletedResourceForeground":"#ff6762","gitDecoration.untrackedResourceForeground":"#60d199","gitDecoration.ignoredResourceForeground":"#636363","merge.currentHeaderBackground":"#9d6afb4d","merge.currentContentBackground":"#9d6afb1f","merge.incomingHeaderBackground":"#68cdf24d","merge.incomingContentBackground":"#68cdf21f","editorOverviewRuler.currentContentForeground":"#9d6afb","editorOverviewRuler.incomingContentForeground":"#68cdf2","terminal.titleForeground":"#8a8a8a","terminal.titleInactiveForeground":"#636363","terminal.background":"#101010","terminal.foreground":"#8a8a8a","terminal.ansiBlack":"#171717","terminal.ansiRed":"#ff2e3f","terminal.ansiGreen":"#0dbe4e","terminal.ansiYellow":"#ffca00","terminal.ansiBlue":"#009fff","terminal.ansiMagenta":"#e130ac","terminal.ansiCyan":"#08c0ef","terminal.ansiWhite":"#bcbcbc","terminal.ansiBrightBlack":"#171717","terminal.ansiBrightRed":"#ff2e3f","terminal.ansiBrightGreen":"#86c427","terminal.ansiBrightYellow":"#ffca00","terminal.ansiBrightBlue":"#009fff","terminal.ansiBrightMagenta":"#e130ac","terminal.ansiBrightCyan":"#08c0ef","terminal.ansiBrightWhite":"#bcbcbc"},"tokenColors":[{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"#636363"}},{"scope":"comment markup.link","settings":{"foreground":"#636363"}},{"scope":["string","constant.other.symbol"],"settings":{"foreground":"#8cda94"}},{"scope":["punctuation.definition.string.begin","punctuation.definition.string.end"],"settings":{"foreground":"#8cda94"}},{"scope":["constant.numeric","constant.language.boolean"],"settings":{"foreground":"#96d9f6"}},{"scope":"constant","settings":{"foreground":"#ffde80"}},{"scope":"punctuation.definition.constant","settings":{"foreground":"#ffde80"}},{"scope":"constant.language","settings":{"foreground":"#96d9f6"}},{"scope":"variable.other.constant","settings":{"foreground":"#ffbc56"}},{"scope":"keyword","settings":{"foreground":"#ff91a8"}},{"scope":"keyword.control","settings":{"foreground":"#ff91a8"}},{"scope":["storage","storage.type","storage.modifier"],"settings":{"foreground":"#ff91a8"}},{"scope":"token.storage","settings":{"foreground":"#ff91a8"}},{"scope":["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],"settings":{"foreground":"#ff91a8"}},{"scope":"keyword.operator.delete","settings":{"foreground":"#ff91a8"}},{"scope":["variable","identifier","meta.definition.variable"],"settings":{"foreground":"#ffba82"}},{"scope":["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],"settings":{"foreground":"#ffba82"}},{"scope":"variable.language","settings":{"foreground":"#ffbc56"}},{"scope":"variable.parameter.function","settings":{"foreground":"#8a8a8a"}},{"scope":"function.parameter","settings":{"foreground":"#8a8a8a"}},{"scope":"variable.parameter","settings":{"foreground":"#8a8a8a"}},{"scope":"variable.parameter.function.language.python","settings":{"foreground":"#ffde80"}},{"scope":"variable.parameter.function.python","settings":{"foreground":"#ffde80"}},{"scope":["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],"settings":{"foreground":"#ba8ffd"}},{"scope":"keyword.other.special-method","settings":{"foreground":"#ba8ffd"}},{"scope":"entity.name.function","settings":{"foreground":"#ba8ffd"}},{"scope":"support.function.console","settings":{"foreground":"#ba8ffd"}},{"scope":["support.type","entity.name.type","entity.name.class","storage.type"],"settings":{"foreground":"#e290f0"}},{"scope":["support.class","entity.name.type.class"],"settings":{"foreground":"#e290f0"}},{"scope":["entity.name.class","variable.other.class.js","variable.other.class.ts"],"settings":{"foreground":"#e290f0"}},{"scope":"entity.name.class.identifier.namespace.type","settings":{"foreground":"#e290f0"}},{"scope":"entity.name.type.namespace","settings":{"foreground":"#ffbc56"}},{"scope":"entity.other.inherited-class","settings":{"foreground":"#e290f0"}},{"scope":"entity.name.namespace","settings":{"foreground":"#ffbc56"}},{"scope":"keyword.operator","settings":{"foreground":"#737373"}},{"scope":["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],"settings":{"foreground":"#68cdf2"}},{"scope":["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],"settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.assignment","settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.assignment.compound","settings":{"foreground":"#ff91a8"}},{"scope":["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],"settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.ternary","settings":{"foreground":"#ff91a8"}},{"scope":"keyword.operator.optional","settings":{"foreground":"#ff91a8"}},{"scope":"punctuation","settings":{"foreground":"#737373"}},{"scope":"punctuation.separator.delimiter","settings":{"foreground":"#737373"}},{"scope":"punctuation.separator.key-value","settings":{"foreground":"#737373"}},{"scope":"punctuation.terminator","settings":{"foreground":"#737373"}},{"scope":"meta.brace","settings":{"foreground":"#737373"}},{"scope":"meta.brace.square","settings":{"foreground":"#737373"}},{"scope":"meta.brace.round","settings":{"foreground":"#737373"}},{"scope":"function.brace","settings":{"foreground":"#737373"}},{"scope":["punctuation.definition.parameters","punctuation.definition.typeparameters"],"settings":{"foreground":"#737373"}},{"scope":["punctuation.definition.block","punctuation.definition.tag"],"settings":{"foreground":"#737373"}},{"scope":["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],"settings":{"foreground":"#737373"}},{"scope":"keyword.operator.expression.import","settings":{"foreground":"#ba8ffd"}},{"scope":"keyword.operator.module","settings":{"foreground":"#ff91a8"}},{"scope":"support.type.object.console","settings":{"foreground":"#ffba82"}},{"scope":["support.module.node","support.type.object.module","entity.name.type.module"],"settings":{"foreground":"#ffbc56"}},{"scope":"support.constant.math","settings":{"foreground":"#ffbc56"}},{"scope":"support.constant.property.math","settings":{"foreground":"#ffde80"}},{"scope":"support.constant.json","settings":{"foreground":"#ffde80"}},{"scope":"support.type.object.dom","settings":{"foreground":"#68cdf2"}},{"scope":["support.variable.dom","support.variable.property.dom"],"settings":{"foreground":"#ffba82"}},{"scope":"support.variable.property.process","settings":{"foreground":"#ffde80"}},{"scope":"meta.property.object","settings":{"foreground":"#ffba82"}},{"scope":"variable.parameter.function.js","settings":{"foreground":"#ffba82"}},{"scope":["keyword.other.template.begin","keyword.other.template.end"],"settings":{"foreground":"#8cda94"}},{"scope":["keyword.other.substitution.begin","keyword.other.substitution.end"],"settings":{"foreground":"#8cda94"}},{"scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],"settings":{"foreground":"#ff91a8"}},{"scope":"meta.template.expression","settings":{"foreground":"#737373"}},{"scope":"punctuation.section.embedded","settings":{"foreground":"#ffba82"}},{"scope":"variable.interpolation","settings":{"foreground":"#ffba82"}},{"scope":["punctuation.section.embedded.begin","punctuation.section.embedded.end"],"settings":{"foreground":"#ff91a8"}},{"scope":"punctuation.quasi.element","settings":{"foreground":"#ff91a8"}},{"scope":["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],"settings":{"foreground":"#e290f0"}},{"scope":"support.type.type.flowtype","settings":{"foreground":"#ba8ffd"}},{"scope":"support.type.primitive","settings":{"foreground":"#e290f0"}},{"scope":["meta.decorator","meta.decorator punctuation.decorator"],"settings":{"foreground":"#97c4ff"}},{"scope":"entity.name.function.decorator","settings":{"foreground":"#97c4ff"}},{"scope":"punctuation.definition.decorator","settings":{"foreground":"#97c4ff"}},{"scope":"support.variable.magic.python","settings":{"foreground":"#ffa685"}},{"scope":"variable.parameter.function.language.special.self.python","settings":{"foreground":"#ffbc56"}},{"scope":["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],"settings":{"foreground":"#737373"}},{"scope":["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],"settings":{"foreground":"#737373"}},{"scope":"support.type.python","settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.logical.python","settings":{"foreground":"#ff91a8"}},{"scope":"meta.function-call.generic.python","settings":{"foreground":"#ba8ffd"}},{"scope":"constant.character.format.placeholder.other.python","settings":{"foreground":"#ffde80"}},{"scope":"meta.function.decorator.python","settings":{"foreground":"#ba8ffd"}},{"scope":["support.token.decorator.python","meta.function.decorator.identifier.python"],"settings":{"foreground":"#68cdf2"}},{"scope":"storage.modifier.lifetime.rust","settings":{"foreground":"#737373"}},{"scope":"support.function.std.rust","settings":{"foreground":"#ba8ffd"}},{"scope":"entity.name.lifetime.rust","settings":{"foreground":"#ffbc56"}},{"scope":"variable.language.rust","settings":{"foreground":"#ffa685"}},{"scope":"keyword.operator.misc.rust","settings":{"foreground":"#737373"}},{"scope":"keyword.operator.sigil.rust","settings":{"foreground":"#ff91a8"}},{"scope":"support.constant.core.rust","settings":{"foreground":"#ffde80"}},{"scope":["meta.function.c","meta.function.cpp"],"settings":{"foreground":"#ffa685"}},{"scope":["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],"settings":{"foreground":"#737373"}},{"scope":["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],"settings":{"foreground":"#ff91a8"}},{"scope":["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],"settings":{"foreground":"#ff91a8"}},{"scope":["punctuation.separator.c","punctuation.separator.cpp"],"settings":{"foreground":"#ff91a8"}},{"scope":["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],"settings":{"foreground":"#68cdf2"}},{"scope":["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],"settings":{"foreground":"#ff91a8"}},{"scope":"variable.c","settings":{"foreground":"#737373"}},{"scope":["storage.type.annotation.java","storage.type.object.array.java"],"settings":{"foreground":"#ffbc56"}},{"scope":"source.java","settings":{"foreground":"#ffa685"}},{"scope":["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],"settings":{"foreground":"#737373"}},{"scope":"meta.method.java","settings":{"foreground":"#ba8ffd"}},{"scope":["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],"settings":{"foreground":"#ffbc56"}},{"scope":"keyword.operator.instanceof.java","settings":{"foreground":"#ff91a8"}},{"scope":"meta.definition.variable.name.java","settings":{"foreground":"#ffa685"}},{"scope":"token.variable.parameter.java","settings":{"foreground":"#737373"}},{"scope":"import.storage.java","settings":{"foreground":"#ffbc56"}},{"scope":"token.package.keyword","settings":{"foreground":"#ff91a8"}},{"scope":"token.package","settings":{"foreground":"#737373"}},{"scope":"token.storage.type.java","settings":{"foreground":"#ffbc56"}},{"scope":"keyword.operator.assignment.go","settings":{"foreground":"#ffbc56"}},{"scope":["keyword.operator.arithmetic.go","keyword.operator.address.go"],"settings":{"foreground":"#ff91a8"}},{"scope":"entity.name.package.go","settings":{"foreground":"#ffbc56"}},{"scope":["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],"settings":{"foreground":"#ffbc56"}},{"scope":"keyword.operator.error-control.php","settings":{"foreground":"#ff91a8"}},{"scope":"keyword.operator.type.php","settings":{"foreground":"#ff91a8"}},{"scope":["punctuation.section.array.begin.php","punctuation.section.array.end.php"],"settings":{"foreground":"#737373"}},{"scope":["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],"settings":{"foreground":"#ffbc56"}},{"scope":["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],"settings":{"foreground":"#ba8ffd"}},{"scope":["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],"settings":{"foreground":"#737373"}},{"scope":["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],"settings":{"foreground":"#ffde80"}},{"scope":["entity.name.goto-label.php","support.other.php"],"settings":{"foreground":"#ba8ffd"}},{"scope":["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],"settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.regexp.php","settings":{"foreground":"#ff91a8"}},{"scope":"keyword.operator.comparison.php","settings":{"foreground":"#68cdf2"}},{"scope":["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],"settings":{"foreground":"#ff91a8"}},{"scope":"variable.other.class.php","settings":{"foreground":"#ffa685"}},{"scope":"invalid.illegal.non-null-typehinted.php","settings":{"foreground":"#d4d4d4"}},{"scope":"variable.other.generic-type.haskell","settings":{"foreground":"#ff91a8"}},{"scope":"storage.type.haskell","settings":{"foreground":"#ffde80"}},{"scope":"storage.type.cs","settings":{"foreground":"#ffbc56"}},{"scope":"entity.name.variable.local.cs","settings":{"foreground":"#ffa685"}},{"scope":"entity.name.label.cs","settings":{"foreground":"#ffbc56"}},{"scope":["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],"settings":{"foreground":"#ffbc56"}},{"scope":["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],"settings":{"foreground":"#ffa685"}},{"scope":"support.constant.edge","settings":{"foreground":"#ff91a8"}},{"scope":"support.type.prelude.elm","settings":{"foreground":"#68cdf2"}},{"scope":"support.constant.elm","settings":{"foreground":"#ffde80"}},{"scope":"entity.global.clojure","settings":{"foreground":"#ffbc56"}},{"scope":"meta.symbol.clojure","settings":{"foreground":"#ffa685"}},{"scope":"constant.keyword.clojure","settings":{"foreground":"#68cdf2"}},{"scope":["meta.arguments.coffee","variable.parameter.function.coffee"],"settings":{"foreground":"#ffa685"}},{"scope":"storage.modifier.import.groovy","settings":{"foreground":"#ffbc56"}},{"scope":"meta.method.groovy","settings":{"foreground":"#ba8ffd"}},{"scope":"meta.definition.variable.name.groovy","settings":{"foreground":"#ffa685"}},{"scope":"meta.definition.class.inherited.classes.groovy","settings":{"foreground":"#8cda94"}},{"scope":"support.variable.semantic.hlsl","settings":{"foreground":"#ffbc56"}},{"scope":["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],"settings":{"foreground":"#ff91a8"}},{"scope":["text.variable","text.bracketed"],"settings":{"foreground":"#ffa685"}},{"scope":["support.type.swift","support.type.vb.asp"],"settings":{"foreground":"#ffbc56"}},{"scope":"meta.scope.prerequisites.makefile","settings":{"foreground":"#ffa685"}},{"scope":"source.makefile","settings":{"foreground":"#ffbc56"}},{"scope":"source.ini","settings":{"foreground":"#8cda94"}},{"scope":"constant.language.symbol.ruby","settings":{"foreground":"#68cdf2"}},{"scope":["function.parameter.ruby","function.parameter.cs"],"settings":{"foreground":"#737373"}},{"scope":"constant.language.symbol.elixir","settings":{"foreground":"#68cdf2"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade","settings":{"foreground":"#ff91a8"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade","settings":{"foreground":"#ff91a8"}},{"scope":"entity.name.function.xi","settings":{"foreground":"#ffbc56"}},{"scope":"entity.name.class.xi","settings":{"foreground":"#68cdf2"}},{"scope":"constant.character.character-class.regexp.xi","settings":{"foreground":"#ffa685"}},{"scope":"constant.regexp.xi","settings":{"foreground":"#ff91a8"}},{"scope":"keyword.control.xi","settings":{"foreground":"#68cdf2"}},{"scope":"invalid.xi","settings":{"foreground":"#737373"}},{"scope":"beginning.punctuation.definition.quote.markdown.xi","settings":{"foreground":"#8cda94"}},{"scope":"beginning.punctuation.definition.list.markdown.xi","settings":{"foreground":"#636363"}},{"scope":"constant.character.xi","settings":{"foreground":"#ba8ffd"}},{"scope":"accent.xi","settings":{"foreground":"#ba8ffd"}},{"scope":"wikiword.xi","settings":{"foreground":"#ffde80"}},{"scope":"constant.other.color.rgb-value.xi","settings":{"foreground":"#d4d4d4"}},{"scope":"punctuation.definition.tag.xi","settings":{"foreground":"#636363"}},{"scope":["support.constant.property-value.scss","support.constant.property-value.css"],"settings":{"foreground":"#ffde80"}},{"scope":["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],"settings":{"foreground":"#68cdf2"}},{"scope":["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],"settings":{"foreground":"#ffde80"}},{"scope":"punctuation.separator.list.comma.css","settings":{"foreground":"#737373"}},{"scope":"support.type.vendored.property-name.css","settings":{"foreground":"#68cdf2"}},{"scope":"support.type.property-name.css","settings":{"foreground":"#68cdf2"}},{"scope":"support.type.property-name","settings":{"foreground":"#737373"}},{"scope":"support.constant.property-value","settings":{"foreground":"#737373"}},{"scope":"support.constant.font-name","settings":{"foreground":"#ffde80"}},{"scope":"entity.other.attribute-name.class.css","settings":{"foreground":"#8eddb2","fontStyle":"normal"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"#ba8ffd","fontStyle":"normal"}},{"scope":["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],"settings":{"foreground":"#68cdf2"}},{"scope":"meta.selector","settings":{"foreground":"#ff91a8"}},{"scope":"selector.sass","settings":{"foreground":"#ffa685"}},{"scope":"rgb-value","settings":{"foreground":"#68cdf2"}},{"scope":"inline-color-decoration rgb-value","settings":{"foreground":"#ffde80"}},{"scope":"less rgb-value","settings":{"foreground":"#ffde80"}},{"scope":"control.elements","settings":{"foreground":"#ffde80"}},{"scope":"keyword.operator.less","settings":{"foreground":"#ffde80"}},{"scope":"entity.name.tag","settings":{"foreground":"#ffa685"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#8eddb2","fontStyle":"normal"}},{"scope":"constant.character.entity","settings":{"foreground":"#ffa685"}},{"scope":"meta.tag","settings":{"foreground":"#737373"}},{"scope":"invalid.illegal.bad-ampersand.html","settings":{"foreground":"#737373"}},{"scope":"markup.heading","settings":{"foreground":"#ffa685"}},{"scope":["markup.heading punctuation.definition.heading","entity.name.section"],"settings":{"foreground":"#ba8ffd"}},{"scope":"entity.name.section.markdown","settings":{"foreground":"#ffa685"}},{"scope":"punctuation.definition.heading.markdown","settings":{"foreground":"#ffa685"}},{"scope":"markup.heading.setext","settings":{"foreground":"#737373"}},{"scope":["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],"settings":{"foreground":"#ffa685"}},{"scope":["markup.bold","todo.bold"],"settings":{"foreground":"#ffde80"}},{"scope":"punctuation.definition.bold","settings":{"foreground":"#ffbc56"}},{"scope":"punctuation.definition.bold.markdown","settings":{"foreground":"#ffde80"}},{"scope":["markup.italic","punctuation.definition.italic","todo.emphasis"],"settings":{"foreground":"#ff91a8","fontStyle":"italic"}},{"scope":"emphasis md","settings":{"foreground":"#ff91a8"}},{"scope":"markup.italic.markdown","settings":{"fontStyle":"italic"}},{"scope":["markup.underline.link.markdown","markup.underline.link.image.markdown"],"settings":{"foreground":"#ff91a8"}},{"scope":["string.other.link.title.markdown","string.other.link.description.markdown"],"settings":{"foreground":"#ba8ffd"}},{"scope":"punctuation.definition.metadata.markdown","settings":{"foreground":"#ffa685"}},{"scope":["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],"settings":{"foreground":"#8cda94"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#ffa685"}},{"scope":"punctuation.definition.list.markdown","settings":{"foreground":"#ffa685"}},{"scope":"beginning.punctuation.definition.list.markdown","settings":{"foreground":"#ffa685"}},{"scope":["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],"settings":{"foreground":"#ffa685"}},{"scope":"markup.quote.markdown","settings":{"foreground":"#636363"}},{"scope":"keyword.other.unit","settings":{"foreground":"#ffa685"}},{"scope":"markup.changed.diff","settings":{"foreground":"#ffbc56"}},{"scope":["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],"settings":{"foreground":"#ba8ffd"}},{"scope":"markup.inserted.diff","settings":{"foreground":"#8cda94"}},{"scope":"markup.deleted.diff","settings":{"foreground":"#ffa685"}},{"scope":"string.regexp","settings":{"foreground":"#92dde4"}},{"scope":"constant.other.character-class.regexp","settings":{"foreground":"#ffa685"}},{"scope":"keyword.operator.quantifier.regexp","settings":{"foreground":"#ffde80"}},{"scope":"constant.character.escape","settings":{"foreground":"#8fe0d0"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json","settings":{"foreground":"#ffa685"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string","settings":{"foreground":"#ffa685"}},{"scope":["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],"settings":{"foreground":"#8cda94"}},{"scope":["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],"settings":{"foreground":"#68cdf2"}},{"scope":"support.type.property-name.json","settings":{"foreground":"#ffa685"}},{"scope":"support.type.property-name.json punctuation","settings":{"foreground":"#ffa685"}},{"scope":"punctuation.definition.block.sequence.item.yaml","settings":{"foreground":"#737373"}},{"scope":"block.scope.end","settings":{"foreground":"#737373"}},{"scope":"block.scope.begin","settings":{"foreground":"#737373"}},{"scope":"token.info-token","settings":{"foreground":"#ba8ffd"}},{"scope":"token.warn-token","settings":{"foreground":"#ffde80"}},{"scope":"token.error-token","settings":{"foreground":"#d4d4d4"}},{"scope":"token.debug-token","settings":{"foreground":"#ff91a8"}},{"scope":"invalid.illegal","settings":{"foreground":"#d4d4d4"}},{"scope":"invalid.broken","settings":{"foreground":"#d4d4d4"}},{"scope":"invalid.deprecated","settings":{"foreground":"#d4d4d4"}},{"scope":"invalid.unimplemented","settings":{"foreground":"#d4d4d4"}}],"semanticTokenColors":{"comment":"#636363","string":"#8cda94","number":"#96d9f6","regexp":"#92dde4","keyword":"#ff91a8","variable":"#ffba82","parameter":"#8a8a8a","property":"#ffba82","function":"#ba8ffd","method":"#ba8ffd","type":"#e290f0","class":"#e290f0","namespace":"#ffbc56","enumMember":"#68cdf2","variable.constant":"#ffde80","variable.defaultLibrary":"#ffbc56","decorator":"#97c4ff"}}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/pierre-dark-tritanopia-Beq2gCRQ.js b/apps/kimi-code/dist-web/assets/pierre-dark-tritanopia-Beq2gCRQ.js new file mode 100644 index 0000000000000000000000000000000000000000..1f13b7d50b83a88646dd02ce0e69daa912ecb08e --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pierre-dark-tritanopia-Beq2gCRQ.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"name":"pierre-dark-tritanopia","displayName":"Pierre Dark Tritanopia","type":"dark","colors":{"editor.background":"#0a0a0a","editor.foreground":"#fafafa","foreground":"#fafafa","focusBorder":"#009fff","selection.background":"#19283c","editor.selectionBackground":"#009fff4d","editor.lineHighlightBackground":"#19283c8c","editorCursor.foreground":"#009fff","editorLineNumber.foreground":"#737373","editorLineNumber.activeForeground":"#a3a3a3","editorIndentGuide.background":"#1d1d1d","editorIndentGuide.activeBackground":"#262626","diffEditor.insertedTextBackground":"#92dde41a","diffEditor.deletedTextBackground":"#ff855e1a","sideBar.background":"#171717","sideBar.foreground":"#a3a3a3","sideBar.border":"#0a0a0a","sideBarTitle.foreground":"#fafafa","sideBarSectionHeader.background":"#171717","sideBarSectionHeader.foreground":"#a3a3a3","sideBarSectionHeader.border":"#0a0a0a","activityBar.background":"#171717","activityBar.foreground":"#fafafa","activityBar.border":"#0a0a0a","activityBar.activeBorder":"#009fff","activityBarBadge.background":"#009fff","activityBarBadge.foreground":"#0a0a0a","titleBar.activeBackground":"#171717","titleBar.activeForeground":"#fafafa","titleBar.inactiveBackground":"#171717","titleBar.inactiveForeground":"#737373","titleBar.border":"#0a0a0a","list.activeSelectionBackground":"#19283c99","list.activeSelectionForeground":"#fafafa","list.inactiveSelectionBackground":"#19283c73","list.hoverBackground":"#19283c59","list.focusOutline":"#009fff","tab.activeBackground":"#0a0a0a","tab.activeForeground":"#fafafa","tab.activeBorderTop":"#009fff","tab.inactiveBackground":"#171717","tab.inactiveForeground":"#737373","tab.border":"#0a0a0a","editorGroupHeader.tabsBackground":"#171717","editorGroupHeader.tabsBorder":"#0a0a0a","panel.background":"#171717","panel.border":"#0a0a0a","panelTitle.activeBorder":"#009fff","panelTitle.activeForeground":"#fafafa","panelTitle.inactiveForeground":"#737373","statusBar.background":"#171717","statusBar.foreground":"#a3a3a3","statusBar.border":"#0a0a0a","statusBar.noFolderBackground":"#171717","statusBar.debuggingBackground":"#ffbc56","statusBar.debuggingForeground":"#0a0a0a","statusBarItem.remoteBackground":"#171717","statusBarItem.remoteForeground":"#a3a3a3","input.background":"#1d1d1d","input.border":"#1d1d1d","input.foreground":"#fafafa","input.placeholderForeground":"#636363","dropdown.background":"#1d1d1d","dropdown.border":"#1d1d1d","dropdown.foreground":"#fafafa","button.background":"#009fff","button.foreground":"#0a0a0a","button.hoverBackground":"#0190e7","textLink.foreground":"#009fff","textLink.activeForeground":"#009fff","notifications.background":"#101010","notifications.foreground":"#fafafa","notifications.border":"#1d1d1d","notificationToast.border":"#1d1d1d","notificationCenter.border":"#1d1d1d","notificationCenterHeader.background":"#101010","notificationCenterHeader.foreground":"#a3a3a3","notificationLink.foreground":"#009fff","notificationsErrorIcon.foreground":"#ff855e","notificationsWarningIcon.foreground":"#ffbc56","notificationsInfoIcon.foreground":"#69b1ff","quickInput.background":"#101010","quickInput.foreground":"#fafafa","quickInputTitle.background":"#101010","widget.border":"#1d1d1d","gitDecoration.addedResourceForeground":"#92dde4","gitDecoration.conflictingResourceForeground":"#ea68bc","gitDecoration.modifiedResourceForeground":"#009fff","gitDecoration.deletedResourceForeground":"#ff855e","gitDecoration.untrackedResourceForeground":"#92dde4","gitDecoration.ignoredResourceForeground":"#737373","merge.currentHeaderBackground":"#ea68bc4d","merge.currentContentBackground":"#ea68bc1f","merge.incomingHeaderBackground":"#69b1ff4d","merge.incomingContentBackground":"#69b1ff1f","editorOverviewRuler.currentContentForeground":"#ea68bc","editorOverviewRuler.incomingContentForeground":"#69b1ff","terminal.titleForeground":"#a3a3a3","terminal.titleInactiveForeground":"#737373","terminal.background":"#171717","terminal.foreground":"#a3a3a3","terminal.ansiBlack":"#171717","terminal.ansiRed":"#ff855e","terminal.ansiGreen":"#64d1db","terminal.ansiYellow":"#ffbc56","terminal.ansiBlue":"#69b1ff","terminal.ansiMagenta":"#ea68bc","terminal.ansiCyan":"#92dde4","terminal.ansiWhite":"#bcbcbc","terminal.ansiBrightBlack":"#171717","terminal.ansiBrightRed":"#ffa685","terminal.ansiBrightGreen":"#92dde4","terminal.ansiBrightYellow":"#ffcc81","terminal.ansiBrightBlue":"#97c4ff","terminal.ansiBrightMagenta":"#f191cc","terminal.ansiBrightCyan":"#92dde4","terminal.ansiBrightWhite":"#bcbcbc"},"tokenColors":[{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"#737373"}},{"scope":"comment markup.link","settings":{"foreground":"#737373"}},{"scope":["string","constant.other.symbol"],"settings":{"foreground":"#92dde4"}},{"scope":["punctuation.definition.string.begin","punctuation.definition.string.end"],"settings":{"foreground":"#92dde4"}},{"scope":["constant.numeric","constant.language.boolean"],"settings":{"foreground":"#69b1ff"}},{"scope":"constant","settings":{"foreground":"#ffcc81"}},{"scope":"punctuation.definition.constant","settings":{"foreground":"#ffcc81"}},{"scope":"constant.language","settings":{"foreground":"#69b1ff"}},{"scope":"variable.other.constant","settings":{"foreground":"#ff855e"}},{"scope":"keyword","settings":{"foreground":"#d568ea"}},{"scope":"keyword.control","settings":{"foreground":"#d568ea"}},{"scope":["storage","storage.type","storage.modifier"],"settings":{"foreground":"#d568ea"}},{"scope":"token.storage","settings":{"foreground":"#d568ea"}},{"scope":["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],"settings":{"foreground":"#d568ea"}},{"scope":"keyword.operator.delete","settings":{"foreground":"#d568ea"}},{"scope":["variable","identifier","meta.definition.variable"],"settings":{"foreground":"#ff855e"}},{"scope":["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],"settings":{"foreground":"#ff855e"}},{"scope":"variable.language","settings":{"foreground":"#ff855e"}},{"scope":"variable.parameter.function","settings":{"foreground":"#a3a3a3"}},{"scope":"function.parameter","settings":{"foreground":"#a3a3a3"}},{"scope":"variable.parameter","settings":{"foreground":"#a3a3a3"}},{"scope":"variable.parameter.function.language.python","settings":{"foreground":"#ffcc81"}},{"scope":"variable.parameter.function.python","settings":{"foreground":"#ffcc81"}},{"scope":["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],"settings":{"foreground":"#97c4ff"}},{"scope":"keyword.other.special-method","settings":{"foreground":"#97c4ff"}},{"scope":"entity.name.function","settings":{"foreground":"#97c4ff"}},{"scope":"support.function.console","settings":{"foreground":"#97c4ff"}},{"scope":["support.type","entity.name.type","entity.name.class","storage.type"],"settings":{"foreground":"#ea68bc"}},{"scope":["support.class","entity.name.type.class"],"settings":{"foreground":"#ea68bc"}},{"scope":["entity.name.class","variable.other.class.js","variable.other.class.ts"],"settings":{"foreground":"#ea68bc"}},{"scope":"entity.name.class.identifier.namespace.type","settings":{"foreground":"#ea68bc"}},{"scope":"entity.name.type.namespace","settings":{"foreground":"#ff855e"}},{"scope":"entity.other.inherited-class","settings":{"foreground":"#ea68bc"}},{"scope":"entity.name.namespace","settings":{"foreground":"#ff855e"}},{"scope":"keyword.operator","settings":{"foreground":"#636363"}},{"scope":["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],"settings":{"foreground":"#00c5d2"}},{"scope":["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],"settings":{"foreground":"#00c5d2"}},{"scope":"keyword.operator.assignment","settings":{"foreground":"#00c5d2"}},{"scope":"keyword.operator.assignment.compound","settings":{"foreground":"#d568ea"}},{"scope":["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],"settings":{"foreground":"#00c5d2"}},{"scope":"keyword.operator.ternary","settings":{"foreground":"#d568ea"}},{"scope":"keyword.operator.optional","settings":{"foreground":"#d568ea"}},{"scope":"punctuation","settings":{"foreground":"#636363"}},{"scope":"punctuation.separator.delimiter","settings":{"foreground":"#636363"}},{"scope":"punctuation.separator.key-value","settings":{"foreground":"#636363"}},{"scope":"punctuation.terminator","settings":{"foreground":"#636363"}},{"scope":"meta.brace","settings":{"foreground":"#636363"}},{"scope":"meta.brace.square","settings":{"foreground":"#636363"}},{"scope":"meta.brace.round","settings":{"foreground":"#636363"}},{"scope":"function.brace","settings":{"foreground":"#636363"}},{"scope":["punctuation.definition.parameters","punctuation.definition.typeparameters"],"settings":{"foreground":"#636363"}},{"scope":["punctuation.definition.block","punctuation.definition.tag"],"settings":{"foreground":"#636363"}},{"scope":["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],"settings":{"foreground":"#636363"}},{"scope":"keyword.operator.expression.import","settings":{"foreground":"#97c4ff"}},{"scope":"keyword.operator.module","settings":{"foreground":"#d568ea"}},{"scope":"support.type.object.console","settings":{"foreground":"#ff855e"}},{"scope":["support.module.node","support.type.object.module","entity.name.type.module"],"settings":{"foreground":"#ff855e"}},{"scope":"support.constant.math","settings":{"foreground":"#ff855e"}},{"scope":"support.constant.property.math","settings":{"foreground":"#ffcc81"}},{"scope":"support.constant.json","settings":{"foreground":"#ffcc81"}},{"scope":"support.type.object.dom","settings":{"foreground":"#00c5d2"}},{"scope":["support.variable.dom","support.variable.property.dom"],"settings":{"foreground":"#ff855e"}},{"scope":"support.variable.property.process","settings":{"foreground":"#ffcc81"}},{"scope":"meta.property.object","settings":{"foreground":"#ff855e"}},{"scope":"variable.parameter.function.js","settings":{"foreground":"#ff855e"}},{"scope":["keyword.other.template.begin","keyword.other.template.end"],"settings":{"foreground":"#92dde4"}},{"scope":["keyword.other.substitution.begin","keyword.other.substitution.end"],"settings":{"foreground":"#92dde4"}},{"scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],"settings":{"foreground":"#d568ea"}},{"scope":"meta.template.expression","settings":{"foreground":"#636363"}},{"scope":"punctuation.section.embedded","settings":{"foreground":"#ff855e"}},{"scope":"variable.interpolation","settings":{"foreground":"#ff855e"}},{"scope":["punctuation.section.embedded.begin","punctuation.section.embedded.end"],"settings":{"foreground":"#d568ea"}},{"scope":"punctuation.quasi.element","settings":{"foreground":"#d568ea"}},{"scope":["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],"settings":{"foreground":"#ea68bc"}},{"scope":"support.type.type.flowtype","settings":{"foreground":"#97c4ff"}},{"scope":"support.type.primitive","settings":{"foreground":"#ea68bc"}},{"scope":["meta.decorator","meta.decorator punctuation.decorator"],"settings":{"foreground":"#69b1ff"}},{"scope":"entity.name.function.decorator","settings":{"foreground":"#69b1ff"}},{"scope":"punctuation.definition.decorator","settings":{"foreground":"#69b1ff"}},{"scope":"support.variable.magic.python","settings":{"foreground":"#ff855e"}},{"scope":"variable.parameter.function.language.special.self.python","settings":{"foreground":"#ff855e"}},{"scope":["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],"settings":{"foreground":"#636363"}},{"scope":["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],"settings":{"foreground":"#636363"}},{"scope":"support.type.python","settings":{"foreground":"#00c5d2"}},{"scope":"keyword.operator.logical.python","settings":{"foreground":"#d568ea"}},{"scope":"meta.function-call.generic.python","settings":{"foreground":"#97c4ff"}},{"scope":"constant.character.format.placeholder.other.python","settings":{"foreground":"#ffcc81"}},{"scope":"meta.function.decorator.python","settings":{"foreground":"#97c4ff"}},{"scope":["support.token.decorator.python","meta.function.decorator.identifier.python"],"settings":{"foreground":"#00c5d2"}},{"scope":"storage.modifier.lifetime.rust","settings":{"foreground":"#636363"}},{"scope":"support.function.std.rust","settings":{"foreground":"#97c4ff"}},{"scope":"entity.name.lifetime.rust","settings":{"foreground":"#ff855e"}},{"scope":"variable.language.rust","settings":{"foreground":"#ff855e"}},{"scope":"keyword.operator.misc.rust","settings":{"foreground":"#636363"}},{"scope":"keyword.operator.sigil.rust","settings":{"foreground":"#d568ea"}},{"scope":"support.constant.core.rust","settings":{"foreground":"#ffcc81"}},{"scope":["meta.function.c","meta.function.cpp"],"settings":{"foreground":"#ff855e"}},{"scope":["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],"settings":{"foreground":"#636363"}},{"scope":["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],"settings":{"foreground":"#d568ea"}},{"scope":["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],"settings":{"foreground":"#d568ea"}},{"scope":["punctuation.separator.c","punctuation.separator.cpp"],"settings":{"foreground":"#d568ea"}},{"scope":["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],"settings":{"foreground":"#00c5d2"}},{"scope":["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],"settings":{"foreground":"#d568ea"}},{"scope":"variable.c","settings":{"foreground":"#636363"}},{"scope":["storage.type.annotation.java","storage.type.object.array.java"],"settings":{"foreground":"#ff855e"}},{"scope":"source.java","settings":{"foreground":"#ff855e"}},{"scope":["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],"settings":{"foreground":"#636363"}},{"scope":"meta.method.java","settings":{"foreground":"#97c4ff"}},{"scope":["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],"settings":{"foreground":"#ff855e"}},{"scope":"keyword.operator.instanceof.java","settings":{"foreground":"#d568ea"}},{"scope":"meta.definition.variable.name.java","settings":{"foreground":"#ff855e"}},{"scope":"token.variable.parameter.java","settings":{"foreground":"#636363"}},{"scope":"import.storage.java","settings":{"foreground":"#ff855e"}},{"scope":"token.package.keyword","settings":{"foreground":"#d568ea"}},{"scope":"token.package","settings":{"foreground":"#636363"}},{"scope":"token.storage.type.java","settings":{"foreground":"#ff855e"}},{"scope":"keyword.operator.assignment.go","settings":{"foreground":"#ff855e"}},{"scope":["keyword.operator.arithmetic.go","keyword.operator.address.go"],"settings":{"foreground":"#d568ea"}},{"scope":"entity.name.package.go","settings":{"foreground":"#ff855e"}},{"scope":["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],"settings":{"foreground":"#ff855e"}},{"scope":"keyword.operator.error-control.php","settings":{"foreground":"#d568ea"}},{"scope":"keyword.operator.type.php","settings":{"foreground":"#d568ea"}},{"scope":["punctuation.section.array.begin.php","punctuation.section.array.end.php"],"settings":{"foreground":"#636363"}},{"scope":["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],"settings":{"foreground":"#ff855e"}},{"scope":["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],"settings":{"foreground":"#97c4ff"}},{"scope":["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],"settings":{"foreground":"#636363"}},{"scope":["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],"settings":{"foreground":"#ffcc81"}},{"scope":["entity.name.goto-label.php","support.other.php"],"settings":{"foreground":"#97c4ff"}},{"scope":["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],"settings":{"foreground":"#00c5d2"}},{"scope":"keyword.operator.regexp.php","settings":{"foreground":"#d568ea"}},{"scope":"keyword.operator.comparison.php","settings":{"foreground":"#00c5d2"}},{"scope":["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],"settings":{"foreground":"#d568ea"}},{"scope":"variable.other.class.php","settings":{"foreground":"#ff855e"}},{"scope":"invalid.illegal.non-null-typehinted.php","settings":{"foreground":"#fafafa"}},{"scope":"variable.other.generic-type.haskell","settings":{"foreground":"#d568ea"}},{"scope":"storage.type.haskell","settings":{"foreground":"#ffcc81"}},{"scope":"storage.type.cs","settings":{"foreground":"#ff855e"}},{"scope":"entity.name.variable.local.cs","settings":{"foreground":"#ff855e"}},{"scope":"entity.name.label.cs","settings":{"foreground":"#ff855e"}},{"scope":["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],"settings":{"foreground":"#ff855e"}},{"scope":["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],"settings":{"foreground":"#ff855e"}},{"scope":"support.constant.edge","settings":{"foreground":"#d568ea"}},{"scope":"support.type.prelude.elm","settings":{"foreground":"#00c5d2"}},{"scope":"support.constant.elm","settings":{"foreground":"#ffcc81"}},{"scope":"entity.global.clojure","settings":{"foreground":"#ff855e"}},{"scope":"meta.symbol.clojure","settings":{"foreground":"#ff855e"}},{"scope":"constant.keyword.clojure","settings":{"foreground":"#00c5d2"}},{"scope":["meta.arguments.coffee","variable.parameter.function.coffee"],"settings":{"foreground":"#ff855e"}},{"scope":"storage.modifier.import.groovy","settings":{"foreground":"#ff855e"}},{"scope":"meta.method.groovy","settings":{"foreground":"#97c4ff"}},{"scope":"meta.definition.variable.name.groovy","settings":{"foreground":"#ff855e"}},{"scope":"meta.definition.class.inherited.classes.groovy","settings":{"foreground":"#92dde4"}},{"scope":"support.variable.semantic.hlsl","settings":{"foreground":"#ff855e"}},{"scope":["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],"settings":{"foreground":"#d568ea"}},{"scope":["text.variable","text.bracketed"],"settings":{"foreground":"#ff855e"}},{"scope":["support.type.swift","support.type.vb.asp"],"settings":{"foreground":"#ff855e"}},{"scope":"meta.scope.prerequisites.makefile","settings":{"foreground":"#ff855e"}},{"scope":"source.makefile","settings":{"foreground":"#ff855e"}},{"scope":"source.ini","settings":{"foreground":"#92dde4"}},{"scope":"constant.language.symbol.ruby","settings":{"foreground":"#00c5d2"}},{"scope":["function.parameter.ruby","function.parameter.cs"],"settings":{"foreground":"#636363"}},{"scope":"constant.language.symbol.elixir","settings":{"foreground":"#00c5d2"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade","settings":{"foreground":"#d568ea"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade","settings":{"foreground":"#d568ea"}},{"scope":"entity.name.function.xi","settings":{"foreground":"#ff855e"}},{"scope":"entity.name.class.xi","settings":{"foreground":"#00c5d2"}},{"scope":"constant.character.character-class.regexp.xi","settings":{"foreground":"#ff855e"}},{"scope":"constant.regexp.xi","settings":{"foreground":"#d568ea"}},{"scope":"keyword.control.xi","settings":{"foreground":"#00c5d2"}},{"scope":"invalid.xi","settings":{"foreground":"#636363"}},{"scope":"beginning.punctuation.definition.quote.markdown.xi","settings":{"foreground":"#92dde4"}},{"scope":"beginning.punctuation.definition.list.markdown.xi","settings":{"foreground":"#737373"}},{"scope":"constant.character.xi","settings":{"foreground":"#97c4ff"}},{"scope":"accent.xi","settings":{"foreground":"#97c4ff"}},{"scope":"wikiword.xi","settings":{"foreground":"#ffcc81"}},{"scope":"constant.other.color.rgb-value.xi","settings":{"foreground":"#fafafa"}},{"scope":"punctuation.definition.tag.xi","settings":{"foreground":"#737373"}},{"scope":["support.constant.property-value.scss","support.constant.property-value.css"],"settings":{"foreground":"#ffcc81"}},{"scope":["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],"settings":{"foreground":"#00c5d2"}},{"scope":["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],"settings":{"foreground":"#ffcc81"}},{"scope":"punctuation.separator.list.comma.css","settings":{"foreground":"#636363"}},{"scope":"support.type.vendored.property-name.css","settings":{"foreground":"#00c5d2"}},{"scope":"support.type.property-name.css","settings":{"foreground":"#00c5d2"}},{"scope":"support.type.property-name","settings":{"foreground":"#636363"}},{"scope":"support.constant.property-value","settings":{"foreground":"#636363"}},{"scope":"support.constant.font-name","settings":{"foreground":"#ffcc81"}},{"scope":"entity.other.attribute-name.class.css","settings":{"foreground":"#64d1db","fontStyle":"normal"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"#97c4ff","fontStyle":"normal"}},{"scope":["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],"settings":{"foreground":"#00c5d2"}},{"scope":"meta.selector","settings":{"foreground":"#d568ea"}},{"scope":"selector.sass","settings":{"foreground":"#ff855e"}},{"scope":"rgb-value","settings":{"foreground":"#00c5d2"}},{"scope":"inline-color-decoration rgb-value","settings":{"foreground":"#ffcc81"}},{"scope":"less rgb-value","settings":{"foreground":"#ffcc81"}},{"scope":"control.elements","settings":{"foreground":"#ffcc81"}},{"scope":"keyword.operator.less","settings":{"foreground":"#ffcc81"}},{"scope":"entity.name.tag","settings":{"foreground":"#ff855e"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#64d1db","fontStyle":"normal"}},{"scope":"constant.character.entity","settings":{"foreground":"#ff855e"}},{"scope":"meta.tag","settings":{"foreground":"#636363"}},{"scope":"invalid.illegal.bad-ampersand.html","settings":{"foreground":"#636363"}},{"scope":"markup.heading","settings":{"foreground":"#ff855e"}},{"scope":["markup.heading punctuation.definition.heading","entity.name.section"],"settings":{"foreground":"#97c4ff"}},{"scope":"entity.name.section.markdown","settings":{"foreground":"#ff855e"}},{"scope":"punctuation.definition.heading.markdown","settings":{"foreground":"#ff855e"}},{"scope":"markup.heading.setext","settings":{"foreground":"#636363"}},{"scope":["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],"settings":{"foreground":"#ff855e"}},{"scope":["markup.bold","todo.bold"],"settings":{"foreground":"#ffcc81"}},{"scope":"punctuation.definition.bold","settings":{"foreground":"#ff855e"}},{"scope":"punctuation.definition.bold.markdown","settings":{"foreground":"#ffcc81"}},{"scope":["markup.italic","punctuation.definition.italic","todo.emphasis"],"settings":{"foreground":"#d568ea","fontStyle":"italic"}},{"scope":"emphasis md","settings":{"foreground":"#d568ea"}},{"scope":"markup.italic.markdown","settings":{"fontStyle":"italic"}},{"scope":["markup.underline.link.markdown","markup.underline.link.image.markdown"],"settings":{"foreground":"#d568ea"}},{"scope":["string.other.link.title.markdown","string.other.link.description.markdown"],"settings":{"foreground":"#97c4ff"}},{"scope":"punctuation.definition.metadata.markdown","settings":{"foreground":"#ff855e"}},{"scope":["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],"settings":{"foreground":"#92dde4"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#ff855e"}},{"scope":"punctuation.definition.list.markdown","settings":{"foreground":"#ff855e"}},{"scope":"beginning.punctuation.definition.list.markdown","settings":{"foreground":"#ff855e"}},{"scope":["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],"settings":{"foreground":"#ff855e"}},{"scope":"markup.quote.markdown","settings":{"foreground":"#737373"}},{"scope":"keyword.other.unit","settings":{"foreground":"#ff855e"}},{"scope":"markup.changed.diff","settings":{"foreground":"#ff855e"}},{"scope":["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],"settings":{"foreground":"#97c4ff"}},{"scope":"markup.inserted.diff","settings":{"foreground":"#92dde4"}},{"scope":"markup.deleted.diff","settings":{"foreground":"#ff855e"}},{"scope":"string.regexp","settings":{"foreground":"#64d1db"}},{"scope":"constant.other.character-class.regexp","settings":{"foreground":"#ff855e"}},{"scope":"keyword.operator.quantifier.regexp","settings":{"foreground":"#ffcc81"}},{"scope":"constant.character.escape","settings":{"foreground":"#64d1db"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json","settings":{"foreground":"#ff855e"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string","settings":{"foreground":"#ff855e"}},{"scope":["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],"settings":{"foreground":"#92dde4"}},{"scope":["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],"settings":{"foreground":"#00c5d2"}},{"scope":"support.type.property-name.json","settings":{"foreground":"#ff855e"}},{"scope":"support.type.property-name.json punctuation","settings":{"foreground":"#ff855e"}},{"scope":"punctuation.definition.block.sequence.item.yaml","settings":{"foreground":"#636363"}},{"scope":"block.scope.end","settings":{"foreground":"#636363"}},{"scope":"block.scope.begin","settings":{"foreground":"#636363"}},{"scope":"token.info-token","settings":{"foreground":"#97c4ff"}},{"scope":"token.warn-token","settings":{"foreground":"#ffcc81"}},{"scope":"token.error-token","settings":{"foreground":"#fafafa"}},{"scope":"token.debug-token","settings":{"foreground":"#d568ea"}},{"scope":"invalid.illegal","settings":{"foreground":"#fafafa"}},{"scope":"invalid.broken","settings":{"foreground":"#fafafa"}},{"scope":"invalid.deprecated","settings":{"foreground":"#fafafa"}},{"scope":"invalid.unimplemented","settings":{"foreground":"#fafafa"}}],"semanticTokenColors":{"comment":"#737373","string":"#92dde4","number":"#69b1ff","regexp":"#64d1db","keyword":"#d568ea","variable":"#ff855e","parameter":"#a3a3a3","property":"#ff855e","function":"#97c4ff","method":"#97c4ff","type":"#ea68bc","class":"#ea68bc","namespace":"#ff855e","enumMember":"#00c5d2","variable.constant":"#ffcc81","variable.defaultLibrary":"#ff855e","decorator":"#69b1ff"}}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/pierre-light-soft-CVdyfjmI.js b/apps/kimi-code/dist-web/assets/pierre-light-soft-CVdyfjmI.js new file mode 100644 index 0000000000000000000000000000000000000000..93725d8c839f7d5544c0ff4d82621667cf87dfde --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pierre-light-soft-CVdyfjmI.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"name":"pierre-light-soft","displayName":"Pierre Light Soft","type":"light","colors":{"editor.background":"#ffffff","editor.foreground":"#525252","foreground":"#525252","focusBorder":"#009fff","selection.background":"#dfebff","editor.selectionBackground":"#009fff2e","editor.lineHighlightBackground":"#dfebff8c","editorCursor.foreground":"#009fff","editorLineNumber.foreground":"#8a8a8a","editorLineNumber.activeForeground":"#737373","editorIndentGuide.background":"#ededed","editorIndentGuide.activeBackground":"#e5e5e5","diffEditor.insertedTextBackground":"#07c48033","diffEditor.deletedTextBackground":"#ff2e3f33","sideBar.background":"#f7f7f7","sideBar.foreground":"#737373","sideBar.border":"#ededed","sideBarTitle.foreground":"#525252","sideBarSectionHeader.background":"#f7f7f7","sideBarSectionHeader.foreground":"#737373","sideBarSectionHeader.border":"#ededed","activityBar.background":"#f7f7f7","activityBar.foreground":"#525252","activityBar.border":"#ededed","activityBar.activeBorder":"#009fff","activityBarBadge.background":"#009fff","activityBarBadge.foreground":"#ffffff","titleBar.activeBackground":"#f7f7f7","titleBar.activeForeground":"#525252","titleBar.inactiveBackground":"#f7f7f7","titleBar.inactiveForeground":"#8a8a8a","titleBar.border":"#ededed","list.activeSelectionBackground":"#dfebffcc","list.activeSelectionForeground":"#525252","list.inactiveSelectionBackground":"#dfebff73","list.hoverBackground":"#dfebff59","list.focusOutline":"#009fff","tab.activeBackground":"#ffffff","tab.activeForeground":"#525252","tab.activeBorderTop":"#009fff","tab.inactiveBackground":"#f7f7f7","tab.inactiveForeground":"#8a8a8a","tab.border":"#ededed","editorGroupHeader.tabsBackground":"#f7f7f7","editorGroupHeader.tabsBorder":"#ededed","panel.background":"#f7f7f7","panel.border":"#ededed","panelTitle.activeBorder":"#009fff","panelTitle.activeForeground":"#525252","panelTitle.inactiveForeground":"#8a8a8a","statusBar.background":"#f7f7f7","statusBar.foreground":"#737373","statusBar.border":"#ededed","statusBar.noFolderBackground":"#f7f7f7","statusBar.debuggingBackground":"#ffca00","statusBar.debuggingForeground":"#ffffff","statusBarItem.remoteBackground":"#f7f7f7","statusBarItem.remoteForeground":"#737373","input.background":"#f5f5f5","input.border":"#d4d4d4","input.foreground":"#525252","input.placeholderForeground":"#a3a3a3","dropdown.background":"#f5f5f5","dropdown.border":"#d4d4d4","dropdown.foreground":"#525252","button.background":"#009fff","button.foreground":"#ffffff","button.hoverBackground":"#1aa9ff","textLink.foreground":"#009fff","textLink.activeForeground":"#009fff","notifications.background":"#fafafa","notifications.foreground":"#525252","notifications.border":"#e5e5e5","notificationToast.border":"#e5e5e5","notificationCenter.border":"#e5e5e5","notificationCenterHeader.background":"#fafafa","notificationCenterHeader.foreground":"#737373","notificationLink.foreground":"#009fff","notificationsErrorIcon.foreground":"#ff2e3f","notificationsWarningIcon.foreground":"#ffca00","notificationsInfoIcon.foreground":"#08c0ef","quickInput.background":"#fafafa","quickInput.foreground":"#525252","quickInputTitle.background":"#fafafa","widget.border":"#e5e5e5","gitDecoration.addedResourceForeground":"#07c480","gitDecoration.conflictingResourceForeground":"#7b43f8","gitDecoration.modifiedResourceForeground":"#009fff","gitDecoration.deletedResourceForeground":"#ff2e3f","gitDecoration.untrackedResourceForeground":"#07c480","gitDecoration.ignoredResourceForeground":"#8a8a8a","merge.currentHeaderBackground":"#7b43f833","merge.currentContentBackground":"#7b43f814","merge.incomingHeaderBackground":"#08c0ef33","merge.incomingContentBackground":"#08c0ef14","editorOverviewRuler.currentContentForeground":"#7b43f8","editorOverviewRuler.incomingContentForeground":"#08c0ef","terminal.titleForeground":"#737373","terminal.titleInactiveForeground":"#8a8a8a","terminal.background":"#f7f7f7","terminal.foreground":"#737373","terminal.ansiBlack":"#1d1d1d","terminal.ansiRed":"#ff2e3f","terminal.ansiGreen":"#0dbe4e","terminal.ansiYellow":"#ffca00","terminal.ansiBlue":"#009fff","terminal.ansiMagenta":"#e130ac","terminal.ansiCyan":"#08c0ef","terminal.ansiWhite":"#bcbcbc","terminal.ansiBrightBlack":"#1d1d1d","terminal.ansiBrightRed":"#ff2e3f","terminal.ansiBrightGreen":"#86c427","terminal.ansiBrightYellow":"#ffca00","terminal.ansiBrightBlue":"#009fff","terminal.ansiBrightMagenta":"#e130ac","terminal.ansiBrightCyan":"#08c0ef","terminal.ansiBrightWhite":"#bcbcbc"},"tokenColors":[{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"#8a8a8a"}},{"scope":"comment markup.link","settings":{"foreground":"#8a8a8a"}},{"scope":["string","constant.other.symbol"],"settings":{"foreground":"#0dbe4e"}},{"scope":["punctuation.definition.string.begin","punctuation.definition.string.end"],"settings":{"foreground":"#0dbe4e"}},{"scope":["constant.numeric","constant.language.boolean"],"settings":{"foreground":"#08c0ef"}},{"scope":"constant","settings":{"foreground":"#ffca00"}},{"scope":"punctuation.definition.constant","settings":{"foreground":"#ffca00"}},{"scope":"constant.language","settings":{"foreground":"#08c0ef"}},{"scope":"variable.other.constant","settings":{"foreground":"#ffab16"}},{"scope":"keyword","settings":{"foreground":"#ff678d"}},{"scope":"keyword.control","settings":{"foreground":"#ff678d"}},{"scope":["storage","storage.type","storage.modifier"],"settings":{"foreground":"#ff678d"}},{"scope":"token.storage","settings":{"foreground":"#ff678d"}},{"scope":["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],"settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.delete","settings":{"foreground":"#ff678d"}},{"scope":["variable","identifier","meta.definition.variable"],"settings":{"foreground":"#fe8c2c"}},{"scope":["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],"settings":{"foreground":"#fe8c2c"}},{"scope":"variable.language","settings":{"foreground":"#ffab16"}},{"scope":"variable.parameter.function","settings":{"foreground":"#737373"}},{"scope":"function.parameter","settings":{"foreground":"#737373"}},{"scope":"variable.parameter","settings":{"foreground":"#737373"}},{"scope":"variable.parameter.function.language.python","settings":{"foreground":"#ffca00"}},{"scope":"variable.parameter.function.python","settings":{"foreground":"#ffca00"}},{"scope":["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],"settings":{"foreground":"#9d6afb"}},{"scope":"keyword.other.special-method","settings":{"foreground":"#9d6afb"}},{"scope":"entity.name.function","settings":{"foreground":"#9d6afb"}},{"scope":"support.function.console","settings":{"foreground":"#9d6afb"}},{"scope":["support.type","entity.name.type","entity.name.class","storage.type"],"settings":{"foreground":"#d568ea"}},{"scope":["support.class","entity.name.type.class"],"settings":{"foreground":"#d568ea"}},{"scope":["entity.name.class","variable.other.class.js","variable.other.class.ts"],"settings":{"foreground":"#d568ea"}},{"scope":"entity.name.class.identifier.namespace.type","settings":{"foreground":"#d568ea"}},{"scope":"entity.name.type.namespace","settings":{"foreground":"#ffab16"}},{"scope":"entity.other.inherited-class","settings":{"foreground":"#d568ea"}},{"scope":"entity.name.namespace","settings":{"foreground":"#ffab16"}},{"scope":"keyword.operator","settings":{"foreground":"#737373"}},{"scope":["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],"settings":{"foreground":"#68cdf2"}},{"scope":["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],"settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.assignment","settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.assignment.compound","settings":{"foreground":"#ff678d"}},{"scope":["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],"settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.ternary","settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.optional","settings":{"foreground":"#ff678d"}},{"scope":"punctuation","settings":{"foreground":"#737373"}},{"scope":"punctuation.separator.delimiter","settings":{"foreground":"#737373"}},{"scope":"punctuation.separator.key-value","settings":{"foreground":"#737373"}},{"scope":"punctuation.terminator","settings":{"foreground":"#737373"}},{"scope":"meta.brace","settings":{"foreground":"#737373"}},{"scope":"meta.brace.square","settings":{"foreground":"#737373"}},{"scope":"meta.brace.round","settings":{"foreground":"#737373"}},{"scope":"function.brace","settings":{"foreground":"#737373"}},{"scope":["punctuation.definition.parameters","punctuation.definition.typeparameters"],"settings":{"foreground":"#737373"}},{"scope":["punctuation.definition.block","punctuation.definition.tag"],"settings":{"foreground":"#737373"}},{"scope":["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],"settings":{"foreground":"#737373"}},{"scope":"keyword.operator.expression.import","settings":{"foreground":"#9d6afb"}},{"scope":"keyword.operator.module","settings":{"foreground":"#ff678d"}},{"scope":"support.type.object.console","settings":{"foreground":"#fe8c2c"}},{"scope":["support.module.node","support.type.object.module","entity.name.type.module"],"settings":{"foreground":"#ffab16"}},{"scope":"support.constant.math","settings":{"foreground":"#ffab16"}},{"scope":"support.constant.property.math","settings":{"foreground":"#ffca00"}},{"scope":"support.constant.json","settings":{"foreground":"#ffca00"}},{"scope":"support.type.object.dom","settings":{"foreground":"#68cdf2"}},{"scope":["support.variable.dom","support.variable.property.dom"],"settings":{"foreground":"#fe8c2c"}},{"scope":"support.variable.property.process","settings":{"foreground":"#ffca00"}},{"scope":"meta.property.object","settings":{"foreground":"#fe8c2c"}},{"scope":"variable.parameter.function.js","settings":{"foreground":"#fe8c2c"}},{"scope":["keyword.other.template.begin","keyword.other.template.end"],"settings":{"foreground":"#0dbe4e"}},{"scope":["keyword.other.substitution.begin","keyword.other.substitution.end"],"settings":{"foreground":"#0dbe4e"}},{"scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],"settings":{"foreground":"#ff678d"}},{"scope":"meta.template.expression","settings":{"foreground":"#737373"}},{"scope":"punctuation.section.embedded","settings":{"foreground":"#fe8c2c"}},{"scope":"variable.interpolation","settings":{"foreground":"#fe8c2c"}},{"scope":["punctuation.section.embedded.begin","punctuation.section.embedded.end"],"settings":{"foreground":"#ff678d"}},{"scope":"punctuation.quasi.element","settings":{"foreground":"#ff678d"}},{"scope":["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],"settings":{"foreground":"#d568ea"}},{"scope":"support.type.type.flowtype","settings":{"foreground":"#9d6afb"}},{"scope":"support.type.primitive","settings":{"foreground":"#d568ea"}},{"scope":["meta.decorator","meta.decorator punctuation.decorator"],"settings":{"foreground":"#69b1ff"}},{"scope":"entity.name.function.decorator","settings":{"foreground":"#69b1ff"}},{"scope":"punctuation.definition.decorator","settings":{"foreground":"#69b1ff"}},{"scope":"support.variable.magic.python","settings":{"foreground":"#ff5d36"}},{"scope":"variable.parameter.function.language.special.self.python","settings":{"foreground":"#ffab16"}},{"scope":["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],"settings":{"foreground":"#737373"}},{"scope":["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],"settings":{"foreground":"#737373"}},{"scope":"support.type.python","settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.logical.python","settings":{"foreground":"#ff678d"}},{"scope":"meta.function-call.generic.python","settings":{"foreground":"#9d6afb"}},{"scope":"constant.character.format.placeholder.other.python","settings":{"foreground":"#ffca00"}},{"scope":"meta.function.decorator.python","settings":{"foreground":"#9d6afb"}},{"scope":["support.token.decorator.python","meta.function.decorator.identifier.python"],"settings":{"foreground":"#68cdf2"}},{"scope":"storage.modifier.lifetime.rust","settings":{"foreground":"#737373"}},{"scope":"support.function.std.rust","settings":{"foreground":"#9d6afb"}},{"scope":"entity.name.lifetime.rust","settings":{"foreground":"#ffab16"}},{"scope":"variable.language.rust","settings":{"foreground":"#ff5d36"}},{"scope":"keyword.operator.misc.rust","settings":{"foreground":"#737373"}},{"scope":"keyword.operator.sigil.rust","settings":{"foreground":"#ff678d"}},{"scope":"support.constant.core.rust","settings":{"foreground":"#ffca00"}},{"scope":["meta.function.c","meta.function.cpp"],"settings":{"foreground":"#ff5d36"}},{"scope":["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],"settings":{"foreground":"#737373"}},{"scope":["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],"settings":{"foreground":"#ff678d"}},{"scope":["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],"settings":{"foreground":"#ff678d"}},{"scope":["punctuation.separator.c","punctuation.separator.cpp"],"settings":{"foreground":"#ff678d"}},{"scope":["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],"settings":{"foreground":"#68cdf2"}},{"scope":["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],"settings":{"foreground":"#ff678d"}},{"scope":"variable.c","settings":{"foreground":"#737373"}},{"scope":["storage.type.annotation.java","storage.type.object.array.java"],"settings":{"foreground":"#ffab16"}},{"scope":"source.java","settings":{"foreground":"#ff5d36"}},{"scope":["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],"settings":{"foreground":"#737373"}},{"scope":"meta.method.java","settings":{"foreground":"#9d6afb"}},{"scope":["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],"settings":{"foreground":"#ffab16"}},{"scope":"keyword.operator.instanceof.java","settings":{"foreground":"#ff678d"}},{"scope":"meta.definition.variable.name.java","settings":{"foreground":"#ff5d36"}},{"scope":"token.variable.parameter.java","settings":{"foreground":"#737373"}},{"scope":"import.storage.java","settings":{"foreground":"#ffab16"}},{"scope":"token.package.keyword","settings":{"foreground":"#ff678d"}},{"scope":"token.package","settings":{"foreground":"#737373"}},{"scope":"token.storage.type.java","settings":{"foreground":"#ffab16"}},{"scope":"keyword.operator.assignment.go","settings":{"foreground":"#ffab16"}},{"scope":["keyword.operator.arithmetic.go","keyword.operator.address.go"],"settings":{"foreground":"#ff678d"}},{"scope":"entity.name.package.go","settings":{"foreground":"#ffab16"}},{"scope":["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],"settings":{"foreground":"#ffab16"}},{"scope":"keyword.operator.error-control.php","settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.type.php","settings":{"foreground":"#ff678d"}},{"scope":["punctuation.section.array.begin.php","punctuation.section.array.end.php"],"settings":{"foreground":"#737373"}},{"scope":["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],"settings":{"foreground":"#ffab16"}},{"scope":["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],"settings":{"foreground":"#9d6afb"}},{"scope":["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],"settings":{"foreground":"#737373"}},{"scope":["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],"settings":{"foreground":"#ffca00"}},{"scope":["entity.name.goto-label.php","support.other.php"],"settings":{"foreground":"#9d6afb"}},{"scope":["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],"settings":{"foreground":"#68cdf2"}},{"scope":"keyword.operator.regexp.php","settings":{"foreground":"#ff678d"}},{"scope":"keyword.operator.comparison.php","settings":{"foreground":"#68cdf2"}},{"scope":["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],"settings":{"foreground":"#ff678d"}},{"scope":"variable.other.class.php","settings":{"foreground":"#ff5d36"}},{"scope":"invalid.illegal.non-null-typehinted.php","settings":{"foreground":"#171717"}},{"scope":"variable.other.generic-type.haskell","settings":{"foreground":"#ff678d"}},{"scope":"storage.type.haskell","settings":{"foreground":"#ffca00"}},{"scope":"storage.type.cs","settings":{"foreground":"#ffab16"}},{"scope":"entity.name.variable.local.cs","settings":{"foreground":"#ff5d36"}},{"scope":"entity.name.label.cs","settings":{"foreground":"#ffab16"}},{"scope":["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],"settings":{"foreground":"#ffab16"}},{"scope":["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],"settings":{"foreground":"#ff5d36"}},{"scope":"support.constant.edge","settings":{"foreground":"#ff678d"}},{"scope":"support.type.prelude.elm","settings":{"foreground":"#68cdf2"}},{"scope":"support.constant.elm","settings":{"foreground":"#ffca00"}},{"scope":"entity.global.clojure","settings":{"foreground":"#ffab16"}},{"scope":"meta.symbol.clojure","settings":{"foreground":"#ff5d36"}},{"scope":"constant.keyword.clojure","settings":{"foreground":"#68cdf2"}},{"scope":["meta.arguments.coffee","variable.parameter.function.coffee"],"settings":{"foreground":"#ff5d36"}},{"scope":"storage.modifier.import.groovy","settings":{"foreground":"#ffab16"}},{"scope":"meta.method.groovy","settings":{"foreground":"#9d6afb"}},{"scope":"meta.definition.variable.name.groovy","settings":{"foreground":"#ff5d36"}},{"scope":"meta.definition.class.inherited.classes.groovy","settings":{"foreground":"#0dbe4e"}},{"scope":"support.variable.semantic.hlsl","settings":{"foreground":"#ffab16"}},{"scope":["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],"settings":{"foreground":"#ff678d"}},{"scope":["text.variable","text.bracketed"],"settings":{"foreground":"#ff5d36"}},{"scope":["support.type.swift","support.type.vb.asp"],"settings":{"foreground":"#ffab16"}},{"scope":"meta.scope.prerequisites.makefile","settings":{"foreground":"#ff5d36"}},{"scope":"source.makefile","settings":{"foreground":"#ffab16"}},{"scope":"source.ini","settings":{"foreground":"#0dbe4e"}},{"scope":"constant.language.symbol.ruby","settings":{"foreground":"#68cdf2"}},{"scope":["function.parameter.ruby","function.parameter.cs"],"settings":{"foreground":"#737373"}},{"scope":"constant.language.symbol.elixir","settings":{"foreground":"#68cdf2"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade","settings":{"foreground":"#ff678d"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade","settings":{"foreground":"#ff678d"}},{"scope":"entity.name.function.xi","settings":{"foreground":"#ffab16"}},{"scope":"entity.name.class.xi","settings":{"foreground":"#68cdf2"}},{"scope":"constant.character.character-class.regexp.xi","settings":{"foreground":"#ff5d36"}},{"scope":"constant.regexp.xi","settings":{"foreground":"#ff678d"}},{"scope":"keyword.control.xi","settings":{"foreground":"#68cdf2"}},{"scope":"invalid.xi","settings":{"foreground":"#737373"}},{"scope":"beginning.punctuation.definition.quote.markdown.xi","settings":{"foreground":"#0dbe4e"}},{"scope":"beginning.punctuation.definition.list.markdown.xi","settings":{"foreground":"#8a8a8a"}},{"scope":"constant.character.xi","settings":{"foreground":"#9d6afb"}},{"scope":"accent.xi","settings":{"foreground":"#9d6afb"}},{"scope":"wikiword.xi","settings":{"foreground":"#ffca00"}},{"scope":"constant.other.color.rgb-value.xi","settings":{"foreground":"#171717"}},{"scope":"punctuation.definition.tag.xi","settings":{"foreground":"#8a8a8a"}},{"scope":["support.constant.property-value.scss","support.constant.property-value.css"],"settings":{"foreground":"#ffca00"}},{"scope":["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],"settings":{"foreground":"#68cdf2"}},{"scope":["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],"settings":{"foreground":"#ffca00"}},{"scope":"punctuation.separator.list.comma.css","settings":{"foreground":"#737373"}},{"scope":"support.type.vendored.property-name.css","settings":{"foreground":"#68cdf2"}},{"scope":"support.type.property-name.css","settings":{"foreground":"#68cdf2"}},{"scope":"support.type.property-name","settings":{"foreground":"#737373"}},{"scope":"support.constant.property-value","settings":{"foreground":"#737373"}},{"scope":"support.constant.font-name","settings":{"foreground":"#ffca00"}},{"scope":"entity.other.attribute-name.class.css","settings":{"foreground":"#07c480","fontStyle":"normal"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"#9d6afb","fontStyle":"normal"}},{"scope":["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],"settings":{"foreground":"#68cdf2"}},{"scope":"meta.selector","settings":{"foreground":"#ff678d"}},{"scope":"selector.sass","settings":{"foreground":"#ff5d36"}},{"scope":"rgb-value","settings":{"foreground":"#68cdf2"}},{"scope":"inline-color-decoration rgb-value","settings":{"foreground":"#ffca00"}},{"scope":"less rgb-value","settings":{"foreground":"#ffca00"}},{"scope":"control.elements","settings":{"foreground":"#ffca00"}},{"scope":"keyword.operator.less","settings":{"foreground":"#ffca00"}},{"scope":"entity.name.tag","settings":{"foreground":"#ff5d36"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#07c480","fontStyle":"normal"}},{"scope":"constant.character.entity","settings":{"foreground":"#ff5d36"}},{"scope":"meta.tag","settings":{"foreground":"#737373"}},{"scope":"invalid.illegal.bad-ampersand.html","settings":{"foreground":"#737373"}},{"scope":"markup.heading","settings":{"foreground":"#ff5d36"}},{"scope":["markup.heading punctuation.definition.heading","entity.name.section"],"settings":{"foreground":"#9d6afb"}},{"scope":"entity.name.section.markdown","settings":{"foreground":"#ff5d36"}},{"scope":"punctuation.definition.heading.markdown","settings":{"foreground":"#ff5d36"}},{"scope":"markup.heading.setext","settings":{"foreground":"#737373"}},{"scope":["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],"settings":{"foreground":"#ff5d36"}},{"scope":["markup.bold","todo.bold"],"settings":{"foreground":"#ffca00"}},{"scope":"punctuation.definition.bold","settings":{"foreground":"#ffab16"}},{"scope":"punctuation.definition.bold.markdown","settings":{"foreground":"#ffca00"}},{"scope":["markup.italic","punctuation.definition.italic","todo.emphasis"],"settings":{"foreground":"#ff678d","fontStyle":"italic"}},{"scope":"emphasis md","settings":{"foreground":"#ff678d"}},{"scope":"markup.italic.markdown","settings":{"fontStyle":"italic"}},{"scope":["markup.underline.link.markdown","markup.underline.link.image.markdown"],"settings":{"foreground":"#ff678d"}},{"scope":["string.other.link.title.markdown","string.other.link.description.markdown"],"settings":{"foreground":"#9d6afb"}},{"scope":"punctuation.definition.metadata.markdown","settings":{"foreground":"#ff5d36"}},{"scope":["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],"settings":{"foreground":"#0dbe4e"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"#ff5d36"}},{"scope":"punctuation.definition.list.markdown","settings":{"foreground":"#ff5d36"}},{"scope":"beginning.punctuation.definition.list.markdown","settings":{"foreground":"#ff5d36"}},{"scope":["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],"settings":{"foreground":"#ff5d36"}},{"scope":"markup.quote.markdown","settings":{"foreground":"#8a8a8a"}},{"scope":"keyword.other.unit","settings":{"foreground":"#ff5d36"}},{"scope":"markup.changed.diff","settings":{"foreground":"#ffab16"}},{"scope":["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],"settings":{"foreground":"#9d6afb"}},{"scope":"markup.inserted.diff","settings":{"foreground":"#0dbe4e"}},{"scope":"markup.deleted.diff","settings":{"foreground":"#ff5d36"}},{"scope":"string.regexp","settings":{"foreground":"#00c5d2"}},{"scope":"constant.other.character-class.regexp","settings":{"foreground":"#ff5d36"}},{"scope":"keyword.operator.quantifier.regexp","settings":{"foreground":"#ffca00"}},{"scope":"constant.character.escape","settings":{"foreground":"#00cab1"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json","settings":{"foreground":"#ff5d36"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string","settings":{"foreground":"#ff5d36"}},{"scope":["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],"settings":{"foreground":"#0dbe4e"}},{"scope":["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],"settings":{"foreground":"#68cdf2"}},{"scope":"support.type.property-name.json","settings":{"foreground":"#ff5d36"}},{"scope":"support.type.property-name.json punctuation","settings":{"foreground":"#ff5d36"}},{"scope":"punctuation.definition.block.sequence.item.yaml","settings":{"foreground":"#737373"}},{"scope":"block.scope.end","settings":{"foreground":"#737373"}},{"scope":"block.scope.begin","settings":{"foreground":"#737373"}},{"scope":"token.info-token","settings":{"foreground":"#9d6afb"}},{"scope":"token.warn-token","settings":{"foreground":"#ffca00"}},{"scope":"token.error-token","settings":{"foreground":"#171717"}},{"scope":"token.debug-token","settings":{"foreground":"#ff678d"}},{"scope":"invalid.illegal","settings":{"foreground":"#171717"}},{"scope":"invalid.broken","settings":{"foreground":"#171717"}},{"scope":"invalid.deprecated","settings":{"foreground":"#171717"}},{"scope":"invalid.unimplemented","settings":{"foreground":"#171717"}}],"semanticTokenColors":{"comment":"#8a8a8a","string":"#0dbe4e","number":"#08c0ef","regexp":"#00c5d2","keyword":"#ff678d","variable":"#fe8c2c","parameter":"#737373","property":"#fe8c2c","function":"#9d6afb","method":"#9d6afb","type":"#d568ea","class":"#d568ea","namespace":"#ffab16","enumMember":"#68cdf2","variable.constant":"#ffca00","variable.defaultLibrary":"#ffab16","decorator":"#69b1ff"}}'));export{e as default}; diff --git a/apps/kimi-code/dist-web/assets/pierre-light-vibrant-DdTDNdfJ.js b/apps/kimi-code/dist-web/assets/pierre-light-vibrant-DdTDNdfJ.js new file mode 100644 index 0000000000000000000000000000000000000000..2411a20952c0f9679d139393d626337b1f877473 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pierre-light-vibrant-DdTDNdfJ.js @@ -0,0 +1 @@ +const o=Object.freeze(JSON.parse('{"name":"pierre-light-vibrant","displayName":"Pierre Light Vibrant","type":"light","colors":{"editor.background":"color(display-p3 1.000000 1.000000 1.000000)","editor.foreground":"color(display-p3 0.039216 0.039216 0.039216)","foreground":"color(display-p3 0.039216 0.039216 0.039216)","focusBorder":"color(display-p3 0.308664 0.645271 1.000000)","selection.background":"color(display-p3 0.883107 0.920057 0.992610)","editor.selectionBackground":"color(display-p3 0.308664 0.645271 1.000000 / 0.180000)","editor.lineHighlightBackground":"color(display-p3 0.883107 0.920057 0.992610 / 0.550000)","editorCursor.foreground":"color(display-p3 0.308664 0.645271 1.000000)","editorLineNumber.foreground":"color(display-p3 0.450980 0.450980 0.450980)","editorLineNumber.activeForeground":"color(display-p3 0.321569 0.321569 0.321569)","editorIndentGuide.background":"color(display-p3 0.898039 0.898039 0.898039)","editorIndentGuide.activeBackground":"color(display-p3 0.831373 0.831373 0.831373)","diffEditor.insertedTextBackground":"color(display-p3 0.266455 0.667541 0.435918 / 0.200000)","diffEditor.deletedTextBackground":"color(display-p3 0.838044 0.219378 0.220424 / 0.200000)","sideBar.background":"color(display-p3 0.960784 0.960784 0.960784)","sideBar.foreground":"color(display-p3 0.321569 0.321569 0.321569)","sideBar.border":"color(display-p3 0.898039 0.898039 0.898039)","sideBarTitle.foreground":"color(display-p3 0.039216 0.039216 0.039216)","sideBarSectionHeader.background":"color(display-p3 0.960784 0.960784 0.960784)","sideBarSectionHeader.foreground":"color(display-p3 0.321569 0.321569 0.321569)","sideBarSectionHeader.border":"color(display-p3 0.898039 0.898039 0.898039)","activityBar.background":"color(display-p3 0.960784 0.960784 0.960784)","activityBar.foreground":"color(display-p3 0.039216 0.039216 0.039216)","activityBar.border":"color(display-p3 0.898039 0.898039 0.898039)","activityBar.activeBorder":"color(display-p3 0.308664 0.645271 1.000000)","activityBarBadge.background":"color(display-p3 0.308664 0.645271 1.000000)","activityBarBadge.foreground":"color(display-p3 1.000000 1.000000 1.000000)","titleBar.activeBackground":"color(display-p3 0.960784 0.960784 0.960784)","titleBar.activeForeground":"color(display-p3 0.039216 0.039216 0.039216)","titleBar.inactiveBackground":"color(display-p3 0.960784 0.960784 0.960784)","titleBar.inactiveForeground":"color(display-p3 0.450980 0.450980 0.450980)","titleBar.border":"color(display-p3 0.898039 0.898039 0.898039)","list.activeSelectionBackground":"color(display-p3 0.883107 0.920057 0.992610 / 0.800000)","list.activeSelectionForeground":"color(display-p3 0.039216 0.039216 0.039216)","list.inactiveSelectionBackground":"color(display-p3 0.883107 0.920057 0.992610 / 0.450000)","list.hoverBackground":"color(display-p3 0.883107 0.920057 0.992610 / 0.350000)","list.focusOutline":"color(display-p3 0.308664 0.645271 1.000000)","tab.activeBackground":"color(display-p3 1.000000 1.000000 1.000000)","tab.activeForeground":"color(display-p3 0.039216 0.039216 0.039216)","tab.activeBorderTop":"color(display-p3 0.308664 0.645271 1.000000)","tab.inactiveBackground":"color(display-p3 0.960784 0.960784 0.960784)","tab.inactiveForeground":"color(display-p3 0.450980 0.450980 0.450980)","tab.border":"color(display-p3 0.898039 0.898039 0.898039)","editorGroupHeader.tabsBackground":"color(display-p3 0.960784 0.960784 0.960784)","editorGroupHeader.tabsBorder":"color(display-p3 0.898039 0.898039 0.898039)","panel.background":"color(display-p3 0.960784 0.960784 0.960784)","panel.border":"color(display-p3 0.898039 0.898039 0.898039)","panelTitle.activeBorder":"color(display-p3 0.308664 0.645271 1.000000)","panelTitle.activeForeground":"color(display-p3 0.039216 0.039216 0.039216)","panelTitle.inactiveForeground":"color(display-p3 0.450980 0.450980 0.450980)","statusBar.background":"color(display-p3 0.960784 0.960784 0.960784)","statusBar.foreground":"color(display-p3 0.321569 0.321569 0.321569)","statusBar.border":"color(display-p3 0.898039 0.898039 0.898039)","statusBar.noFolderBackground":"color(display-p3 0.960784 0.960784 0.960784)","statusBar.debuggingBackground":"color(display-p3 0.883654 0.721037 0.210874)","statusBar.debuggingForeground":"color(display-p3 1.000000 1.000000 1.000000)","statusBarItem.remoteBackground":"color(display-p3 0.960784 0.960784 0.960784)","statusBarItem.remoteForeground":"color(display-p3 0.321569 0.321569 0.321569)","input.background":"color(display-p3 0.929412 0.929412 0.929412)","input.border":"color(display-p3 0.831373 0.831373 0.831373)","input.foreground":"color(display-p3 0.039216 0.039216 0.039216)","input.placeholderForeground":"color(display-p3 0.541176 0.541176 0.541176)","dropdown.background":"color(display-p3 0.929412 0.929412 0.929412)","dropdown.border":"color(display-p3 0.831373 0.831373 0.831373)","dropdown.foreground":"color(display-p3 0.039216 0.039216 0.039216)","button.background":"color(display-p3 0.308664 0.645271 1.000000)","button.foreground":"color(display-p3 1.000000 1.000000 1.000000)","button.hoverBackground":"color(display-p3 0.376471 0.682353 1.000000)","textLink.foreground":"color(display-p3 0.308664 0.645271 1.000000)","textLink.activeForeground":"color(display-p3 0.308664 0.645271 1.000000)","notifications.background":"color(display-p3 0.968627 0.968627 0.968627)","notifications.foreground":"color(display-p3 0.039216 0.039216 0.039216)","notifications.border":"color(display-p3 0.898039 0.898039 0.898039)","notificationToast.border":"color(display-p3 0.898039 0.898039 0.898039)","notificationCenter.border":"color(display-p3 0.898039 0.898039 0.898039)","notificationCenterHeader.background":"color(display-p3 0.968627 0.968627 0.968627)","notificationCenterHeader.foreground":"color(display-p3 0.321569 0.321569 0.321569)","notificationLink.foreground":"color(display-p3 0.308664 0.645271 1.000000)","notificationsErrorIcon.foreground":"color(display-p3 0.838044 0.219378 0.220424)","notificationsWarningIcon.foreground":"color(display-p3 0.883654 0.721037 0.210874)","notificationsInfoIcon.foreground":"color(display-p3 0.246852 0.642335 0.817202)","quickInput.background":"color(display-p3 0.968627 0.968627 0.968627)","quickInput.foreground":"color(display-p3 0.039216 0.039216 0.039216)","quickInputTitle.background":"color(display-p3 0.968627 0.968627 0.968627)","widget.border":"color(display-p3 0.898039 0.898039 0.898039)","gitDecoration.addedResourceForeground":"color(display-p3 0.266455 0.667541 0.435918)","gitDecoration.conflictingResourceForeground":"color(display-p3 0.391345 0.215644 0.853560)","gitDecoration.modifiedResourceForeground":"color(display-p3 0.308664 0.645271 1.000000)","gitDecoration.deletedResourceForeground":"color(display-p3 0.838044 0.219378 0.220424)","gitDecoration.untrackedResourceForeground":"color(display-p3 0.266455 0.667541 0.435918)","gitDecoration.ignoredResourceForeground":"color(display-p3 0.450980 0.450980 0.450980)","merge.currentHeaderBackground":"color(display-p3 0.391345 0.215644 0.853560 / 0.200000)","merge.currentContentBackground":"color(display-p3 0.391345 0.215644 0.853560 / 0.080000)","merge.incomingHeaderBackground":"color(display-p3 0.246852 0.642335 0.817202 / 0.200000)","merge.incomingContentBackground":"color(display-p3 0.246852 0.642335 0.817202 / 0.080000)","editorOverviewRuler.currentContentForeground":"color(display-p3 0.391345 0.215644 0.853560)","editorOverviewRuler.incomingContentForeground":"color(display-p3 0.246852 0.642335 0.817202)","terminal.titleForeground":"color(display-p3 0.321569 0.321569 0.321569)","terminal.titleInactiveForeground":"color(display-p3 0.450980 0.450980 0.450980)","terminal.background":"color(display-p3 0.960784 0.960784 0.960784)","terminal.foreground":"color(display-p3 0.321569 0.321569 0.321569)","terminal.ansiBlack":"color(display-p3 0.113725 0.113725 0.113725)","terminal.ansiRed":"color(display-p3 0.838044 0.219378 0.220424)","terminal.ansiGreen":"color(display-p3 0.266455 0.667541 0.435918)","terminal.ansiYellow":"color(display-p3 0.883654 0.721037 0.210874)","terminal.ansiBlue":"color(display-p3 0.227104 0.537899 0.881328)","terminal.ansiMagenta":"color(display-p3 0.733164 0.179473 0.572580)","terminal.ansiCyan":"color(display-p3 0.246852 0.642335 0.817202)","terminal.ansiWhite":"color(display-p3 0.737255 0.737255 0.737255)","terminal.ansiBrightBlack":"color(display-p3 0.113725 0.113725 0.113725)","terminal.ansiBrightRed":"color(display-p3 0.838044 0.219378 0.220424)","terminal.ansiBrightGreen":"color(display-p3 0.516667 0.680013 0.208825)","terminal.ansiBrightYellow":"color(display-p3 0.883654 0.721037 0.210874)","terminal.ansiBrightBlue":"color(display-p3 0.227104 0.537899 0.881328)","terminal.ansiBrightMagenta":"color(display-p3 0.733164 0.179473 0.572580)","terminal.ansiBrightCyan":"color(display-p3 0.246852 0.642335 0.817202)","terminal.ansiBrightWhite":"color(display-p3 0.737255 0.737255 0.737255)"},"tokenColors":[{"scope":["comment","punctuation.definition.comment"],"settings":{"foreground":"color(display-p3 0.450980 0.450980 0.450980)"}},{"scope":"comment markup.link","settings":{"foreground":"color(display-p3 0.450980 0.450980 0.450980)"}},{"scope":["string","constant.other.symbol"],"settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":["punctuation.definition.string.begin","punctuation.definition.string.end"],"settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":["constant.numeric","constant.language.boolean"],"settings":{"foreground":"color(display-p3 0.246852 0.642335 0.817202)"}},{"scope":"constant","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"punctuation.definition.constant","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"constant.language","settings":{"foreground":"color(display-p3 0.246852 0.642335 0.817202)"}},{"scope":"variable.other.constant","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"keyword","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"keyword.control","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["storage","storage.type","storage.modifier"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"token.storage","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["keyword.operator.new","keyword.operator.expression.instanceof","keyword.operator.expression.typeof","keyword.operator.expression.void","keyword.operator.expression.delete","keyword.operator.expression.in","keyword.operator.expression.of","keyword.operator.expression.keyof"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"keyword.operator.delete","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["variable","identifier","meta.definition.variable"],"settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":["variable.other.readwrite","meta.object-literal.key","support.variable.property","support.variable.object.process","support.variable.object.node"],"settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":"variable.language","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"variable.parameter.function","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"function.parameter","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"variable.parameter","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"variable.parameter.function.language.python","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"variable.parameter.function.python","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":["support.function","entity.name.function","meta.function-call","meta.require","support.function.any-method","variable.function"],"settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"keyword.other.special-method","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"entity.name.function","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"support.function.console","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":["support.type","entity.name.type","entity.name.class","storage.type"],"settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":["support.class","entity.name.type.class"],"settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":["entity.name.class","variable.other.class.js","variable.other.class.ts"],"settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":"entity.name.class.identifier.namespace.type","settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":"entity.name.type.namespace","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"entity.other.inherited-class","settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":"entity.name.namespace","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"keyword.operator","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["keyword.operator.logical","keyword.operator.bitwise","keyword.operator.channel"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["keyword.operator.arithmetic","keyword.operator.comparison","keyword.operator.relational","keyword.operator.increment","keyword.operator.decrement"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"keyword.operator.assignment","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"keyword.operator.assignment.compound","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["keyword.operator.assignment.compound.js","keyword.operator.assignment.compound.ts"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"keyword.operator.ternary","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"keyword.operator.optional","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"punctuation","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"punctuation.separator.delimiter","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"punctuation.separator.key-value","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"punctuation.terminator","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"meta.brace","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"meta.brace.square","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"meta.brace.round","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"function.brace","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["punctuation.definition.parameters","punctuation.definition.typeparameters"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["punctuation.definition.block","punctuation.definition.tag"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["meta.tag.tsx","meta.tag.jsx","meta.tag.js","meta.tag.ts"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"keyword.operator.expression.import","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"keyword.operator.module","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"support.type.object.console","settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":["support.module.node","support.type.object.module","entity.name.type.module"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"support.constant.math","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"support.constant.property.math","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"support.constant.json","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"support.type.object.dom","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["support.variable.dom","support.variable.property.dom"],"settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":"support.variable.property.process","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"meta.property.object","settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":"variable.parameter.function.js","settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":["keyword.other.template.begin","keyword.other.template.end"],"settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":["keyword.other.substitution.begin","keyword.other.substitution.end"],"settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"meta.template.expression","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"punctuation.section.embedded","settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":"variable.interpolation","settings":{"foreground":"color(display-p3 0.854172 0.502144 0.209646)"}},{"scope":["punctuation.section.embedded.begin","punctuation.section.embedded.end"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"punctuation.quasi.element","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["support.type.primitive.ts","support.type.builtin.ts","support.type.primitive.tsx","support.type.builtin.tsx"],"settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":"support.type.type.flowtype","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"support.type.primitive","settings":{"foreground":"color(display-p3 0.660755 0.179954 0.815400)"}},{"scope":["meta.decorator","meta.decorator punctuation.decorator"],"settings":{"foreground":"color(display-p3 0.227104 0.537899 0.881328)"}},{"scope":"entity.name.function.decorator","settings":{"foreground":"color(display-p3 0.227104 0.537899 0.881328)"}},{"scope":"punctuation.definition.decorator","settings":{"foreground":"color(display-p3 0.227104 0.537899 0.881328)"}},{"scope":"support.variable.magic.python","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"variable.parameter.function.language.special.self.python","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["punctuation.separator.period.python","punctuation.separator.element.python","punctuation.parenthesis.begin.python","punctuation.parenthesis.end.python"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["punctuation.definition.arguments.begin.python","punctuation.definition.arguments.end.python","punctuation.separator.arguments.python","punctuation.definition.list.begin.python","punctuation.definition.list.end.python"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"support.type.python","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"keyword.operator.logical.python","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"meta.function-call.generic.python","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"constant.character.format.placeholder.other.python","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"meta.function.decorator.python","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":["support.token.decorator.python","meta.function.decorator.identifier.python"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"storage.modifier.lifetime.rust","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"support.function.std.rust","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"entity.name.lifetime.rust","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"variable.language.rust","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"keyword.operator.misc.rust","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"keyword.operator.sigil.rust","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"support.constant.core.rust","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":["meta.function.c","meta.function.cpp"],"settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["punctuation.section.block.begin.bracket.curly.cpp","punctuation.section.block.end.bracket.curly.cpp","punctuation.terminator.statement.c","punctuation.section.block.begin.bracket.curly.c","punctuation.section.block.end.bracket.curly.c","punctuation.section.parens.begin.bracket.round.c","punctuation.section.parens.end.bracket.round.c","punctuation.section.parameters.begin.bracket.round.c","punctuation.section.parameters.end.bracket.round.c"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["keyword.operator.assignment.c","keyword.operator.comparison.c","keyword.operator.c","keyword.operator.increment.c","keyword.operator.decrement.c","keyword.operator.bitwise.shift.c"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["keyword.operator.assignment.cpp","keyword.operator.comparison.cpp","keyword.operator.cpp","keyword.operator.increment.cpp","keyword.operator.decrement.cpp","keyword.operator.bitwise.shift.cpp"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["punctuation.separator.c","punctuation.separator.cpp"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["support.type.posix-reserved.c","support.type.posix-reserved.cpp"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["keyword.operator.sizeof.c","keyword.operator.sizeof.cpp"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"variable.c","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["storage.type.annotation.java","storage.type.object.array.java"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"source.java","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["punctuation.section.block.begin.java","punctuation.section.block.end.java","punctuation.definition.method-parameters.begin.java","punctuation.definition.method-parameters.end.java","meta.method.identifier.java","punctuation.section.method.begin.java","punctuation.section.method.end.java","punctuation.terminator.java","punctuation.section.class.begin.java","punctuation.section.class.end.java","punctuation.section.inner-class.begin.java","punctuation.section.inner-class.end.java","meta.method-call.java","punctuation.section.class.begin.bracket.curly.java","punctuation.section.class.end.bracket.curly.java","punctuation.section.method.begin.bracket.curly.java","punctuation.section.method.end.bracket.curly.java","punctuation.separator.period.java","punctuation.bracket.angle.java","punctuation.definition.annotation.java","meta.method.body.java"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"meta.method.java","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":["storage.modifier.import.java","storage.type.java","storage.type.generic.java"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"keyword.operator.instanceof.java","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"meta.definition.variable.name.java","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"token.variable.parameter.java","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"import.storage.java","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"token.package.keyword","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"token.package","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"token.storage.type.java","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"keyword.operator.assignment.go","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["keyword.operator.arithmetic.go","keyword.operator.address.go"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"entity.name.package.go","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["support.other.namespace.use.php","support.other.namespace.use-as.php","support.other.namespace.php","entity.other.alias.php","meta.interface.php"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"keyword.operator.error-control.php","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"keyword.operator.type.php","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["punctuation.section.array.begin.php","punctuation.section.array.end.php"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["storage.type.php","meta.other.type.phpdoc.php","keyword.other.type.php","keyword.other.array.phpdoc.php"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["meta.function-call.php","meta.function-call.object.php","meta.function-call.static.php"],"settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":["punctuation.definition.parameters.begin.bracket.round.php","punctuation.definition.parameters.end.bracket.round.php","punctuation.separator.delimiter.php","punctuation.section.scope.begin.php","punctuation.section.scope.end.php","punctuation.terminator.expression.php","punctuation.definition.arguments.begin.bracket.round.php","punctuation.definition.arguments.end.bracket.round.php","punctuation.definition.storage-type.begin.bracket.round.php","punctuation.definition.storage-type.end.bracket.round.php","punctuation.definition.array.begin.bracket.round.php","punctuation.definition.array.end.bracket.round.php","punctuation.definition.begin.bracket.round.php","punctuation.definition.end.bracket.round.php","punctuation.definition.begin.bracket.curly.php","punctuation.definition.end.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php","punctuation.definition.section.switch-block.start.bracket.curly.php","punctuation.definition.section.switch-block.begin.bracket.curly.php","punctuation.definition.section.switch-block.end.bracket.curly.php"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["support.constant.ext.php","support.constant.std.php","support.constant.core.php","support.constant.parser-token.php"],"settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":["entity.name.goto-label.php","support.other.php"],"settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":["keyword.operator.logical.php","keyword.operator.bitwise.php","keyword.operator.arithmetic.php"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"keyword.operator.regexp.php","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"keyword.operator.comparison.php","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["keyword.operator.heredoc.php","keyword.operator.nowdoc.php"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"variable.other.class.php","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"invalid.illegal.non-null-typehinted.php","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}},{"scope":"variable.other.generic-type.haskell","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"storage.type.haskell","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"storage.type.cs","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"entity.name.variable.local.cs","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"entity.name.label.cs","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["entity.name.scope-resolution.function.call","entity.name.scope-resolution.function.definition"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["punctuation.definition.delayed.unison","punctuation.definition.list.begin.unison","punctuation.definition.list.end.unison","punctuation.definition.ability.begin.unison","punctuation.definition.ability.end.unison","punctuation.operator.assignment.as.unison","punctuation.separator.pipe.unison","punctuation.separator.delimiter.unison","punctuation.definition.hash.unison"],"settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"support.constant.edge","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"support.type.prelude.elm","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"support.constant.elm","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"entity.global.clojure","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"meta.symbol.clojure","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"constant.keyword.clojure","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["meta.arguments.coffee","variable.parameter.function.coffee"],"settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"storage.modifier.import.groovy","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"meta.method.groovy","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"meta.definition.variable.name.groovy","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"meta.definition.class.inherited.classes.groovy","settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":"support.variable.semantic.hlsl","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["support.type.texture.hlsl","support.type.sampler.hlsl","support.type.object.hlsl","support.type.object.rw.hlsl","support.type.fx.hlsl","support.type.object.hlsl"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["text.variable","text.bracketed"],"settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["support.type.swift","support.type.vb.asp"],"settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"meta.scope.prerequisites.makefile","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"source.makefile","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"source.ini","settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":"constant.language.symbol.ruby","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["function.parameter.ruby","function.parameter.cs"],"settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"constant.language.symbol.elixir","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"entity.name.function.xi","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"entity.name.class.xi","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"constant.character.character-class.regexp.xi","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"constant.regexp.xi","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"keyword.control.xi","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"invalid.xi","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"beginning.punctuation.definition.quote.markdown.xi","settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":"beginning.punctuation.definition.list.markdown.xi","settings":{"foreground":"color(display-p3 0.450980 0.450980 0.450980)"}},{"scope":"constant.character.xi","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"accent.xi","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"wikiword.xi","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"constant.other.color.rgb-value.xi","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}},{"scope":"punctuation.definition.tag.xi","settings":{"foreground":"color(display-p3 0.450980 0.450980 0.450980)"}},{"scope":["support.constant.property-value.scss","support.constant.property-value.css"],"settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":["keyword.operator.css","keyword.operator.scss","keyword.operator.less"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":["support.constant.color.w3c-standard-color-name.css","support.constant.color.w3c-standard-color-name.scss"],"settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"punctuation.separator.list.comma.css","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"support.type.vendored.property-name.css","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"support.type.property-name.css","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"support.type.property-name","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"support.constant.property-value","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"support.constant.font-name","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"entity.other.attribute-name.class.css","settings":{"foreground":"color(display-p3 0.266455 0.667541 0.435918)","fontStyle":"normal"}},{"scope":"entity.other.attribute-name.id","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)","fontStyle":"normal"}},{"scope":["entity.other.attribute-name.pseudo-element","entity.other.attribute-name.pseudo-class"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"meta.selector","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"selector.sass","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"rgb-value","settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"inline-color-decoration rgb-value","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"less rgb-value","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"control.elements","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"keyword.operator.less","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"entity.name.tag","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"color(display-p3 0.266455 0.667541 0.435918)","fontStyle":"normal"}},{"scope":"constant.character.entity","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"meta.tag","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"invalid.illegal.bad-ampersand.html","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"markup.heading","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["markup.heading punctuation.definition.heading","entity.name.section"],"settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"entity.name.section.markdown","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"punctuation.definition.heading.markdown","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"markup.heading.setext","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":["markup.heading.setext.1.markdown","markup.heading.setext.2.markdown"],"settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["markup.bold","todo.bold"],"settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"punctuation.definition.bold","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":"punctuation.definition.bold.markdown","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":["markup.italic","punctuation.definition.italic","todo.emphasis"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)","fontStyle":"italic"}},{"scope":"emphasis md","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"markup.italic.markdown","settings":{"fontStyle":"italic"}},{"scope":["markup.underline.link.markdown","markup.underline.link.image.markdown"],"settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":["string.other.link.title.markdown","string.other.link.description.markdown"],"settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"punctuation.definition.metadata.markdown","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["markup.inline.raw.markdown","markup.inline.raw.string.markdown"],"settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":"punctuation.definition.list.begin.markdown","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"punctuation.definition.list.markdown","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"beginning.punctuation.definition.list.markdown","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["punctuation.definition.string.begin.markdown","punctuation.definition.string.end.markdown"],"settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"markup.quote.markdown","settings":{"foreground":"color(display-p3 0.450980 0.450980 0.450980)"}},{"scope":"keyword.other.unit","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"markup.changed.diff","settings":{"foreground":"color(display-p3 0.870477 0.613222 0.203432)"}},{"scope":["meta.diff.header.from-file","meta.diff.header.to-file","punctuation.definition.from-file.diff","punctuation.definition.to-file.diff"],"settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"markup.inserted.diff","settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":"markup.deleted.diff","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"string.regexp","settings":{"foreground":"color(display-p3 0.262058 0.668164 0.717478)"}},{"scope":"constant.other.character-class.regexp","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"keyword.operator.quantifier.regexp","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"constant.character.escape","settings":{"foreground":"color(display-p3 0.272343 0.688141 0.603353)"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":["source.json meta.structure.dictionary.json > value.json > string.quoted.json","source.json meta.structure.array.json > value.json > string.quoted.json","source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation","source.json meta.structure.array.json > value.json > string.quoted.json > punctuation"],"settings":{"foreground":"color(display-p3 0.259723 0.647032 0.276349)"}},{"scope":["source.json meta.structure.dictionary.json > constant.language.json","source.json meta.structure.array.json > constant.language.json"],"settings":{"foreground":"color(display-p3 0.327292 0.790977 0.995660)"}},{"scope":"support.type.property-name.json","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"support.type.property-name.json punctuation","settings":{"foreground":"color(display-p3 0.846123 0.351499 0.208754)"}},{"scope":"punctuation.definition.block.sequence.item.yaml","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"block.scope.end","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"block.scope.begin","settings":{"foreground":"color(display-p3 0.388235 0.388235 0.388235)"}},{"scope":"token.info-token","settings":{"foreground":"color(display-p3 0.391345 0.215644 0.853560)"}},{"scope":"token.warn-token","settings":{"foreground":"color(display-p3 0.883654 0.721037 0.210874)"}},{"scope":"token.error-token","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}},{"scope":"token.debug-token","settings":{"foreground":"color(display-p3 0.834880 0.207921 0.387456)"}},{"scope":"invalid.illegal","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}},{"scope":"invalid.broken","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}},{"scope":"invalid.deprecated","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}},{"scope":"invalid.unimplemented","settings":{"foreground":"color(display-p3 0.039216 0.039216 0.039216)"}}],"semanticTokenColors":{"comment":"color(display-p3 0.450980 0.450980 0.450980)","string":"color(display-p3 0.259723 0.647032 0.276349)","number":"color(display-p3 0.246852 0.642335 0.817202)","regexp":"color(display-p3 0.262058 0.668164 0.717478)","keyword":"color(display-p3 0.834880 0.207921 0.387456)","variable":"color(display-p3 0.854172 0.502144 0.209646)","parameter":"color(display-p3 0.388235 0.388235 0.388235)","property":"color(display-p3 0.854172 0.502144 0.209646)","function":"color(display-p3 0.391345 0.215644 0.853560)","method":"color(display-p3 0.391345 0.215644 0.853560)","type":"color(display-p3 0.660755 0.179954 0.815400)","class":"color(display-p3 0.660755 0.179954 0.815400)","namespace":"color(display-p3 0.870477 0.613222 0.203432)","enumMember":"color(display-p3 0.327292 0.790977 0.995660)","variable.constant":"color(display-p3 0.883654 0.721037 0.210874)","variable.defaultLibrary":"color(display-p3 0.870477 0.613222 0.203432)","decorator":"color(display-p3 0.227104 0.537899 0.881328)"}}'));export{o as default}; diff --git a/apps/kimi-code/dist-web/assets/prisma-Dd19v3D-.js b/apps/kimi-code/dist-web/assets/prisma-Dd19v3D-.js new file mode 100644 index 0000000000000000000000000000000000000000..0cd402e3732ffc443181b13232b49bcef83966c0 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/prisma-Dd19v3D-.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse('{"displayName":"Prisma","fileTypes":["prisma"],"name":"prisma","patterns":[{"include":"#triple_comment"},{"include":"#double_comment"},{"include":"#multi_line_comment"},{"include":"#model_block_definition"},{"include":"#config_block_definition"},{"include":"#enum_block_definition"},{"include":"#type_definition"}],"repository":{"array":{"begin":"\\\\[","beginCaptures":{"1":{"name":"punctuation.definition.tag.prisma"}},"end":"]","endCaptures":{"1":{"name":"punctuation.definition.tag.prisma"}},"name":"source.prisma.array","patterns":[{"include":"#value"}]},"assignment":{"patterns":[{"begin":"^\\\\s*(\\\\w+)\\\\s*(=)\\\\s*","beginCaptures":{"1":{"name":"variable.other.assignment.prisma"},"2":{"name":"keyword.operator.terraform"}},"end":"\\\\n","patterns":[{"include":"#value"},{"include":"#double_comment_inline"}]}]},"attribute":{"captures":{"1":{"name":"entity.name.function.attribute.prisma"}},"match":"(@@?[.\\\\w]+)","name":"source.prisma.attribute"},"attribute_with_arguments":{"begin":"(@@?[.\\\\w]+)(\\\\()","beginCaptures":{"1":{"name":"entity.name.function.attribute.prisma"},"2":{"name":"punctuation.definition.tag.prisma"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.tag.prisma"}},"name":"source.prisma.attribute.with_arguments","patterns":[{"include":"#named_argument"},{"include":"#value"}]},"boolean":{"match":"\\\\b(true|false)\\\\b","name":"constant.language.boolean.prisma"},"config_block_definition":{"begin":"^\\\\s*(generator|datasource)\\\\s+([A-Za-z]\\\\w*)\\\\s+(\\\\{)","beginCaptures":{"1":{"name":"storage.type.config.prisma"},"2":{"name":"entity.name.type.config.prisma"},"3":{"name":"punctuation.definition.tag.prisma"}},"end":"\\\\s*}","endCaptures":{"1":{"name":"punctuation.definition.tag.prisma"}},"name":"source.prisma.embedded.source","patterns":[{"include":"#triple_comment"},{"include":"#double_comment"},{"include":"#multi_line_comment"},{"include":"#assignment"}]},"double_comment":{"begin":"//","end":"$\\\\n?","name":"comment.prisma"},"double_comment_inline":{"match":"//[^\\\\n]*","name":"comment.prisma"},"double_quoted_string":{"begin":"\\"","beginCaptures":{"0":{"name":"string.quoted.double.start.prisma"}},"end":"\\"","endCaptures":{"0":{"name":"string.quoted.double.end.prisma"}},"name":"unnamed","patterns":[{"include":"#string_interpolation"},{"match":"([-%./:=?@\\\\\\\\_\\\\w]+)","name":"string.quoted.double.prisma"}]},"enum_block_definition":{"begin":"^\\\\s*(enum)\\\\s+([A-Za-z]\\\\w*)\\\\s+(\\\\{)","beginCaptures":{"1":{"name":"storage.type.enum.prisma"},"2":{"name":"entity.name.type.enum.prisma"},"3":{"name":"punctuation.definition.tag.prisma"}},"end":"\\\\s*}","endCaptures":{"0":{"name":"punctuation.definition.tag.prisma"}},"name":"source.prisma.embedded.source","patterns":[{"include":"#triple_comment"},{"include":"#double_comment"},{"include":"#multi_line_comment"},{"include":"#enum_value_definition"}]},"enum_value_definition":{"patterns":[{"captures":{"1":{"name":"variable.other.assignment.prisma"}},"match":"^\\\\s*(\\\\w+)\\\\s*"},{"include":"#attribute_with_arguments"},{"include":"#attribute"}]},"field_definition":{"name":"scalar.field","patterns":[{"captures":{"1":{"name":"variable.other.assignment.prisma"},"2":{"name":"invalid.illegal.colon.prisma"},"3":{"name":"variable.language.relations.prisma"},"4":{"name":"support.type.primitive.prisma"},"5":{"name":"keyword.operator.list_type.prisma"},"6":{"name":"keyword.operator.optional_type.prisma"},"7":{"name":"invalid.illegal.required_type.prisma"}},"match":"^\\\\s*(\\\\w+)(\\\\s*:)?\\\\s+((?!(?:Int|BigInt|String|DateTime|Bytes|Decimal|Float|Json|Boolean)\\\\b)\\\\b\\\\w+)?(Int|BigInt|String|DateTime|Bytes|Decimal|Float|Json|Boolean)?(\\\\[])?(\\\\?)?(!)?"},{"include":"#attribute_with_arguments"},{"include":"#attribute"}]},"functional":{"begin":"(\\\\w+)(\\\\()","beginCaptures":{"1":{"name":"support.function.functional.prisma"},"2":{"name":"punctuation.definition.tag.prisma"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.tag.prisma"}},"name":"source.prisma.functional","patterns":[{"include":"#value"}]},"identifier":{"patterns":[{"match":"\\\\b(\\\\w)+\\\\b","name":"support.constant.constant.prisma"}]},"literal":{"name":"source.prisma.literal","patterns":[{"include":"#boolean"},{"include":"#number"},{"include":"#double_quoted_string"},{"include":"#identifier"}]},"map_key":{"name":"source.prisma.key","patterns":[{"captures":{"1":{"name":"variable.parameter.key.prisma"},"2":{"name":"punctuation.definition.separator.key-value.prisma"}},"match":"(\\\\w+)\\\\s*(:)\\\\s*"}]},"model_block_definition":{"begin":"^\\\\s*(model|type|view)\\\\s+([A-Za-z]\\\\w*)\\\\s*(\\\\{)","beginCaptures":{"1":{"name":"storage.type.model.prisma"},"2":{"name":"entity.name.type.model.prisma"},"3":{"name":"punctuation.definition.tag.prisma"}},"end":"\\\\s*}","endCaptures":{"0":{"name":"punctuation.definition.tag.prisma"}},"name":"source.prisma.embedded.source","patterns":[{"include":"#triple_comment"},{"include":"#double_comment"},{"include":"#multi_line_comment"},{"include":"#field_definition"}]},"multi_line_comment":{"begin":"/\\\\*","end":"\\\\*/","name":"comment.prisma"},"named_argument":{"name":"source.prisma.named_argument","patterns":[{"include":"#map_key"},{"include":"#value"}]},"number":{"match":"((0([Xx])\\\\h*)|([-+])?\\\\b(([0-9]+\\\\.?[0-9]*)|(\\\\.[0-9]+))(([Ee])([-+])?[0-9]+)?)([DFLUdfglu]|UL|ul)?\\\\b","name":"constant.numeric.prisma"},"string_interpolation":{"patterns":[{"begin":"\\\\$\\\\{","beginCaptures":{"0":{"name":"keyword.control.interpolation.start.prisma"}},"end":"\\\\s*}","endCaptures":{"0":{"name":"keyword.control.interpolation.end.prisma"}},"name":"source.tag.embedded.source.prisma","patterns":[{"include":"#value"}]}]},"triple_comment":{"begin":"///","end":"$\\\\n?","name":"comment.prisma"},"type_definition":{"patterns":[{"captures":{"1":{"name":"storage.type.type.prisma"},"2":{"name":"entity.name.type.type.prisma"},"3":{"name":"support.type.primitive.prisma"}},"match":"^\\\\s*(type)\\\\s+(\\\\w+)\\\\s*=\\\\s*(\\\\w+)"},{"include":"#attribute_with_arguments"},{"include":"#attribute"}]},"value":{"name":"source.prisma.value","patterns":[{"include":"#array"},{"include":"#functional"},{"include":"#literal"}]}},"scopeName":"source.prisma"}')),n=[e];export{n as default}; diff --git a/apps/kimi-code/dist-web/assets/proto-C7zT0LnQ.js b/apps/kimi-code/dist-web/assets/proto-C7zT0LnQ.js new file mode 100644 index 0000000000000000000000000000000000000000..40d8ad50828e4202a45c792597c4613503858a83 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/proto-C7zT0LnQ.js @@ -0,0 +1 @@ +const e=Object.freeze(JSON.parse(`{"displayName":"Protocol Buffer 3","fileTypes":["proto"],"name":"proto","patterns":[{"include":"#comments"},{"include":"#syntax"},{"include":"#package"},{"include":"#import"},{"include":"#optionStmt"},{"include":"#message"},{"include":"#enum"},{"include":"#service"}],"repository":{"comments":{"patterns":[{"begin":"/\\\\*","end":"\\\\*/","name":"comment.block.proto"},{"begin":"//","end":"$\\\\n?","name":"comment.line.double-slash.proto"}]},"constants":{"match":"\\\\b(true|false|max|[A-Z_]+)\\\\b","name":"constant.language.proto"},"enum":{"begin":"(enum)(\\\\s+)([A-Za-z][0-9A-Z_a-z]*)(\\\\s*)(\\\\{)?","beginCaptures":{"1":{"name":"keyword.other.proto"},"3":{"name":"entity.name.class.proto"}},"end":"}","patterns":[{"include":"#reserved"},{"include":"#optionStmt"},{"include":"#comments"},{"begin":"([A-Za-z][0-9A-Z_a-z]*)\\\\s*(=)\\\\s*(-?0[Xx]\\\\h+|-?[0-9]+)","beginCaptures":{"1":{"name":"variable.other.proto"},"2":{"name":"keyword.operator.assignment.proto"},"3":{"name":"constant.numeric.proto"}},"end":"(;)","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"include":"#fieldOptions"}]}]},"field":{"begin":"\\\\s*(optional|repeated|required)?\\\\s*(\\\\.?[.\\\\w]+)\\\\s+(\\\\w+)\\\\s*(=)\\\\s*(0[Xx]\\\\h+|[0-9]+)","beginCaptures":{"1":{"name":"storage.modifier.proto"},"2":{"name":"storage.type.proto"},"3":{"name":"variable.other.proto"},"4":{"name":"keyword.operator.assignment.proto"},"5":{"name":"constant.numeric.proto"}},"end":"(;)","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"include":"#fieldOptions"}]},"fieldOptions":{"begin":"\\\\[","end":"]","patterns":[{"include":"#constants"},{"include":"#number"},{"include":"#string"},{"include":"#subMsgOption"},{"include":"#optionName"}]},"ident":{"match":"\\\\.?[A-Za-z][.0-9A-Z_a-z]*","name":"entity.name.class.proto"},"import":{"captures":{"1":{"name":"keyword.other.proto"},"2":{"name":"keyword.other.proto"},"3":{"name":"string.quoted.double.proto.import"},"4":{"name":"punctuation.terminator.proto"}},"match":"\\\\s*(import)\\\\s+(weak|public)?\\\\s*(\\"[^\\"]+\\")\\\\s*(;)"},"kv":{"begin":"(\\\\w+)\\\\s*(:)","beginCaptures":{"1":{"name":"keyword.other.proto"},"2":{"name":"punctuation.separator.key-value.proto"}},"end":"(;)|,|(?=[/A-Z_a-z}])","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"include":"#constants"},{"include":"#number"},{"include":"#string"},{"include":"#subMsgOption"}]},"mapfield":{"begin":"\\\\s*(map)\\\\s*(<)\\\\s*(\\\\.?[.\\\\w]+)\\\\s*,\\\\s*(\\\\.?[.\\\\w]+)\\\\s*(>)\\\\s+(\\\\w+)\\\\s*(=)\\\\s*(\\\\d+)","beginCaptures":{"1":{"name":"storage.type.proto"},"2":{"name":"punctuation.definition.typeparameters.begin.proto"},"3":{"name":"storage.type.proto"},"4":{"name":"storage.type.proto"},"5":{"name":"punctuation.definition.typeparameters.end.proto"},"6":{"name":"variable.other.proto"},"7":{"name":"keyword.operator.assignment.proto"},"8":{"name":"constant.numeric.proto"}},"end":"(;)","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"include":"#fieldOptions"}]},"message":{"begin":"(message|extend)(\\\\s+)([A-Z_a-z][.0-9A-Z_a-z]*)(\\\\s*)(\\\\{)?","beginCaptures":{"1":{"name":"keyword.other.proto"},"3":{"name":"entity.name.class.message.proto"}},"end":"}","patterns":[{"include":"#reserved"},{"include":"$self"},{"include":"#enum"},{"include":"#optionStmt"},{"include":"#comments"},{"include":"#oneof"},{"include":"#field"},{"include":"#mapfield"}]},"method":{"begin":"(rpc)\\\\s+([A-Za-z][0-9A-Z_a-z]*)","beginCaptures":{"1":{"name":"keyword.other.proto"},"2":{"name":"entity.name.function"}},"end":"}|(;)","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"include":"#comments"},{"include":"#optionStmt"},{"include":"#rpcKeywords"},{"include":"#ident"}]},"number":{"match":"\\\\b((0([Xx])\\\\h*)|(([0-9]+\\\\.?[0-9]*)|(\\\\.[0-9]+))(([Ee])([-+])?[0-9]+)?)\\\\b","name":"constant.numeric.proto"},"oneof":{"begin":"(oneof)\\\\s+([A-Za-z][0-9A-Z_a-z]*)\\\\s*\\\\{?","beginCaptures":{"1":{"name":"keyword.other.proto"},"2":{"name":"variable.other.proto"}},"end":"}","patterns":[{"include":"#optionStmt"},{"include":"#comments"},{"include":"#field"}]},"optionName":{"captures":{"1":{"name":"support.other.proto"},"2":{"name":"support.other.proto"},"3":{"name":"support.other.proto"}},"match":"(\\\\w+|\\\\(\\\\w+(\\\\.\\\\w+)*\\\\))(\\\\.\\\\w+)*"},"optionStmt":{"begin":"(option)\\\\s+(\\\\w+|\\\\(\\\\w+(\\\\.\\\\w+)*\\\\))(\\\\.\\\\w+)*\\\\s*(=)","beginCaptures":{"1":{"name":"keyword.other.proto"},"2":{"name":"support.other.proto"},"3":{"name":"support.other.proto"},"4":{"name":"support.other.proto"},"5":{"name":"keyword.operator.assignment.proto"}},"end":"(;)","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"include":"#constants"},{"include":"#number"},{"include":"#string"},{"include":"#subMsgOption"}]},"package":{"captures":{"1":{"name":"keyword.other.proto"},"2":{"name":"string.unquoted.proto.package"},"3":{"name":"punctuation.terminator.proto"}},"match":"\\\\s*(package)\\\\s+([.\\\\w]+)\\\\s*(;)"},"reserved":{"begin":"(reserved)\\\\s+","beginCaptures":{"1":{"name":"keyword.other.proto"}},"end":"(;)","endCaptures":{"1":{"name":"punctuation.terminator.proto"}},"patterns":[{"captures":{"1":{"name":"constant.numeric.proto"},"3":{"name":"keyword.other.proto"},"4":{"name":"constant.numeric.proto"}},"match":"(\\\\d+)(\\\\s+(to)\\\\s+(\\\\d+))?"},{"include":"#string"}]},"rpcKeywords":{"match":"\\\\b(stream|returns)\\\\b","name":"keyword.other.proto"},"service":{"begin":"(service)\\\\s+([A-Za-z][.0-9A-Z_a-z]*)\\\\s*\\\\{?","beginCaptures":{"1":{"name":"keyword.other.proto"},"2":{"name":"entity.name.class.message.proto"}},"end":"}","patterns":[{"include":"#comments"},{"include":"#optionStmt"},{"include":"#method"}]},"storagetypes":{"match":"\\\\b(double|float|int32|int64|uint32|uint64|sint32|sint64|fixed32|fixed64|sfixed32|sfixed64|bool|string|bytes)\\\\b","name":"storage.type.proto"},"string":{"match":"([\\"'])(?:\\\\\\\\.|[^\\\\\\\\])*?\\\\1","name":"string.quoted.double.proto"},"subMsgOption":{"begin":"\\\\{","end":"}","patterns":[{"include":"#kv"},{"include":"#comments"}]},"syntax":{"captures":{"1":{"name":"keyword.other.proto"},"2":{"name":"keyword.operator.assignment.proto"},"3":{"name":"string.quoted.double.proto.syntax"},"4":{"name":"punctuation.terminator.proto"}},"match":"\\\\s*(syntax)\\\\s*(=)\\\\s*(\\"proto[23]\\")\\\\s*(;)"}},"scopeName":"source.proto","aliases":["protobuf"]}`)),t=[e];export{t as default}; diff --git a/apps/kimi-code/dist-web/assets/pug-DKIMFp6K.js b/apps/kimi-code/dist-web/assets/pug-DKIMFp6K.js new file mode 100644 index 0000000000000000000000000000000000000000..3a3b2ade0d275bb35c5d0b7fe5d09643bcccaa58 --- /dev/null +++ b/apps/kimi-code/dist-web/assets/pug-DKIMFp6K.js @@ -0,0 +1 @@ +import e from"./javascript-wDzz0qaB.js";import n from"./css-CLj8gQPS.js";import t from"./html-pp8916En.js";const a=Object.freeze(JSON.parse(`{"displayName":"Pug","name":"pug","patterns":[{"match":"^(!!!|doctype)(\\\\s*[-0-9A-Z_a-z]+)?","name":"meta.tag.sgml.doctype.html"},{"begin":"^(\\\\s*)//-","end":"^(?!(\\\\1\\\\s)|\\\\s*$)","name":"comment.unbuffered.block.pug"},{"begin":"^(\\\\s*)//","end":"^(?!(\\\\1\\\\s)|\\\\s*$)","name":"string.comment.buffered.block.pug","patterns":[{"captures":{"1":{"name":"invalid.illegal.comment.comment.block.pug"}},"match":"^\\\\s*(//)(?!-)","name":"string.comment.buffered.block.pug"}]},{"begin":"","endCaptures":{"0":{"name":"punctuation.definition.comment.html"}},"name":"comment.block.html"},"html-template":{"begin":"^(templ) ((?:\\\\((?:[A-Z_a-z][0-9A-Z_a-z]*\\\\s+\\\\*?[A-Z_a-z][0-9A-Z_a-z]*|\\\\*?[A-Z_a-z][0-9A-Z_a-z]*)\\\\)\\\\s*)?[A-Z_a-z][0-9A-Z_a-z]*([(\\\\[]))","beginCaptures":{"1":{"name":"keyword.control.go"},"2":{"patterns":[{"include":"source.go"}]}},"end":"(?<=^}$)","name":"html-template.templ","patterns":[{"begin":"(?<=\\\\()","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.round.go"}},"name":"params.html-template.templ","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\[)","end":"(])","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.square.go"}},"name":"type-params.html-template.templ","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\))\\\\s*(\\\\{)$","beginCaptures":{"1":{"name":"punctuation.definition.begin.bracket.curly.go"}},"end":"^(})$","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.curly.go"}},"name":"block.html-template.templ","patterns":[{"include":"#template-node"}]}]},"if-expression":{"begin":"^\\\\s*(if)\\\\s","beginCaptures":{"1":{"name":"keyword.control.go"}},"end":"(?<=})","name":"if.html-template.templ","patterns":[{"begin":"(?<=if\\\\s)","end":"(\\\\{)$","endCaptures":{"1":{"name":"punctuation.definition.begin.bracket.curly.go"}},"name":"expression.if.html-template.templ","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\{)$","end":"^\\\\s*(})","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.curly.go"}},"name":"block.if.html-template.templ","patterns":[{"include":"#template-node"}]}]},"import-expression":{"patterns":[{"begin":"(@)((?:[A-z][0-9A-z]*\\\\.)?[A-z][0-9A-z]*(?:[({]|$))","beginCaptures":{"1":{"name":"keyword.control.go"},"2":{"patterns":[{"include":"source.go"}]}},"end":"(?<=\\\\))$|(?<=})$|(?<=$)","name":"import-expression.templ","patterns":[{"begin":"(?<=[0-9A-z]\\\\{)","end":"\\\\s*(})(\\\\.[A-z][0-9A-z]*\\\\()","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.curly.go"},"2":{"patterns":[{"include":"source.go"}]}},"name":"struct-method.import-expression.templ","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\()","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.round.go"}},"name":"params.import-expression.templ","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\))\\\\s(\\\\{)$","beginCaptures":{"1":{"name":"punctuation.brace.open"}},"end":"^\\\\s*(})$","endCaptures":{"1":{"name":"punctuation.brace.close"}},"name":"children.import-expression.templ","patterns":[{"include":"#template-node"}]}]}]},"inline-element":{"begin":"(\\\\\\\\\\\\s]))","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.inline.any.html"}},"end":"((?: ?/)?>)","endCaptures":{"1":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.inline.any.html","patterns":[{"include":"#tag-stuff"}]},"raw-go":{"begin":"\\\\{\\\\{","beginCaptures":{"0":{"name":"start.raw-go.templ"},"1":{"name":"punctuation.brace.open"}},"end":"}}","endCaptures":{"0":{"name":"end.raw-go.templ"},"1":{"name":"punctuation.brace.open"}},"name":"raw-go.templ","patterns":[{"include":"source.go"}]},"script-element":{"begin":"(<)(script)([^>]*)(>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#tag-stuff"}]},"4":{"name":"punctuation.definition.tag.html"}},"end":"<\/script>","endCaptures":{"0":{"patterns":[{"include":"#close-element"}]}},"name":"meta.tag.script.html","patterns":[{"include":"source.js"}]},"script-template":{"begin":"^(script) ([A-z][0-9A-z]*\\\\()","beginCaptures":{"1":{"name":"keyword.control.go"},"2":{"patterns":[{"include":"source.go"}]}},"end":"(?<=^}$)","name":"script-template.templ","patterns":[{"begin":"(?<=\\\\()","end":"(\\\\))","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.round.go"}},"name":"params.script-template.templ","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\))\\\\s*(\\\\{)$","beginCaptures":{"1":{"name":"punctuation.definition.begin.bracket.curly.go"}},"end":"^(})$","endCaptures":{"1":{"name":"punctuation.definition.end.bracket.curly.go"}},"name":"block.script-template.templ","patterns":[{"include":"source.js"}]}]},"sgml":{"begin":"","name":"meta.tag.sgml.html","patterns":[{"begin":"(?i:DOCTYPE)","captures":{"1":{"name":"entity.name.tag.doctype.html"}},"end":"(?=>)","name":"meta.tag.sgml.doctype.html","patterns":[{"match":"\\"[^\\">]*\\"","name":"string.quoted.double.doctype.identifiers-and-DTDs.html"}]},{"begin":"\\\\[CDATA\\\\[","end":"]](?=>)","name":"constant.other.inline-data.html"},{"match":"(\\\\s*)(?!--|>)\\\\S(\\\\s*)","name":"invalid.illegal.bad-comments-or-CDATA.html"}]},"string-double-quoted":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.html"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.html"}},"name":"string.quoted.double.html","patterns":[{"include":"#entities"}]},"string-expression":{"begin":"\\\\{\\\\s+","beginCaptures":{"0":{"name":"start.string-expression.templ"}},"end":"}","endCaptures":{"0":{"name":"end.string-expression.templ"}},"name":"expression.html-template.templ","patterns":[{"include":"source.go"}]},"style-element":{"begin":"(<)(style)([^>]*)(>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.html"},"2":{"name":"entity.name.tag.html"},"3":{"patterns":[{"include":"#tag-stuff"}]},"4":{"name":"punctuation.definition.tag.html"}},"end":"","endCaptures":{"0":{"patterns":[{"include":"#close-element"}]}},"name":"meta.tag.style.html","patterns":[{"include":"source.css"}]},"switch-expression":{"begin":"^\\\\s*switch .+?\\\\{$","captures":{"0":{"name":"meta.embedded.block.go","patterns":[{"include":"source.go"}]}},"end":"^\\\\s*}$","name":"switch.html-template.templ","patterns":[{"include":"#template-node"},{"include":"#case-expression"},{"include":"#default-expression"}]},"tag-else-attribute":{"begin":"\\\\s(else)\\\\s(\\\\{)$","beginCaptures":{"1":{"name":"keyword.control.go"},"2":{"name":"punctuation.brace.open"}},"end":"^\\\\s*(})$","endCaptures":{"1":{"name":"punctuation.brace.close"}},"name":"else.attribute.html","patterns":[{"include":"#tag-stuff"}]},"tag-else-if-attribute":{"begin":"\\\\s(else if)\\\\s","beginCaptures":{"1":{"name":"keyword.control.go"}},"end":"(?<=})","name":"else-if.attribute.html","patterns":[{"begin":"(?<=if\\\\s)","end":"(\\\\{)$","endCaptures":{"1":{"name":"punctuation.brace.open"}},"name":"expression.else-if.attribute.html","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\{)$","end":"^\\\\s*(})","endCaptures":{"1":{"name":"punctuation.brace.close"}},"name":"block.else-if.attribute.html","patterns":[{"include":"#tag-stuff"}]}]},"tag-generic-attribute":{"match":"(?<=[^=])\\\\b([-0-:A-Za-z]+)","name":"entity.other.attribute-name.html"},"tag-id-attribute":{"begin":"\\\\b(id)\\\\b\\\\s*(=)","captures":{"1":{"name":"entity.other.attribute-name.id.html"},"2":{"name":"punctuation.separator.key-value.html"}},"end":"(?!\\\\G)(?<=[\\"'[^/<>\\\\s]])","name":"meta.attribute-with-value.id.html","patterns":[{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.html"}},"contentName":"meta.toc-list.id.html","end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.html"}},"name":"string.quoted.double.html","patterns":[{"include":"#entities"}]},{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.html"}},"contentName":"meta.toc-list.id.html","end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.html"}},"name":"string.quoted.single.html","patterns":[{"include":"#entities"}]},{"captures":{"0":{"name":"meta.toc-list.id.html"}},"match":"(?<==)(?:[^\\"'/<>{}\\\\s]|/(?!>))+","name":"string.unquoted.html"}]},"tag-if-attribute":{"begin":"^\\\\s*(if)\\\\s","beginCaptures":{"1":{"name":"keyword.control.go"}},"end":"(?<=})","name":"if.attribute.html","patterns":[{"begin":"(?<=if\\\\s)","end":"(\\\\{)$","endCaptures":{"1":{"name":"punctuation.brace.open"}},"name":"expression.if.attribute.html","patterns":[{"include":"source.go"}]},{"begin":"(?<=\\\\{)$","end":"^\\\\s*(})","endCaptures":{"1":{"name":"punctuation.brace.close"}},"name":"block.if.attribute.html","patterns":[{"include":"#tag-stuff"}]}]},"tag-stuff":{"patterns":[{"include":"#tag-id-attribute"},{"include":"#tag-generic-attribute"},{"include":"#string-double-quoted"},{"include":"#string-expression"},{"include":"#tag-if-attribute"},{"include":"#tag-else-if-attribute"},{"include":"#tag-else-attribute"}]},"template-node":{"patterns":[{"include":"#string-expression"},{"include":"#call-expression"},{"include":"#import-expression"},{"include":"#script-element"},{"include":"#style-element"},{"include":"#element"},{"include":"#html-comment"},{"include":"#go-comment-block"},{"include":"#go-comment-double-slash"},{"include":"#sgml"},{"include":"#block-element"},{"include":"#inline-element"},{"include":"#close-element"},{"include":"#else-if-expression"},{"include":"#if-expression"},{"include":"#else-expression"},{"include":"#for-expression"},{"include":"#switch-expression"},{"include":"#raw-go"}]}},"scopeName":"source.templ","embeddedLangs":["go","javascript","css"]}`)),s=[...e,...t,...n,i];export{s as default}; diff --git a/apps/kimi-code/dist-web/assets/twig-CW1WmMYd.js b/apps/kimi-code/dist-web/assets/twig-CW1WmMYd.js new file mode 100644 index 0000000000000000000000000000000000000000..e396e5cc78d0c2eb060e5527d5f8818c8a94516c --- /dev/null +++ b/apps/kimi-code/dist-web/assets/twig-CW1WmMYd.js @@ -0,0 +1 @@ +import t from"./css-CLj8gQPS.js";import e from"./javascript-wDzz0qaB.js";import n from"./scss-D5BDwBP9.js";import i from"./php-Csjmro_R.js";import a from"./python-B6aJPvgy.js";import s from"./ruby-DyJCeAvU.js";import"./html-pp8916En.js";import"./xml-sdJ4AIDG.js";import"./java-CylS5w8V.js";import"./sql-CRqJ_cUM.js";import"./json-Cp-IABpG.js";import"./haml-D5jkg6IW.js";import"./graphql-ChdNCCLP.js";import"./typescript-BPQ3VLAy.js";import"./jsx-g9-lgVsj.js";import"./tsx-COt5Ahok.js";import"./cpp-UfJy6YNI.js";import"./regexp-CDVJQ6XC.js";import"./glsl-DplSGwfg.js";import"./c-BIGW1oBm.js";import"./shellscript-Yzrsuije.js";import"./lua-BaeVxFsk.js";import"./yaml-Buea-lGh.js";const r=Object.freeze(JSON.parse(`{"displayName":"Twig","fileTypes":["twig","html.twig"],"firstLineMatch":"|)$|\\\\{%\\\\s+(autoescape|block|embed|filter|for|if|macro|raw|sandbox|set|spaceless|trans|verbatim))","foldingStopMarker":"(|^(?!.*?$|\\\\{%\\\\s+end(autoescape|block|embed|filter|for|if|macro|raw|sandbox|set|spaceless|trans|verbatim))","name":"twig","patterns":[{"begin":"(<)([0-:A-Za-z]++)(?=[^>]*>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.html"},"2":{"name":"entity.name.tag.html"}},"end":"(>(<)/)(\\\\2)(>)","endCaptures":{"1":{"name":"punctuation.definition.tag.html"},"2":{"name":"meta.scope.between-tag-pair.html"},"3":{"name":"entity.name.tag.html"},"4":{"name":"punctuation.definition.tag.html"}},"name":"meta.tag.any.html","patterns":[{"include":"#tag-stuff"}]},{"begin":"(<\\\\?)(xml)","captures":{"1":{"name":"punctuation.definition.tag.html"},"2":{"name":"entity.name.tag.xml.html"}},"end":"(\\\\?>)","name":"meta.tag.preprocessor.xml.html","patterns":[{"include":"#tag-generic-attribute"},{"include":"#string-double-quoted"},{"include":"#string-single-quoted"}]},{"begin":" + com.apple.security.cs.allow-jit + + + + com.apple.security.cs.allow-unsigned-executable-memory + + + + com.apple.security.cs.disable-library-validation + + + + com.apple.security.cs.allow-dyld-environment-variables + + + diff --git a/apps/kimi-code/scripts/native/exec.mjs b/apps/kimi-code/scripts/native/exec.mjs new file mode 100644 index 0000000000000000000000000000000000000000..03ebe5b0c17f4c4006e6189028d7697e497de139 --- /dev/null +++ b/apps/kimi-code/scripts/native/exec.mjs @@ -0,0 +1,61 @@ +import { execFile } from 'node:child_process'; +import { basename } from 'node:path'; +import { promisify } from 'node:util'; + +import { appRoot } from './paths.mjs'; + +const execFileAsync = promisify(execFile); + +export function commandForExecFile(command, args, platform = process.platform, env = process.env) { + if (platform !== 'win32' || !/\.(?:bat|cmd)$/i.test(command)) { + return { command, args }; + } + const shellCommand = [command, ...args] + .map((arg) => `"${String(arg).replaceAll('"', '""')}"`) + .join(' '); + return { + command: env.ComSpec ?? 'cmd.exe', + args: ['/d', '/s', '/c', `"${shellCommand}"`], + options: { windowsVerbatimArguments: true }, + }; +} + +export function fail(message) { + console.error(message); + process.exit(1); +} + +export async function run(command, args, options = {}) { + const exec = commandForExecFile(command, args); + try { + const { stdout, stderr } = await execFileAsync(exec.command, exec.args, { + cwd: appRoot, + maxBuffer: 1024 * 1024 * 16, + ...exec.options, + ...options, + }); + if (stdout.trim()) console.log(stdout.trim()); + if (stderr.trim()) console.error(stderr.trim()); + } catch (error) { + const details = [error.stdout?.trim(), error.stderr?.trim(), error.message] + .filter(Boolean) + .join('\n'); + fail(`Command failed: ${basename(command)} ${args.join(' ')}\n${details}`); + } +} + +export async function tryRun(command, args, options = {}) { + const exec = commandForExecFile(command, args); + try { + await execFileAsync(exec.command, exec.args, { + cwd: appRoot, + maxBuffer: 1024 * 1024 * 16, + ...exec.options, + }); + } catch (error) { + const details = [error.stdout?.trim(), error.stderr?.trim(), error.message] + .filter(Boolean) + .join('\n'); + console.warn(`Warning: ${basename(command)} ${args.join(' ')} failed.\n${details}`); + } +} diff --git a/apps/kimi-code/scripts/native/manifest.mjs b/apps/kimi-code/scripts/native/manifest.mjs new file mode 100644 index 0000000000000000000000000000000000000000..99f3b3a3d16e516df4c4985a42d048488a67e3f8 --- /dev/null +++ b/apps/kimi-code/scripts/native/manifest.mjs @@ -0,0 +1,38 @@ +export const NATIVE_ASSET_MANIFEST_VERSION = 2; +export const WEB_ASSET_MANIFEST_VERSION = 1; + +export const MINIDB_TEXT_BUILD_WORKER_ASSET = Object.freeze({ + key: 'minidb-text-build-worker', + relativePath: 'runtime/minidb/text-build-worker.mjs', + mode: 0o644, +}); + +export const KAP_SEARCH_WORKER_ASSET = Object.freeze({ + key: 'kap-search-worker', + relativePath: 'runtime/kap-server/search-worker.mjs', + mode: 0o644, +}); + +export function buildManifestKey(target) { + return `native/${target}/manifest.json`; +} + +export function buildRuntimeAssetKey(target, key) { + return `native/${target}/runtime/${key}`; +} + +export function isManifestVersionSupported(version) { + return version === NATIVE_ASSET_MANIFEST_VERSION; +} + +export function buildAssetKey(target, packageRoot, relativePath) { + return `native/${target}/${packageRoot}/${relativePath}`; +} + +export function buildWebManifestKey(target) { + return `web/${target}/manifest.json`; +} + +export function buildWebAssetKey(target, relativePath) { + return `web/${target}/dist-web/${relativePath}`; +} diff --git a/apps/kimi-code/scripts/native/native-deps.mjs b/apps/kimi-code/scripts/native/native-deps.mjs new file mode 100644 index 0000000000000000000000000000000000000000..273f3386e52503b909f7d652585ae89bbe06ff21 --- /dev/null +++ b/apps/kimi-code/scripts/native/native-deps.mjs @@ -0,0 +1,105 @@ +/** + * Native dependency registry. + * + * Each entry describes one native-bearing npm package: how to resolve its + * install root, what to collect (JS only / native binary only / both), and + * which other registered dep it nests under (for `pnpm`-style nested resolves). + * + * Adding a new native package = appending one object here. No edits to + * NATIVE_TARGETS table or resolvePackageRoot if/else chain. + */ + +export const SUPPORTED_TARGETS = Object.freeze([ + 'darwin-arm64', + 'darwin-x64', + 'linux-arm64', + 'linux-x64', + 'win32-arm64', + 'win32-x64', +]); + +const clipboardSubpackageByTarget = Object.freeze({ + 'darwin-arm64': '@mariozechner/clipboard-darwin-arm64', + 'darwin-x64': '@mariozechner/clipboard-darwin-x64', + 'linux-arm64': '@mariozechner/clipboard-linux-arm64-gnu', + 'linux-x64': '@mariozechner/clipboard-linux-x64-gnu', + 'win32-arm64': '@mariozechner/clipboard-win32-arm64-msvc', + 'win32-x64': '@mariozechner/clipboard-win32-x64-msvc', +}); + +// pi-tui ships platform-specific native helpers: +// - darwin: clipboard + Shift-modifier detection for Terminal.app Shift+Enter +// - linux: X11 clipboard +// - win32: clipboard + enable ENABLE_VIRTUAL_TERMINAL_INPUT so Shift+Tab is distinguishable +const piTuiNativeFileByTarget = Object.freeze({ + 'darwin-arm64': ['native/darwin/prebuilds/darwin-arm64/darwin-platform.node'], + 'darwin-x64': ['native/darwin/prebuilds/darwin-x64/darwin-platform.node'], + 'linux-arm64': ['native/linux/prebuilds/linux-arm64/linux-platform-x11.node'], + 'linux-x64': ['native/linux/prebuilds/linux-x64/linux-platform-x11.node'], + 'win32-arm64': ['native/win32/prebuilds/win32-arm64/win32-platform.node'], + 'win32-x64': ['native/win32/prebuilds/win32-x64/win32-platform.node'], +}); + +export function isSupportedTarget(target) { + return SUPPORTED_TARGETS.includes(target); +} + +/** + * @typedef {Object} NativeDepDescriptor + * @property {string} id — stable internal id used for parent refs + * @property {(target: string) => string} name + * — npm package name (may depend on target) + * @property {'js-only'|'native-files'|'js-and-native-file'|'native-file-only'|'virtual'} collect + * @property {string|null} parent + * — id of another registered dep this nests under (for pnpm), + * or null for top-level (resolvable from app root) + * @property {(target: string) => string[]} [nativeFileRelatives] + * — explicit list of .node files relative to package root + * (used by 'js-and-native-file' and 'native-file-only'; + * native-files mode auto-scans *.node). 'native-file-only' collects + * package.json + these .node files but skips the package entry JS. + */ + +/** @type {readonly NativeDepDescriptor[]} */ +export const nativeDeps = Object.freeze([ + { + id: 'clipboard-host', + name: () => '@mariozechner/clipboard', + collect: 'js-only', + parent: null, + }, + { + id: 'clipboard-target', + name: (target) => clipboardSubpackageByTarget[target], + collect: 'native-files', + parent: 'clipboard-host', + }, + { + id: 'pi-tui', + name: () => '@moonshot-ai/pi-tui', + // pi-tui's JS is bundled into main.cjs, so only the platform-specific + // native helper (.node under native/) ships alongside the binary — its + // dist/ JS is intentionally NOT collected (it stays in the bundle). This + // keeps the SEA native-asset payload small. + collect: 'native-file-only', + parent: null, + nativeFileRelatives: (target) => piTuiNativeFileByTarget[target] ?? [], + }, +]); + +/** + * Resolve which deps need collecting for a given build target, with concrete names. + */ +export function resolveTargetDeps(target) { + if (!isSupportedTarget(target)) { + throw new Error(`Unsupported native asset target: ${target}`); + } + return nativeDeps + .filter((d) => d.collect !== 'virtual') + .map((d) => ({ + ...d, + resolvedName: d.name(target), + nativeFileRelatives: d.nativeFileRelatives?.(target) ?? [], + parentName: d.parent ? nativeDeps.find((p) => p.id === d.parent)?.name(target) ?? null : null, + })); +} diff --git a/apps/kimi-code/scripts/native/package.mjs b/apps/kimi-code/scripts/native/package.mjs new file mode 100644 index 0000000000000000000000000000000000000000..e146af0abb81d7b7fd6bac8da4875fd3bac2c70b --- /dev/null +++ b/apps/kimi-code/scripts/native/package.mjs @@ -0,0 +1,53 @@ +import { createHash } from 'node:crypto'; +import { createReadStream, createWriteStream } from 'node:fs'; +import { mkdir, stat, writeFile } from 'node:fs/promises'; +import { basename, resolve } from 'node:path'; +import { pipeline } from 'node:stream/promises'; + +import { ZipFile } from 'yazl'; + +import { executableName, nativeArtifactsDir, nativeBinPath, targetTriple } from './paths.mjs'; + +const target = targetTriple(); +const execName = executableName(); +const sourceBinary = nativeBinPath(target); +const artifactsDir = nativeArtifactsDir(); + +// Flat-name archive for GH Release (GitHub Release assets do not support subdirectories). +const artifactName = `kimi-code-${target}.zip`; +const artifactPath = resolve(artifactsDir, artifactName); +const checksumPath = `${artifactPath}.sha256`; + +function fail(message) { + console.error(message); + process.exit(1); +} + +async function sha256(path) { + return await new Promise((resolveHash, reject) => { + const hash = createHash('sha256'); + const stream = createReadStream(path); + stream.on('error', reject); + stream.on('data', (chunk) => hash.update(chunk)); + stream.on('end', () => resolveHash(hash.digest('hex'))); + }); +} + +try { + await stat(sourceBinary); +} catch { + fail(`Native executable not found at ${sourceBinary}. Run build:native:sea first.`); +} + +await mkdir(artifactsDir, { recursive: true }); + +const zip = new ZipFile(); +zip.addFile(sourceBinary, execName, { mode: 0o100755 }); +zip.end(); +await pipeline(zip.outputStream, createWriteStream(artifactPath)); + +const digest = await sha256(artifactPath); +await writeFile(checksumPath, `${digest} ${basename(artifactPath)}\n`); + +console.log(`Wrote native artifact: ${artifactPath}`); +console.log(`Wrote artifact checksum: ${checksumPath}`); diff --git a/apps/kimi-code/scripts/native/paths.mjs b/apps/kimi-code/scripts/native/paths.mjs new file mode 100644 index 0000000000000000000000000000000000000000..ca0462072424c6ea746967eb5471ab4301f238e8 --- /dev/null +++ b/apps/kimi-code/scripts/native/paths.mjs @@ -0,0 +1,57 @@ +import { resolve } from 'node:path'; + +export const appRoot = resolve(import.meta.dirname, '..', '..'); + +export function targetTriple({ platform = process.platform, arch = process.arch, env = process.env } = {}) { + return env.KIMI_CODE_BUILD_TARGET ?? `${platform}-${arch}`; +} + +export function executableName(platform = process.platform) { + return platform === 'win32' ? 'kimi.exe' : 'kimi'; +} + +export function nativeDistRoot() { + return resolve(appRoot, 'dist-native'); +} + +export function nativeIntermediatesDir() { + return resolve(nativeDistRoot(), 'intermediates'); +} + +export function nativeBinDir(target = targetTriple()) { + return resolve(nativeDistRoot(), 'bin', target); +} + +export function nativeBinPath(target = targetTriple(), platform = process.platform) { + return resolve(nativeBinDir(target), executableName(platform)); +} + +export function nativeJsBundlePath() { + return resolve(nativeIntermediatesDir(), 'main.cjs'); +} + +export function nativeBlobPath() { + return resolve(nativeIntermediatesDir(), 'kimi.blob'); +} + +export function nativeSeaConfigPath() { + return resolve(nativeIntermediatesDir(), 'sea-config.json'); +} + +export function nativeManifestDir(target = targetTriple()) { + return resolve(nativeIntermediatesDir(), 'native-assets', target); +} + +export function nativeArtifactsDir() { + return resolve(nativeDistRoot(), 'artifacts'); +} + +export function nativeSmokeHome() { + return resolve(nativeDistRoot(), 'smoke-home'); +} + +export function nativeManifestKey(target = targetTriple()) { + return `native/${target}/manifest.json`; +} + +export const SEA_SENTINEL_FUSE = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2'; diff --git a/apps/kimi-code/scripts/native/produce-manifest.mjs b/apps/kimi-code/scripts/native/produce-manifest.mjs new file mode 100644 index 0000000000000000000000000000000000000000..0a0a9140e00963ac64fa335413985411c4c28e36 --- /dev/null +++ b/apps/kimi-code/scripts/native/produce-manifest.mjs @@ -0,0 +1,109 @@ +/** + * Build the per-release native artifact set and `manifest.json` from the + * matrix runners' zip archives. + * + * Usage: + * node produce-manifest.mjs + * + * Input dir must contain files matching: kimi-code-.zip(.sha256) + * (produced by package.mjs across the 6 native-build matrix runners). The + * zip is the only form in which binaries leave the matrix runners, so this + * script extracts each bare executable and emits next to it: + * kimi-code-.zst zstd -19, consumed by the staged updater + * kimi-code-.tar.gz consumed by install.sh / install.ps1 + * .sha256 sidecars in ` ` format + * manifest.json platform entries pair the bare binary with + * its compressed variant (`checksum` is always + * the hash of what `compressed` inflates to) + * + * Requires `unzip`, `zstd`, and `tar` on PATH (preinstalled on + * GitHub-hosted runners). + */ + +import { execFile } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { createReadStream } from 'node:fs'; +import { mkdtemp, readdir, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { basename, join, resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import { fail, run } from './exec.mjs'; + +const execFileAsync = promisify(execFile); + +const [, , inputDir, tag] = process.argv; +if (!inputDir || !tag) { + console.error('Usage: produce-manifest.mjs '); + process.exit(1); +} + +// Tag 格式 `@moonshot-ai/kimi-code@x.y.z` 或 `vx.y.z` 或 `x.y.z`,都归一化到 x.y.z +const version = tag.replace(/^@moonshot-ai\/kimi-code@/, '').replace(/^v/, ''); + +for (const tool of ['unzip', 'zstd', 'tar']) { + try { + await execFileAsync('sh', ['-c', `command -v ${tool}`]); + } catch { + fail(`produce-manifest.mjs requires \`${tool}\` on PATH (preinstalled on GitHub-hosted runners).`); + } +} + +async function sha256File(path) { + return await new Promise((resolveHash, reject) => { + const hash = createHash('sha256'); + const stream = createReadStream(path); + stream.on('error', reject); + stream.on('data', (chunk) => hash.update(chunk)); + stream.on('end', () => resolveHash(hash.digest('hex'))); + }); +} + +const entries = await readdir(inputDir); +const sumFiles = entries.filter((f) => /^kimi-code-[a-z0-9-]+\.zip\.sha256$/.test(f)); +if (sumFiles.length === 0) { + fail(`No kimi-code-.zip.sha256 files found in ${inputDir}`); +} + +const platforms = {}; +for (const sumFile of sumFiles.sort()) { + // kimi-code-darwin-arm64.zip.sha256 → darwin-arm64 + const target = basename(sumFile, '.sha256').replace(/^kimi-code-/, '').replace(/\.zip$/, ''); + const zipName = `kimi-code-${target}.zip`; + const exeName = target.startsWith('win32') ? 'kimi.exe' : 'kimi'; + // The CDN bare-binary layout carries the .exe suffix on Windows + // (src/constant/app.ts); the updater's fallback downloads this filename. + const binaryName = target.startsWith('win32') ? `kimi-code-${target}.exe` : `kimi-code-${target}`; + const artifactBase = `kimi-code-${target}`; + const zstName = `${artifactBase}.zst`; + const tarballName = `${artifactBase}.tar.gz`; + + const workDir = await mkdtemp(join(tmpdir(), `native-manifest-${target}-`)); + try { + await run('unzip', ['-o', resolve(inputDir, zipName), '-d', workDir]); + const exePath = join(workDir, exeName); + const binaryChecksum = await sha256File(exePath); + await run('zstd', ['-T0', '-19', '-q', '-f', '-o', resolve(inputDir, zstName), exePath]); + await run('tar', ['-C', workDir, '-czf', resolve(inputDir, tarballName), exeName]); + + const zstChecksum = await sha256File(resolve(inputDir, zstName)); + const tarballChecksum = await sha256File(resolve(inputDir, tarballName)); + await writeFile(resolve(inputDir, `${zstName}.sha256`), `${zstChecksum} ${zstName}\n`); + await writeFile(resolve(inputDir, `${tarballName}.sha256`), `${tarballChecksum} ${tarballName}\n`); + + platforms[target] = { + filename: binaryName, + checksum: binaryChecksum, + compressed: { filename: zstName, checksum: zstChecksum }, + }; + } finally { + await rm(workDir, { recursive: true, force: true }); + } +} + +const manifest = { version, tag, platforms }; +const manifestPath = resolve(inputDir, 'manifest.json'); + +await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + +console.log(`Wrote ${manifestPath} (${Object.keys(platforms).length} platforms)`); diff --git a/apps/kimi-code/scripts/native/resolve-release.mjs b/apps/kimi-code/scripts/native/resolve-release.mjs new file mode 100644 index 0000000000000000000000000000000000000000..10b4f9724b1bd5a49af23472674b1a50d410843d --- /dev/null +++ b/apps/kimi-code/scripts/native/resolve-release.mjs @@ -0,0 +1,55 @@ +import { appendFile, readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; + +import { appRoot } from './paths.mjs'; + +const packageName = '@moonshot-ai/kimi-code'; +const packageJson = JSON.parse( + await readFile(resolve(appRoot, 'package.json'), 'utf-8'), +); + +function parsePublishedPackages() { + const raw = process.env['CHANGESETS_PUBLISHED_PACKAGES']; + if (raw === undefined || raw.trim().length === 0) { + return []; + } + + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +} + +function outputLine(name, value) { + return `${name}=${value}\n`; +} + +const publishedPackage = parsePublishedPackages().find( + (entry) => + typeof entry === 'object' && + entry !== null && + entry.name === packageName && + typeof entry.version === 'string', +); + +const version = publishedPackage?.version ?? packageJson.version; +const shouldPublish = publishedPackage !== undefined; +const tag = `${packageName}@${version}`; +const githubOutput = process.env['GITHUB_OUTPUT']; + +if (githubOutput !== undefined) { + await appendFile( + githubOutput, + [ + outputLine('should_publish', String(shouldPublish)), + outputLine('version', version), + outputLine('tag', tag), + ].join(''), + ); +} + +console.log(`should_publish=${String(shouldPublish)}`); +console.log(`version=${version}`); +console.log(`tag=${tag}`); diff --git a/apps/kimi-code/scripts/native/smoke.mjs b/apps/kimi-code/scripts/native/smoke.mjs new file mode 100644 index 0000000000000000000000000000000000000000..dbff8c7e927d177a99196bfacc2d46160945779f --- /dev/null +++ b/apps/kimi-code/scripts/native/smoke.mjs @@ -0,0 +1,92 @@ +import { execFile } from 'node:child_process'; +import { mkdir, readFile, rm, stat } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { promisify } from 'node:util'; + +import { appRoot, nativeBinPath, nativeSmokeHome, targetTriple } from './paths.mjs'; + +const execFileAsync = promisify(execFile); +const target = targetTriple(); +const executablePath = nativeBinPath(target); +const smokeHome = nativeSmokeHome(); +const packageJson = JSON.parse(await readFile(resolve(appRoot, 'package.json'), 'utf-8')); +const expectedVersion = packageJson.version; + +function fail(message) { + console.error(message); + process.exit(1); +} + +async function ensureExecutableExists() { + try { + await stat(executablePath); + } catch { + fail(`Native executable not found at ${executablePath}. Run build:native:sea first.`); + } +} + +async function runKimi(args) { + try { + const { stdout, stderr } = await execFileAsync(executablePath, args, { + cwd: appRoot, + maxBuffer: 1024 * 1024 * 16, + }); + return `${stdout}${stderr}`; + } catch (error) { + const detail = [error.stdout?.trim(), error.stderr?.trim(), error.message] + .filter(Boolean) + .join('\n'); + fail(`Native smoke failed: ${executablePath} ${args.join(' ')}\n${detail}`); + } +} + +async function runKimiWithEnv(args, env) { + try { + const { stdout, stderr } = await execFileAsync(executablePath, args, { + cwd: appRoot, + env: { ...process.env, ...env }, + maxBuffer: 1024 * 1024 * 16, + }); + return `${stdout}${stderr}`; + } catch (error) { + const detail = [error.stdout?.trim(), error.stderr?.trim(), error.message] + .filter(Boolean) + .join('\n'); + fail(`Native smoke failed: ${executablePath} ${args.join(' ')}\n${detail}`); + } +} + +function assertIncludes(output, expected, command) { + if (!output.includes(expected)) { + fail(`Native smoke output for "${command}" did not include "${expected}".\n${output}`); + } +} + +await ensureExecutableExists(); + +const versionOutput = await runKimi(['--version']); +assertIncludes(versionOutput, expectedVersion, '--version'); + +const helpOutput = await runKimi(['--help']); +assertIncludes(helpOutput, 'Usage: kimi', '--help'); + +const exportHelpOutput = await runKimi(['export', '--help']); +assertIncludes(exportHelpOutput, 'Usage: kimi export', 'export --help'); + +const smokeCache = resolve(smokeHome, 'cache'); +await rm(smokeHome, { recursive: true, force: true }); +await mkdir(smokeCache, { recursive: true }); +try { + const nativeAssetOutput = await runKimiWithEnv(['--version'], { + KIMI_CODE_CACHE_DIR: smokeCache, + KIMI_CODE_HOME: smokeHome, + KIMI_CODE_NATIVE_ASSET_SMOKE: '1', + }); + assertIncludes(nativeAssetOutput, `Native asset smoke passed: ${target}`, 'native asset smoke'); + assertIncludes(nativeAssetOutput, 'MiniDb worker build passed', 'MiniDb worker smoke'); + assertIncludes(nativeAssetOutput, 'search worker ready', 'search worker smoke'); +} finally { + await rm(smokeHome, { recursive: true, force: true }); +} + +console.log(`Native smoke passed: ${executablePath}`); diff --git a/apps/kimi-code/scripts/native/web-assets.mjs b/apps/kimi-code/scripts/native/web-assets.mjs new file mode 100644 index 0000000000000000000000000000000000000000..8f8a893c5fb2f9074b977fdbe590654be147f860 --- /dev/null +++ b/apps/kimi-code/scripts/native/web-assets.mjs @@ -0,0 +1,118 @@ +import { createHash } from 'node:crypto'; +import { existsSync } from 'node:fs'; +import { readdir, readFile, stat } from 'node:fs/promises'; +import { join, relative, resolve } from 'node:path'; + +import { + WEB_ASSET_MANIFEST_VERSION, + buildWebAssetKey, + buildWebManifestKey, +} from './manifest.mjs'; + +export { WEB_ASSET_MANIFEST_VERSION }; + +const WEB_ASSETS_DIR = 'dist-web'; + +function toPosixPath(path) { + return path.split('\\').join('/'); +} + +function sha256(bytes) { + return createHash('sha256').update(bytes).digest('hex'); +} + +async function listFiles(root) { + const files = []; + + async function walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + await walk(path); + continue; + } + if (entry.isFile()) { + files.push(path); + } + } + } + + await walk(root); + return files; +} + +async function assertBuiltAssetRoot({ assetRoot, requiredFile, message }) { + const requiredPath = join(assetRoot, requiredFile); + try { + const info = await stat(requiredPath); + if (!info.isFile()) { + throw new Error(`${requiredFile} is not a file`); + } + } catch { + throw new Error(message); + } +} + +export function webAssetManifestKey(target) { + return buildWebManifestKey(target); +} + +export function webAssetKey(target, relativePath) { + return buildWebAssetKey(target, relativePath); +} + +async function collectAssetRoot({ + appRoot, + target, + root, + requiredFile, + missingMessage, + assetKey, +}) { + const assetRoot = resolve(appRoot, ...root.split('/')); + await assertBuiltAssetRoot({ assetRoot, requiredFile, message: missingMessage }); + + const files = (await listFiles(assetRoot)).sort((a, b) => a.localeCompare(b)); + const manifestFiles = []; + const assets = {}; + + for (const file of files) { + if (!existsSync(file)) continue; + const bytes = await readFile(file); + const relativePath = toPosixPath(relative(assetRoot, file)); + const key = assetKey(target, relativePath); + manifestFiles.push({ + assetKey: key, + relativePath, + sha256: sha256(bytes), + }); + assets[key] = file; + } + + const manifest = { + version: WEB_ASSET_MANIFEST_VERSION, + target, + root, + files: manifestFiles, + }; + + return { + manifest, + manifestJson: `${JSON.stringify(manifest, null, 2)}\n`, + assets, + }; +} + +export async function collectWebAssets({ appRoot, target }) { + const buildCommand = + 'pnpm --filter @moonshot-ai/kimi-web run build && pnpm --filter @moonshot-ai/kimi-code run build'; + return collectAssetRoot({ + appRoot, + target, + root: WEB_ASSETS_DIR, + requiredFile: 'index.html', + missingMessage: `Kimi web build output was not found at ${resolve(appRoot, WEB_ASSETS_DIR)}. Run \`${buildCommand}\` before building native SEA assets. App root: ${appRoot}`, + assetKey: webAssetKey, + }); +} diff --git a/apps/kimi-code/scripts/postinstall/migrate.mjs b/apps/kimi-code/scripts/postinstall/migrate.mjs new file mode 100644 index 0000000000000000000000000000000000000000..b134ab3990985ae993013348b1306352ea0c27e6 --- /dev/null +++ b/apps/kimi-code/scripts/postinstall/migrate.mjs @@ -0,0 +1,348 @@ +/** + * Detection of the previous Python `kimi-cli` shim and the actual + * filesystem operations that perform (or refuse) the rename. + * + * Detection: + * - {@link detectLegacyShims}: walks the caller-supplied + * `pathString` and returns every legacy `kimi` shim along the + * way (in PATH order). A shim qualifies when it realpath-resolves + * outside our own installed package root and its head 4 KiB + * contains the `kimi_cli` module marker — the setuptools + * entry-point format produced by `uv tool install`, + * `pipx install`, `pip install`, etc. Returning all hits (not + * just the first) matters because a user with both uv- and + * pipx-installed `kimi-cli` has two legacy shims in different + * dirs, and renaming only the earlier one leaves the later one + * shadowing our new CLI. Callers should pass the `detection` + * field from `postinstallPaths()` so detection sees the union of + * the shell PATH and the installer's PATH. + * - {@link isLegacyShim}: same criterion in standalone form, used to + * decide whether an existing `kimi-legacy` is itself a legacy CLI + * (safe to consolidate over) or a user-managed file (preserve). + * + * Classify + execute (two-phase): + * - {@link classifyShim}: pre-flight inspection that says what we + * COULD do to a given shim. Returns one of `renameable`, + * `consolidate`, `delete-only`, `blocked`. No filesystem writes. + * - {@link renameInPlace} / {@link deleteShim}: the primitive + * operations that actually mutate the filesystem. Run after the + * orchestrator has looked at the full set of classifications and + * decided to proceed. + * + * Splitting classification from execution lets the orchestrator make + * the abort-or-proceed decision once, against the whole detected set, + * rather than discovering mid-loop that something failed and ending up + * with a misleading "kimi now launches the new CLI" notice in front of + * a "permission denied" notice. Uses `fs.lstat` (not `fs.access`) to + * detect dangling symlinks at the target so we don't clobber them. + * + * Every helper accepts an optional trailing `platform` argument + * (`'posix' | 'win32'`, defaulting to the real `process.platform`) so + * Windows forms (PATHEXT expansion, extension-preserving rename + * targets, system-dir heuristics) can be exercised in tests on any + * host OS. + */ + +import { constants as fsConstants, promises as fs } from 'node:fs'; + +import { executableCandidates, pathFlavor } from './platform.mjs'; + +const LEGACY_BIN = 'kimi'; +const LEGACY_RENAME = 'kimi-legacy'; +const PYTHON_MARKER = 'kimi_cli'; + +// Read window for the marker sniff. +// POSIX: setuptools entry-point scripts are a few hundred bytes — +// 4 KiB is generous. +// Windows: `uv tool install` produces a Rust-built launcher .exe +// (~45 KiB) and the `kimi_cli` module name sits embedded +// near the END of the file (verified offset ≈ 44103 on +// uv 0.11). Cap reads at 256 KiB so a hostile or +// unexpectedly large file can't make us hold a lot of +// memory. +const SHIM_SNIFF_BYTES_POSIX = 4096; +const SHIM_SNIFF_BYTES_WINDOWS_MAX = 256 * 1024; + +function pathEntries(pathString, platform) { + const { delimiter } = pathFlavor(platform); + if (!pathString) return []; + const seen = new Set(); + const out = []; + for (const entry of pathString.split(delimiter)) { + if (!entry || seen.has(entry)) continue; + seen.add(entry); + out.push(entry); + } + return out; +} + +async function isExecutableFile(filePath, platform) { + try { + const info = await fs.stat(filePath); + if (!info.isFile()) return false; + // Windows: stat().mode doesn't reflect ACLs in any useful way. + // Callers already restrict to PATHEXT candidates, so existence + // suffices. + if (platform === 'win32') return true; + return (info.mode & 0o111) !== 0; + } catch { + return false; + } +} + +async function readShimHead(filePath, platform) { + let handle; + try { + handle = await fs.open(filePath, 'r'); + const stat = await handle.stat(); + const limit = + platform === 'win32' ? SHIM_SNIFF_BYTES_WINDOWS_MAX : SHIM_SNIFF_BYTES_POSIX; + const target = Math.min(stat.size, limit); + const buffer = Buffer.alloc(target); + const { bytesRead } = await handle.read(buffer, 0, target, 0); + // `latin1` is a 1-to-1 byte→char mapping; we're searching for an + // ASCII substring, so we don't want UTF-8 decoding to mangle the + // bytes around the marker. + return buffer.subarray(0, bytesRead).toString('latin1'); + } catch { + return null; + } finally { + if (handle) await handle.close().catch(() => {}); + } +} + +/** + * Walk `pathString` and return every legacy `kimi` shim along the + * way, in PATH order. The orchestrator renames each in turn — a + * single rename is insufficient when the user has multiple legacy + * installs (e.g. one from `uv tool install` and another from `pipx + * install`) in different directories, because the survivor still + * shadows the new CLI. + * + * Each entry has the same shape as the previous single-return + * value: `{ shimPath, realPath }`. The empty array means + * "fresh-install / no-op". + */ +export async function detectLegacyShims(ownRoot, pathString, platform = process.platform) { + const { sep, join } = pathFlavor(platform); + const ownRootPrefix = ownRoot ? ownRoot + sep : null; + const candidates = executableCandidates(LEGACY_BIN, platform); + const results = []; + const seenShims = new Set(); + + for (const dir of pathEntries(pathString, platform)) { + for (const name of candidates) { + const shimPath = join(dir, name); + if (seenShims.has(shimPath)) continue; + if (!(await isExecutableFile(shimPath, platform))) continue; + + let realPath; + try { + realPath = await fs.realpath(shimPath); + } catch { + continue; + } + + // Defence-in-depth: never touch a `kimi` that resolves into our + // own installed package. The `kimi_cli` marker check below + // already excludes the manager's generated wrapper today, but + // this layer keeps us safe if anything in our bundle ever + // happens to contain the marker substring. + if ( + ownRootPrefix !== null && + (realPath === ownRoot || realPath.startsWith(ownRootPrefix)) + ) { + continue; + } + + const head = await readShimHead(realPath, platform); + if (!head || !head.includes(PYTHON_MARKER)) continue; + + seenShims.add(shimPath); + results.push({ shimPath, realPath }); + } + } + return results; +} + +/** + * Does the file at `p` look like the legacy Python `kimi-cli`? + * + * Same criterion as {@link detectLegacyShim} uses to recognize the + * original shim: realpath-resolvable and the first 4 KiB of the + * resolved file contains the `kimi_cli` module name. Used to decide + * whether an existing `kimi-legacy` is itself a legacy shim (safe to + * drop the duplicate `kimi`) or a user-managed file we must not + * clobber. + */ +export async function isLegacyShim(p, platform = process.platform) { + let real; + try { + real = await fs.realpath(p); + } catch { + return false; + } + const head = await readShimHead(real, platform); + return Boolean(head && head.includes(PYTHON_MARKER)); +} + +async function pathExists(p) { + try { + // lstat (not access/stat) so a dangling symlink at `p` still + // reports as existing — `fs.access` follows symlinks and would + // return ENOENT for a broken link, after which `fs.rename` would + // silently replace it. + await fs.lstat(p); + return true; + } catch { + return false; + } +} + +/** + * Compute where `shimPath` should be renamed to. Preserves the file + * extension so a Windows `C:\…\kimi.exe` ends up at `kimi-legacy.exe` + * rather than an extension-less `kimi-legacy` that `kimi.exe -- legacy` + * shells won't run. + */ +export function renameTargetFor(shimPath, platform = process.platform) { + const { dirname, extname, join } = pathFlavor(platform); + const ext = extname(shimPath); // "" on POSIX, ".exe" on Windows + return join(dirname(shimPath), LEGACY_RENAME + ext); +} + +/** + * Is the directory containing `shimPath` a system-managed location + * the current user can't write to? + * + * POSIX: dir owned by uid 0 (root) — captures + * `sudo pip install kimi-cli` → `/usr/local/bin/`. + * + * Windows: dir under one of the well-known system roots + * (`C:\Program Files`, `C:\ProgramData`, `C:\Windows`). uv tool + * installs land in user space (`%USERPROFILE%\.local\bin`) so this + * path almost never fires on Windows in practice, but the heuristic + * correctly classifies the rare admin-prefix install case. + * + * The dedicated permission-denied notice (`logPermissionDenied`) + * uses this to switch from a bare "rename it manually" message to a + * sudo-aware / admin-aware explanation. + */ +export async function isSystemOwnedDir(shimPath, platform = process.platform) { + const { dirname } = pathFlavor(platform); + if (platform === 'win32') { + const dir = dirname(shimPath).toLowerCase(); + const systemRoots = [ + 'c:\\program files', + 'c:\\program files (x86)', + 'c:\\programdata', + 'c:\\windows', + ]; + return systemRoots.some( + (root) => dir === root || dir.startsWith(root + '\\'), + ); + } + try { + const info = await fs.stat(dirname(shimPath)); + return info.uid === 0; + } catch { + return false; + } +} + +async function canWriteDir(dir) { + try { + // For `fs.rename` and `fs.unlink` the parent dir needs to be both + // writable and executable (POSIX `wx`). `fs.access` follows the + // same semantics. On Windows ACL details are coarse but + // `fs.access(W_OK)` is a reasonable best-effort. + await fs.access(dir, fsConstants.W_OK | fsConstants.X_OK); + return true; + } catch { + return false; + } +} + +/** + * Pre-flight inspection of a single legacy shim. Returns what action + * we could take WITHOUT executing it. The orchestrator uses these + * classifications to decide the whole-set strategy (abort vs proceed, + * which shim becomes kimi-legacy) before any filesystem writes + * happen. + * + * Result shapes (all carry `shimPath` and `target` so the renderer + * has the paths): + * - `renameable` : can `fs.rename(shim → target)` cleanly; + * target slot is free. + * - `consolidate` : target already exists and is itself a legacy + * shim; we'd `fs.unlink(shim)` and leave the + * existing `kimi-legacy` as the canonical + * fallback (functionally equivalent — same + * upstream package). + * - `delete-only` : target exists but is a user-managed file we + * won't clobber. We can still `fs.unlink(shim)` + * to stop the shadowing; the + * "preserve original kimi" invariant fails for + * THIS dir (we tell the user). + * - `blocked` : we can't write to the parent dir. Carries + * `isSystemPath` so the renderer can suggest + * sudo (POSIX) or admin PowerShell (Windows). + */ +export async function classifyShim(shimPath, platform = process.platform) { + const { dirname } = pathFlavor(platform); + const target = renameTargetFor(shimPath, platform); + const dir = dirname(shimPath); + + if (!(await canWriteDir(dir))) { + return { + kind: 'blocked', + shimPath, + target, + isSystemPath: await isSystemOwnedDir(shimPath, platform), + }; + } + + if (await pathExists(target)) { + if (await isLegacyShim(target, platform)) { + return { kind: 'consolidate', shimPath, target }; + } + return { kind: 'delete-only', shimPath, target }; + } + + return { kind: 'renameable', shimPath, target }; +} + +/** + * Execute an `fs.rename`. Pre-flight classification establishes + * whether this is expected to succeed; this primitive just runs the + * call and wraps the error. + */ +export async function renameInPlace(shimPath, target) { + try { + await fs.rename(shimPath, target); + return { success: true }; + } catch (err) { + const code = err && typeof err === 'object' ? err.code : undefined; + const message = err instanceof Error ? err.message : String(err); + return { success: false, code, message }; + } +} + +/** + * Execute an `fs.unlink`. Used when: + * - we're consolidating onto an existing legacy `kimi-legacy`, or + * - we couldn't rename (foreign target) but can still remove the + * shadow, or + * - this is a non-first shim and we just want to clear it out so + * PATH order resolves to our new CLI. + */ +export async function deleteShim(shimPath) { + try { + await fs.unlink(shimPath); + return { success: true }; + } catch (err) { + const code = err && typeof err === 'object' ? err.code : undefined; + const message = err instanceof Error ? err.message : String(err); + return { success: false, code, message }; + } +} diff --git a/apps/kimi-code/scripts/postinstall/platform.mjs b/apps/kimi-code/scripts/postinstall/platform.mjs new file mode 100644 index 0000000000000000000000000000000000000000..52c77b8f0f0020cff37422a2137a2c8651ec7d6a --- /dev/null +++ b/apps/kimi-code/scripts/postinstall/platform.mjs @@ -0,0 +1,29 @@ +import { posix, win32 } from 'node:path'; + +export function pathFlavor(platform) { + return platform === 'win32' + ? { + delimiter: ';', + sep: '\\', + join: win32.join, + dirname: win32.dirname, + extname: win32.extname, + } + : { + delimiter: ':', + sep: '/', + join: posix.join, + dirname: posix.dirname, + extname: posix.extname, + }; +} + +export function executableCandidates(basename, platform = process.platform) { + if (platform !== 'win32') return [basename]; + const pathext = (process.env['PATHEXT'] ?? '.EXE;.CMD;.BAT;.COM') + .toLowerCase() + .split(';') + .map((e) => e.trim()) + .filter(Boolean); + return [basename, ...pathext.map((ext) => basename + ext)]; +} diff --git a/apps/kimi-code/scripts/postinstall/reach.mjs b/apps/kimi-code/scripts/postinstall/reach.mjs new file mode 100644 index 0000000000000000000000000000000000000000..666404995912f8e55270406685bb67601b153a3f --- /dev/null +++ b/apps/kimi-code/scripts/postinstall/reach.mjs @@ -0,0 +1,440 @@ +/** + * Where the user actually types things, and what `kimi` resolves to + * from there. + * + * Covers: + * + * - Package-manager detection ({@link detectPackageManager}) and + * manager-specific command hints ({@link pmGlobalBinCommand}, + * {@link pmGlobalInstallCommand}) used in user-facing notices. + * - Global-install gating ({@link isGlobalInstall}) — what counts as + * a global install across npm / yarn classic / pnpm. + * - Own-package-root location ({@link ownPackageRoot}) — walks up + * from `import.meta.dirname` looking for `package.json`. + * - User-shell PATH ({@link userShellPath}) — spawns `$SHELL -l` so + * we can check reachability from the shell the user will type + * `kimi` into, not just the installer's environment. + * - The combined PATH dispatcher ({@link postinstallPaths}) — + * called once by the orchestrator so detection and reachability + * stay symmetric and the shell probe doesn't run twice. + * - The reachability check ({@link findFirstResolvableKimi}) — + * walks PATH treating the to-be-renamed legacy shims as gone + * and reports what wins resolution. Distinguishes our own shim + * from a blocked legacy that's still in the way vs. an + * unknown/foreign `kimi` (e.g. a user-written wrapper). + * + * All functions are pure w.r.t. the filesystem (no mutations). + */ + +import { spawn } from 'node:child_process'; +import { promises as fs } from 'node:fs'; +import { delimiter, dirname, join } from 'node:path'; + +import { executableCandidates, pathFlavor } from './platform.mjs'; + +const LEGACY_BIN = 'kimi'; +const IS_WINDOWS = process.platform === 'win32'; + +/** + * Identify which package manager ran us. `npm_config_user_agent` is + * set by npm, yarn (classic + berry), and pnpm, and starts with the + * manager's name plus version. Defaults to `'npm'` for unknown / + * missing values. + */ +export function detectPackageManager() { + const ua = process.env['npm_config_user_agent'] ?? ''; + if (ua.startsWith('pnpm/')) return 'pnpm'; + if (ua.startsWith('yarn/')) return 'yarn'; + return 'npm'; +} + +/** + * Manager-specific shell command that prints (or expands to) the + * global bin directory. Used in the PATH-fix hint so the suggestion + * is valid regardless of which manager the user ran. + */ +export function pmGlobalBinCommand(pm) { + switch (pm) { + case 'pnpm': + return 'pnpm bin -g'; + case 'yarn': + return 'yarn global bin'; + case 'npm': + default: + return 'npm prefix -g'; + } +} + +/** Manager-specific reinstall command, used in the success-notice hint. */ +export function pmGlobalInstallCommand(pm, pkg) { + switch (pm) { + case 'pnpm': + return `pnpm add -g ${pkg}`; + case 'yarn': + return `yarn global add ${pkg}`; + case 'npm': + default: + return `npm install -g ${pkg}`; + } +} + +/** + * Did the user run a global install via some Node package manager? + * + * We accept four signals, any of which means "this install is + * landing in the manager's global bin directory": + * + * - `npm_config_global === 'true'` — set by `npm install -g`, and + * by pnpm on its global paths for back-compat. + * - `pnpm_config_global === 'true'` — set by pnpm in addition to + * the npm-compat flag above. + * - `npm_config_location === 'global'` — set by npm 7+ when the + * user passes `--location=global` (or runs `npm config set + * location global` persistently). npm intentionally does NOT + * also set `npm_config_global` in this case, so without this + * branch the migration silently no-ops for `npm install + * --location=global @moonshot-ai/kimi-code` — verified on npm + * 11.13.0. + * - {@link isYarnClassicGlobalAdd} — yarn classic does NOT set + * `npm_config_global` for `yarn global add`. The only reliable + * signal is parsing `npm_config_argv` and seeing the `global` + * subcommand. Verified on yarn 1.22.22. + * + * Local installs, `npx`, `pnpm dlx`, and workspace bootstraps leave + * all four signals false. + * + * Yarn berry (v2+) intentionally has no global-install concept, so + * it doesn't matter here. Postinstall on yarn berry runs in local + * context. + */ +export function isGlobalInstall() { + return ( + process.env['npm_config_global'] === 'true' || + process.env['pnpm_config_global'] === 'true' || + process.env['npm_config_location'] === 'global' || + isYarnClassicGlobalAdd() + ); +} + +/** + * `yarn global add` (yarn classic, v1.x) runs lifecycle scripts but + * leaves both `npm_config_global` and `npm_config_location` unset. + * The only reliable in-band signal is `npm_config_argv`, which yarn + * populates with the original command line as JSON: + * { original: ["global", "add", "", "--prefix=..."] } + * Parse it and require both: + * - `npm_config_user_agent` starts with `yarn/1.` (yarn classic; + * yarn berry has no global concept anyway). + * - Some token in argv is literally `"global"` AND the very next + * token is a known yarn-global subcommand (`add`, `remove`, + * etc). This handles the simple case (`yarn global add foo` → + * argv `["global","add",...]`) and the value-taking-flag case + * (`yarn --cwd /tmp global add foo` → argv `["--cwd","/tmp", + * "global","add",...]`) without having to maintain yarn's full + * flag table. It rejects `yarn add global` (the next token is + * undefined) and `yarn add @scope/global` (the literal string + * `"global"` doesn't appear). The remaining false positives + * (e.g., `yarn add global add` — installing two packages, one + * literally named `global`) are caught downstream by the + * reachability gate: a local install's bin dir isn't on PATH, + * so `isOwnCliResolvableFirst` will refuse to migrate. + */ +function isYarnClassicGlobalAdd() { + const ua = process.env['npm_config_user_agent'] ?? ''; + if (!ua.startsWith('yarn/1.')) return false; + const raw = process.env['npm_config_argv']; + if (!raw) return false; + let argv; + try { + argv = JSON.parse(raw); + } catch { + return false; + } + if (!Array.isArray(argv?.original)) return false; + const globalIdx = argv.original.indexOf('global'); + if (globalIdx === -1) return false; + const next = argv.original[globalIdx + 1]; + return typeof next === 'string' && YARN_GLOBAL_SUBCOMMANDS.has(next); +} + +// Yarn 1.x global subcommands. The install-class ones (`add`, +// `upgrade`, `upgrade-interactive`) are the ones that actually run +// our postinstall, but the read-only ones are included so the +// detection is consistent across all `yarn global ...` invocations. +const YARN_GLOBAL_SUBCOMMANDS = new Set([ + 'add', + 'remove', + 'upgrade', + 'upgrade-interactive', + 'list', + 'bin', + 'dir', +]); + +/** + * Locate the realpath of our own installed package root. + * + * Callers pass the starting directory (typically `import.meta.dirname` + * of the entry script, which lives at `/scripts/`). We + * walk up looking for the nearest `package.json`, then `realpath` the + * directory so symlinked install layouts (e.g. `/bin/kimi` + * symlinked into `lib/node_modules/.../dist/main.mjs`) compare equal + * in the caller's prefix check. + * + * Returns null if no `package.json` is found within a few levels — + * callers should treat that as "can't locate ourselves" and bail. + */ +export async function ownPackageRoot(startDir) { + let dir = startDir; + for (let i = 0; i < 6; i++) { + try { + await fs.access(join(dir, 'package.json')); + try { + return await fs.realpath(dir); + } catch { + return dir; + } + } catch { + // No `package.json` here; walk up. + } + const parent = dirname(dir); + if (parent === dir) break; + dir = parent; + } + return null; +} + +async function isExecutableFile(filePath, platform) { + try { + const info = await fs.stat(filePath); + if (!info.isFile()) return false; + // Windows: ACLs aren't visible through stat().mode meaningfully — + // existence + a recognized extension is what PATHEXT-style lookup + // checks. Callers only pass us candidates that already match an + // extension in `executableCandidates()`, so "is a file" suffices. + if (platform === 'win32') return true; + return (info.mode & 0o111) !== 0; + } catch { + return false; + } +} + +// Package-manager shim generators embed the package's resolved path +// into the wrapper file. So any shim whose first KB contains our +// package name is one we own. Used as a fallback when realpath alone +// can't catch the shim — that happens for: +// - Windows cmd-shims (literal `.cmd` / `.ps1` files, not symlinks) +// - pnpm POSIX shims (literal `/bin/sh` scripts, not symlinks; pnpm +// does not symlink into the package root the way npm/yarn classic +// do on POSIX) +const PACKAGE_NAME_MARKERS = ['@moonshot-ai/kimi-code', '@moonshot-ai\\kimi-code']; + +async function shimReferencesOwnPackage(shimPath) { + try { + const handle = await fs.open(shimPath, 'r'); + try { + const buf = Buffer.alloc(4096); + const { bytesRead } = await handle.read(buf, 0, 4096, 0); + const text = buf.subarray(0, bytesRead).toString('latin1'); + return PACKAGE_NAME_MARKERS.some((m) => text.includes(m)); + } finally { + await handle.close().catch(() => {}); + } + } catch { + return false; + } +} + +async function classifyShim(shim, ownRoot, ownPrefix) { + let real; + try { + real = await fs.realpath(shim); + } catch { + return 'unreadable'; + } + if (real === ownRoot || real.startsWith(ownPrefix)) return 'own'; + if (await shimReferencesOwnPackage(shim)) return 'own'; + return 'other'; +} + +/** + * Walk `pathString` and report what the user's shell would resolve + * `kimi` to, AFTER the to-be-removed shims in `actionableShimPaths` + * are pretended gone. Returns the first match by PATH order: + * + * - { kind: 'own' } — our shim wins. + * - { kind: 'blocked-legacy', shim } — a legacy `kimi` we + * detected but couldn't touch (a "blocked" shim) wins. + * - { kind: 'foreign', path } — something else wins: a + * `kimi` we didn't recognize as a legacy CLI and didn't generate + * ourselves (e.g. a user-managed wrapper script in `~/bin`). + * - { kind: 'none' } — no `kimi` resolves at all. + * + * Used by the orchestrator to give an accurate "why the takeover + * can't proceed" notice: a blocked-legacy blocker needs different + * remediation (sudo / admin delete) than a foreign blocker (the + * user's own file, which only they can decide what to do with). + * + * `allDetectedShimPaths` is every legacy shim our detector found + * (both blocked and actionable). It lets us distinguish a blocked + * legacy that survived our hypothetical removal pass from a totally + * unknown `kimi`. + */ +export async function findFirstResolvableKimi( + ownRoot, + pathString, + actionableShimPaths, + allDetectedShimPaths, + platform = process.platform, +) { + if (!ownRoot || !pathString) return { kind: 'none' }; + const { delimiter: flavorDelimiter, join: flavorJoin, sep: flavorSep } = pathFlavor(platform); + const ownPrefix = ownRoot + flavorSep; + const candidates = executableCandidates(LEGACY_BIN, platform); + const skipSet = new Set(actionableShimPaths ?? []); + const knownLegacySet = new Set(allDetectedShimPaths ?? []); + const seenDirs = new Set(); + for (const dir of pathString.split(flavorDelimiter)) { + if (!dir || seenDirs.has(dir)) continue; + seenDirs.add(dir); + for (const name of candidates) { + const shim = flavorJoin(dir, name); + if (skipSet.has(shim)) continue; + if (!(await isExecutableFile(shim, platform))) continue; + const kind = await classifyShim(shim, ownRoot, ownPrefix); + if (kind === 'unreadable') continue; + if (kind === 'own') return { kind: 'own' }; + if (knownLegacySet.has(shim)) { + return { kind: 'blocked-legacy', shim }; + } + return { kind: 'foreign', path: shim }; + } + } + return { kind: 'none' }; +} + +/** + * Read the user's default shell's view of `PATH`. + * + * Why: `process.env.PATH` reflects the environment of whichever + * shell the user happened to invoke the package manager from, which + * may or may not match the daily-driver shell they'll later type + * `kimi` into. A `~/.zshrc`-only PATH entry, a `~/.bash_profile` + * that doesn't source `~/.bashrc`, or a sudo'd install that scrubs + * HOME all break the installer's-PATH heuristic. + * + * We spawn `$SHELL -l -c 'printf %s "$PATH"'` so the shell reads + * its login-profile files (`.profile`, `.bash_profile`, `.zprofile`). + * `-i` would also pull in interactive rc files (`.bashrc`, `.zshrc`) + * but it requires a tty for some shells and is much more likely to + * have side effects (prompts, agent startup) — we accept the + * narrower view and let `'unknown'` fall through to a gentler + * check. + * + * Outcomes: + * { kind: 'ok', path: string } — shell printed its PATH. + * { kind: 'unknown', reason: string } — `$SHELL` missing, spawn + * failed, timed out, or + * shell printed no `PATH`. + */ +export async function userShellPath() { + // Windows has no `$SHELL`/login-shell concept worth probing — cmd.exe + // and PowerShell don't have profile files in the rc-chain sense, and + // their PATH already comes from the user's persistent registry env + // (which is what `process.env.PATH` reflects). Skip the spawn and + // let the caller fall back to `process.env.PATH`. + if (IS_WINDOWS) return { kind: 'unknown', reason: 'windows skip' }; + + const shell = process.env['SHELL']; + if (!shell) return { kind: 'unknown', reason: 'no SHELL env var' }; + + return new Promise((resolve) => { + let settled = false; + const settle = (value) => { + if (settled) return; + settled = true; + resolve(value); + }; + + let stdout = ''; + // Wrap PATH in delimiters we can parse out, defensively, in case + // the shell prints anything else (motd, prompt redraw, …). + const probe = + 'printf "<<>>%s<<>>\\n" "$PATH"'; + const child = spawn(shell, ['-l', '-c', probe], { + stdio: ['ignore', 'pipe', 'ignore'], + }); + child.stdout.on('data', (chunk) => { + stdout += chunk.toString('utf-8'); + }); + + // Bound the wait. Login rc files are usually quick, but a hostile + // `.profile` could hang indefinitely. + const timer = setTimeout(() => { + child.kill('SIGKILL'); + settle({ kind: 'unknown', reason: 'shell spawn timed out' }); + }, 5000); + + child.on('close', (code) => { + clearTimeout(timer); + const match = stdout.match( + /<<>>([\s\S]*?)<<>>/, + ); + if (match && match[1].length > 0) { + settle({ kind: 'ok', path: match[1] }); + return; + } + settle({ kind: 'unknown', reason: `no PATH printed (exit ${code})` }); + }); + child.on('error', (err) => { + clearTimeout(timer); + settle({ kind: 'unknown', reason: `spawn error: ${err.message}` }); + }); + }); +} + +/** + * Compute the two PATH strings the postinstall consults. + * + * - `detection`: a `delimiter`-joined union of the user's shell + * PATH and `process.env.PATH`, deduplicated. Used by + * {@link detectLegacyShim} to walk for legacy shims. We union + * because either source may contain a legacy `kimi` we want to + * rename — including one that lives in a directory the + * installer's environment can't see but the user's shell can + * (e.g. a sanitized lifecycle env from a packaged manager), and + * vice versa. + * + * - `reachability`: the user's shell PATH if we can probe it, else + * `process.env.PATH`. Used to verify our own shim is on the PATH + * the user will actually type `kimi` into. We do NOT union here: + * a shim that's only in the installer's PATH wouldn't help the + * user after the install, so unioning would mis-classify the + * install as reachable. + * + * Returns a single object so the (potentially slow) shell-probe runs + * just once per postinstall. + */ +export async function postinstallPaths() { + const shellResult = await userShellPath(); + const processPath = process.env['PATH'] ?? ''; + const shellPathStr = shellResult.kind === 'ok' ? shellResult.path : null; + const reachability = shellPathStr ?? processPath; + const detection = unionPaths(shellPathStr, processPath); + return { detection, reachability }; +} + +function unionPaths(...paths) { + const seen = new Set(); + const out = []; + for (const p of paths) { + if (!p) continue; + for (const entry of p.split(delimiter)) { + if (!entry || seen.has(entry)) continue; + seen.add(entry); + out.push(entry); + } + } + return out.join(delimiter); +} + diff --git a/apps/kimi-code/scripts/postinstall/takeover.mjs b/apps/kimi-code/scripts/postinstall/takeover.mjs new file mode 100644 index 0000000000000000000000000000000000000000..f04ae8115f7069a7f28f4dd04f2b70698adac8cc --- /dev/null +++ b/apps/kimi-code/scripts/postinstall/takeover.mjs @@ -0,0 +1,98 @@ +import { findFirstResolvableKimi } from './reach.mjs'; +import { + classifyShim, + deleteShim, + detectLegacyShims, + renameInPlace, +} from './migrate.mjs'; + +export async function planTakeover(ownRoot, detectionPath, reachabilityPath, platform) { + const detections = await detectLegacyShims(ownRoot, detectionPath, platform); + if (detections.length === 0) return { kind: /** @type {const} */ ('noop') }; + + const classifications = await Promise.all( + detections.map(async (detection) => { + const c = await classifyShim(detection.shimPath, platform); + return { ...c, detection }; + }), + ); + + const actionable = classifications.filter((c) => c.kind !== 'blocked'); + const blocked = classifications.filter((c) => c.kind === 'blocked'); + const blocker = await findFirstResolvableKimi( + ownRoot, + reachabilityPath, + actionable.map((c) => c.shimPath), + classifications.map((c) => c.shimPath), + platform, + ); + + if (blocker.kind === 'own') { + return { kind: /** @type {const} */ ('proceed'), detections, classifications, actionable, blocked }; + } + if (blocker.kind === 'blocked-legacy') { + return { kind: /** @type {const} */ ('blocked'), blocked, actionable }; + } + if (blocker.kind === 'foreign') { + return { kind: /** @type {const} */ ('foreign'), path: blocker.path }; + } + return { kind: /** @type {const} */ ('not-on-path'), detection: detections[0] }; +} + +export async function executeTakeover(classifications) { + const renames = []; + const consolidates = []; + const skippedForeignTarget = []; + const deletes = []; + const errors = []; + let preserved = false; + + for (const c of classifications) { + if (c.kind === 'blocked') continue; + + if (!preserved) { + if (c.kind === 'renameable') { + const r = await renameInPlace(c.shimPath, c.target); + if (r.success) { + renames.push(c); + preserved = true; + } else { + errors.push({ ...c, ...r }); + } + continue; + } + if (c.kind === 'consolidate') { + const r = await deleteShim(c.shimPath); + if (r.success) { + consolidates.push(c); + preserved = true; + } else { + errors.push({ ...c, ...r }); + } + continue; + } + if (c.kind === 'delete-only') { + const r = await deleteShim(c.shimPath); + if (r.success) { + skippedForeignTarget.push(c); + } else { + errors.push({ ...c, ...r }); + } + continue; + } + } else { + const r = await deleteShim(c.shimPath); + if (r.success) { + deletes.push(c); + } else { + errors.push({ ...c, ...r }); + } + } + } + + return { renames, consolidates, skippedForeignTarget, deletes, errors, preserved }; +} + +export async function verifyTakeover(ownRoot, reachabilityPath, allDetectedShimPaths, platform) { + return findFirstResolvableKimi(ownRoot, reachabilityPath, [], allDetectedShimPaths, platform); +} diff --git a/apps/kimi-code/scripts/postinstall/ui.mjs b/apps/kimi-code/scripts/postinstall/ui.mjs new file mode 100644 index 0000000000000000000000000000000000000000..a8763b7a895e16552ce3af82f49b3229964249e1 --- /dev/null +++ b/apps/kimi-code/scripts/postinstall/ui.mjs @@ -0,0 +1,549 @@ +/** + * User-facing output for the postinstall: where lines go, ANSI styling, + * the fixed-width box layout, and the four outcome renderers: + * + * - `logMigrationDone` — the takeover succeeded (one or more legacy + * shims were processed). Lists every action taken: renames, + * consolidates, delete-only, plain deletes, and harmless blocked + * leftovers. Footer branches three ways: preserved-somewhere + * (standard "type kimi-legacy"), only skippedForeignTarget (we + * couldn't save the old CLI because a user file took the name), + * and only blockedHarmless (just notes the leftovers, no + * phantom-file talk). + * - `logMigrationBlocked` — a legacy `kimi` we can't remove sits + * on PATH ahead of our shim. Nothing was touched; user is told + * which paths need their manual attention with sudo / admin. + * - `logForeignKimiInTheWay` — a `kimi` we don't recognize (not + * ours, not a legacy CLI) sits ahead of our shim on PATH. User + * needs to delete or rename their own file. Different remediation + * from `logMigrationBlocked`. + * - `logNewCliNotOnPath` — we found a legacy but our own shim + * isn't on the user's shell PATH at all. Same "touch nothing" + * behavior, different prose. + * + * This module is intentionally self-contained: no PATH walking, no fs + * mutations, no shell spawning — just rendering. The orchestrator + * (`postinstall.mjs`) makes the abort-or-proceed decision once and + * calls exactly one renderer at the end. + */ + +import { writeFileSync } from 'node:fs'; + +import { pmGlobalInstallCommand, pmGlobalBinCommand } from './reach.mjs'; + +// Fixed-width box rendering. 80 cols is the de facto terminal default. +// We can't reliably read TTY width from a piped postinstall context, so +// we pin the width and truncate long content with an ellipsis if needed. +const BOX_WIDTH = 80; +const BOX_INNER = BOX_WIDTH - 2; // chars between the two vertical borders +const BOX_PAD_LEFT = 2; // leading spaces inside the box for breathing room + +// ANSI styling. Disabled when NO_COLOR is set (https://no-color.org/). +// We can't reliably tell whether `/dev/tty`'s far end supports color, +// but modern terminals all do; users who want plain output can set +// NO_COLOR. +const USE_COLOR = !process.env['NO_COLOR']; +const ANSI_ESCAPE = /\x1b\[[0-9;]*[a-zA-Z]/g; +const C_RESET = USE_COLOR ? '\x1b[0m' : ''; +const C_DIM = USE_COLOR ? '\x1b[2m' : ''; +const C_BOLD_GREEN = USE_COLOR ? '\x1b[1;32m' : ''; +const C_BOLD_YELLOW = USE_COLOR ? '\x1b[1;33m' : ''; +const C_CYAN = USE_COLOR ? '\x1b[36m' : ''; + +function color(c, text) { + return USE_COLOR ? c + text + C_RESET : text; +} + +function visibleLength(s) { + return s.replace(ANSI_ESCAPE, '').length; +} + +function stripAnsi(s) { + return s.replace(ANSI_ESCAPE, ''); +} + +// Platform-specific path to the controlling terminal device. Writing +// here bypasses the package manager's lifecycle stdout capture (npm 7+ +// hides script stdout/stderr by default). On POSIX it's `/dev/tty`; +// on Windows it's the special filename `CON`, which Node resolves to +// the console device. (The fully-qualified `\\.\CON` form looks +// equivalent but Node appends a trailing backslash that breaks the +// open call — confirmed empirically on Windows 11 / Node 22.) +const TERMINAL_DEVICE = process.platform === 'win32' ? 'CON' : '/dev/tty'; + +/** + * Print a user-facing line. npm 7+ captures lifecycle stdout/stderr by + * default, so messages here would be invisible to a user running + * `npm install -g`. Writing directly to the platform's terminal + * device bypasses the manager's capture when one is available + * (interactive terminals). In CI / non-TTY contexts the device isn't + * writable; fall back to stdout so the message is still preserved in + * npm's lifecycle log under `~/.npm/_logs/`, with ANSI stripped so + * the log file stays readable. + */ +export function notify(line) { + const text = line + '\n'; + try { + writeFileSync(TERMINAL_DEVICE, text); + return; + } catch { + // Terminal device not writable (CI, sandboxed environments). + } + process.stdout.write(stripAnsi(text)); +} + +// Single-quote `path` for safe interpolation in a POSIX `sh` command. +// Wraps in single quotes and escapes any embedded `'` as `'\''`. +function quotePosixPath(path) { + return "'" + path.replace(/'/g, "'\\''") + "'"; +} + +// Single-quote `path` for safe interpolation in a PowerShell command. +// PowerShell single-quoted strings disable expansion; embedded `'` is +// escaped by doubling. +function quotePowerShellPath(path) { + return "'" + path.replace(/'/g, "''") + "'"; +} + +function boxBorder(left, right, fill = '─') { + return color(C_DIM, left + fill.repeat(BOX_INNER) + right); +} + +function boxLine(content = '') { + const visible = visibleLength(content); + const padding = + visible < BOX_INNER ? ' '.repeat(BOX_INNER - visible) : ''; + return color(C_DIM, '│') + content + padding + color(C_DIM, '│'); +} + +function pad(content) { + return ' '.repeat(BOX_PAD_LEFT) + content; +} + +function renderBox(lines) { + const out = [boxBorder('╭', '╮'), boxLine('')]; + for (const line of lines) out.push(boxLine(line)); + out.push(boxLine(''), boxBorder('╰', '╯')); + return out; +} + +function emit(lines) { + notify(''); + for (const line of lines) notify(line); + notify(''); +} + +function pathInBox(path) { + // 7-space lead = box pad (2) + prose indent (3) + nesting under + // label (2). We intentionally do NOT truncate overflowing content: + // for command lines (`sudo rm `, `mv `), left-truncation + // would swallow the command verb and leave the user with + // un-copy-pasteable instructions. Long lines just overflow the box + // border, which is visually less pretty but keeps the content + // intact. + const lead = ' '.repeat(BOX_PAD_LEFT + 5); + return lead + color(C_CYAN, path); +} + +function successHeading(text) { + return pad(color(C_BOLD_GREEN, '✓ ' + text)); +} + +function warningHeading(text) { + return pad(color(C_BOLD_YELLOW, '! ' + text)); +} + +/** + * The takeover completed. Renders one box that lists every action + * taken, so the user sees a single coherent picture even when several + * shims were involved. + * + * Sections (each only shown when non-empty): + * - "Renamed" — the first PATH-order shim, preserved as + * `kimi-legacy`. The "`kimi` now launches the new CLI" claim is + * safe to make here because the orchestrator already verified + * reachability after this set of removals. + * - "Consolidated" — first shim's `kimi-legacy` already pointed at + * a legacy file (re-migration case); we deleted the duplicate + * source and kept the existing target. Same end state, different + * mechanism. + * - "Couldn't preserve as kimi-legacy" — first shim's `kimi-legacy` + * slot was a user-managed file; we deleted the source `kimi` to + * remove the shadow but left their file alone, so no fallback + * exists in that dir. + * - "Also removed" — non-first PATH-order shims that would have + * shadowed our new shim. Just `unlink`ed. + * - "Note: legacy left behind" — blocked shims that couldn't be + * removed but PATH order means they don't shadow us; the user + * can clean them up at leisure. + * - "Errors" — anything that failed during execution despite + * pre-flight saying it should work (race conditions, transient + * fs errors). Listed last so the user can see what to retry. + */ +export function logMigrationDone(outcomes, pm) { + const reinstallCmd = pmGlobalInstallCommand(pm, '@moonshot-ai/kimi-code'); + const { + renames, + consolidates, + skippedForeignTarget, + deletes, + blockedHarmless, + errors, + } = outcomes; + + const lines = [successHeading('kimi now runs the new version'), '']; + + if (renames.length > 0) { + lines.push(pad(' Renamed your old kimi so you can still run it as')); + lines.push(pad(' kimi-legacy:')); + for (const c of renames) { + lines.push(pathInBox(c.shimPath + ' -> ' + c.target)); + } + lines.push(''); + } + + if (consolidates.length > 0) { + lines.push(pad(' Removed an extra copy of your old kimi (kimi-legacy')); + lines.push(pad(' was already set up here from before):')); + for (const c of consolidates) { + lines.push(pathInBox(c.shimPath)); + lines.push(pathInBox(' (kimi-legacy is at ' + c.target + ')')); + } + lines.push(''); + } + + if (skippedForeignTarget.length > 0) { + lines.push(pad(' Removed your old kimi (a file you created was already')); + lines.push(pad(' using the name kimi-legacy, so we left it alone):')); + for (const c of skippedForeignTarget) { + lines.push(pathInBox(c.shimPath)); + lines.push(pathInBox(' (your file at ' + c.target + ' is untouched)')); + } + lines.push(''); + } + + if (deletes.length > 0) { + lines.push(pad(' Also removed (these would have run instead of the')); + lines.push(pad(' new kimi if we left them):')); + for (const c of deletes) { + lines.push(pathInBox(c.shimPath)); + } + lines.push(''); + } + + if (blockedHarmless.length > 0) { + lines.push(pad(' Note: we can\'t change these files, but it\'s OK —')); + lines.push(pad(' they won\'t run instead of the new kimi:')); + for (const c of blockedHarmless) { + lines.push(pathInBox(c.shimPath)); + } + lines.push(''); + } + + if (errors.length > 0) { + lines.push(pad(' Some changes didn\'t go through:')); + for (const e of errors) { + lines.push( + pathInBox(e.shimPath + ' (' + (e.message ?? e.code ?? 'error') + ')'), + ); + } + lines.push(''); + } + + // Footer has three branches based on what actually happened: + // + // 1. Preserved somewhere (rename or consolidate): the old CLI is + // available as `kimi-legacy`. Standard takeover footer. + // 2. Only skippedForeignTarget (no rename, no consolidate, no + // blockedHarmless): user has a file they made called + // `kimi-legacy`, so we couldn't save the old CLI under that + // name. Explain the situation honestly. + // 3. Only blockedHarmless (no rename, no consolidate, no + // skippedForeignTarget): we have nothing to celebrate or + // apologize for — the "Note: we can't change these files but + // it's OK" section above already covers it. Plain footer. + // + // If both skippedForeignTarget AND blockedHarmless are present + // (but no preservation), branch 2 wins — the foreign-target story + // is the more useful one for the user to know about. + const preservedSomewhere = renames.length > 0 || consolidates.length > 0; + if (preservedSomewhere) { + lines.push( + pad(' Now typing `kimi` runs the new version. To run the old'), + pad(' version, type `kimi-legacy` instead. Your settings from'), + pad(' the old version will be moved over the first time you'), + pad(' run `kimi`.'), + '', + pad(' Note: if you reinstall the old kimi later (e.g. with'), + pad(' `uv tool`, `pip`, or `pipx`), it will put `kimi` back.'), + pad(' Run this command again to switch to the new one:'), + pathInBox(reinstallCmd), + '', + pad(' If typing `kimi` still runs the old version, open a new'), + pad(' terminal window — your current one may have remembered'), + pad(' the old path.'), + ); + } else if (skippedForeignTarget.length > 0) { + lines.push( + pad(' Now typing `kimi` runs the new version. Your settings'), + pad(' from the old version will be moved over the first time'), + pad(' you run `kimi`.'), + '', + pad(' We couldn\'t save the old kimi as `kimi-legacy` because'), + pad(' that name was already taken by a file you\'d created.'), + pad(' If you need the old kimi back, install it again with'), + pad(' `uv tool install kimi-cli` (or pipx / pip).'), + '', + pad(' If typing `kimi` still runs the old version, open a new'), + pad(' terminal window — your current one may have remembered'), + pad(' the old path.'), + ); + } else { + lines.push( + pad(' Now typing `kimi` runs the new version. Your settings'), + pad(' from the old version will be moved over the first time'), + pad(' you run `kimi`.'), + '', + pad(' If typing `kimi` still runs the old version, open a new'), + pad(' terminal window — your current one may have remembered'), + pad(' the old path.'), + ); + } + + emit(renderBox(lines)); +} + +/** + * At least one blocked legacy shim still sits on PATH ahead of where + * our new shim would land. We refused to touch anything (pre-flight + * abort), so neither the user's existing setup nor the new install + * gets a half-migrated state. List each blocking path with the + * platform-appropriate manual fix. + */ +export function logMigrationBlocked(blocked, actionable, pm) { + const isWindows = process.platform === 'win32'; + const reinstallCmd = pmGlobalInstallCommand(pm, '@moonshot-ai/kimi-code'); + + const lines = [ + warningHeading('Can\'t switch to the new kimi yet'), + '', + pad(' There\'s an old kimi on your computer that we can\'t change.'), + pad(' As long as it\'s there, typing `kimi` will still run the old'), + pad(' version. Files we can\'t change:'), + ]; + + for (const c of blocked) { + lines.push(pathInBox(c.shimPath)); + } + + lines.push('', pad(' Please delete them yourself, then install again:')); + + for (const c of blocked) { + if (isWindows && c.isSystemPath) { + // Admin PowerShell needed. + lines.push(pathInBox('# in an elevated PowerShell:')); + lines.push(pathInBox('Remove-Item ' + quotePowerShellPath(c.shimPath))); + } else if (c.isSystemPath) { + lines.push(pathInBox('sudo rm ' + quotePosixPath(c.shimPath))); + } else if (isWindows) { + lines.push(pathInBox('Remove-Item ' + quotePowerShellPath(c.shimPath))); + } else { + lines.push(pathInBox('rm ' + quotePosixPath(c.shimPath))); + } + } + + if (actionable.length > 0) { + lines.push( + '', + pad(' We also found these old kimi files. We could remove them'), + pad(' ourselves, once the ones above are gone:'), + ); + for (const c of actionable) { + lines.push(pathInBox(c.shimPath)); + } + } + + lines.push( + '', + pad(' After deleting them, install again to finish:'), + pathInBox(reinstallCmd), + '', + pad(' Nothing on your computer was changed.'), + ); + + emit(renderBox(lines)); +} + +/** + * The reachability check found a `kimi` ahead of our shim on PATH + * that's neither ours nor a legacy Python CLI — almost certainly a + * wrapper the user wrote themselves (or installed from somewhere we + * don't recognize). Deleting blocked legacy shims wouldn't help + * here: the foreign file would still win resolution. So the + * remediation is "delete or rename your own file", which only the + * user can decide. + */ +export function logForeignKimiInTheWay(foreignPath, pm) { + const reinstallCmd = pmGlobalInstallCommand(pm, '@moonshot-ai/kimi-code'); + emit( + renderBox([ + warningHeading('Can\'t switch to the new kimi yet'), + '', + pad(' There\'s another file called `kimi` on your computer that\'s'), + pad(' not the new CLI and not the old one — it looks like'), + pad(' something you set up yourself. As long as it\'s there,'), + pad(' typing `kimi` will run it instead of the new version.'), + '', + pad(' We found it at:'), + pathInBox(foreignPath), + '', + pad(' To use the new kimi, delete or rename that file, then'), + pad(' install again:'), + pathInBox(reinstallCmd), + '', + pad(' Nothing on your computer was changed.'), + ]), + ); +} + +/** + * A takeover that was executed but did NOT hold up under post-execution + * verification: `kimi` still resolves to a legacy/foreign file (or to + * nothing at all). The heading must not claim success — list what was + * actually changed, what still blocks resolution, and how to finish + * the job by hand. + */ +export function logMigrationIncomplete(input, pm) { + const { outcomes, verify } = input; + const { renames, consolidates, skippedForeignTarget, deletes, errors } = outcomes; + const isWindows = process.platform === 'win32'; + const reinstallCmd = pmGlobalInstallCommand(pm, '@moonshot-ai/kimi-code'); + + const lines = [warningHeading('Couldn\'t finish switching to the new kimi'), '']; + + if (verify.kind === 'blocked-legacy') { + lines.push( + pad(' Typing `kimi` still runs the old version. This file is in'), + pad(' the way and we couldn\'t change it:'), + pathInBox(verify.shim), + '', + ); + } else if (verify.kind === 'foreign') { + lines.push( + pad(' Typing `kimi` runs a file we don\'t recognize (not the new'), + pad(' CLI, not the old one). It\'s still in the way:'), + pathInBox(verify.path), + '', + ); + } else { + lines.push( + pad(' Typing `kimi` currently finds nothing at all — the old'), + pad(' shim was removed but the new one isn\'t reachable yet.'), + '', + ); + } + + const changed = [ + ...renames.map((c) => c.shimPath + ' -> ' + c.target), + ...consolidates.map((c) => c.shimPath + ' (removed; kimi-legacy kept)'), + ...skippedForeignTarget.map((c) => c.shimPath + ' (removed)'), + ...deletes.map((c) => c.shimPath + ' (removed)'), + ]; + if (changed.length > 0) { + lines.push(pad(' Changes already made:')); + for (const line of changed) lines.push(pathInBox(line)); + lines.push(''); + } + + if (errors.length > 0) { + lines.push(pad(' Changes that didn\'t go through:')); + for (const e of errors) { + lines.push(pathInBox(e.shimPath + ' (' + (e.message ?? e.code ?? 'error') + ')')); + } + lines.push(''); + } + + if (verify.kind === 'blocked-legacy') { + const c = verify; + lines.push(pad(' Delete it yourself, then install again:')); + if (isWindows) { + lines.push(pathInBox('Remove-Item ' + quotePowerShellPath(c.shim))); + } else { + lines.push(pathInBox('rm ' + quotePosixPath(c.shim))); + lines.push(pad(' (use sudo if it\'s in a system directory)')); + } + lines.push(pathInBox(reinstallCmd), ''); + } else if (verify.kind === 'foreign') { + lines.push( + pad(' Delete or rename that file, then install again:'), + pathInBox(reinstallCmd), + '', + ); + } else { + lines.push( + pad(' Open a new terminal and check `which kimi`. If it finds'), + pad(' nothing, reinstall to restore a working shim:'), + pathInBox(reinstallCmd), + '', + ); + } + + if (renames.length > 0 || consolidates.length > 0) { + lines.push( + pad(' The old version is still available as `kimi-legacy`.'), + ); + } + + emit(renderBox(lines)); +} + +/** + * The legacy `kimi` was found, but the directory where the package + * manager placed the new `kimi` shim is not on the user's PATH. + * Renaming the legacy shim now would leave the user with NO reachable + * `kimi` command — the new one would still not be discoverable by + * their shell. Show them the PATH fix and leave the legacy CLI alone. + * + * The PATH-fix hint uses the manager-specific subshell command (one + * of `npm prefix -g`, `yarn global bin`, `pnpm bin -g`) so it works + * regardless of which manager the user ran, and renders in the + * syntax of the user's likely shell: + * - POSIX : `export PATH=...`. + * - Windows: `$env:Path = ...` (PowerShell). + * On Windows, npm places global shims directly under `` (no + * `bin` subdir), and pnpm/yarn already report the bin dir, so we + * skip the `/bin` suffix the POSIX branch needs for npm. + */ +export function logNewCliNotOnPath(detection, pm) { + const isWindows = process.platform === 'win32'; + const binCmd = pmGlobalBinCommand(pm); + const reinstallCmd = pmGlobalInstallCommand(pm, '@moonshot-ai/kimi-code'); + + const newPathHint = isWindows + ? `$env:Path = "$(${binCmd});$env:Path"` + : pm === 'npm' + ? `export PATH="$(${binCmd})/bin:$PATH"` + : `export PATH="$(${binCmd}):$PATH"`; + const rcLabel = isWindows ? 'PowerShell profile' : 'shell rc'; + + emit( + renderBox([ + warningHeading('New kimi is installed, but your terminal can\'t find it'), + '', + pad(' The old kimi is still here:'), + pathInBox(detection.shimPath), + '', + pad(' The new kimi was installed by ' + pm + ', but it landed in a'), + pad(' folder your terminal doesn\'t search. (Your terminal looks'), + pad(' for commands in folders listed in your PATH.) If we removed'), + pad(' the old kimi now, typing `kimi` wouldn\'t find anything.'), + '', + pad(' Add the new kimi\'s folder to your PATH (and save the change'), + pad(' in your ' + rcLabel + ' so it sticks), then install again:'), + pathInBox(newPathHint), + pathInBox(reinstallCmd), + '', + pad(' The old kimi is still where it was.'), + ]), + ); +} diff --git a/apps/kimi-code/test/cli/acp.test.ts b/apps/kimi-code/test/cli/acp.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..11bc0a0789694a636efe26dc411e84359b674a6b --- /dev/null +++ b/apps/kimi-code/test/cli/acp.test.ts @@ -0,0 +1,166 @@ +/** + * `kimi acp` + * + * Verifies that the ACP sub-command is registered on the program and that + * the action wires `@moonshot-ai/acp-server`'s `runAcpServer` (the real server + * is stubbed so the test doesn't actually take over stdio). The module is + * loaded via a lazy dynamic import in the action, so the mock intercepts that + * import. + */ + +import { Command } from 'commander'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('@moonshot-ai/acp-server', () => ({ + runAcpServer: vi.fn(async () => undefined), +})); + +import { runAcpServer } from '@moonshot-ai/acp-server'; + +import { registerAcpCommand } from '#/cli/sub/acp'; +import { getDataDir } from '#/utils/paths'; + +class ExitCalled extends Error { + constructor(public code: number | string | null | undefined) { + super(`process.exit(${String(code)})`); + } +} + +describe('kimi acp', () => { + let exitSpy: ReturnType; + let stderrSpy: ReturnType; + + beforeEach(() => { + vi.mocked(runAcpServer).mockClear(); + exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code?: number | string | null) => { + throw new ExitCalled(code); + }) as never); + stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true); + }); + + afterEach(() => { + exitSpy.mockRestore(); + stderrSpy.mockRestore(); + vi.unstubAllEnvs(); + }); + + it('registers an `acp` subcommand on the program', () => { + const program = new Command('kimi'); + registerAcpCommand(program); + + const acp = program.commands.find((c) => c.name() === 'acp'); + expect(acp).toBeDefined(); + expect(acp?.description()).toMatch(/Agent Client Protocol/); + }); + + it('invokes runAcpServer with the host options and exits 0 on success', async () => { + const program = new Command('kimi').exitOverride(); + registerAcpCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'acp'])).rejects.toThrow(ExitCalled); + + expect(runAcpServer).toHaveBeenCalledTimes(1); + const optsArg = vi.mocked(runAcpServer).mock.calls[0]?.[0]; + expect(optsArg).toEqual( + expect.objectContaining({ + homeDir: getDataDir(), + agentInfo: { name: 'Kimi Code CLI', version: expect.any(String) }, + }), + ); + expect(exitSpy).toHaveBeenCalledWith(0); + }); + + it('forwards KIMI_CODE_HOME to terminalAuthEnv and homeDir when set', async () => { + const previous = process.env['KIMI_CODE_HOME']; + process.env['KIMI_CODE_HOME'] = '/tmp/kimi-debug'; + try { + const program = new Command('kimi').exitOverride(); + registerAcpCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'acp'])).rejects.toThrow(ExitCalled); + + const optsArg = vi.mocked(runAcpServer).mock.calls[0]?.[0]; + expect(optsArg).toEqual( + expect.objectContaining({ + homeDir: '/tmp/kimi-debug', + terminalAuthEnv: { KIMI_CODE_HOME: '/tmp/kimi-debug' }, + }), + ); + } finally { + if (previous === undefined) { + delete process.env['KIMI_CODE_HOME']; + } else { + process.env['KIMI_CODE_HOME'] = previous; + } + } + }); + + it('omits terminalAuthEnv when KIMI_CODE_HOME is unset', async () => { + const previous = process.env['KIMI_CODE_HOME']; + delete process.env['KIMI_CODE_HOME']; + try { + const program = new Command('kimi').exitOverride(); + registerAcpCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'acp'])).rejects.toThrow(ExitCalled); + + const optsArg = vi.mocked(runAcpServer).mock.calls[0]?.[0] as { + terminalAuthEnv?: unknown; + }; + expect(optsArg.terminalAuthEnv).toBeUndefined(); + } finally { + if (previous !== undefined) { + process.env['KIMI_CODE_HOME'] = previous; + } + } + }); + + it('forwards process.argv[1] as terminalAuthLegacyCommand', async () => { + const program = new Command('kimi').exitOverride(); + registerAcpCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'acp'])).rejects.toThrow(ExitCalled); + + const optsArg = vi.mocked(runAcpServer).mock.calls[0]?.[0] as { + terminalAuthLegacyCommand?: string; + }; + // process.argv[1] points at the test runner entry — non-empty + // absolute-ish path, exactly what we want forwarded. + expect(typeof optsArg.terminalAuthLegacyCommand).toBe('string'); + expect((optsArg.terminalAuthLegacyCommand ?? '').length).toBeGreaterThan(0); + expect(optsArg.terminalAuthLegacyCommand).toBe(process.argv[1]); + }); + + it('exits without starting the ACP server when --login is passed', async () => { + // Stub the SDK harness so runLoginFlow doesn't hit a real OAuth endpoint: + // harness.auth.login resolves immediately and triggers exit 0. + const loginStub = vi.fn(async () => ({ providerName: 'kimi-code' })); + vi.doMock(import('@moonshot-ai/kimi-code-sdk'), async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + createKimiHarness: () => + ({ + auth: { login: loginStub }, + }) as unknown as ReturnType, + }; + }); + vi.resetModules(); + const { registerAcpCommand: freshRegister } = await import('#/cli/sub/acp'); + try { + const program = new Command('kimi').exitOverride(); + freshRegister(program); + + await expect(program.parseAsync(['node', 'kimi', 'acp', '--login'])).rejects.toThrow( + ExitCalled, + ); + + expect(loginStub).toHaveBeenCalledTimes(1); + expect(runAcpServer).not.toHaveBeenCalled(); + expect(exitSpy).toHaveBeenCalledWith(0); + } finally { + vi.doUnmock('@moonshot-ai/kimi-code-sdk'); + vi.resetModules(); + } + }); +}); diff --git a/apps/kimi-code/test/cli/doctor.test.ts b/apps/kimi-code/test/cli/doctor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9745d76a2b4f8941eddbe22beba2fe19e8bbcdbe --- /dev/null +++ b/apps/kimi-code/test/cli/doctor.test.ts @@ -0,0 +1,455 @@ +import { mkdir, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; + +import { Command } from 'commander'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + handleDoctor, + registerDoctorCommand, + type DoctorDeps, +} from '#/cli/sub/doctor'; + +let dir: string; + +beforeEach(async () => { + dir = join(tmpdir(), `kimi-doctor-${Date.now()}-${Math.random().toString(36).slice(2)}`); + await mkdir(dir, { recursive: true }); +}); + +afterEach(async () => { + vi.unstubAllEnvs(); + await rm(dir, { recursive: true, force: true }); +}); + +function makeDeps(): { + deps: DoctorDeps; + stdout: string[]; + stderr: string[]; + exitCodes: number[]; +} { + const stdout: string[] = []; + const stderr: string[] = []; + const exitCodes: number[] = []; + return { + deps: { + cwd: () => dir, + defaultConfigPath: () => join(dir, 'config.toml'), + defaultTuiConfigPath: () => join(dir, 'tui.toml'), + stdout: { write: (chunk) => stdout.push(chunk) > 0 }, + stderr: { write: (chunk) => stderr.push(chunk) > 0 }, + exit: (code) => { + exitCodes.push(code); + throw new Error(`exit ${String(code)}`); + }, + }, + stdout, + stderr, + exitCodes, + }; +} + +async function writeValidConfig(path = join(dir, 'config.toml')): Promise { + await writeFile( + path, + ` +[providers.kimi] +type = "kimi" +base_url = "https://api.example.com/v1" +api_key = "YOUR_API_KEY" + +[models.kimi] +provider = "kimi" +model = "kimi" +max_context_size = 262144 +`, + 'utf-8', + ); +} + +async function writeValidTuiConfig(path = join(dir, 'tui.toml')): Promise { + await writeFile( + path, + ` +theme = "dark" + +[editor] +command = "code --wait" + +[notifications] +enabled = true +notification_condition = "unfocused" + +[upgrade] +auto_install = true +`, + 'utf-8', + ); +} + +describe('kimi doctor', () => { + it('skips missing default config files without failing', async () => { + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, {}); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain('SKIP config.toml'); + expect(out).toContain('SKIP tui.toml'); + expect(out).toContain('built-in defaults will apply'); + }); + + it('keeps v2 validation for a valid config', async () => { + const configPath = join(dir, 'config.toml'); + await writeFile( + configPath, + ` +default_model = "kimi" + +[providers.kimi] +type = "kimi" +base_url = "https://api.example.com/v1" +api_key = "YOUR_API_KEY" + +[models.kimi] +provider = "kimi" +model = "kimi" +protocol = "openai" +max_context_size = 262144 +`, + 'utf-8', + ); + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + expect(stdout.join('')).toContain(`OK config.toml ${configPath}`); + }); + + it('reports schema-invalid sections', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +[models.kimi] +provider = "kimi" +model = "kimi" +max_context_size = "large" +`, + 'utf-8', + ); + const { deps, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(1); + const err = stderr.join(''); + expect(err).toContain('Validation issues:'); + expect(err).toContain('models.kimi.max_context_size:'); + }); + + it('checks only config.toml when the config target is selected', async () => { + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain('SKIP config.toml'); + expect(out).not.toContain('tui.toml'); + }); + + it('checks only tui.toml when the tui target is selected', async () => { + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'tui' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain('SKIP tui.toml'); + expect(out).not.toContain('config.toml'); + }); + + it('treats a missing explicit target path as an error', async () => { + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config', path: './missing.toml' }); + + expect(code).toBe(1); + expect(stdout.join('')).toBe(''); + const err = stderr.join(''); + expect(err).toContain('Kimi doctor found 1 issue.'); + expect(err).toContain(`ERROR config.toml ${resolve(dir, 'missing.toml')}`); + expect(err).toContain('File does not exist.'); + expect(err).not.toContain('tui.toml'); + }); + + it('checks a valid explicit config path routed through commander', async () => { + const configPath = join(dir, 'candidate-config.toml'); + await writeValidConfig(configPath); + const { deps, stdout, stderr, exitCodes } = makeDeps(); + const program = new Command('kimi'); + registerDoctorCommand(program, deps); + + await program.parseAsync(['node', 'kimi', 'doctor', 'config', './candidate-config.toml']); + + expect(exitCodes).toEqual([]); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain(`OK config.toml ${configPath}`); + expect(out).not.toContain('tui.toml'); + expect(out).toContain('All checked config files are valid.'); + }); + + it('does not resolve the default config path when an explicit config path is provided', async () => { + const configPath = join(dir, 'candidate-config.toml'); + await writeValidConfig(configPath); + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor( + { + ...deps, + defaultConfigPath: () => { + throw new Error('default config path should not be resolved'); + }, + }, + { target: 'config', path: './candidate-config.toml' }, + ); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + expect(stdout.join('')).toContain(`OK config.toml ${configPath}`); + }); + + it('checks a valid explicit tui path routed through commander', async () => { + const tuiConfigPath = join(dir, 'candidate-tui.toml'); + await writeValidTuiConfig(tuiConfigPath); + const { deps, stdout, stderr, exitCodes } = makeDeps(); + const program = new Command('kimi'); + registerDoctorCommand(program, deps); + + await program.parseAsync(['node', 'kimi', 'doctor', 'tui', './candidate-tui.toml']); + + expect(exitCodes).toEqual([]); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain(`OK tui.toml ${tuiConfigPath}`); + expect(out).not.toContain('config.toml'); + expect(out).toContain('All checked config files are valid.'); + }); + + it('aggregates config.toml and tui.toml parse errors', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +[providers.kimi] +type = "kimi" + +[models.kimi] +provider = "kimi" +model = "kimi" +max_context_size = 0 +`, + 'utf-8', + ); + await writeFile(join(dir, 'tui.toml'), 'editor = 123\n', 'utf-8'); + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, {}); + + expect(code).toBe(1); + expect(stdout.join('')).toBe(''); + const err = stderr.join(''); + expect(err).toContain('Kimi doctor found 2 issues.'); + expect(err).toContain(`ERROR config.toml ${join(dir, 'config.toml')}`); + expect(err).toContain('max_context_size'); + expect(err).toContain(`ERROR tui.toml ${join(dir, 'tui.toml')}`); + expect(err).toContain('editor'); + }); + + it('formats Zod validation issues with field paths for tui.toml', async () => { + await writeFile( + join(dir, 'tui.toml'), + ` +editor = 123 + +[notifications] +enabled = "yes" +`, + 'utf-8', + ); + const { deps, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'tui' }); + + expect(code).toBe(1); + const err = stderr.join(''); + expect(err).toContain('Validation issues:'); + expect(err).toContain('editor:'); + expect(err).toContain('notifications.enabled:'); + }); + + it('formats wrapped Zod validation issues with TOML-style field paths for config.toml', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +[providers.kimi] +type = "kimi" + +[models.kimi] +provider = "kimi" +model = "kimi" +max_context_size = "large" +`, + 'utf-8', + ); + const { deps, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(1); + const err = stderr.join(''); + expect(err).toContain('Validation issues:'); + expect(err).toContain('models.kimi.max_context_size:'); + }); +}); + +describe('kimi doctor (default v2 config validation)', () => { + afterEach(() => { + delete process.env['KIMI_LOOP_MAX_RETRIES_PER_STEP']; + delete process.env['KIMI_LOOP_MAX_ATTEMPTS_PER_STEP']; + }); + + it('accepts a config valid for the v2 engine, including schema-less keys', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +default_model = "kimi" + +[providers.kimi] +type = "kimi" +base_url = "https://api.example.com/v1" +api_key = "YOUR_API_KEY" + +[models.kimi] +provider = "kimi" +model = "kimi" +max_context_size = 262144 +`, + 'utf-8', + ); + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + expect(stdout.join('')).toContain(`OK config.toml ${join(dir, 'config.toml')}`); + }); + + it('reports schema-invalid sections with TOML-style field paths', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +[models.kimi] +provider = "kimi" +model = "kimi" +max_context_size = "large" +`, + 'utf-8', + ); + const { deps, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(1); + const err = stderr.join(''); + expect(err).toContain('Validation issues:'); + expect(err).toContain('models.kimi.max_context_size:'); + }); + + it('warns about unknown top-level keys without failing', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +[providrs.kimi] +type = "kimi" +`, + 'utf-8', + ); + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain(`OK config.toml ${join(dir, 'config.toml')}`); + expect(out).toContain('Unknown top-level key ignored by the v2 engine: providrs.'); + }); + + it('reports TOML syntax errors with line and column', async () => { + await writeFile(join(dir, 'config.toml'), '[providers.kimi\ntype = "kimi"\n', 'utf-8'); + const { deps, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(1); + const err = stderr.join(''); + expect(err).toContain('Invalid TOML in'); + expect(err).toMatch(/\(line \d+, column \d+\)/); + }); + + it('warns about deprecated config keys without failing', async () => { + await writeFile( + join(dir, 'config.toml'), + ` +[loop_control] +max_retries_per_step = 3 +`, + 'utf-8', + ); + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + const out = stdout.join(''); + expect(out).toContain(`OK config.toml ${join(dir, 'config.toml')}`); + expect(out).toContain("'max_retries_per_step' is deprecated"); + expect(out).toContain("rename it to 'max_attempts_per_step'"); + }); + + it('warns about a deprecated env var that supplies a value', async () => { + await writeFile(join(dir, 'config.toml'), '[loop_control]\n', 'utf-8'); + process.env['KIMI_LOOP_MAX_RETRIES_PER_STEP'] = '5'; + const { deps, stdout, stderr } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stderr.join('')).toBe(''); + expect(stdout.join('')).toContain( + 'Environment variable KIMI_LOOP_MAX_RETRIES_PER_STEP is deprecated; use KIMI_LOOP_MAX_ATTEMPTS_PER_STEP instead.', + ); + }); + + it('does not warn about the deprecated env var when the primary one is set', async () => { + await writeFile(join(dir, 'config.toml'), '[loop_control]\n', 'utf-8'); + process.env['KIMI_LOOP_MAX_RETRIES_PER_STEP'] = '5'; + process.env['KIMI_LOOP_MAX_ATTEMPTS_PER_STEP'] = '5'; + const { deps, stdout } = makeDeps(); + + const code = await handleDoctor(deps, { target: 'config' }); + + expect(code).toBe(0); + expect(stdout.join('')).not.toContain('KIMI_LOOP_MAX_RETRIES_PER_STEP'); + }); +}); diff --git a/apps/kimi-code/test/cli/export.test.ts b/apps/kimi-code/test/cli/export.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2720f47551176e929159b05ceb4676b576d4d247 --- /dev/null +++ b/apps/kimi-code/test/cli/export.test.ts @@ -0,0 +1,564 @@ +/** + * `kimi export` + * + * Verifies the CLI layer: argument handling, previous-session confirmation, + * error reporting, and delegation to the session export implementation. + */ + +import { mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import type { createKimiDeviceId as createKimiDeviceIdFn } from '@moonshot-ai/kimi-code-oauth'; +import { Command } from 'commander'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { handleExport, registerExportCommand } from '#/cli/sub/export'; +import { refreshKimiRegion } from '#/utils/region'; +import type { ExportDeps } from '#/cli/sub/export'; +import type { + ExportSessionInput, + ExportSessionManifest, + ExportSessionResult, + SessionSummary, +} from '@moonshot-ai/kimi-code-sdk'; + +let tmp: string; + +type CreateKimiDeviceId = typeof createKimiDeviceIdFn; + +const mocks = vi.hoisted(() => ({ + kimiHarnessConstructor: vi.fn(), + harnessEnsureConfigFile: vi.fn(), + harnessGetConfig: vi.fn(async () => ({ + providers: {}, + defaultModel: 'k2', + telemetry: true, + })), + harnessGetCachedAccessToken: vi.fn(), + harnessExportSession: vi.fn(), + harnessClose: vi.fn(async () => {}), + harnessTrack: vi.fn(), + createKimiDeviceId: vi.fn(() => 'device-1'), + initializeTelemetry: vi.fn(), + shutdownTelemetry: vi.fn(), + telemetryTrack: vi.fn(), + setTelemetryContext: vi.fn(), + withTelemetryContext: vi.fn(), + resolveKimiHome: vi.fn((homeDir?: string) => homeDir ?? '/tmp/kimi-export-home'), + harnessCreatesDeviceIdOnConstruction: false, +})); + +vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => { + const actual = await importOriginal(); + const createFakeHarness = (options: { readonly homeDir?: string } | undefined) => { + const homeDir = options?.homeDir ?? '/tmp/kimi-export-home'; + if (mocks.harnessCreatesDeviceIdOnConstruction) { + mocks.createKimiDeviceId(homeDir); + } + return { + homeDir, + auth: { + getCachedAccessToken: mocks.harnessGetCachedAccessToken, + }, + ensureConfigFile: mocks.harnessEnsureConfigFile, + getConfig: mocks.harnessGetConfig, + track: mocks.harnessTrack, + exportSession: mocks.harnessExportSession, + close: mocks.harnessClose, + }; + }; + return { + ...actual, + resolveKimiHome: mocks.resolveKimiHome, + createKimiHarness: (...args: unknown[]) => { + mocks.kimiHarnessConstructor(...args); + return createFakeHarness(args[0] as { readonly homeDir?: string } | undefined); + }, + }; +}); + +vi.mock('@moonshot-ai/kimi-code-oauth', async () => { + const actual = await vi.importActual( + '@moonshot-ai/kimi-code-oauth', + ); + return { + ...actual, + createKimiDeviceId: mocks.createKimiDeviceId, + KIMI_CODE_PROVIDER_NAME: 'kimi-code', + }; +}); + +vi.mock('@moonshot-ai/kimi-telemetry', () => ({ + initializeTelemetry: mocks.initializeTelemetry, + shutdownTelemetry: mocks.shutdownTelemetry, + track: mocks.telemetryTrack, + setTelemetryContext: mocks.setTelemetryContext, + withTelemetryContext: mocks.withTelemetryContext, +})); + +beforeEach(() => { + // Pin region to cn: the telemetry endpoint assertion must not follow the + // dev machine's own login/marker state. + vi.stubEnv('KIMI_CODE_OAUTH_HOST', 'https://auth.kimi.com'); + refreshKimiRegion(); + tmp = mkdtempSync(join(tmpdir(), 'kimi-export-')); +}); + +afterEach(() => { + vi.unstubAllEnvs(); + refreshKimiRegion(); + rmSync(tmp, { recursive: true, force: true }); + vi.clearAllMocks(); + mocks.harnessGetConfig.mockResolvedValue({ + providers: {}, + defaultModel: 'k2', + telemetry: true, + }); + mocks.createKimiDeviceId.mockImplementation(() => 'device-1'); + mocks.resolveKimiHome.mockImplementation( + (homeDir?: string) => homeDir ?? '/tmp/kimi-export-home', + ); + mocks.harnessCreatesDeviceIdOnConstruction = false; +}); + +function makeSummary(id: string, overrides: Partial = {}): SessionSummary { + return { + id, + workDir: tmp, + sessionDir: join(tmp, 'sessions', id), + createdAt: 1, + updatedAt: 2, + ...overrides, + }; +} + +function makeResult(id: string, zipPath: string): ExportSessionResult { + const manifest: ExportSessionManifest = { + sessionId: id, + exportedAt: '2026-04-18T12:00:00.000Z', + kimiCodeVersion: '1.27.0', + wireProtocolVersion: '1.0', + os: 'test', + nodejsVersion: '22.0.0', + workspaceDir: tmp, + }; + return { + zipPath, + entries: ['manifest.json', 'wire.jsonl'], + sessionDir: join(tmp, 'sessions', id), + manifest, + }; +} + +function makeDeps(overrides: Partial = {}): { + deps: ExportDeps; + stdout: string[]; + stderr: string[]; + exitCodes: number[]; + exportInputs: ExportSessionInput[]; + listedWorkDirs: string[]; +} { + const stdout: string[] = []; + const stderr: string[] = []; + const exitCodes: number[] = []; + const exportInputs: ExportSessionInput[] = []; + const listedWorkDirs: string[] = []; + const deps: ExportDeps = { + listSessions: async (workDir) => { + listedWorkDirs.push(workDir); + return []; + }, + exportSession: async (input) => { + exportInputs.push(input); + return makeResult(input.id, input.outputPath ?? join(tmp, `${input.id}.zip`)); + }, + confirmPreviousSession: async () => true, + getInstallSource: async () => 'npm-global', + getShellEnv: () => ({ term: 'xterm-256color', shell: '/bin/zsh' }), + version: '1.0.0-test', + cwd: () => tmp, + stdout: { + write: (chunk: string) => { + stdout.push(chunk); + return true; + }, + }, + stderr: { + write: (chunk: string) => { + stderr.push(chunk); + return true; + }, + }, + exit: ((code: number) => { + exitCodes.push(code); + throw new ExitCalled(code); + }) as ExportDeps['exit'], + ...overrides, + }; + return { deps, stdout, stderr, exitCodes, exportInputs, listedWorkDirs }; +} + +class ExitCalled extends Error { + constructor(public readonly code: number) { + super(`exit(${code})`); + } +} + +async function runExport( + deps: ExportDeps, + args: { + sessionId?: string; + output?: string; + yes?: boolean; + includeGlobalLog?: boolean; + } = {}, +): Promise { + try { + await handleExport(deps, args.sessionId, args.output, { + yes: args.yes ?? false, + includeGlobalLog: args.includeGlobalLog ?? true, + }); + } catch (error) { + if (error instanceof ExitCalled) return; + throw error; + } +} + +describe('kimi export', () => { + it('delegates a named session export and prints the resulting zip path', async () => { + const output = join(tmp, 'out.zip'); + const { deps, stdout, stderr, exitCodes, exportInputs, listedWorkDirs } = makeDeps(); + + await runExport(deps, { sessionId: 'ses_test123456', output }); + + expect(exitCodes).toEqual([]); + expect(stderr).toEqual([]); + expect(listedWorkDirs).toEqual([]); + expect(exportInputs).toEqual([{ id: 'ses_test123456', outputPath: output, includeGlobalLog: true, version: '1.0.0-test', installSource: 'npm-global', shellEnv: { term: 'xterm-256color', shell: '/bin/zsh' } }]); + expect(stdout.join('').trim()).toBe(output); + }); + + it('omits outputPath when the caller does not provide --output', async () => { + const { deps, stdout, exportInputs } = makeDeps(); + + await runExport(deps, { sessionId: 'session_default_output' }); + + expect(exportInputs).toEqual([{ id: 'session_default_output', includeGlobalLog: true, version: '1.0.0-test', installSource: 'npm-global', shellEnv: { term: 'xterm-256color', shell: '/bin/zsh' } }]); + expect(stdout.join('').trim()).toBe(join(tmp, 'session_default_output.zip')); + }); + + it('exits 1 when no session-id is provided and no previous session exists', async () => { + const { deps, stderr, exitCodes, exportInputs, listedWorkDirs } = makeDeps(); + + await runExport(deps); + + expect(listedWorkDirs).toEqual([tmp]); + expect(exportInputs).toEqual([]); + expect(exitCodes).toContain(1); + expect(stderr.join('').toLowerCase()).toContain('no previous session'); + }); + + it('surfaces export errors for a named session', async () => { + const { deps, stderr, exitCodes } = makeDeps({ + exportSession: async () => { + throw new Error('Session "ses_does_not_exist" was not found'); + }, + }); + + await runExport(deps, { sessionId: 'ses_does_not_exist' }); + + expect(exitCodes).toContain(1); + expect(stderr.join('').toLowerCase()).toContain('not found'); + }); + + it('falls back to the most-recent session when no id is supplied', async () => { + const previous = makeSummary('ses_fallback'); + const output = join(tmp, 'fallback.zip'); + const { deps, stdout, exitCodes, exportInputs } = makeDeps({ + listSessions: async () => [previous], + }); + + await runExport(deps, { output }); + + expect(exitCodes).toEqual([]); + expect(exportInputs).toEqual([{ id: 'ses_fallback', outputPath: output, includeGlobalLog: true, version: '1.0.0-test', installSource: 'npm-global', shellEnv: { term: 'xterm-256color', shell: '/bin/zsh' } }]); + expect(stdout.join('').trim()).toBe(output); + }); + + it('confirms before exporting the previous session when no id is supplied', async () => { + const previous = makeSummary('ses_confirm', { title: 'Prod debug' }); + const summaries: unknown[] = []; + const { deps, stdout, exitCodes, exportInputs } = makeDeps({ + listSessions: async () => [previous], + confirmPreviousSession: async (summary) => { + summaries.push(summary); + return false; + }, + }); + + await runExport(deps, { output: join(tmp, 'cancelled.zip') }); + + expect(exitCodes).toEqual([]); + expect(exportInputs).toEqual([]); + expect(stdout.join('')).toContain('Export cancelled.'); + expect(summaries).toEqual([ + { + workDir: tmp, + sessionId: 'ses_confirm', + sessionDir: join(tmp, 'sessions', 'ses_confirm'), + title: 'Prod debug', + }, + ]); + }); + + it('skips previous-session confirmation with --yes', async () => { + const previous = makeSummary('ses_yes'); + const { deps, exitCodes, exportInputs } = makeDeps({ + listSessions: async () => [previous], + confirmPreviousSession: async () => { + throw new Error('confirm should not be called'); + }, + }); + + await runExport(deps, { output: join(tmp, 'yes.zip'), yes: true }); + + expect(exitCodes).toEqual([]); + expect(exportInputs).toEqual([{ id: 'ses_yes', outputPath: join(tmp, 'yes.zip'), includeGlobalLog: true, version: '1.0.0-test', installSource: 'npm-global', shellEnv: { term: 'xterm-256color', shell: '/bin/zsh' } }]); + }); + + it('describes the user-facing command without implementation details', () => { + const program = new Command('kimi'); + const { deps } = makeDeps(); + + registerExportCommand(program, deps); + + const command = program.commands.find((item) => item.name() === 'export'); + expect(command?.description()).toBe('Export a session as a ZIP archive.'); + expect(command?.description()).not.toMatch(/sdk/i); + }); + + it('parses --no-include-global-log as an option when no session id is given', async () => { + const previous = makeSummary('ses_global_log'); + const { deps, stdout, exitCodes, exportInputs } = makeDeps({ + listSessions: async () => [previous], + confirmPreviousSession: async () => true, + }); + const program = new Command('kimi'); + registerExportCommand(program, deps); + + await program.parseAsync(['node', 'kimi', 'export', '--no-include-global-log', '-y']); + + expect(exitCodes).toEqual([]); + expect(exportInputs).toEqual([{ id: 'ses_global_log', version: '1.0.0-test', installSource: 'npm-global', shellEnv: { term: 'xterm-256color', shell: '/bin/zsh' } }]); + expect(stdout.join('').trim()).toBe(join(tmp, 'ses_global_log.zip')); + }); + + it('parses options after an explicit session id', async () => { + const output = join(tmp, 'after-id.zip'); + const { deps, exitCodes, exportInputs } = makeDeps(); + const program = new Command('kimi'); + registerExportCommand(program, deps); + + await program.parseAsync([ + 'node', + 'kimi', + 'export', + 'ses_after_id', + '-o', + output, + '-y', + '--no-include-global-log', + ]); + + expect(exitCodes).toEqual([]); + expect(exportInputs).toEqual([ + { id: 'ses_after_id', outputPath: output, version: '1.0.0-test', installSource: 'npm-global', shellEnv: { term: 'xterm-256color', shell: '/bin/zsh' } }, + ]); + }); + + it('initializes and flushes telemetry around default export tracking', async () => { + const program = new Command('kimi'); + const output = join(tmp, 'telemetry.zip'); + mocks.harnessExportSession.mockResolvedValue(makeResult('ses_telemetry', output)); + + registerExportCommand(program, { + cwd: () => tmp, + stdout: { + write: () => true, + }, + stderr: { + write: () => true, + }, + exit: ((code: number) => { + throw new ExitCalled(code); + }) as ExportDeps['exit'], + getShellEnv: () => ({ term: 'xterm-256color', shell: '/bin/zsh' }), + }); + + await program.parseAsync(['node', 'kimi', 'export', 'ses_telemetry', '--output', output], { + from: 'node', + }); + + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledWith( + expect.objectContaining({ + telemetry: { + track: mocks.telemetryTrack, + setContext: mocks.setTelemetryContext, + withContext: mocks.withTelemetryContext, + }, + }), + ); + expect(mocks.harnessEnsureConfigFile).toHaveBeenCalledOnce(); + expect(mocks.harnessGetConfig).toHaveBeenCalledOnce(); + expect(mocks.createKimiDeviceId).toHaveBeenCalledWith( + '/tmp/kimi-export-home', + expect.objectContaining({ onFirstLaunch: expect.any(Function) }), + ); + expect(mocks.initializeTelemetry).toHaveBeenCalledWith({ + homeDir: '/tmp/kimi-export-home', + deviceId: 'device-1', + enabled: true, + appName: 'kimi-code-cli', + version: expect.any(String), + uiMode: 'shell', + model: 'k2', + sessionId: undefined, + endpoint: expect.any(Function), + getAccessToken: expect.any(Function), + onUnexpectedError: expect.any(Function), + }); + // The endpoint resolver defers to the active region profile at flush time. + const telemetryOptions = mocks.initializeTelemetry.mock.calls[0]![0] as { + endpoint: () => string; + }; + expect(telemetryOptions.endpoint()).toBe('https://telemetry-logs.kimi.com/v1/event'); + expect(mocks.initializeTelemetry.mock.invocationCallOrder[0]).toBeLessThan( + mocks.harnessExportSession.mock.invocationCallOrder[0]!, + ); + expect(mocks.harnessExportSession).toHaveBeenCalledWith({ + id: 'ses_telemetry', + outputPath: output, + version: expect.any(String), + includeGlobalLog: true, + installSource: expect.any(String), + shellEnv: expect.objectContaining({ shell: expect.any(String) }), + }); + expect(mocks.shutdownTelemetry).toHaveBeenCalledWith({ timeoutMs: 3000 }); + expect(mocks.harnessExportSession.mock.invocationCallOrder[0]).toBeLessThan( + mocks.shutdownTelemetry.mock.invocationCallOrder[0]!, + ); + }); + + it('passes enabled false when default export config disables telemetry', async () => { + const program = new Command('kimi'); + const output = join(tmp, 'telemetry-disabled.zip'); + mocks.harnessGetConfig.mockResolvedValue({ + providers: {}, + defaultModel: 'k2', + telemetry: false, + }); + mocks.harnessExportSession.mockResolvedValue(makeResult('ses_disabled', output)); + + registerExportCommand(program, { + cwd: () => tmp, + stdout: { + write: () => true, + }, + stderr: { + write: () => true, + }, + exit: ((code: number) => { + throw new ExitCalled(code); + }) as ExportDeps['exit'], + }); + + await program.parseAsync(['node', 'kimi', 'export', 'ses_disabled', '--output', output], { + from: 'node', + }); + + expect(mocks.initializeTelemetry).toHaveBeenCalledWith( + expect.objectContaining({ + enabled: false, + }), + ); + expect(mocks.shutdownTelemetry).toHaveBeenCalledWith({ timeoutMs: 3000 }); + }); + + it('tracks first launch around default export telemetry before harness construction can create the device id', async () => { + const program = new Command('kimi'); + const output = join(tmp, 'telemetry-first-launch.zip'); + mocks.harnessCreatesDeviceIdOnConstruction = true; + const createdHomes = new Set(); + mocks.createKimiDeviceId.mockImplementation((homeDir, options) => { + const deviceId = `device-for-${homeDir}`; + if (!createdHomes.has(homeDir)) { + createdHomes.add(homeDir); + options?.onFirstLaunch?.(deviceId); + } + return deviceId; + }); + mocks.harnessExportSession.mockResolvedValue(makeResult('ses_first_launch', output)); + + registerExportCommand(program, { + cwd: () => tmp, + stdout: { + write: () => true, + }, + stderr: { + write: () => true, + }, + exit: ((code: number) => { + throw new ExitCalled(code); + }) as ExportDeps['exit'], + }); + + await program.parseAsync(['node', 'kimi', 'export', 'ses_first_launch', '--output', output], { + from: 'node', + }); + + expect(mocks.createKimiDeviceId).toHaveBeenNthCalledWith( + 1, + '/tmp/kimi-export-home', + expect.objectContaining({ onFirstLaunch: expect.any(Function) }), + ); + expect(mocks.createKimiDeviceId.mock.invocationCallOrder[0]).toBeLessThan( + mocks.kimiHarnessConstructor.mock.invocationCallOrder[0]!, + ); + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledWith( + expect.objectContaining({ homeDir: '/tmp/kimi-export-home' }), + ); + expect(mocks.harnessTrack).toHaveBeenCalledWith('first_launch'); + expect(mocks.initializeTelemetry.mock.invocationCallOrder[0]).toBeLessThan( + mocks.harnessTrack.mock.invocationCallOrder[0]!, + ); + }); + + it('builds the harness through the SDK factory', async () => { + const program = new Command('kimi'); + const output = join(tmp, 'engine.zip'); + mocks.harnessExportSession.mockResolvedValue(makeResult('ses_engine', output)); + + registerExportCommand(program, { + cwd: () => tmp, + stdout: { + write: () => true, + }, + stderr: { + write: () => true, + }, + exit: ((code: number) => { + throw new ExitCalled(code); + }) as ExportDeps['exit'], + }); + + await program.parseAsync(['node', 'kimi', 'export', 'ses_engine', '--output', output], { + from: 'node', + }); + + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledTimes(1); + expect(mocks.harnessExportSession).toHaveBeenCalledWith( + expect.objectContaining({ id: 'ses_engine', outputPath: output }), + ); + }); +}); diff --git a/apps/kimi-code/test/cli/goal-prompt.test.ts b/apps/kimi-code/test/cli/goal-prompt.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..acc3aba7402e8ecd1d1240ea8a0c46d386e1812d --- /dev/null +++ b/apps/kimi-code/test/cli/goal-prompt.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, it } from 'vitest'; + +import { + GOAL_EXIT_CODES, + formatGoalSummaryText, + goalExitCode, + goalSummaryJson, + parseHeadlessGoalCreate, +} from '#/cli/goal-prompt'; + +function snapshot(overrides: Record = {}) { + return { + goalId: 'g1', + objective: 'work', + status: 'complete', + turnsUsed: 2, + tokensUsed: 120, + wallClockMs: 0, + budget: {} as never, + ...overrides, + }; +} + +describe('goalExitCode', () => { + it('maps final statuses to distinct codes', () => { + expect(goalExitCode('complete')).toBe(GOAL_EXIT_CODES.complete); + expect(goalExitCode('blocked')).toBe(GOAL_EXIT_CODES.blocked); + expect(goalExitCode('paused')).toBe(GOAL_EXIT_CODES.paused); + expect(goalExitCode(undefined)).toBe(0); + expect(goalExitCode('impossible')).toBe(0); + expect(new Set(Object.values(GOAL_EXIT_CODES)).size).toBe(Object.values(GOAL_EXIT_CODES).length); + }); +}); + +describe('parseHeadlessGoalCreate', () => { + it('parses a create command into objective + replace', () => { + const result = parseHeadlessGoalCreate('/goal Ship feature X'); + expect(result).toEqual({ objective: 'Ship feature X', replace: false }); + }); + + it('returns undefined for non-goal prompts and non-create subcommands', () => { + expect(parseHeadlessGoalCreate('say hello')).toBeUndefined(); + expect(parseHeadlessGoalCreate('/goal status')).toBeUndefined(); + expect(parseHeadlessGoalCreate('/goal pause')).toBeUndefined(); + }); + + it('rejects malformed goal create prompts instead of falling through', () => { + expect(() => parseHeadlessGoalCreate(`/goal ${'x'.repeat(4001)}`)).toThrow( + 'Goal objective is too long', + ); + }); +}); + +describe('goal summary', () => { + it('includes id, status, reason, and usage', () => { + const summary = goalSummaryJson( + snapshot({ + status: 'blocked', + terminalReason: 'need creds', + }) as never, + ); + expect(summary).toMatchObject({ + type: 'goal.summary', + goalId: 'g1', + status: 'blocked', + reason: 'need creds', + turnsUsed: 2, + tokensUsed: 120, + }); + }); + + it('renders a null goal', () => { + expect(goalSummaryJson(null).status).toBeNull(); + expect(formatGoalSummaryText(null)).toContain('no goal'); + }); +}); diff --git a/apps/kimi-code/test/cli/headless-exit.test.ts b/apps/kimi-code/test/cli/headless-exit.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a977a70d2dda641ae24a45207fec133e69fe4d15 --- /dev/null +++ b/apps/kimi-code/test/cli/headless-exit.test.ts @@ -0,0 +1,125 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import type { Writable } from 'node:stream'; + +import { drainStdio, finalizeHeadlessRun, scheduleHeadlessForceExit } from '#/cli/headless-exit'; + +describe('scheduleHeadlessForceExit', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('force-exits with the lazily-resolved exit code after the grace period', () => { + vi.useFakeTimers(); + const exit = vi.fn(); + let code = 0; + const handle = scheduleHeadlessForceExit({ exit }, () => code, 2000); + // The exit code can be set after scheduling (e.g. a goal turn maps its + // terminal status to process.exitCode); it must be read at fire time. + code = 7; + + expect(exit).not.toHaveBeenCalled(); + vi.advanceTimersByTime(1999); + expect(exit).not.toHaveBeenCalled(); + vi.advanceTimersByTime(1); + expect(exit).toHaveBeenCalledWith(7); + + clearTimeout(handle); + }); + + it('schedules an unref\'d timer so a healthy run still exits naturally', () => { + // Real timers: an un-unref'd guard would itself keep the event loop alive, + // turning the fix into a regression (every healthy run would wait the full + // grace before exiting). hasRef() must be false. + const exit = vi.fn(); + const handle = scheduleHeadlessForceExit({ exit }, () => 0, 60_000); + expect((handle as { hasRef?: () => boolean }).hasRef?.()).toBe(false); + clearTimeout(handle); + }); + + it('does not fire once cancelled via clearTimeout', () => { + vi.useFakeTimers(); + const exit = vi.fn(); + const handle = scheduleHeadlessForceExit({ exit }, () => 0, 2000); + clearTimeout(handle); + vi.advanceTimersByTime(5000); + expect(exit).not.toHaveBeenCalled(); + }); +}); + +describe('drainStdio', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('resolves once buffered output has flushed', async () => { + let flush: (() => void) | undefined; + const stream = { + write: vi.fn((_chunk: string, cb: () => void) => { + flush = cb; + return false; + }), + } as unknown as Writable; + + let resolved = false; + const done = drainStdio([stream], 5000).then(() => { + resolved = true; + }); + await Promise.resolve(); + expect(resolved).toBe(false); // still draining + + flush?.(); // consumer caught up + await done; + expect(resolved).toBe(true); + }); + + it('gives up after the timeout when the consumer never drains', async () => { + vi.useFakeTimers(); + // write() never invokes its flush callback — a permanently-stuck consumer. + const stream = { write: vi.fn(() => false) } as unknown as Writable; + + let resolved = false; + const done = drainStdio([stream], 3000).then(() => { + resolved = true; + }); + await vi.advanceTimersByTimeAsync(2999); + expect(resolved).toBe(false); + await vi.advanceTimersByTimeAsync(1); + await done; + expect(resolved).toBe(true); + }); +}); + +describe('finalizeHeadlessRun', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('flushes stdio before arming the force-exit so buffered output is not truncated', async () => { + vi.useFakeTimers(); + let flush: (() => void) | undefined; + const stream = { + write: vi.fn((_chunk: string, cb: () => void) => { + flush = cb; + return false; + }), + } as unknown as Writable; + const exit = vi.fn(); + + const done = finalizeHeadlessRun({ exit }, [stream], () => 0, { + drainTimeoutMs: 5000, + graceMs: 2000, + }); + + // Output is still draining: even well past the force-exit grace, we must NOT + // have armed/fired the exit — doing so would truncate the buffered output. + await vi.advanceTimersByTimeAsync(4000); + expect(exit).not.toHaveBeenCalled(); + + // Consumer catches up → drain completes → only now is the backstop armed. + flush?.(); + await done; + expect(exit).not.toHaveBeenCalled(); + await vi.advanceTimersByTimeAsync(2000); + expect(exit).toHaveBeenCalledWith(0); + }); +}); diff --git a/apps/kimi-code/test/cli/login.test.ts b/apps/kimi-code/test/cli/login.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d602660a7af20f122d38aa1b82f054466cff7c10 --- /dev/null +++ b/apps/kimi-code/test/cli/login.test.ts @@ -0,0 +1,198 @@ +/** + * `kimi login` + * + * Verifies that the login sub-command is registered on the program and + * that the action drives `harness.auth.login`, prints the device code to + * stderr, and exits with the right code on success / failure. + */ + +import { Command } from 'commander'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { OAuthAccessDeniedError } from '@moonshot-ai/kimi-code-oauth'; + +const mockLogin = vi.fn(); + +vi.mock('@moonshot-ai/kimi-code-sdk', async () => { + const actual = await vi.importActual( + '@moonshot-ai/kimi-code-sdk', + ); + return { + ...actual, + createKimiHarness: vi.fn(() => ({ + auth: { + login: mockLogin, + }, + })), + }; +}); + +vi.mock('#/utils/open-url', () => ({ openUrl: vi.fn() })); + +import { createKimiHarness } from '@moonshot-ai/kimi-code-sdk'; + +import { registerLoginCommand } from '#/cli/sub/login'; +import { openUrl } from '#/utils/open-url'; + +class ExitCalled extends Error { + constructor(public code: number | string | null | undefined) { + super(`process.exit(${String(code)})`); + } +} + +describe('kimi login', () => { + let exitSpy: ReturnType; + let stderrSpy: ReturnType; + + beforeEach(() => { + mockLogin.mockReset(); + vi.mocked(openUrl).mockReset(); + vi.mocked(createKimiHarness).mockClear(); + exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code?: number | string | null) => { + throw new ExitCalled(code); + }) as never); + stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true); + }); + + afterEach(() => { + exitSpy.mockRestore(); + stderrSpy.mockRestore(); + }); + + it('registers a `login` subcommand on the program', () => { + const program = new Command('kimi'); + registerLoginCommand(program); + + const login = program.commands.find((c) => c.name() === 'login'); + expect(login).toBeDefined(); + expect(login?.description()).toMatch(/[Aa]uthenticat/); + }); + + it('invokes harness.auth.login and exits 0 on success', async () => { + mockLogin.mockResolvedValue({ providerName: 'kimi-code', ok: true }); + + const program = new Command('kimi').exitOverride(); + registerLoginCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'login'])).rejects.toThrow(ExitCalled); + + expect(mockLogin).toHaveBeenCalledTimes(1); + expect(mockLogin).toHaveBeenCalledWith( + undefined, + expect.objectContaining({ + signal: expect.any(AbortSignal), + onDeviceCode: expect.any(Function), + }), + ); + expect(exitSpy).toHaveBeenCalledWith(0); + }); + + it('prints device code prompt to stderr', async () => { + mockLogin.mockImplementation( + async ( + _providerName: string | undefined, + options: { + onDeviceCode?: (data: { + userCode: string; + verificationUri: string; + verificationUriComplete: string; + expiresIn: number | null; + }) => void | Promise; + }, + ) => { + await options.onDeviceCode?.({ + userCode: 'ABCD-EFGH', + verificationUri: 'https://example.com/v', + verificationUriComplete: 'https://example.com/v?code=ABCD-EFGH', + expiresIn: 600, + }); + return { providerName: 'kimi-code', ok: true }; + }, + ); + + const program = new Command('kimi').exitOverride(); + registerLoginCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'login'])).rejects.toThrow(ExitCalled); + + const writtenChunks = stderrSpy.mock.calls.map((call: unknown[]) => String(call[0])); + expect(writtenChunks.some((chunk: string) => chunk.includes('ABCD-EFGH'))).toBe(true); + expect(writtenChunks.some((chunk: string) => chunk.includes('https://example.com/v'))).toBe( + true, + ); + expect(openUrl).toHaveBeenCalledWith('https://example.com/v?code=ABCD-EFGH'); + expect(exitSpy).toHaveBeenCalledWith(0); + }); + + it('still prints device code prompt when opening the browser fails', async () => { + vi.mocked(openUrl).mockImplementation(() => { + throw new Error('no browser'); + }); + mockLogin.mockImplementation( + async ( + _providerName: string | undefined, + options: { + onDeviceCode?: (data: { + userCode: string; + verificationUri: string; + verificationUriComplete: string; + expiresIn: number | null; + }) => void | Promise; + }, + ) => { + await options.onDeviceCode?.({ + userCode: 'ABCD-EFGH', + verificationUri: 'https://example.com/v', + verificationUriComplete: 'https://example.com/v?code=ABCD-EFGH', + expiresIn: 600, + }); + return { providerName: 'kimi-code', ok: true }; + }, + ); + + const program = new Command('kimi').exitOverride(); + registerLoginCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'login'])).rejects.toThrow(ExitCalled); + + const writtenChunks = stderrSpy.mock.calls.map((call: unknown[]) => String(call[0])); + expect(writtenChunks.some((chunk: string) => chunk.includes('ABCD-EFGH'))).toBe(true); + expect(writtenChunks.some((chunk: string) => chunk.includes('https://example.com/v'))).toBe( + true, + ); + expect(openUrl).toHaveBeenCalledWith('https://example.com/v?code=ABCD-EFGH'); + expect(exitSpy).toHaveBeenCalledWith(0); + }); + + it('exits 1 when auth.login throws', async () => { + mockLogin.mockRejectedValue(new Error('boom')); + + const program = new Command('kimi').exitOverride(); + registerLoginCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'login'])).rejects.toThrow(ExitCalled); + + const writtenChunks = stderrSpy.mock.calls.map((call: unknown[]) => String(call[0])); + expect(writtenChunks.some((chunk: string) => chunk.includes('boom'))).toBe(true); + expect(exitSpy).toHaveBeenCalledWith(1); + }); + + it('prints "Login cancelled" with the original message when the user denies authorization', async () => { + mockLogin.mockRejectedValue( + new OAuthAccessDeniedError('Authorization denied: The resource owner denied the request'), + ); + + const program = new Command('kimi').exitOverride(); + registerLoginCommand(program); + + await expect(program.parseAsync(['node', 'kimi', 'login'])).rejects.toThrow(ExitCalled); + + const writtenChunks = stderrSpy.mock.calls.map((call: unknown[]) => String(call[0])); + expect( + writtenChunks.some((chunk: string) => + chunk.includes('Login cancelled: Authorization denied: The resource owner denied the request'), + ), + ).toBe(true); + expect(exitSpy).toHaveBeenCalledWith(1); + }); +}); diff --git a/apps/kimi-code/test/cli/main.test.ts b/apps/kimi-code/test/cli/main.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..edaf222842acffc27b3ac459e289382842c0c058 --- /dev/null +++ b/apps/kimi-code/test/cli/main.test.ts @@ -0,0 +1,505 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { ErrorCodes, KimiError } from '@moonshot-ai/kimi-code-sdk'; + +import { validateOptions } from '#/cli/options'; +import type { CLIOptions } from '#/cli/options'; +import type * as OptionsModule from '#/cli/options'; +import { runPrompt } from '#/cli/run-prompt'; +import { runShell } from '#/cli/run-shell'; +import { formatStartupError } from '#/cli/startup-error'; +import { runUpdatePreflight } from '#/cli/update/preflight'; +import { handleMainCommand, handleUpgradeCommand, main } from '#/main'; + +const mocks = vi.hoisted(() => { + const parse = vi.fn(); + return { + parse, + createProgram: vi.fn(() => ({ parse })), + getVersion: vi.fn(() => '0.0.1-alpha.2'), + validateOptions: vi.fn(), + runUpdatePreflight: vi.fn(), + runShell: vi.fn(), + runPrompt: vi.fn(), + installCrashHandlers: vi.fn(), + track: vi.fn(), + setTelemetryContext: vi.fn(), + withTelemetryContext: vi.fn(), + shutdownTelemetry: vi.fn(), + createCliTelemetryBootstrap: vi.fn(() => ({ + homeDir: '/tmp/kimi-home', + deviceId: 'device-id', + firstLaunch: false, + })), + initializeCliTelemetry: vi.fn(), + handleUpgrade: vi.fn(), + flushDiagnosticLogs: vi.fn(), + finalizeHeadlessRun: vi.fn(), + log: { + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + debug: vi.fn(), + }, + harness: { + homeDir: '/tmp/kimi-home', + ensureConfigFile: vi.fn(), + getConfig: vi.fn(), + close: vi.fn(), + track: vi.fn(), + }, + KimiHarness: vi.fn(), + createKimiHarness: vi.fn(), + maybeRelaunch: vi.fn(async () => false), + runUpdateDownloadCommand: vi.fn(async () => 0), + }; +}); + +vi.mock('@moonshot-ai/kimi-telemetry', () => ({ + installCrashHandlers: mocks.installCrashHandlers, + track: mocks.track, + setTelemetryContext: mocks.setTelemetryContext, + withTelemetryContext: mocks.withTelemetryContext, + shutdownTelemetry: mocks.shutdownTelemetry, +})); + +vi.mock('@moonshot-ai/kimi-code-sdk', async () => { + const actual = await vi.importActual( + '@moonshot-ai/kimi-code-sdk', + ); + class MockKimiHarness { + readonly homeDir = mocks.harness.homeDir; + readonly ensureConfigFile = mocks.harness.ensureConfigFile; + readonly getConfig = mocks.harness.getConfig; + readonly close = mocks.harness.close; + readonly track = mocks.harness.track; + + constructor(...args: unknown[]) { + mocks.KimiHarness(...args); + } + } + return { + ...actual, + createKimiHarness: (...args: unknown[]) => { + mocks.createKimiHarness(...args); + return mocks.harness; + }, + flushDiagnosticLogs: mocks.flushDiagnosticLogs, + KimiHarness: MockKimiHarness, + log: mocks.log, + }; +}); + +vi.mock('../../src/cli/telemetry', () => ({ + createCliTelemetryBootstrap: mocks.createCliTelemetryBootstrap, + initializeCliTelemetry: mocks.initializeCliTelemetry, +})); + +vi.mock('../../src/cli/sub/upgrade', () => ({ + handleUpgrade: mocks.handleUpgrade, +})); + +vi.mock('../../src/cli/commands', () => ({ + createProgram: mocks.createProgram, +})); + +vi.mock('../../src/cli/version', async () => { + const actual = await vi.importActual( + '../../src/cli/version.js', + ); + return { + ...actual, + getVersion: mocks.getVersion, + }; +}); + +vi.mock('../../src/cli/options', async () => { + const actual = await vi.importActual('../../src/cli/options.js'); + return { + ...actual, + validateOptions: mocks.validateOptions, + }; +}); + +vi.mock('../../src/cli/update/preflight', () => ({ + runUpdatePreflight: mocks.runUpdatePreflight, +})); + +vi.mock('../../src/cli/update/native-swap', () => ({ + maybeRelaunchWithStagedNativeUpdate: mocks.maybeRelaunch, +})); + +vi.mock('../../src/cli/sub/update-download', () => ({ + runUpdateDownloadCommand: mocks.runUpdateDownloadCommand, +})); + +vi.mock('../../src/cli/run-shell', () => ({ + runShell: mocks.runShell, +})); + +vi.mock('../../src/cli/run-prompt', () => ({ + runPrompt: mocks.runPrompt, +})); + +vi.mock('../../src/cli/headless-exit', () => ({ + finalizeHeadlessRun: mocks.finalizeHeadlessRun, +})); + +class ExitCalled extends Error { + constructor(readonly code: number) { + super(`exit(${code})`); + } +} + +function defaultOpts(): CLIOptions { + return { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }; +} + +async function waitForAssertion(assertion: () => void): Promise { + let lastError: unknown; + for (let attempt = 0; attempt < 20; attempt += 1) { + try { + assertion(); + return; + } catch (error) { + lastError = error; + await new Promise((resolve) => setTimeout(resolve, 0)); + } + } + throw lastError; +} + +/** main() now boots asynchronously (after the staged-swap check resolves). */ +async function waitForProgramArgs(): Promise { + await waitForAssertion(() => { + expect(mocks.createProgram).toHaveBeenCalled(); + }); + return mocks.createProgram.mock.calls[0] as unknown as unknown[]; +} + +async function runHandleMainCommand(opts: CLIOptions): Promise { + const exitSpy = vi.spyOn(process, 'exit').mockImplementation((code?: string | number | null) => { + throw new ExitCalled(Number(code ?? 0)); + }); + try { + await handleMainCommand(opts, '0.0.1-alpha.2'); + return null; + } catch (error) { + if (error instanceof ExitCalled) { + return error.code; + } + throw error; + } finally { + exitSpy.mockRestore(); + } +} + +async function runHandleUpgradeCommand(yes = false): Promise { + const exitSpy = vi.spyOn(process, 'exit').mockImplementation((code?: string | number | null) => { + throw new ExitCalled(Number(code ?? 0)); + }); + try { + await handleUpgradeCommand('0.0.1-alpha.2', yes); + throw new Error('expected process.exit'); + } catch (error) { + if (error instanceof ExitCalled) { + return error.code; + } + throw error; + } finally { + exitSpy.mockRestore(); + } +} + +describe('main entry command handling', () => { + afterEach(() => { + vi.clearAllMocks(); + }); + + beforeEach(() => { + vi.clearAllMocks(); + mocks.harness.ensureConfigFile.mockResolvedValue(undefined); + mocks.harness.getConfig.mockResolvedValue({ + defaultModel: 'kimi-k2', + telemetry: true, + }); + mocks.harness.close.mockResolvedValue(undefined); + mocks.shutdownTelemetry.mockResolvedValue(undefined); + mocks.handleUpgrade.mockResolvedValue(0); + mocks.flushDiagnosticLogs.mockResolvedValue(undefined); + }); + + it('runs update preflight before starting the shell', async () => { + const opts = defaultOpts(); + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'shell' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runShell.mockResolvedValue(void 0); + + const exitCode = await runHandleMainCommand(opts); + + expect(exitCode).toBeNull(); + expect(validateOptions).toHaveBeenCalledWith(opts); + expect(runUpdatePreflight).toHaveBeenCalledWith('0.0.1-alpha.2', { track: expect.any(Function) }); + expect(mocks.runUpdatePreflight.mock.invocationCallOrder[0]).toBeLessThan( + mocks.runShell.mock.invocationCallOrder[0]!, + ); + expect(runShell).toHaveBeenCalledWith(opts, '0.0.1-alpha.2'); + }); + + it('runs prompt mode without interactive update preflight', async () => { + const opts: CLIOptions = { + ...defaultOpts(), + prompt: 'explain the repo', + }; + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'print' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runPrompt.mockResolvedValue(void 0); + + const exitCode = await runHandleMainCommand(opts); + + expect(exitCode).toBeNull(); + expect(runUpdatePreflight).toHaveBeenCalledWith('0.0.1-alpha.2', { + track: expect.any(Function), + isTTY: false, + }); + expect(runPrompt).toHaveBeenCalledWith(opts, '0.0.1-alpha.2'); + expect(runShell).not.toHaveBeenCalled(); + }); + + it('does not force-exit from the reusable handler in print mode', async () => { + const opts: CLIOptions = { ...defaultOpts(), prompt: 'explain the repo' }; + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'print' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runPrompt.mockResolvedValue(void 0); + + const outcome = await handleMainCommand(opts, '0.0.1-alpha.2'); + + // Process disposition belongs to the entrypoint, never to this reusable, + // unit-tested handler: arming a process.exit here would kill the test runner + // or any embedding host. The handler only reports what ran. + expect(mocks.finalizeHeadlessRun).not.toHaveBeenCalled(); + expect(outcome).toEqual({ headlessCompleted: true }); + }); + + it('reports no headless completion for interactive (shell) mode', async () => { + const opts = defaultOpts(); + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'shell' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runShell.mockResolvedValue(void 0); + + const outcome = await handleMainCommand(opts, '0.0.1-alpha.2'); + + expect(outcome).toEqual({ headlessCompleted: false }); + expect(mocks.finalizeHeadlessRun).not.toHaveBeenCalled(); + }); + + it('arms the force-exit fallback at the entrypoint after a completed headless run', async () => { + const opts: CLIOptions = { ...defaultOpts(), prompt: 'explain the repo' }; + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'print' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runPrompt.mockResolvedValue(void 0); + mocks.finalizeHeadlessRun.mockResolvedValue(void 0); + + main(); + const programArgs = await waitForProgramArgs(); + const mainAction = programArgs[1] as (opts: CLIOptions) => void; + mainAction(opts); + + await waitForAssertion(() => { + expect(mocks.finalizeHeadlessRun).toHaveBeenCalledTimes(1); + }); + // The exit code is resolved lazily so a goal turn that sets process.exitCode wins. + const forceExitArgs = mocks.finalizeHeadlessRun.mock.calls[0] as unknown as unknown[]; + expect(typeof forceExitArgs[2]).toBe('function'); + }); + + it('sets the failure exit code before awaiting startup failure logging', async () => { + const originalExitCode = process.exitCode; + const opts: CLIOptions = { ...defaultOpts(), prompt: 'explain the repo' }; + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'print' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runPrompt.mockRejectedValue(new Error('provider failed')); + mocks.flushDiagnosticLogs.mockImplementation(() => new Promise(() => {})); + const exitSpy = vi.spyOn(process, 'exit').mockImplementation((code?: string | number | null) => { + throw new ExitCalled(Number(code ?? 0)); + }); + + try { + main(); + const programArgs = await waitForProgramArgs(); + const mainAction = programArgs[1] as (opts: CLIOptions) => void; + mainAction(opts); + + await waitForAssertion(() => { + expect(mocks.flushDiagnosticLogs).toHaveBeenCalledTimes(1); + }); + expect(process.exitCode).toBe(1); + expect(exitSpy).not.toHaveBeenCalled(); + } finally { + exitSpy.mockRestore(); + process.exitCode = originalExitCode; + } + }); + + it('keeps shell mode update preflight interactive by default', async () => { + const opts = defaultOpts(); + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'shell' }); + mocks.runUpdatePreflight.mockResolvedValue('continue'); + mocks.runShell.mockResolvedValue(void 0); + + const exitCode = await runHandleMainCommand(opts); + + expect(exitCode).toBeNull(); + expect(runUpdatePreflight).toHaveBeenCalledWith('0.0.1-alpha.2', { + track: expect.any(Function), + }); + expect(runShell).toHaveBeenCalledWith(opts, '0.0.1-alpha.2'); + }); + + it('installs crash handlers before parsing CLI arguments', async () => { + main(); + + expect(mocks.installCrashHandlers).toHaveBeenCalledTimes(1); + await waitForAssertion(() => { + expect(mocks.installCrashHandlers.mock.invocationCallOrder[0]).toBeLessThan( + mocks.createProgram.mock.invocationCallOrder[0]!, + ); + expect(mocks.parse).toHaveBeenCalledWith(process.argv); + }); + }); + + it('runs the staged-swap check before bootstrap and skips startup when it relaunches', async () => { + mocks.maybeRelaunch.mockResolvedValueOnce(true); + + main(); + + await waitForAssertion(() => { + expect(mocks.maybeRelaunch).toHaveBeenCalledTimes(1); + }); + // Relaunched → the parent must sit on the child, never bootstrap. + await new Promise((resolve) => setTimeout(resolve, 20)); + expect(mocks.createProgram).not.toHaveBeenCalled(); + }); + + it('passes the runtime context to the staged-swap check', async () => { + main(); + + await waitForAssertion(() => { + expect(mocks.maybeRelaunch).toHaveBeenCalledWith( + expect.objectContaining({ + exePath: process.execPath, + argv: process.argv, + currentVersion: '0.0.1-alpha.2', + isNative: false, + }), + ); + }); + }); + + it('sets the process title during startup', () => { + const originalTitle = process.title; + try { + process.title = 'kimi-test-runner'; + main(); + + expect(process.title).toBe('kimi-code'); + } finally { + process.title = originalTitle; + } + }); + + it('exits early when update preflight requests process exit', async () => { + const opts = defaultOpts(); + mocks.validateOptions.mockReturnValue({ options: opts, uiMode: 'shell' }); + mocks.runUpdatePreflight.mockResolvedValue('exit'); + mocks.runShell.mockResolvedValue(void 0); + + const exitCode = await runHandleMainCommand(opts); + + expect(exitCode).toBe(0); + expect(runShell).not.toHaveBeenCalled(); + }); + + it('initializes and flushes telemetry around the upgrade command', async () => { + const exitCode = await runHandleUpgradeCommand(); + + expect(exitCode).toBe(0); + expect(mocks.createCliTelemetryBootstrap).toHaveBeenCalledTimes(1); + expect(mocks.createKimiHarness).toHaveBeenCalledWith(expect.objectContaining({ + homeDir: '/tmp/kimi-home', + telemetry: { + track: mocks.track, + withContext: mocks.withTelemetryContext, + setContext: mocks.setTelemetryContext, + }, + })); + expect(mocks.harness.ensureConfigFile).toHaveBeenCalledTimes(1); + expect(mocks.initializeCliTelemetry).toHaveBeenCalledWith(expect.objectContaining({ + harness: expect.objectContaining({ + homeDir: '/tmp/kimi-home', + }), + bootstrap: { + homeDir: '/tmp/kimi-home', + deviceId: 'device-id', + firstLaunch: false, + }, + config: { + defaultModel: 'kimi-k2', + telemetry: true, + }, + version: '0.0.1-alpha.2', + uiMode: 'shell', + })); + expect(mocks.handleUpgrade).toHaveBeenCalledWith('0.0.1-alpha.2', { + track: mocks.track, + logger: mocks.log, + yes: false, + }); + expect(mocks.shutdownTelemetry).toHaveBeenCalledWith({ timeoutMs: 3000 }); + expect(mocks.harness.close).toHaveBeenCalledTimes(1); + }); + + it('formats Kimi startup errors with structured fields', () => { + const error = new KimiError( + ErrorCodes.SHELL_GIT_BASH_NOT_FOUND, + 'Git Bash was not found on this Windows host. Checked: C:\\Program Files\\Git\\bin\\bash.exe.', + ); + const red = (text: string): string => `\u001B[31m${text}\u001B[39m`; + + expect(formatStartupError(error, { errorStyle: red })).toBe( + [ + '\u001B[31merror: Git Bash not found\u001B[39m', + '', + '\u001B[31mmessage:\u001B[39m', + '\u001B[31mGit Bash was not found on this Windows host. Checked: C:\\Program Files\\Git\\bin\\bash.exe.\u001B[39m', + '', + ].join('\n'), + ); + }); + + it('keeps generic startup errors on the legacy fallback path', () => { + expect(formatStartupError(new Error('Provider not set'), { errorStyle: (text) => text })).toBe( + 'error: failed to start shell: Provider not set\n', + ); + }); + + it('formats generic prompt mode errors without saying shell', () => { + expect( + formatStartupError(new Error('Provider not set'), { + errorStyle: (text) => text, + operation: 'run prompt', + }), + ).toBe('error: failed to run prompt: Provider not set\n'); + }); +}); diff --git a/apps/kimi-code/test/cli/options.test.ts b/apps/kimi-code/test/cli/options.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa1cfb2cac4e84aa4a07a715bfaf050954aa5c24 --- /dev/null +++ b/apps/kimi-code/test/cli/options.test.ts @@ -0,0 +1,624 @@ +/** + * Scenario: top-level CLI option parsing, validation, and help discovery. + * Responsibilities: accepted arguments map to CLIOptions and invalid combinations fail early. + * Wiring: Commander is real; command handlers and output sinks are local test boundaries. + * Run: pnpm -C apps/kimi-code exec vitest run test/cli/options.test.ts + */ + +import { describe, expect, it, vi } from 'vitest'; + +import { createProgram } from '#/cli/commands'; +import type { CLIOptions } from '#/cli/options'; +import { OptionConflictError, OUTPUT_FORMAT_ENV, resolveOutputFormat, validateOptions } from '#/cli/options'; + +function parse(argv: string[]): CLIOptions { + let captured: CLIOptions | undefined; + + const program = createProgram( + '0.1.0-test', + (opts) => { + captured = opts; + }, + () => {}, + ); + + program.exitOverride(); + program.configureOutput({ + writeOut: () => {}, + writeErr: () => {}, + }); + + program.parse(['node', 'kimi', ...argv]); + + if (captured === undefined) { + throw new Error('Main action handler was not called'); + } + return captured; +} + +describe('CLI options parsing', () => { + describe('defaults', () => { + it('returns defaults when no arguments are given', () => { + const opts = parse([]); + expect(opts.yolo).toBe(false); + expect(opts.plan).toBe(false); + expect(opts.continue).toBe(false); + expect(opts.session).toBeUndefined(); + expect(opts.model).toBeUndefined(); + expect(opts.outputFormat).toBeUndefined(); + expect(opts.prompt).toBeUndefined(); + expect(opts.skillsDirs).toEqual([]); + expect(opts.agent).toBeUndefined(); + expect(opts.agentFiles).toEqual([]); + expect(opts.addDirs).toEqual([]); + }); + }); + + describe('--version', () => { + it('prints the version string and exits', () => { + let output = ''; + const program = createProgram( + '1.2.3', + () => {}, + () => {}, + ); + program.exitOverride(); + program.configureOutput({ + writeOut: (s) => { + output += s; + }, + }); + + expect(() => program.parse(['node', 'kimi', '--version'])).toThrow(); + expect(output).toContain('1.2.3'); + }); + + it('supports -V as a short alias', () => { + let output = ''; + const program = createProgram( + '4.5.6', + () => {}, + () => {}, + ); + program.exitOverride(); + program.configureOutput({ + writeOut: (s) => { + output += s; + }, + }); + + expect(() => program.parse(['node', 'kimi', '-V'])).toThrow(); + expect(output).toContain('4.5.6'); + }); + }); + + describe('hidden plugin node runner', () => { + it('routes __plugin_run_node without calling the main action', () => { + const pluginRunnerCalls: Array<{ entry: string; args: readonly string[] }> = []; + const program = createProgram( + '0.0.0', + () => { + throw new Error('main action should not run'); + }, + () => {}, + (entry, args) => { + pluginRunnerCalls.push({ entry, args }); + }, + ); + program.exitOverride(); + program.configureOutput({ + writeOut: () => {}, + writeErr: () => {}, + }); + + program.parse([ + 'node', + 'kimi', + '__plugin_run_node', + '/plugin/tool.mjs', + '--', + 'query', + '--flag', + ]); + + expect(pluginRunnerCalls).toEqual([{ entry: '/plugin/tool.mjs', args: ['query', '--flag'] }]); + }); + }); + + describe('--yolo family', () => { + it('--yolo sets yolo to true', () => { + expect(parse(['--yolo']).yolo).toBe(true); + }); + + it('-y sets yolo to true', () => { + expect(parse(['-y']).yolo).toBe(true); + }); + + it('--yes sets yolo to true (hidden alias)', () => { + expect(parse(['--yes']).yolo).toBe(true); + }); + + it('--auto-approve sets yolo to true (hidden alias)', () => { + expect(parse(['--auto-approve']).yolo).toBe(true); + }); + }); + + describe('--session / --resume / --continue', () => { + it('-S sets session', () => { + expect(parse(['-S', 'sess-123']).session).toBe('sess-123'); + }); + + it('-r is an alias for --session', () => { + expect(parse(['-r', 'sess-456']).session).toBe('sess-456'); + }); + + it('--resume is an alias for --session', () => { + expect(parse(['--resume', 'sess-789']).session).toBe('sess-789'); + }); + + it('bare -S (no id) yields empty string — triggers the picker', () => { + expect(parse(['-S']).session).toBe(''); + }); + + it('-C sets continue', () => { + expect(parse(['-C']).continue).toBe(true); + }); + + it('-c is an alias for --continue', () => { + expect(parse(['-c']).continue).toBe(true); + }); + + it('--continue and --session combined raises a conflict', () => { + const opts = parse(['--continue', '--session', 'abc123']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Cannot combine --continue, --session.'); + }); + }); + + describe('--plan', () => { + it('sets plan mode flag', () => { + expect(parse(['--plan']).plan).toBe(true); + }); + }); + + describe('--auto / --yolo / --plan with --session / --continue', () => { + it('allows --auto with --continue', () => { + const opts = parse(['--auto', '--continue']); + expect(opts.auto).toBe(true); + expect(opts.continue).toBe(true); + expect(validateOptions(opts).uiMode).toBe('shell'); + }); + + it('allows --auto with an explicit session id', () => { + const opts = parse(['--auto', '--session', 'ses_123']); + expect(opts.auto).toBe(true); + expect(opts.session).toBe('ses_123'); + expect(validateOptions(opts).uiMode).toBe('shell'); + }); + + it('allows --yolo with --continue', () => { + const opts = parse(['--yolo', '--continue']); + expect(opts.yolo).toBe(true); + expect(opts.continue).toBe(true); + expect(validateOptions(opts).uiMode).toBe('shell'); + }); + + it('allows --yolo with an explicit session id', () => { + const opts = parse(['--yolo', '--session', 'ses_123']); + expect(opts.yolo).toBe(true); + expect(opts.session).toBe('ses_123'); + expect(validateOptions(opts).uiMode).toBe('shell'); + }); + + it('allows --plan with --continue', () => { + const opts = parse(['--plan', '--continue']); + expect(opts.plan).toBe(true); + expect(opts.continue).toBe(true); + expect(validateOptions(opts).uiMode).toBe('shell'); + }); + + it('allows --plan with an explicit session id', () => { + const opts = parse(['--plan', '--session', 'ses_123']); + expect(opts.plan).toBe(true); + expect(opts.session).toBe('ses_123'); + expect(validateOptions(opts).uiMode).toBe('shell'); + }); + }); + + describe('--model / -m', () => { + it('parses -m as a model override', () => { + expect(parse(['-m', 'kimi-code/k2']).model).toBe('kimi-code/k2'); + }); + + it('parses --model=value as a model override', () => { + expect(parse(['--model=kimi-code/k2.5']).model).toBe('kimi-code/k2.5'); + }); + + it('rejects empty model values', () => { + const opts = parse(['--model', ' ']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Model cannot be empty.'); + }); + }); + + describe('--prompt / -p', () => { + it('parses -p as prompt mode', () => { + const opts = parse(['-p', 'explain this repo']); + expect(opts.prompt).toBe('explain this repo'); + expect(validateOptions(opts).uiMode).toBe('print'); + }); + + it('parses --prompt=value as prompt mode', () => { + const opts = parse(['--prompt=explain this repo']); + expect(opts.prompt).toBe('explain this repo'); + expect(validateOptions(opts).uiMode).toBe('print'); + }); + + it('rejects empty prompt values before reaching the SDK', () => { + const opts = parse(['-p', ' ']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Prompt cannot be empty.'); + }); + + it('allows prompt mode with --continue', () => { + const opts = parse(['-p', 'continue here', '--continue']); + expect(opts.continue).toBe(true); + expect(validateOptions(opts).uiMode).toBe('print'); + }); + + it('allows prompt mode with a concrete session id', () => { + const opts = parse(['-p', 'resume here', '--session', 'ses_123']); + expect(opts.session).toBe('ses_123'); + expect(validateOptions(opts).uiMode).toBe('print'); + }); + + it('rejects prompt mode with bare --session picker', () => { + const opts = parse(['-p', 'resume here', '--session']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow( + 'Cannot use --session without an id in prompt mode.', + ); + }); + + it('rejects prompt mode with --yolo because prompt mode always uses auto permission', () => { + const opts = parse(['-p', 'run this', '--yolo']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Cannot combine --prompt with --yolo.'); + }); + + it('rejects prompt mode with --plan', () => { + const opts = parse(['-p', 'run this', '--plan']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Cannot combine --prompt with --plan.'); + }); + + it('parses --output-format=stream-json in prompt mode', () => { + const opts = parse(['-p', 'run this', '--output-format=stream-json']); + expect(opts.outputFormat).toBe('stream-json'); + expect(validateOptions(opts).uiMode).toBe('print'); + }); + + it('parses --output-format text in prompt mode', () => { + const opts = parse(['-p', 'run this', '--output-format', 'text']); + expect(opts.outputFormat).toBe('text'); + }); + + it('rejects --output-format outside prompt mode', () => { + const opts = parse(['--output-format=stream-json']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow( + 'Output format is only supported in prompt mode.', + ); + }); + }); + + describe('KIMI_MODEL_OUTPUT_FORMAT', () => { + it('defaults to text when unset in prompt mode', () => { + expect(resolveOutputFormat({ prompt: 'run this', outputFormat: undefined }, {})).toBe('text'); + }); + + it('uses stream-json from the env in prompt mode', () => { + expect( + resolveOutputFormat( + { prompt: 'run this', outputFormat: undefined }, + { [OUTPUT_FORMAT_ENV]: 'stream-json' }, + ), + ).toBe('stream-json'); + }); + + it('uses text from the env in prompt mode', () => { + expect( + resolveOutputFormat( + { prompt: 'run this', outputFormat: undefined }, + { [OUTPUT_FORMAT_ENV]: 'text' }, + ), + ).toBe('text'); + }); + + it('trims surrounding whitespace from the env value', () => { + expect( + resolveOutputFormat( + { prompt: 'run this', outputFormat: undefined }, + { [OUTPUT_FORMAT_ENV]: ' stream-json ' }, + ), + ).toBe('stream-json'); + }); + + it('lets the --output-format flag override the env', () => { + expect( + resolveOutputFormat( + { prompt: 'run this', outputFormat: 'text' }, + { [OUTPUT_FORMAT_ENV]: 'stream-json' }, + ), + ).toBe('text'); + }); + + it('ignores the env outside prompt mode', () => { + expect( + resolveOutputFormat( + { prompt: undefined, outputFormat: undefined }, + { [OUTPUT_FORMAT_ENV]: 'stream-json' }, + ), + ).toBe('text'); + }); + + it('rejects an invalid env value', () => { + expect(() => + resolveOutputFormat( + { prompt: 'run this', outputFormat: undefined }, + { [OUTPUT_FORMAT_ENV]: 'json' }, + ), + ).toThrow(OptionConflictError); + expect(() => + resolveOutputFormat( + { prompt: 'run this', outputFormat: undefined }, + { [OUTPUT_FORMAT_ENV]: 'json' }, + ), + ).toThrow('Invalid KIMI_MODEL_OUTPUT_FORMAT value "json"'); + }); + + it('fails validation fast for an invalid env value in prompt mode', () => { + const opts = parse(['-p', 'run this']); + expect(() => validateOptions(opts, { [OUTPUT_FORMAT_ENV]: 'json' })).toThrow( + OptionConflictError, + ); + }); + + it('does not validate the env outside prompt mode', () => { + const opts = parse([]); + expect(() => validateOptions(opts, { [OUTPUT_FORMAT_ENV]: 'json' })).not.toThrow(); + }); + }); + + describe('--skills-dir', () => { + it('collects repeated skill directories', () => { + expect(parse(['--skills-dir', '/one', '--skills-dir=/two']).skillsDirs).toEqual([ + '/one', + '/two', + ]); + }); + }); + + describe('--agent / --agent-file', () => { + it('describes agent selectors as new-session-only', () => { + const help = createProgram('0.1.0-test', () => {}, () => {}).helpInformation(); + const normalizedHelp = help.replaceAll(/\s+/g, ' '); + + expect(normalizedHelp).toContain('Agent profile to start the new session with.'); + expect(normalizedHelp).not.toContain('print-mode invocation'); + }); + + it('parses a single --agent', () => { + const opts = parse(['-p', 'hi', '--agent', 'reviewer']); + expect(opts.agent).toBe('reviewer'); + expect(opts.agentFiles).toEqual([]); + }); + + it('parses a single --agent-file', () => { + const opts = parse(['-p', 'hi', '--agent-file', 'a.md']); + expect(opts.agent).toBeUndefined(); + expect(opts.agentFiles).toEqual(['a.md']); + }); + + it('rejects repeated --agent', () => { + expect(() => parse(['-p', 'hi', '--agent', 'reviewer', '--agent', 'writer'])).toThrow( + '--agent may only be specified once.', + ); + }); + + it('rejects repeated --agent-file', () => { + expect(() => + parse(['-p', 'hi', '--agent-file', 'a.md', '--agent-file', 'b.md']), + ).toThrow('--agent-file may only be specified once.'); + }); + + it('rejects combining --agent with --agent-file', () => { + expect(() => + parse(['-p', 'hi', '--agent', 'reviewer', '--agent-file', 'reviewer.md']), + ).toThrow("option '--agent ' cannot be used with option '--agent-file '"); + }); + + it('rejects multiple agent files passed directly to validation', () => { + const opts = parse(['-p', 'hi', '--agent-file', 'a.md']); + expect(() => validateOptions({ ...opts, agentFiles: ['a.md', 'b.md'] })).toThrow( + '--agent-file may only be specified once.', + ); + }); + + it('rejects mixed agent selectors passed directly to validation', () => { + const opts = parse(['-p', 'hi', '--agent', 'reviewer']); + expect(() => validateOptions({ ...opts, agentFiles: ['reviewer.md'] })).toThrow( + 'Cannot combine --agent with --agent-file.', + ); + }); + + it('rejects --agent-file with --session', () => { + const opts = parse(['-p', 'hi', '--agent-file', 'a.md', '--session', 'ses_123']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow( + 'Cannot combine --agent/--agent-file with --session/--continue', + ); + }); + + it('rejects --agent-file with --continue', () => { + const opts = parse(['-p', 'hi', '--agent-file', 'a.md', '--continue']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow( + 'Cannot combine --agent/--agent-file with --session/--continue', + ); + }); + + it('rejects --agent with --session', () => { + const opts = parse(['-p', 'hi', '--agent', 'reviewer', '--session', 'ses_123']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow( + 'Cannot combine --agent/--agent-file with --session/--continue', + ); + }); + + it('rejects --agent with --continue in shell mode', () => { + const opts = parse(['--agent', 'reviewer', '--continue']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow( + 'Cannot combine --agent/--agent-file with --session/--continue', + ); + }); + + it('rejects empty agent values', () => { + const opts = parse(['-p', 'hi', '--agent', ' ']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Agent cannot be empty.'); + }); + + it('rejects empty agent file values', () => { + const opts = parse(['-p', 'hi', '--agent-file', ' ']); + expect(() => validateOptions(opts)).toThrow(OptionConflictError); + expect(() => validateOptions(opts)).toThrow('Agent file path cannot be empty.'); + }); + + it('accepts the flags in shell mode', () => { + expect(validateOptions(parse(['--agent', 'reviewer']), {}).uiMode).toBe('shell'); + expect(validateOptions(parse(['--agent-file', 'a.md']), {}).uiMode).toBe('shell'); + }); + + it('accepts the flags in prompt mode', () => { + const opts = parse(['-p', 'hi', '--agent-file', 'a.md']); + expect(validateOptions(opts, {}).uiMode).toBe('print'); + }); + + it('accepts --agent in prompt mode', () => { + const opts = parse(['-p', 'hi', '--agent', 'reviewer']); + expect(validateOptions(opts, {}).uiMode).toBe('print'); + }); + }); + + describe('--add-dir', () => { + it('parses one additional workspace directory', () => { + expect(parse(['--add-dir', '/shared']).addDirs).toEqual(['/shared']); + }); + + it('parses repeated additional workspace directories', () => { + expect(parse(['--add-dir', '/one', '--add-dir=/two']).addDirs).toEqual(['/one', '/two']); + }); + }); + + describe('sub-commands', () => { + it('routes upgrade without calling the main action', () => { + const upgradeYes: boolean[] = []; + const program = createProgram( + '0.0.0', + () => { + throw new Error('main action should not run'); + }, + () => {}, + () => {}, + (yes) => { + upgradeYes.push(yes); + }, + ); + program.exitOverride(); + program.configureOutput({ + writeOut: () => {}, + writeErr: () => {}, + }); + + program.parse(['node', 'kimi', 'upgrade']); + + expect(upgradeYes).toEqual([false]); + }); + + it('routes update alias to the upgrade handler', () => { + const upgradeYes: boolean[] = []; + const program = createProgram( + '0.0.0', + () => { + throw new Error('main action should not run'); + }, + () => {}, + () => {}, + (yes) => { + upgradeYes.push(yes); + }, + ); + program.exitOverride(); + program.configureOutput({ + writeOut: () => {}, + writeErr: () => {}, + }); + + program.parse(['node', 'kimi', 'update', '-y']); + + expect(upgradeYes).toEqual([true]); + }); + + it('registers the visible sub-commands', () => { + const program = createProgram( + '0.0.0', + () => {}, + () => {}, + ); + const commandNames: string[] = program.commands + .filter((command) => !command.name().startsWith('__') && !(command as unknown as { _hidden?: boolean })._hidden) + .map((command) => command.name()); + expect(commandNames).toEqual([ + 'export', + 'fork', + 'provider', + 'session', + 'acp', + 'web', + 'server', + 'rc', + 'login', + 'doctor', + 'vis', + 'migrate', + 'upgrade', + ]); + }); + + }); + + describe('rejected flags', () => { + it('any removed flag is unknown to Commander', () => { + for (const arg of [ + '--verbose', + '--debug', + '--work-dir=/', + '--config=x', + '--thinking', + '--print', + '--wire', + '--raw-model', + '--config-file=x', + '--quiet', + '--final-message-only', + '--input-format=text', + '--mcp-config={}', + '--mcp-config-file=/', + ]) { + expect(() => parse([arg])).toThrow(); + } + }); + }); +}); diff --git a/apps/kimi-code/test/cli/provider.test.ts b/apps/kimi-code/test/cli/provider.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..30540caaf6b7add8858bce36cf8a0214dd612c18 --- /dev/null +++ b/apps/kimi-code/test/cli/provider.test.ts @@ -0,0 +1,1146 @@ +/** + * `kimi provider` CLI unit tests. The handlers receive an injected `getHarness` + * + capturing stdout/stderr, so we test the wiring end-to-end without booting + * a real harness or hitting the network. + */ + +import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'; +import { Command } from 'commander'; +import type { KimiConfig } from '@moonshot-ai/kimi-code-sdk'; + +import { + handleCatalogAdd, + handleCatalogList, + handleProviderAdd, + handleProviderList, + handleProviderRemove, + registerProviderCommand, + type ProviderDeps, +} from '#/cli/sub/provider'; + +// Spy on the SDK harness factory so the default-deps construction can be +// asserted without booting a real engine. The real implementations stay in +// place for everything else the handlers use. +const harnessRouting = vi.hoisted(() => ({ + kimiHarnessConstructor: vi.fn(), + harness: undefined as unknown, +})); + +vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + createKimiHarness: (...args: unknown[]) => { + harnessRouting.kimiHarnessConstructor(...args); + return harnessRouting.harness; + }, + }; +}); + +class ExitCalled extends Error { + constructor(public readonly code: number) { + super(`exit(${code})`); + } +} + +interface FakeHarness { + ensureConfigFile: () => Promise; + getConfig: () => Promise; + setConfig: (patch: Partial) => Promise; + removeProvider: (providerId: string) => Promise; + close: () => Promise; +} + +function makeHarness(initial: KimiConfig): { + harness: FakeHarness; + current: () => KimiConfig; + setConfigCalls: Array>; + removeCalls: string[]; +} { + // `persisted` simulates the on-disk config; the real RPC's `removeProvider` + // reads from / writes to disk on every call. Tests must + // model this: anything the handler builds up in its in-memory `config` + // object disappears unless it is flushed via `setConfig` BEFORE the next + // `removeProvider`. + let persisted: KimiConfig = structuredClone(initial); + const setConfigCalls: Array> = []; + const removeCalls: string[] = []; + const harness: FakeHarness = { + ensureConfigFile: async () => {}, + getConfig: async () => structuredClone(persisted), + setConfig: async (patch) => { + setConfigCalls.push(structuredClone(patch)); + // Mirror the real `setKimiConfig`: deep-merge with undefined keys + // skipped. This is + // load-bearing for tests that assert `setConfig({defaultModel: + // undefined})` does NOT wipe a key from disk — only `removeProvider` + // can. + const next: Record = { ...persisted }; + for (const [key, value] of Object.entries(patch)) { + if (value === undefined) continue; + next[key] = value; + } + persisted = next as KimiConfig; + return structuredClone(persisted); + }, + removeProvider: async (providerId) => { + removeCalls.push(providerId); + const nextProviders = { ...persisted.providers }; + delete nextProviders[providerId]; + const nextModels = { ...persisted.models }; + let removedDefault = false; + for (const [alias, model] of Object.entries(nextModels)) { + if (model.provider === providerId) { + delete nextModels[alias]; + if (persisted.defaultModel === alias) removedDefault = true; + } + } + persisted = { ...persisted, providers: nextProviders, models: nextModels }; + if (removedDefault) persisted = { ...persisted, defaultModel: undefined }; + return structuredClone(persisted); + }, + close: async () => {}, + }; + return { + harness, + current: () => persisted, + setConfigCalls, + removeCalls, + }; +} + +function makeDeps( + harness: FakeHarness, + overrides: Partial = {}, +): { + deps: ProviderDeps; + stdout: string[]; + stderr: string[]; + exitCodes: number[]; +} { + const stdout: string[] = []; + const stderr: string[] = []; + const exitCodes: number[] = []; + const deps: ProviderDeps = { + getHarness: () => harness as unknown as ProviderDeps extends { getHarness: () => infer R } + ? R + : never, + stdout: { + write: (chunk: string) => { + stdout.push(chunk); + return true; + }, + }, + stderr: { + write: (chunk: string) => { + stderr.push(chunk); + return true; + }, + }, + env: {}, + exit: ((code: number) => { + exitCodes.push(code); + throw new ExitCalled(code); + }) as ProviderDeps['exit'], + ...overrides, + }; + return { deps, stdout, stderr, exitCodes }; +} + +async function tryRun(fn: () => Promise): Promise { + try { + return await fn(); + } catch (error) { + if (error instanceof ExitCalled) return undefined; + throw error; + } +} + +const REGISTRY_URL = 'https://registry.example.test/v1/models/api.json'; +const REGISTRY_BODY = { + kohub: { + id: 'kohub', + name: 'KoHub Anthropic', + api: 'https://registry.example.test', + type: 'anthropic', + models: { + 'claude-opus-4-7': { id: 'claude-opus-4-7', name: 'Claude Opus 4-7', tool_call: true }, + }, + }, + 'kohub-responses': { + id: 'kohub-responses', + name: 'KoHub Responses', + api: 'https://registry.example.test/v1', + type: 'openai_responses', + models: { + 'gpt-5.5': { id: 'gpt-5.5', name: 'GPT 5.5', reasoning: true }, + }, + }, +}; + +let originalFetch: typeof globalThis.fetch; + +beforeEach(() => { + originalFetch = globalThis.fetch; +}); + +afterEach(() => { + globalThis.fetch = originalFetch; + vi.restoreAllMocks(); +}); + +function mockRegistryFetch(body: unknown = REGISTRY_BODY, status = 200): ReturnType { + const fetchMock = vi.fn( + async () => + new Response(JSON.stringify(body), { + status, + headers: { 'Content-Type': 'application/json' }, + }), + ); + globalThis.fetch = fetchMock as unknown as typeof globalThis.fetch; + return fetchMock; +} + +const CATALOG_BODY = { + anthropic: { + id: 'anthropic', + name: 'Anthropic', + npm: '@ai-sdk/anthropic', + api: 'https://api.anthropic.com', + env: ['ANTHROPIC_API_KEY'], + models: { + 'claude-opus-4-7': { + id: 'claude-opus-4-7', + name: 'Claude Opus 4.7', + limit: { context: 200_000, output: 64_000 }, + tool_call: true, + reasoning: true, + modalities: { input: ['text', 'image'], output: ['text'] }, + }, + 'claude-haiku-4-5': { + id: 'claude-haiku-4-5', + name: 'Claude Haiku 4.5', + limit: { context: 200_000, output: 16_000 }, + tool_call: true, + modalities: { input: ['text'], output: ['text'] }, + }, + }, + }, + openai: { + id: 'openai', + name: 'OpenAI', + npm: '@ai-sdk/openai', + api: 'https://api.openai.com/v1', + env: ['OPENAI_API_KEY'], + models: { + 'gpt-5.5': { + id: 'gpt-5.5', + name: 'GPT 5.5', + limit: { context: 1_048_576, output: 128_000 }, + tool_call: true, + reasoning: true, + modalities: { input: ['text', 'image'], output: ['text'] }, + }, + }, + }, +}; + +describe('kimi provider add', () => { + it('imports providers and models from a custom registry, persisting source on each provider', async () => { + const fetchMock = mockRegistryFetch(); + const { harness, current, setConfigCalls } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleProviderAdd(deps, REGISTRY_URL, { apiKey: 'sk-test-token' }), + ); + + expect(exitCodes).toEqual([]); + expect(stderr.join('')).toBe(''); + expect(fetchMock).toHaveBeenCalledWith( + REGISTRY_URL, + expect.objectContaining({ + headers: expect.objectContaining({ Authorization: 'Bearer sk-test-token' }), + }), + ); + + const finalConfig = current(); + expect(Object.keys(finalConfig.providers).toSorted()).toEqual(['kohub', 'kohub-responses']); + const kohub = finalConfig.providers['kohub']!; + expect(kohub.type).toBe('anthropic'); + expect(kohub.baseUrl).toBe('https://registry.example.test'); + expect(kohub.apiKey).toBe('sk-test-token'); + expect(kohub.source).toEqual({ + kind: 'apiJson', + url: REGISTRY_URL, + apiKey: 'sk-test-token', + }); + + expect(finalConfig.models?.['kohub/claude-opus-4-7']).toMatchObject({ + provider: 'kohub', + model: 'claude-opus-4-7', + }); + expect(finalConfig.models?.['kohub-responses/gpt-5.5']).toMatchObject({ + provider: 'kohub-responses', + model: 'gpt-5.5', + }); + + // The single setConfig patch should carry both providers and models. + expect(setConfigCalls).toHaveLength(1); + expect(Object.keys(setConfigCalls[0]?.providers ?? {}).toSorted()).toEqual([ + 'kohub', + 'kohub-responses', + ]); + + const output = stdout.join(''); + expect(output).toContain('Imported 2 providers (2 models)'); + expect(output).toContain('- kohub'); + expect(output).toContain('- kohub-responses'); + }); + + it('drops a stale provider before re-applying when the id already exists', async () => { + mockRegistryFetch(); + const initial: KimiConfig = { + providers: { + kohub: { + type: 'kimi', + baseUrl: 'https://stale.example.test', + apiKey: 'old', + }, + }, + models: { + 'kohub/stale-model': { + provider: 'kohub', + model: 'stale-model', + maxContextSize: 1024, + capabilities: [], + }, + }, + } as unknown as KimiConfig; + const { harness, removeCalls, current } = makeHarness(initial); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleProviderAdd(deps, REGISTRY_URL, { apiKey: 'sk-new' }), + ); + + expect(exitCodes).toEqual([]); + expect(removeCalls).toContain('kohub'); + // The stale model alias must be gone; the registry's alias must be in. + expect(current().models?.['kohub/stale-model']).toBeUndefined(); + expect(current().models?.['kohub/claude-opus-4-7']).toBeDefined(); + }); + + it('preserves newly-imported providers when a later registry entry replaces an existing id', async () => { + // Regression test for the codex P1: `harness.removeProvider` re-reads + // from disk on each call, so applying the loop body without flushing + // would silently drop providers added earlier in the same iteration. + // The handler now removes every stale id up front in a single batch. + mockRegistryFetch(); + const initial: KimiConfig = { + providers: { + // The registry will replace this one. + 'kohub-responses': { + type: 'openai_responses', + baseUrl: 'https://stale.example.test/v1', + apiKey: 'old', + }, + }, + models: { + 'kohub-responses/legacy-model': { + provider: 'kohub-responses', + model: 'legacy-model', + maxContextSize: 1024, + capabilities: [], + }, + }, + } as unknown as KimiConfig; + const { harness, current } = makeHarness(initial); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleProviderAdd(deps, REGISTRY_URL, { apiKey: 'sk-fresh' }), + ); + + expect(exitCodes).toEqual([]); + const final = current(); + // BOTH providers must end up in the final config — `kohub` was newly + // added in the loop, `kohub-responses` was replaced. The old bug dropped + // `kohub` because the second iteration's `removeProvider` reloaded a + // disk-backed config that had not yet been persisted with `kohub`. + expect(final.providers['kohub']).toBeDefined(); + expect(final.providers['kohub-responses']).toBeDefined(); + expect(final.providers['kohub-responses']?.apiKey).toBe('sk-fresh'); + expect(final.models?.['kohub/claude-opus-4-7']).toBeDefined(); + expect(final.models?.['kohub-responses/gpt-5.5']).toBeDefined(); + expect(final.models?.['kohub-responses/legacy-model']).toBeUndefined(); + }); + + it('reads the api key from KIMI_REGISTRY_API_KEY when --api-key is omitted', async () => { + const fetchMock = mockRegistryFetch(); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, exitCodes } = makeDeps(harness, { + env: { KIMI_REGISTRY_API_KEY: 'sk-env-token' }, + }); + + await tryRun(() => handleProviderAdd(deps, REGISTRY_URL, {})); + + expect(exitCodes).toEqual([]); + expect(fetchMock).toHaveBeenCalledWith( + REGISTRY_URL, + expect.objectContaining({ + headers: expect.objectContaining({ Authorization: 'Bearer sk-env-token' }), + }), + ); + }); + + it('exits 1 with a clear message when no api key is supplied anywhere', async () => { + const fetchMock = mockRegistryFetch(); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleProviderAdd(deps, REGISTRY_URL, {})); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toMatch(/missing api key/i); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it('exits 1 when the registry fetch fails with an HTTP error', async () => { + mockRegistryFetch({ message: 'invalid token' }, 401); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleProviderAdd(deps, REGISTRY_URL, { apiKey: 'sk-bad' }), + ); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toMatch(/HTTP 401/); + }); +}); + +describe('kimi provider remove', () => { + it('removes a provider and reports success', async () => { + const initial: KimiConfig = { + providers: { + kohub: { type: 'anthropic', baseUrl: 'https://x', apiKey: 'k' }, + }, + models: { + 'kohub/m': { + provider: 'kohub', + model: 'm', + maxContextSize: 1024, + capabilities: [], + }, + }, + } as unknown as KimiConfig; + const { harness, removeCalls, current } = makeHarness(initial); + const { deps, stdout, exitCodes } = makeDeps(harness); + + await tryRun(() => handleProviderRemove(deps, 'kohub')); + + expect(exitCodes).toEqual([]); + expect(removeCalls).toEqual(['kohub']); + expect(current().providers['kohub']).toBeUndefined(); + expect(stdout.join('')).toContain('Removed provider "kohub"'); + }); + + it('exits 1 when the provider id does not exist', async () => { + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleProviderRemove(deps, 'nope')); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('Provider "nope" not found'); + }); +}); + +describe('kimi provider list', () => { + const config: KimiConfig = { + providers: { + kohub: { + type: 'anthropic', + baseUrl: 'https://x', + apiKey: 'k', + source: { kind: 'apiJson', url: REGISTRY_URL, apiKey: 'k' }, + }, + 'managed:kimi-code': { + type: 'kimi', + baseUrl: 'https://api.kimi.com/coding/v1', + oauth: { storage: 'file', key: 'oauth/kimi-code' }, + }, + manual: { type: 'openai', baseUrl: 'https://y', apiKey: 'm' }, + }, + models: { + 'kohub/a': { + provider: 'kohub', + model: 'a', + maxContextSize: 1024, + capabilities: [], + }, + 'kohub/b': { + provider: 'kohub', + model: 'b', + maxContextSize: 1024, + capabilities: [], + }, + 'manual/x': { + provider: 'manual', + model: 'x', + maxContextSize: 1024, + capabilities: [], + }, + }, + defaultModel: 'kohub/a', + } as unknown as KimiConfig; + + it('renders one row per provider with counts and source labels', async () => { + const { harness } = makeHarness(config); + const { deps, stdout } = makeDeps(harness); + + await tryRun(() => handleProviderList(deps, { json: false })); + + const out = stdout.join(''); + expect(out).toMatch(/kohub\s+type=anthropic\s+models=2\s+source=apiJson\(/); + expect(out).toMatch(/managed:kimi-code\s+type=kimi\s+models=0\s+source=oauth/); + expect(out).toMatch(/manual\s+type=openai\s+models=1\s+source=inline/); + expect(out).toContain('Default model: kohub/a'); + }); + + it('prints a friendly message when nothing is configured', async () => { + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout } = makeDeps(harness); + + await tryRun(() => handleProviderList(deps, { json: false })); + + expect(stdout.join('')).toContain('No providers configured'); + }); + + it('emits parseable JSON with --json', async () => { + const { harness } = makeHarness(config); + const { deps, stdout } = makeDeps(harness); + + await tryRun(() => handleProviderList(deps, { json: true })); + + const parsed = JSON.parse(stdout.join('')) as { + providers: Record; + models: Record; + }; + expect(Object.keys(parsed.providers).toSorted()).toEqual([ + 'kohub', + 'managed:kimi-code', + 'manual', + ]); + expect(Object.keys(parsed.models)).toContain('kohub/a'); + }); +}); + +describe('registerProviderCommand', () => { + it('describes the user-facing subcommand and routes flags through commander', async () => { + const fetchMock = mockRegistryFetch(); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, exitCodes, stdout } = makeDeps(harness); + + const program = new Command('kimi'); + registerProviderCommand(program, deps); + + const providerCmd = program.commands.find((c) => c.name() === 'provider'); + expect(providerCmd?.description()).toMatch(/Manage LLM providers/i); + + await tryRun(() => + program.parseAsync( + ['node', 'kimi', 'provider', 'add', REGISTRY_URL, '--api-key', 'sk-cli'], + { from: 'node' }, + ), + ); + + expect(exitCodes).toEqual([]); + expect(fetchMock).toHaveBeenCalledWith( + REGISTRY_URL, + expect.objectContaining({ + headers: expect.objectContaining({ Authorization: 'Bearer sk-cli' }), + }), + ); + expect(Object.keys(current().providers).toSorted()).toEqual(['kohub', 'kohub-responses']); + expect(stdout.join('')).toContain('Imported 2 providers'); + }); + + it('reports write failures on stderr and exits 1 instead of crashing', async () => { + const { harness } = makeHarness({ + providers: { kimi: { type: 'kimi' } }, + } as unknown as KimiConfig); + // Simulate the strict write path rejecting because config.toml is invalid. + harness.removeProvider = async () => { + throw new Error( + 'Cannot change settings while config.toml is invalid — fix it first (run `kimi doctor` for details).', + ); + }; + const { deps, stderr, exitCodes } = makeDeps(harness); + + const program = new Command('kimi'); + registerProviderCommand(program, deps); + + await tryRun(() => + program.parseAsync(['node', 'kimi', 'provider', 'remove', 'kimi'], { from: 'node' }), + ); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('Cannot change settings'); + expect(stderr.join('')).not.toContain(' at '); // no stack trace dump + }); +}); + +describe('kimi provider catalog list', () => { + it('lists catalog providers with wire/model counts, sorted by id', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogList(deps, undefined, { json: false })); + + expect(exitCodes).toEqual([]); + const out = stdout.join(''); + expect(out).toMatch(/^anthropic\s+wire=anthropic\s+models=2\s+Anthropic\n/); + expect(out).toMatch(/openai\s+wire=openai\s+models=1\s+OpenAI/); + // anthropic before openai (alphabetical). + expect(out.indexOf('anthropic')).toBeLessThan(out.indexOf('openai')); + }); + + it('filters case-insensitively by id and name substring', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout } = makeDeps(harness); + + await tryRun(() => handleCatalogList(deps, undefined, { json: false, filter: 'open' })); + + const out = stdout.join(''); + expect(out).toContain('openai'); + expect(out).not.toContain('anthropic'); + }); + + it('drills into a specific providerId and lists its models with capabilities', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout } = makeDeps(harness); + + await tryRun(() => handleCatalogList(deps, 'anthropic', { json: false })); + + const out = stdout.join(''); + expect(out).toMatch(/^Anthropic \(anthropic\)/); + expect(out).toMatch(/claude-opus-4-7\s+ctx=200000.*tool_use.*thinking.*image_in/); + expect(out).toMatch(/claude-haiku-4-5\s+ctx=200000.*tool_use/); + }); + + it('exits 1 when the requested providerId is missing from the catalog', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogList(deps, 'unknown', { json: false })); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('Provider "unknown" not found in catalog'); + }); + + it('emits parseable JSON for the providerId view', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout } = makeDeps(harness); + + await tryRun(() => handleCatalogList(deps, 'openai', { json: true })); + + const parsed = JSON.parse(stdout.join('')) as { + providerId: string; + models: Array<{ id: string }>; + }; + expect(parsed.providerId).toBe('openai'); + expect(parsed.models.map((m) => m.id)).toEqual(['gpt-5.5']); + }); + + it('honors --url override when supplied', async () => { + const fetchMock = mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps } = makeDeps(harness); + + await tryRun(() => + handleCatalogList(deps, undefined, { json: true, url: 'https://example.test/catalog.json' }), + ); + + expect(fetchMock).toHaveBeenCalledWith('https://example.test/catalog.json', expect.any(Object)); + }); +}); + +describe('kimi provider catalog add', () => { + it('imports a provider from the catalog without changing the default model', async () => { + mockRegistryFetch(CATALOG_BODY); + const initial: KimiConfig = { + providers: { + other: { type: 'kimi', baseUrl: 'https://x', apiKey: 'k' }, + }, + models: { + 'other/main': { + provider: 'other', + model: 'main', + maxContextSize: 1024, + capabilities: [], + }, + }, + defaultModel: 'other/main', + thinking: { enabled: true }, + } as unknown as KimiConfig; + const { harness, current, setConfigCalls } = makeHarness(initial); + const { deps, stdout, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { apiKey: 'sk-ant-token' }), + ); + + expect(exitCodes).toEqual([]); + const finalConfig = current(); + expect(finalConfig.providers['anthropic']).toMatchObject({ + type: 'anthropic', + apiKey: 'sk-ant-token', + }); + // Catalog import populates the model aliases. + expect(finalConfig.models?.['anthropic/claude-opus-4-7']).toMatchObject({ + provider: 'anthropic', + model: 'claude-opus-4-7', + }); + expect(finalConfig.models?.['anthropic/claude-haiku-4-5']).toBeDefined(); + // The unrelated provider's model survives, and remains the default. + expect(finalConfig.models?.['other/main']).toBeDefined(); + expect(finalConfig.defaultModel).toBe('other/main'); + expect(finalConfig.thinking?.enabled).toBe(true); + // The patch sent over `setConfig` must explicitly carry the preserved default. + expect(setConfigCalls[0]?.defaultModel).toBe('other/main'); + expect(stdout.join('')).toContain('Imported Anthropic (anthropic)'); + }); + + it('sets default_model when --default-model is supplied and the model exists', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness, current, setConfigCalls } = makeHarness({ + providers: {}, + } as KimiConfig); + const { deps, stdout, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { + apiKey: 'sk-ant-token', + defaultModel: 'claude-opus-4-7', + }), + ); + + expect(exitCodes).toEqual([]); + expect(current().defaultModel).toBe('anthropic/claude-opus-4-7'); + expect(setConfigCalls[0]?.defaultModel).toBe('anthropic/claude-opus-4-7'); + expect(stdout.join('')).toContain('Default model set to anthropic/claude-opus-4-7'); + }); + + it('rejects an unknown --default-model with a helpful hint', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { + apiKey: 'sk-ant-token', + defaultModel: 'does-not-exist', + }), + ); + + expect(exitCodes).toEqual([1]); + const err = stderr.join(''); + expect(err).toContain('"does-not-exist" is not in provider "anthropic"'); + expect(err).toContain('kimi provider catalog list anthropic'); + }); + + it('preserves an existing default_model when re-importing the same provider without --default-model', async () => { + // Regression test for the codex P2: `removeProvider` clears + // `defaultModel` if it pointed at one of the provider's aliases. The + // handler must capture the previous default BEFORE calling + // `removeProvider`, otherwise rotating the api key on an already- + // configured provider would silently wipe the user's chosen default. + mockRegistryFetch(CATALOG_BODY); + const initial: KimiConfig = { + providers: { + anthropic: { + type: 'anthropic', + baseUrl: 'https://api.anthropic.com', + apiKey: 'sk-old', + }, + }, + models: { + 'anthropic/claude-opus-4-7': { + provider: 'anthropic', + model: 'claude-opus-4-7', + maxContextSize: 200_000, + capabilities: ['tool_use', 'thinking', 'image_in'], + }, + }, + defaultModel: 'anthropic/claude-opus-4-7', + thinking: { enabled: true }, + } as unknown as KimiConfig; + const { harness, current } = makeHarness(initial); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { apiKey: 'sk-rotated' }), + ); + + expect(exitCodes).toEqual([]); + expect(current().providers['anthropic']?.apiKey).toBe('sk-rotated'); + // Previous default and thinking flag must survive the re-import. + expect(current().defaultModel).toBe('anthropic/claude-opus-4-7'); + expect(current().thinking?.enabled).toBe(true); + }); + + it('preserves thinking.enabled when --default-model is supplied to a thinking-capable model', async () => { + // Regression test for the codex P2: `applyCatalogProvider` always + // assigns `thinking.enabled` from `options.thinking`. Hardcoding `false` + // silently disabled thinking even when the user previously had it on + // and is just importing a known provider. The handler now threads the + // previous value through. + mockRegistryFetch(CATALOG_BODY); + const initial: KimiConfig = { + providers: {}, + thinking: { enabled: true }, + } as unknown as KimiConfig; + const { harness, current, setConfigCalls } = makeHarness(initial); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { + apiKey: 'sk-ant', + defaultModel: 'claude-opus-4-7', + }), + ); + + expect(exitCodes).toEqual([]); + expect(current().defaultModel).toBe('anthropic/claude-opus-4-7'); + expect(current().thinking?.enabled).toBe(true); + expect(setConfigCalls[0]?.thinking?.enabled).toBe(true); + }); + + it('does not persist thinking.enabled=false for first-time setup with --default-model', async () => { + // Regression test for codex P2 follow-up: previously the handler fell + // back to `false` when `thinking.enabled` was unset, but + // `resolveThinkingEffort` treats `thinking.enabled === false` as an + // explicit "off" request. A fresh `kimi provider catalog add + // anthropic --default-model claude-opus-4-7` must NOT silently disable + // thinking — it should leave `thinking.enabled` unset so the runtime + // uses the per-model default. + mockRegistryFetch(CATALOG_BODY); + // Note: `thinking.enabled` is omitted on purpose to model a fresh user. + const { harness, current, setConfigCalls } = makeHarness({ + providers: {}, + } as KimiConfig); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { + apiKey: 'sk-ant', + defaultModel: 'claude-opus-4-7', + }), + ); + + expect(exitCodes).toEqual([]); + expect(current().defaultModel).toBe('anthropic/claude-opus-4-7'); + // Must NOT be `false`. `undefined` lets the runtime resolver pick the + // per-model default; `false` would force `'off'`. + expect(current().thinking?.enabled).toBeUndefined(); + expect(setConfigCalls[0]?.thinking?.enabled).toBeUndefined(); + }); + + it('drops a stale default_model when the catalog refresh no longer contains it', async () => { + // Regression test for codex P2: when the user previously chose + // `anthropic/legacy` as default and a refresh of the same provider no + // longer ships that model, restoring the previous default would point + // `default_model` at a non-existent alias and break the next session. + // The handler now checks whether the alias still resolves and clears + // it otherwise. + mockRegistryFetch(CATALOG_BODY); + const initial: KimiConfig = { + providers: { + anthropic: { + type: 'anthropic', + baseUrl: 'https://api.anthropic.com', + apiKey: 'sk-old', + }, + }, + models: { + 'anthropic/legacy-claude': { + provider: 'anthropic', + model: 'legacy-claude', + maxContextSize: 200_000, + capabilities: [], + }, + }, + defaultModel: 'anthropic/legacy-claude', + } as unknown as KimiConfig; + const { harness, current } = makeHarness(initial); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'anthropic', { apiKey: 'sk-rotated' }), + ); + + expect(exitCodes).toEqual([]); + // The legacy alias must have been replaced by the catalog's models. + expect(current().models?.['anthropic/legacy-claude']).toBeUndefined(); + expect(current().models?.['anthropic/claude-opus-4-7']).toBeDefined(); + // The dangling default must NOT have been restored — it would point at + // a non-existent alias. The handler clears it instead. + expect(current().defaultModel).toBeUndefined(); + }); + + it('falls back to KIMI_REGISTRY_API_KEY when --api-key is omitted', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, exitCodes } = makeDeps(harness, { + env: { KIMI_REGISTRY_API_KEY: 'sk-env' }, + }); + + await tryRun(() => handleCatalogAdd(deps, 'openai', {})); + + expect(exitCodes).toEqual([]); + expect(current().providers['openai']).toMatchObject({ apiKey: 'sk-env' }); + }); + + it('lets --base-url override the catalog-declared endpoint', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'openai', { + apiKey: 'sk-o', + baseUrl: 'https://proxy.example.test/v1', + }), + ); + + expect(exitCodes).toEqual([]); + expect(current().providers['openai']).toMatchObject({ + type: 'openai', + baseUrl: 'https://proxy.example.test/v1', + }); + }); + + it('strips a trailing /v1 from --base-url for Anthropic-wire imports', async () => { + mockRegistryFetch({ + 'claude-gateway': { + id: 'claude-gateway', + name: 'Claude Gateway', + npm: '@custom/claude-gateway', + models: { 'claude-x': { id: 'claude-x', limit: { context: 1000 } } }, + }, + }); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'claude-gateway', { + apiKey: 'sk-gw', + baseUrl: 'https://claude-gateway.example.test/v1', + }), + ); + + expect(exitCodes).toEqual([]); + expect(current().providers['claude-gateway']).toMatchObject({ + type: 'anthropic', + // The Anthropic SDK appends /v1/messages itself — persisting the /v1 + // would double it (/v1/v1/messages). + baseUrl: 'https://claude-gateway.example.test', + }); + }); + + it('rejects an empty --base-url instead of persisting a blank endpoint', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogAdd(deps, 'openai', { apiKey: 'sk-o', baseUrl: ' ' })); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('--base-url cannot be empty'); + await expect(harness.getConfig().then((c) => c.providers['openai'])).resolves.toBeUndefined(); + }); + + it('requires --base-url for a non-official Anthropic-compatible vendor without one', async () => { + mockRegistryFetch({ + 'claude-gateway': { + id: 'claude-gateway', + name: 'Claude Gateway', + npm: '@custom/claude-gateway', + models: { 'claude-x': { id: 'claude-x', limit: { context: 1000 } } }, + }, + }); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogAdd(deps, 'claude-gateway', { apiKey: 'sk-gw' })); + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('--base-url'); + + await tryRun(() => + handleCatalogAdd(deps, 'claude-gateway', { + apiKey: 'sk-gw', + baseUrl: 'https://claude-gateway.example.test', + }), + ); + expect(current().providers['claude-gateway']).toMatchObject({ + type: 'anthropic', + baseUrl: 'https://claude-gateway.example.test', + }); + }); + + it('exits 1 when the api key is missing and skips the network', async () => { + const fetchMock = mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogAdd(deps, 'anthropic', {})); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toMatch(/missing api key/i); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it('exits 1 when the providerId is missing from the catalog', async () => { + mockRegistryFetch(CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'no-such-id', { apiKey: 'sk-x' }), + ); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('Provider "no-such-id" not found in catalog'); + }); + + const GUESS_CATALOG_BODY = { + xai: { + id: 'xai', + name: 'xAI', + npm: '@ai-sdk/xai', + env: ['XAI_API_KEY'], + models: { + 'grok-4': { + id: 'grok-4', + limit: { context: 256_000 }, + reasoning: true, + reasoning_options: [{ type: 'effort', values: ['none', 'low', 'medium', 'high'] }], + }, + }, + }, + bedrock: { + id: 'amazon-bedrock', + name: 'Amazon Bedrock', + npm: '@ai-sdk/amazon-bedrock', + models: { 'claude-x': { id: 'claude-x', limit: { context: 1000 } } }, + }, + azure: { + id: 'azure', + name: 'Azure', + npm: '@ai-sdk/azure', + env: ['AZURE_API_KEY'], + models: { 'gpt-x': { id: 'gpt-x', limit: { context: 1000 } } }, + }, + }; + + it('guesses openai for a vendor-specific SDK and requires --base-url', async () => { + mockRegistryFetch(GUESS_CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogAdd(deps, 'xai', { apiKey: 'sk-xai' })); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('--base-url'); + await expect(harness.getConfig().then((c) => c.providers['xai'])).resolves.toBeUndefined(); + }); + + it('imports a guessed vendor with --base-url, carrying off_effort and a guess note', async () => { + mockRegistryFetch(GUESS_CATALOG_BODY); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stdout, exitCodes } = makeDeps(harness); + + await tryRun(() => + handleCatalogAdd(deps, 'xai', { apiKey: 'sk-xai', baseUrl: 'https://api.x.ai/v1' }), + ); + + expect(exitCodes).toEqual([]); + expect(current().providers['xai']).toMatchObject({ + type: 'openai', + baseUrl: 'https://api.x.ai/v1', + apiKey: 'sk-xai', + }); + expect(current().models?.['xai/grok-4']).toMatchObject({ + supportEfforts: ['low', 'medium', 'high'], + offEffort: 'none', + }); + expect(stdout.join('')).toContain('guessed "openai"'); + }); + + it('refuses a proprietary SDK (bedrock) instead of guessing', async () => { + mockRegistryFetch(GUESS_CATALOG_BODY); + const { harness } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogAdd(deps, 'bedrock', { apiKey: 'sk-x' })); + + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('proprietary'); + }); + + it('requires --base-url for a vendor with no catalog endpoint (azure shape)', async () => { + mockRegistryFetch(GUESS_CATALOG_BODY); + const { harness, current } = makeHarness({ providers: {} } as KimiConfig); + const { deps, stderr, exitCodes } = makeDeps(harness); + + await tryRun(() => handleCatalogAdd(deps, 'azure', { apiKey: 'sk-az' })); + expect(exitCodes).toEqual([1]); + expect(stderr.join('')).toContain('--base-url'); + + await tryRun(() => + handleCatalogAdd(deps, 'azure', { apiKey: 'sk-az', baseUrl: 'https://res.example.test/openai/v1' }), + ); + expect(current().providers['azure']).toMatchObject({ + type: 'openai', + baseUrl: 'https://res.example.test/openai/v1', + }); + }); +}); + +describe('kimi provider engine routing', () => { + beforeEach(() => { + harnessRouting.kimiHarnessConstructor.mockClear(); + harnessRouting.harness = makeHarness({ providers: {} } as KimiConfig).harness; + }); + + afterEach(() => { + vi.unstubAllEnvs(); + }); + + function registerWithDefaultHarness(program: Command): void { + registerProviderCommand(program, { + stdout: { write: () => true }, + stderr: { write: () => true }, + env: {}, + exit: ((code: number) => { + throw new ExitCalled(code); + }) as ProviderDeps['exit'], + }); + } + + it('builds the harness through the SDK factory', async () => { + const program = new Command('kimi'); + registerWithDefaultHarness(program); + + await program.parseAsync(['node', 'kimi', 'provider', 'list'], { from: 'node' }); + + expect(harnessRouting.kimiHarnessConstructor).toHaveBeenCalledTimes(1); + }); +}); diff --git a/apps/kimi-code/test/cli/run-prompt.test.ts b/apps/kimi-code/test/cli/run-prompt.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ace5f861579a15dec2d0241497c5fd8e58c1fd5e --- /dev/null +++ b/apps/kimi-code/test/cli/run-prompt.test.ts @@ -0,0 +1,108 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { runPrompt } from '#/cli/run-prompt'; + +const mocks = vi.hoisted(() => ({ + runV2Print: vi.fn( + async ( + opts: { readonly outputFormat?: string }, + version: string, + io?: { + readonly stdout?: { write(chunk: string): boolean }; + readonly stderr?: { write(chunk: string): boolean }; + }, + ) => { + const stdout = io?.stdout ?? process.stdout; + const stderr = io?.stderr ?? process.stderr; + const outputFormat = opts?.outputFormat ?? 'text'; + if (outputFormat === 'stream-json') { + stdout.write( + `${JSON.stringify({ role: 'meta', type: 'system.version', version })}\n`, + ); + stdout.write(`${JSON.stringify({ role: 'assistant', content: 'hello world' })}\n`); + stdout.write( + `${JSON.stringify({ + role: 'meta', + type: 'session.resume_hint', + session_id: 'ses_prompt', + command: 'kimi -r ses_prompt', + content: 'To resume this session: kimi -r ses_prompt', + })}\n`, + ); + return; + } + stderr.write(`kimi version ${version}\n`); + stdout.write('• hello world\n\n'); + stderr.write('To resume this session: kimi -r ses_prompt\n'); + }, + ), +})); + +vi.mock('../../src/cli/v2/run-v2-print', () => ({ + runV2Print: mocks.runV2Print, +})); + +function opts(overrides: Partial[0]> = {}) { + return { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: 'say hello', + skillsDirs: [], + agent: undefined, + agentFiles: [], + addDirs: [], + ...overrides, + }; +} + +function writer(columns?: number) { + let text = ''; + return { + columns, + write: vi.fn((chunk: string) => { + text += chunk; + return true; + }), + text: () => text, + }; +} + +describe('runPrompt', () => { + afterEach(() => { + vi.clearAllMocks(); + }); + + it('emits the version first in text mode', async () => { + const stdout = writer(); + const stderr = writer(); + + await runPrompt(opts(), '1.2.3-test', { stdout, stderr }); + + expect(mocks.runV2Print).toHaveBeenCalled(); + expect(stderr.write).toHaveBeenNthCalledWith(1, 'kimi version 1.2.3-test\n'); + expect(stderr.text().startsWith('kimi version 1.2.3-test\n')).toBe(true); + expect(stdout.text()).toBe('• hello world\n\n'); + }); + + it('emits the version first in stream-json mode', async () => { + const stdout = writer(); + const stderr = writer(); + + await runPrompt(opts({ outputFormat: 'stream-json' }), '1.2.3-test', { + stdout, + stderr, + }); + + expect(mocks.runV2Print).toHaveBeenCalled(); + const lines = stdout.text().split('\n'); + expect(lines[0]).toBe( + '{"role":"meta","type":"system.version","version":"1.2.3-test"}', + ); + expect(stderr.text()).toBe(''); + }); +}); diff --git a/apps/kimi-code/test/cli/run-shell.test.ts b/apps/kimi-code/test/cli/run-shell.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..40ca1d742d1a3848e5c29a06e4d19765e43ec375 --- /dev/null +++ b/apps/kimi-code/test/cli/run-shell.test.ts @@ -0,0 +1,983 @@ +import { execFileSync } from 'node:child_process'; + +import type { createKimiDeviceId as createKimiDeviceIdFn } from '@moonshot-ai/kimi-code-oauth'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { runShell } from '#/cli/run-shell'; +import { refreshKimiRegion } from '#/utils/region'; + +import { captureProcessWrite, ExitCalled, mockProcessExit } from '../helpers/process'; + +type CreateKimiDeviceId = typeof createKimiDeviceIdFn; + +const mocks = vi.hoisted(() => { + type TuiConfigFallback = { + theme: 'dark' | 'light' | 'auto'; + editorCommand: string | null; + notifications: { enabled: boolean; condition: 'unfocused' | 'always' }; + }; + + class TuiConfigParseError extends Error { + readonly fallback: TuiConfigFallback; + + constructor(fallback: TuiConfigFallback) { + super('Invalid TUI config in ~/.kimi-code/tui.toml; using defaults.'); + this.fallback = fallback; + } + } + + const lifecycleTrack = vi.fn(); + + return { + loadTuiConfig: vi.fn(), + detectTerminalTheme: vi.fn(), + kimiHarnessConstructor: vi.fn(), + harnessEnsureConfigFile: vi.fn(), + harnessGetConfig: vi.fn(async () => ({ + providers: {}, + defaultModel: 'k2', + telemetry: true, + })), + harnessGetConfigDiagnostics: vi.fn(async () => ({ warnings: [] as readonly string[] })), + harnessGetCachedAccessToken: vi.fn(), + harnessClose: vi.fn(), + detectPendingMigration: vi.fn<() => Promise>(async () => null), + harnessTrack: vi.fn(), + kimiTuiConstructor: vi.fn(), + tuiStart: vi.fn(), + tuiGetStartupMcpMs: vi.fn(async () => 0), + tuiGetCurrentSessionId: vi.fn(() => ''), + tuiHasSessionContent: vi.fn(() => false), + createKimiDeviceId: vi.fn(() => 'device-1'), + initializeTelemetry: vi.fn(), + setCrashPhase: vi.fn(), + shutdownTelemetry: vi.fn(), + telemetryTrack: vi.fn(), + setTelemetryContext: vi.fn(), + lifecycleTrack, + withTelemetryContext: vi.fn(() => ({ + track: lifecycleTrack, + })), + resolveKimiHome: vi.fn((homeDir?: string) => homeDir ?? '/tmp/kimi-code-test-home'), + flushDiagnosticLogsSync: vi.fn(), + harnessCreatesDeviceIdOnConstruction: false, + execFileSync: vi.fn(() => ''), + spawnSync: vi.fn(), + resolveCommandPath: vi.fn(() => '/bin/stty' as string | undefined), + TuiConfigParseError, + }; +}); + +vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => { + const actual = await importOriginal(); + const makeHarnessStub = (args: unknown[]) => { + const options = args[0] as { readonly homeDir?: string } | undefined; + const homeDir = options?.homeDir ?? '/tmp/kimi-code-test-home'; + return { + homeDir, + auth: { + getCachedAccessToken: mocks.harnessGetCachedAccessToken, + }, + ensureConfigFile: mocks.harnessEnsureConfigFile, + getConfig: mocks.harnessGetConfig, + getConfigDiagnostics: mocks.harnessGetConfigDiagnostics, + close: mocks.harnessClose, + track: mocks.harnessTrack, + }; + }; + return { + ...actual, + resolveKimiHome: mocks.resolveKimiHome, + flushDiagnosticLogsSync: mocks.flushDiagnosticLogsSync, + createKimiHarness: (...args: unknown[]) => { + const options = args[0] as { readonly homeDir?: string } | undefined; + const homeDir = options?.homeDir ?? '/tmp/kimi-code-test-home'; + if (mocks.harnessCreatesDeviceIdOnConstruction) { + mocks.createKimiDeviceId(homeDir); + } + mocks.kimiHarnessConstructor(...args); + return makeHarnessStub(args); + }, + }; +}); + +vi.mock('@moonshot-ai/kimi-code-oauth', async () => { + const actual = await vi.importActual( + '@moonshot-ai/kimi-code-oauth', + ); + return { + ...actual, + createKimiDeviceId: mocks.createKimiDeviceId, + KIMI_CODE_PROVIDER_NAME: 'kimi-code', + }; +}); + +vi.mock('@moonshot-ai/kimi-telemetry', () => ({ + initializeTelemetry: mocks.initializeTelemetry, + setCrashPhase: mocks.setCrashPhase, + shutdownTelemetry: mocks.shutdownTelemetry, + track: mocks.telemetryTrack, + setTelemetryContext: mocks.setTelemetryContext, + withTelemetryContext: mocks.withTelemetryContext, +})); + +vi.mock('../../src/tui/config', () => ({ + loadTuiConfig: mocks.loadTuiConfig, + TuiConfigParseError: mocks.TuiConfigParseError, +})); + +vi.mock('../../src/tui/index', () => ({ + KimiTUI: class { + onExit?: () => Promise; + + readonly state = { ui: { mode: 'regular' as const } }; + + constructor(...args: unknown[]) { + mocks.kimiTuiConstructor(this, ...args); + } + + start = mocks.tuiStart; + getStartupMcpMs = mocks.tuiGetStartupMcpMs; + getCurrentSessionId = mocks.tuiGetCurrentSessionId; + hasSessionContent = mocks.tuiHasSessionContent; + }, +})); + +vi.mock('../../src/tui/theme/detect', () => ({ + detectTerminalTheme: mocks.detectTerminalTheme, +})); + +vi.mock('../../src/migration/index', async (importOriginal) => ({ + ...(await importOriginal()), + detectPendingMigration: mocks.detectPendingMigration, +})); + +vi.mock('node:child_process', () => ({ + execFileSync: mocks.execFileSync, + spawnSync: mocks.spawnSync, +})); + +vi.mock('../../src/utils/process/resolve-command', () => ({ + resolveCommandPath: mocks.resolveCommandPath, +})); + +describe('runShell', () => { + beforeEach(() => { + // Pin region to cn: the telemetry endpoint assertion below must not + // follow the dev machine's own login/marker state. + vi.stubEnv('KIMI_CODE_OAUTH_HOST', 'https://auth.kimi.com'); + refreshKimiRegion(); + }); + + afterEach(() => { + vi.clearAllMocks(); + vi.unstubAllEnvs(); + refreshKimiRegion(); + mocks.harnessGetConfig.mockResolvedValue({ + providers: {}, + defaultModel: 'k2', + telemetry: true, + }); + mocks.tuiGetStartupMcpMs.mockResolvedValue(0); + mocks.tuiGetCurrentSessionId.mockReturnValue(''); + mocks.tuiHasSessionContent.mockReturnValue(false); + mocks.createKimiDeviceId.mockImplementation(() => 'device-1'); + mocks.resolveKimiHome.mockImplementation( + (homeDir?: string) => homeDir ?? '/tmp/kimi-code-test-home', + ); + mocks.resolveCommandPath.mockImplementation(() => '/bin/stty'); + mocks.harnessCreatesDeviceIdOnConstruction = false; + }); + + const minimalCliOptions = { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }; + + function stubTuiStartup(): void { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + } + + function withEnv(patch: Record, fn: () => Promise): Promise { + const saved: Record = {}; + for (const key of Object.keys(patch)) { + saved[key] = process.env[key]; + const value = patch[key]; + if (value === undefined) { + delete process.env[key]; + } else { + process.env[key] = value; + } + } + return fn().finally(() => { + for (const key of Object.keys(patch)) { + const value = saved[key]; + if (value === undefined) { + delete process.env[key]; + } else { + process.env[key] = value; + } + } + }); + } + + it('builds the harness through the SDK factory', async () => { + stubTuiStartup(); + await runShell(minimalCliOptions, '1.2.3-test'); + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledTimes(1); + }); + + it('constructs KimiHarness and KimiTUI with startup input', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + mocks.tuiGetStartupMcpMs.mockResolvedValue(47); + mocks.tuiGetCurrentSessionId.mockReturnValue('ses-startup'); + + const cliOptions = { + session: undefined, + continue: false, + yolo: true, + auto: false, + plan: true, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + addDirs: ['../shared', '/tmp/extra'], + }; + + await runShell(cliOptions, '1.2.3-test'); + + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledWith( + expect.objectContaining({ + identity: expect.objectContaining({ + productName: 'kimi-code-cli', + version: '1.2.3-test', + }), + sessionStartedProperties: { yolo: true, auto: false, plan: true, afk: false }, + }), + ); + expect(mocks.harnessEnsureConfigFile).toHaveBeenCalledOnce(); + expect(mocks.harnessEnsureConfigFile.mock.invocationCallOrder[0]).toBeLessThan( + mocks.harnessGetConfig.mock.invocationCallOrder[0]!, + ); + // stty is resolved to an absolute path before the trust gate and skipped + // entirely on Windows (a bare `stty` name would resolve into the + // untrusted cwd). + if (process.platform !== 'win32') { + expect(execFileSync).toHaveBeenCalledWith('/bin/stty', ['-ixon'], { + stdio: ['inherit', 'ignore', 'ignore'], + }); + } else { + expect(execFileSync).not.toHaveBeenCalled(); + } + expect(mocks.kimiTuiConstructor).toHaveBeenCalledTimes(1); + expect(mocks.createKimiDeviceId).toHaveBeenCalledWith( + '/tmp/kimi-code-test-home', + expect.any(Object), + ); + expect(mocks.initializeTelemetry).toHaveBeenCalledWith({ + homeDir: '/tmp/kimi-code-test-home', + deviceId: 'device-1', + enabled: true, + appName: 'kimi-code-cli', + version: '1.2.3-test', + uiMode: 'shell', + model: 'k2', + sessionId: undefined, + endpoint: expect.any(Function), + getAccessToken: expect.any(Function), + onUnexpectedError: expect.any(Function), + }); + // The endpoint resolver defers to the active region profile at flush time. + const telemetryOptions = mocks.initializeTelemetry.mock.calls[0]![0] as { + endpoint: () => string; + }; + expect(telemetryOptions.endpoint()).toBe('https://telemetry-logs.kimi.com/v1/event'); + expect(mocks.setCrashPhase).toHaveBeenCalledWith('runtime'); + + const [, harness, startupInput] = mocks.kimiTuiConstructor.mock.calls[0]!; + expect(harness).toBeTypeOf('object'); + expect(startupInput).toMatchObject({ + cliOptions, + additionalDirs: ['../shared', '/tmp/extra'], + tuiConfig: { + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }, + version: '1.2.3-test', + workDir: process.cwd(), + telemetryDisabled: false, + }); + expect(mocks.tuiStart).toHaveBeenCalledOnce(); + expect(mocks.withTelemetryContext).toHaveBeenCalledWith({ sessionId: 'ses-startup' }); + expect(mocks.lifecycleTrack).toHaveBeenCalledWith('startup_perf', { + duration_ms: expect.any(Number), + config_ms: expect.any(Number), + init_ms: expect.any(Number), + mcp_ms: 47, + tui_mode: 'regular', + }); + }); + + it('never runs stty on Windows, where it would resolve into the untrusted cwd', async () => { + stubTuiStartup(); + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { value: 'win32' }); + try { + await runShell(minimalCliOptions, '1.2.3-test'); + expect(execFileSync).not.toHaveBeenCalled(); + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + } + }); + + it('skips stty when it cannot be resolved outside the untrusted cwd', async () => { + stubTuiStartup(); + if (process.platform === 'win32') return; + mocks.resolveCommandPath.mockReturnValue(undefined); + await runShell(minimalCliOptions, '1.2.3-test'); + expect(mocks.resolveCommandPath).toHaveBeenCalledWith('stty'); + expect(execFileSync).not.toHaveBeenCalled(); + }); + + it('resolves the --agent profile into the TUI startup input', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: 'reviewer', + agentFiles: [], + }, + '1.2.3-test', + ); + + const [, , startupInput] = mocks.kimiTuiConstructor.mock.calls[0]!; + expect(startupInput).toMatchObject({ agentProfile: 'reviewer' }); + }); + + it('forwards the telemetry opt-out from config to the TUI startup input', async () => { + stubTuiStartup(); + mocks.harnessGetConfig.mockResolvedValue({ + providers: {}, + defaultModel: 'k2', + telemetry: false, + }); + + await runShell(minimalCliOptions, '1.2.3-test'); + + const [, , startupInput] = mocks.kimiTuiConstructor.mock.calls[0]!; + expect(startupInput).toMatchObject({ telemetryDisabled: true }); + }); + + it('forwards skillsDirs from CLI options to the harness', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: ['/skills'], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledWith( + expect.objectContaining({ skillDirs: ['/skills'] }), + ); + }); + + it('tracks first launch when device id creation reports first launch', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + mocks.createKimiDeviceId.mockImplementationOnce((homeDir, options) => { + const deviceId = `device-for-${homeDir}`; + options?.onFirstLaunch?.(deviceId); + return deviceId; + }); + + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + expect(mocks.createKimiDeviceId).toHaveBeenCalledWith( + '/tmp/kimi-code-test-home', + expect.objectContaining({ onFirstLaunch: expect.any(Function) }), + ); + expect(mocks.harnessTrack).toHaveBeenCalledWith('first_launch'); + }); + + it('registers first launch before harness construction can create the device id', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + mocks.harnessCreatesDeviceIdOnConstruction = true; + const createdHomes = new Set(); + mocks.createKimiDeviceId.mockImplementation((homeDir, options) => { + const deviceId = `device-for-${homeDir}`; + if (!createdHomes.has(homeDir)) { + createdHomes.add(homeDir); + options?.onFirstLaunch?.(deviceId); + } + return deviceId; + }); + + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + expect(mocks.createKimiDeviceId).toHaveBeenNthCalledWith( + 1, + '/tmp/kimi-code-test-home', + expect.objectContaining({ onFirstLaunch: expect.any(Function) }), + ); + expect(mocks.createKimiDeviceId.mock.invocationCallOrder[0]).toBeLessThan( + mocks.kimiHarnessConstructor.mock.invocationCallOrder[0]!, + ); + expect(mocks.kimiHarnessConstructor).toHaveBeenCalledWith( + expect.objectContaining({ homeDir: '/tmp/kimi-code-test-home' }), + ); + expect(mocks.harnessTrack).toHaveBeenCalledWith('first_launch'); + }); + + it('binds startup_perf to the session captured before MCP metrics resolve', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + let currentSessionId = 'ses-startup'; + mocks.tuiGetCurrentSessionId.mockImplementation(() => currentSessionId); + mocks.tuiGetStartupMcpMs.mockImplementation(async () => { + currentSessionId = 'ses-later'; + return 47; + }); + + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + expect(mocks.withTelemetryContext).toHaveBeenCalledWith({ sessionId: 'ses-startup' }); + expect(mocks.withTelemetryContext).not.toHaveBeenCalledWith({ sessionId: 'ses-later' }); + expect(mocks.lifecycleTrack).toHaveBeenCalledWith('startup_perf', { + duration_ms: expect.any(Number), + config_ms: expect.any(Number), + init_ms: expect.any(Number), + mcp_ms: 47, + tui_mode: 'regular', + }); + }); + + it('bridges OAuth refresh outcomes to telemetry', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + const [harnessOptions] = mocks.kimiHarnessConstructor.mock.calls[0] as [ + { + readonly onOAuthRefresh: ( + outcome: + | { readonly success: true } + | { readonly success: false; readonly reason: 'unauthorized' | 'network_or_other' }, + ) => void; + }, + ]; + + harnessOptions.onOAuthRefresh({ success: true }); + harnessOptions.onOAuthRefresh({ success: false, reason: 'unauthorized' }); + harnessOptions.onOAuthRefresh({ success: false, reason: 'network_or_other' }); + + expect(mocks.telemetryTrack).toHaveBeenCalledWith('oauth_refresh', { outcome: 'success' }); + expect(mocks.telemetryTrack).toHaveBeenCalledWith('oauth_refresh', { + outcome: 'error', + reason: 'unauthorized', + }); + expect(mocks.telemetryTrack).toHaveBeenCalledWith('oauth_refresh', { + outcome: 'error', + reason: 'network_or_other', + }); + }); + + it('detects auto theme and forwards config parse warnings as startup notice', async () => { + mocks.loadTuiConfig.mockRejectedValue( + new mocks.TuiConfigParseError({ + theme: 'auto', + editorCommand: 'vim', + notifications: { enabled: true, condition: 'always' }, + }), + ); + mocks.detectTerminalTheme.mockResolvedValue('light'); + mocks.tuiStart.mockResolvedValue(undefined); + + await runShell( + { + session: '', + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + expect(mocks.detectTerminalTheme).toHaveBeenCalledOnce(); + const [, , startupInput] = mocks.kimiTuiConstructor.mock.calls[0]!; + expect(startupInput).toMatchObject({ + startupNotice: 'Invalid TUI config in ~/.kimi-code/tui.toml; using defaults.', + tuiConfig: { + theme: 'auto', + editorCommand: 'vim', + notifications: { enabled: true, condition: 'always' }, + }, + }); + }); + + it('leaves config.toml diagnostics to the TUI instead of the startup notice', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.harnessGetConfigDiagnostics.mockResolvedValue({ + warnings: ['Ignored invalid config in config.toml: loop_control.'], + }); + mocks.tuiStart.mockResolvedValue(undefined); + + await runShell( + { + session: '', + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + // Diagnostics render in warning yellow via `showConfigWarningsIfAny` at + // `finishStartup`; the (dim) startup notice stays reserved for things like + // tui.toml parse errors, so the same warning is not shown twice. + const [, , startupInput] = mocks.kimiTuiConstructor.mock.calls[0]!; + expect(startupInput).toMatchObject({ + startupNotice: undefined, + }); + }); + + it('flushes diagnostic logs synchronously before exiting on a runtime crash', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + + const processOnSpy = vi.spyOn(process, 'on'); + const stdout = captureProcessWrite('stdout'); + const exitSpy = mockProcessExit(); + + try { + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + const handler = processOnSpy.mock.calls.find( + ([event]) => event === 'uncaughtException', + )?.[1] as ((error: unknown) => void) | undefined; + expect(handler).toBeDefined(); + + // The async log sink cannot flush before process.exit() runs, so the + // crash handler must force a synchronous flush or the crash reason is + // lost (regression: uncaughtException logs never reached disk). + expect(() => handler?.(new Error('boom'))).toThrow(ExitCalled); + expect(mocks.flushDiagnosticLogsSync).toHaveBeenCalledOnce(); + expect(exitSpy).toHaveBeenCalledWith(1); + expect(mocks.flushDiagnosticLogsSync.mock.invocationCallOrder[0]!).toBeLessThan( + exitSpy.mock.invocationCallOrder[0]!, + ); + } finally { + processOnSpy.mockRestore(); + exitSpy.mockRestore(); + stdout.restore(); + } + }); + + it('flushes diagnostic logs synchronously before exiting on an unhandled rejection', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + + const processOnSpy = vi.spyOn(process, 'on'); + const stdout = captureProcessWrite('stdout'); + const exitSpy = mockProcessExit(); + + try { + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + + const handler = processOnSpy.mock.calls.find( + ([event]) => event === 'unhandledRejection', + )?.[1] as ((reason: unknown) => void) | undefined; + expect(handler).toBeDefined(); + + expect(() => handler?.(new Error('boom'))).toThrow(ExitCalled); + expect(mocks.flushDiagnosticLogsSync).toHaveBeenCalledOnce(); + expect(exitSpy).toHaveBeenCalledWith(1); + expect(mocks.flushDiagnosticLogsSync.mock.invocationCallOrder[0]!).toBeLessThan( + exitSpy.mock.invocationCallOrder[0]!, + ); + } finally { + processOnSpy.mockRestore(); + exitSpy.mockRestore(); + stdout.restore(); + } + }); + + it('closes the harness when TUI startup fails', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockRejectedValue(new Error('boom')); + + await expect( + runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ), + ).rejects.toThrow('boom'); + + expect(mocks.setCrashPhase).toHaveBeenCalledWith('shutdown'); + expect(mocks.harnessTrack).toHaveBeenCalledWith('exit', { + duration_ms: expect.any(Number), + tui_mode: 'regular', + }); + expect(mocks.shutdownTelemetry).toHaveBeenCalledOnce(); + expect(mocks.harnessClose).toHaveBeenCalledOnce(); + }); + + it('tracks exit and prints resume instructions from the TUI exit handler', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + mocks.tuiGetCurrentSessionId.mockReturnValue('ses-1'); + mocks.tuiHasSessionContent.mockReturnValue(true); + + const stdout = captureProcessWrite('stdout'); + const stderr = captureProcessWrite('stderr'); + const exitSpy = mockProcessExit(); + + try { + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + const [tui] = mocks.kimiTuiConstructor.mock.calls[0]!; + mocks.harnessTrack.mockClear(); + mocks.lifecycleTrack.mockClear(); + mocks.withTelemetryContext.mockClear(); + + await expect((tui as { onExit: () => Promise }).onExit()).rejects.toBeInstanceOf( + ExitCalled, + ); + + expect(mocks.setCrashPhase).toHaveBeenCalledWith('shutdown'); + expect(mocks.withTelemetryContext).toHaveBeenCalledWith({ sessionId: 'ses-1' }); + expect(mocks.lifecycleTrack).toHaveBeenCalledWith('exit', { + duration_ms: expect.any(Number), + tui_mode: 'regular', + }); + expect(mocks.harnessTrack).not.toHaveBeenCalledWith('exit', expect.anything()); + expect(mocks.shutdownTelemetry).toHaveBeenCalledOnce(); + expect(stdout.text()).toBe(' Bye!\n'); + expect(stderr.text()).toContain(' To resume this session: kimi -r ses-1'); + } finally { + exitSpy.mockRestore(); + stdout.restore(); + stderr.restore(); + } + }); + + it('prints the opened web URL from the TUI exit handler when set', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.tuiStart.mockResolvedValue(undefined); + mocks.tuiGetCurrentSessionId.mockReturnValue('ses-1'); + mocks.tuiHasSessionContent.mockReturnValue(true); + + const stdout = captureProcessWrite('stdout'); + const stderr = captureProcessWrite('stderr'); + const exitSpy = mockProcessExit(); + + try { + await runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + ); + const [tui] = mocks.kimiTuiConstructor.mock.calls[0]!; + const openedUrl = 'http://127.0.0.1:58627/sessions/ses-1#token=tok-1'; + (tui as { exitOpenUrl?: string }).exitOpenUrl = openedUrl; + + await expect((tui as { onExit: () => Promise }).onExit()).rejects.toBeInstanceOf( + ExitCalled, + ); + + expect(stderr.text()).toContain(' To resume this session: kimi -r ses-1'); + expect(stderr.text()).toContain('open '); + expect(stderr.text()).toContain(openedUrl); + } finally { + exitSpy.mockRestore(); + stdout.restore(); + stderr.restore(); + } + }); + + it('surfaces an invalid target config as an error for kimi migrate, not silently', async () => { + mocks.loadTuiConfig.mockResolvedValue({ + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + }); + mocks.detectPendingMigration.mockResolvedValue({ totalSessions: 1 }); + mocks.harnessGetConfig.mockRejectedValue( + new Error('Invalid configuration in ~/.kimi-code/config.toml'), + ); + + // A broken config.toml must fail loudly — `kimi migrate` must not swallow + // it and proceed, or the user never learns their config is broken. + await expect( + runShell( + { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + '1.2.3-test', + { migrateOnly: true }, + ), + ).rejects.toThrow('Invalid configuration'); + expect(mocks.tuiStart).not.toHaveBeenCalled(); + }); + + it('refuses migration when KIMI_SHARE_DIR resolves to the Kimi Code home', async () => { + const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true); + try { + await withEnv({ KIMI_SHARE_DIR: '/tmp/kimi-code-test-home' }, async () => { + await runShell(minimalCliOptions, '1.2.3-test', { migrateOnly: true }); + }); + expect(mocks.detectPendingMigration).not.toHaveBeenCalled(); + expect(mocks.harnessClose).toHaveBeenCalledOnce(); + expect(mocks.tuiStart).not.toHaveBeenCalled(); + expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('KIMI_SHARE_DIR')); + } finally { + stderrSpy.mockRestore(); + } + }); +}); diff --git a/apps/kimi-code/test/cli/run-v2-print.test.ts b/apps/kimi-code/test/cli/run-v2-print.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a82e65063c29f1ea46ed1dedec66162ee9779559 --- /dev/null +++ b/apps/kimi-code/test/cli/run-v2-print.test.ts @@ -0,0 +1,522 @@ +import { PRINT_WAIT_CEILING_S_DEFAULT } from '@moonshot-ai/agent-core-v2'; +import { describe, expect, it, vi } from 'vitest'; + +import { + applyPrintBackgroundPolicy, + createPrintTurnEndings, + formatTrustGatedMcpWarning, + PrintSteeredTurnFailedError, + type PrintTurnEnding, + type PrintTurnEndings, +} from '#/cli/v2/run-v2-print'; + +function ending( + turnId: number, + reason: PrintTurnEnding['reason'] = 'completed', +): PrintTurnEnding { + return { type: 'turn.ended', turnId, reason } as unknown as PrintTurnEnding; +} + +interface ScriptedEntry { + readonly event: PrintTurnEnding; + /** Side effect applied when this entry is consumed (e.g. mutate pending). */ + readonly apply?: () => void; +} + +/** + * Scripted `PrintTurnEndings`: replays queued endings (honouring `skipTurnId`), + * then resolves `null` once the script is exhausted (the wait "timed out"). + */ +function scriptedTurnEndings(entries: ScriptedEntry[]): PrintTurnEndings { + const queue = [...entries]; + return { + next: async (_remainingMs: number, skipTurnId: number) => { + while (queue.length > 0) { + const entry = queue.shift()!; + if (entry.event.turnId === skipTurnId) continue; + entry.apply?.(); + return entry.event; + } + return null; + }, + }; +} + +describe('applyPrintBackgroundPolicy', () => { + it('exit returns immediately without draining or waiting', async () => { + const drain = vi.fn(async () => {}); + const countPending = vi.fn(() => 1); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 60, + maxTurns: 50, + countPending, + drain, + turnEndings: scriptedTurnEndings([]), + skipTurnId: 1, + warn: () => {}, + now: () => Date.now(), + }); + expect(drain).not.toHaveBeenCalled(); + expect(countPending).not.toHaveBeenCalled(); + }); + + it('drain drains once and returns', async () => { + const drain = vi.fn(async () => {}); + await applyPrintBackgroundPolicy({ + mode: 'drain', + ceilingS: 60, + maxTurns: 50, + countPending: () => 1, + drain, + turnEndings: scriptedTurnEndings([]), + skipTurnId: 1, + warn: () => {}, + now: () => Date.now(), + }); + expect(drain).toHaveBeenCalledTimes(1); + }); + + it('steer returns once background tasks are quiescent', async () => { + let pending = 1; + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'steer', + ceilingS: 60, + maxTurns: 50, + countPending: () => pending, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + // The main turn's own buffered ending is skipped. + { event: ending(1) }, + // A background task completed and steered a new turn; it finished and + // no tasks remain. + { event: ending(2), apply: () => { pending = 0; } }, + ]), + skipTurnId: 1, + warn, + now: () => Date.now(), + }); + expect(warn).not.toHaveBeenCalled(); + }); + + it('steer finishes with a warning when max turns is reached', async () => { + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'steer', + ceilingS: 60, + maxTurns: 2, + countPending: () => 1, + drain: async () => {}, + turnEndings: scriptedTurnEndings([{ event: ending(2) }, { event: ending(3) }]), + skipTurnId: 1, + warn, + now: () => Date.now(), + }); + expect(warn).toHaveBeenCalledTimes(1); + expect(warn.mock.calls[0]?.[0]).toContain('max turns'); + }); + + it('steer finishes with a warning when the ceiling is reached', async () => { + let now = 0; + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'steer', + ceilingS: 10, + maxTurns: 50, + countPending: () => 1, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + { event: ending(2), apply: () => { now = 10_001; } }, + ]), + skipTurnId: 1, + warn, + now: () => now, + }); + expect(warn).toHaveBeenCalledTimes(1); + expect(warn.mock.calls[0]?.[0]).toContain('ceiling'); + }); + + it('steer returns when the wait times out with tasks still pending', async () => { + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'steer', + ceilingS: 60, + maxTurns: 50, + countPending: () => 1, + drain: async () => {}, + // Empty script: no further turn ends before the deadline. + turnEndings: scriptedTurnEndings([]), + skipTurnId: 1, + warn, + now: () => Date.now(), + }); + expect(warn).not.toHaveBeenCalled(); + }); + + it('steer throws when a steered turn does not complete', async () => { + await expect( + applyPrintBackgroundPolicy({ + mode: 'steer', + ceilingS: 60, + maxTurns: 50, + countPending: () => 1, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + { + event: { + type: 'turn.ended', + turnId: 2, + reason: 'failed', + error: { code: 'provider.overloaded', message: 'try later' }, + } as PrintTurnEnding, + }, + ]), + skipTurnId: 1, + warn: () => {}, + now: () => Date.now(), + }), + ).rejects.toThrow(PrintSteeredTurnFailedError); + }); + + it('waits for goal continuation turns before applying the mode', async () => { + let active = true; + let consumed = 0; + const drain = vi.fn(async () => {}); + await applyPrintBackgroundPolicy({ + mode: 'drain', + ceilingS: 60, + maxTurns: 50, + countPending: () => 0, + drain, + turnEndings: scriptedTurnEndings([ + { event: ending(2), apply: () => { consumed += 1; } }, + { + event: ending(3), + apply: () => { + consumed += 1; + active = false; + }, + }, + ]), + skipTurnId: 1, + warn: () => {}, + now: () => Date.now(), + goalActive: () => active, + }); + // Both continuation turns ended before the mode ('drain') ran. + expect(consumed).toBe(2); + expect(drain).toHaveBeenCalledTimes(1); + }); + + it('warns and returns when the goal wait hits the ceiling', async () => { + let now = 0; + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 10, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + // No continuation turn ever ends; the poll interval elapses each time. + turnEndings: { + next: async () => { + now = 10_001; + return null; + }, + }, + skipTurnId: 1, + warn, + now: () => now, + goalActive: () => true, + }); + expect(warn).toHaveBeenCalledTimes(1); + expect(warn.mock.calls[0]?.[0]).toContain('goal wait ceiling'); + }); + + it('exits the goal wait promptly when the goal settles without a turn ending', async () => { + let active = true; + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + // Poll interval elapses; the goal settles (paused/blocked) mid-wait + // without producing a turn.ended. + turnEndings: { + next: async () => { + active = false; + return null; + }, + }, + skipTurnId: 1, + warn, + now: () => Date.now(), + goalActive: () => active, + }); + expect(warn).not.toHaveBeenCalled(); + }); + + it('keeps an exit-mode run alive until a pending cron fire steered a turn', async () => { + let nextFire: number | null = 60_000; + let fireTurnEnded = false; + const cronNextFireAt = vi.fn(() => nextFire); + const countPending = vi.fn(() => 0); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + { + // The cron fire steered this turn; once it ends the one-shot task + // is gone. + event: ending(2), + apply: () => { + fireTurnEnded = true; + nextFire = null; + }, + }, + ]), + skipTurnId: 1, + warn: () => {}, + now: () => 0, + cronNextFireAt, + }); + // The policy waited for the fire turn's ending instead of returning + // immediately, then re-read the (now empty) cron schedule. + expect(fireTurnEnded).toBe(true); + expect(cronNextFireAt).toHaveBeenCalledTimes(2); + // 'exit' never consults background tasks. + expect(countPending).not.toHaveBeenCalled(); + }); + + it('throws when a cron-fire steered turn does not complete', async () => { + await expect( + applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + { + event: { + type: 'turn.ended', + turnId: 2, + reason: 'failed', + error: { code: 'provider.overloaded', message: 'try later' }, + } as PrintTurnEnding, + }, + ]), + skipTurnId: 1, + warn: () => {}, + now: () => 0, + cronNextFireAt: () => 60_000, + }), + ).rejects.toThrow(PrintSteeredTurnFailedError); + }); + + it('keeps waiting while a recurring cron advances its next fire time', async () => { + let nextFire: number | null = 10_000; + const cronNextFireAt = vi.fn(() => nextFire); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + // First fire: the recurring task advances to its next slot. + { event: ending(2), apply: () => { nextFire = 20_000; } }, + // Second fire: the task is deleted, no future fire remains. + { event: ending(3), apply: () => { nextFire = null; } }, + ]), + skipTurnId: 1, + warn: () => {}, + now: () => 0, + cronNextFireAt, + }); + expect(cronNextFireAt).toHaveBeenCalledTimes(3); + }); + + it('re-reads the cron schedule when the fire wait times out without a turn', async () => { + let nextFire: number | null = 10_000; + const cronNextFireAt = vi.fn(() => { + const value = nextFire; + // The task was removed between the first query and the re-check. + nextFire = null; + return value; + }); + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + // Empty script: the fire produced no turn before the grace elapsed. + turnEndings: scriptedTurnEndings([]), + skipTurnId: 1, + warn, + now: () => 0, + cronNextFireAt, + }); + expect(cronNextFireAt).toHaveBeenCalledTimes(2); + expect(warn).not.toHaveBeenCalled(); + }); + + it('warns and stops cron waiting when the next fire time is stuck in the past', async () => { + const warn = vi.fn(); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + // No turn ever ends: the tick is wedged and never fires the overdue task. + turnEndings: scriptedTurnEndings([]), + skipTurnId: 1, + warn, + now: () => 1_000, + cronNextFireAt: () => 500, + }); + expect(warn).toHaveBeenCalledTimes(1); + expect(warn.mock.calls[0]?.[0]).toContain('cron'); + }); + + it('finishes goal waiting before consulting the cron schedule', async () => { + let active = true; + let consumed = 0; + let nextFire: number | null = 60_000; + let cronFirstCallAtConsumed = -1; + const cronNextFireAt = vi.fn(() => { + if (cronFirstCallAtConsumed === -1) cronFirstCallAtConsumed = consumed; + return nextFire; + }); + await applyPrintBackgroundPolicy({ + mode: 'exit', + ceilingS: 3600, + maxTurns: 50, + countPending: () => 0, + drain: async () => {}, + turnEndings: scriptedTurnEndings([ + { event: ending(2), apply: () => { consumed += 1; } }, + { + event: ending(3), + apply: () => { + consumed += 1; + active = false; + }, + }, + // The pending cron fire steered this turn. + { event: ending(4), apply: () => { nextFire = null; } }, + ]), + skipTurnId: 1, + warn: () => {}, + now: () => 0, + goalActive: () => active, + cronNextFireAt, + }); + // Both goal continuation turns ended before the cron schedule was read. + expect(cronFirstCallAtConsumed).toBe(2); + expect(cronNextFireAt).toHaveBeenCalled(); + }); + + it('steer keeps waiting under the default ceiling with tasks pending', async () => { + let pending = 1; + const turnEndings = createPrintTurnEndings(); + const policy = applyPrintBackgroundPolicy({ + mode: 'steer', + ceilingS: PRINT_WAIT_CEILING_S_DEFAULT, + maxTurns: 50, + countPending: () => pending, + drain: async () => {}, + turnEndings, + skipTurnId: 1, + warn: () => {}, + now: () => Date.now(), + }); + // The default ceiling is ~24.8 days: with tasks still pending the wait + // must not return null early and end the run here. + const early = await Promise.race([ + policy.then(() => 'returned' as const), + new Promise<'waiting'>((resolve) => setTimeout(() => { + resolve('waiting'); + }, 50)), + ]); + expect(early).toBe('waiting'); + // A background task completion steered a new turn; once it ends and no + // tasks remain, the policy returns. + pending = 0; + turnEndings.push(ending(2)); + await policy; + }); +}); + +describe('createPrintTurnEndings', () => { + it('buffers events pushed before next() and skips the given turn id', async () => { + const endings = createPrintTurnEndings(); + endings.push(ending(1)); + endings.push(ending(2)); + await expect(endings.next(1000, 1)).resolves.toMatchObject({ turnId: 2 }); + }); + + it('delivers a pushed event to a pending next()', async () => { + const endings = createPrintTurnEndings(); + const pending = endings.next(1000, 1); + endings.push(ending(3)); + await expect(pending).resolves.toMatchObject({ turnId: 3 }); + }); + + it('resolves null when the remaining time elapses', async () => { + const endings = createPrintTurnEndings(); + await expect(endings.next(5, 1)).resolves.toBeNull(); + }); + + it('keeps waiting when only the skipped turn ends', async () => { + const endings = createPrintTurnEndings(); + const pending = endings.next(1000, 1); + endings.push(ending(1)); + endings.push(ending(4)); + await expect(pending).resolves.toMatchObject({ turnId: 4 }); + }); + + it('does not resolve null early when the budget exceeds the timer ceiling', async () => { + const endings = createPrintTurnEndings(); + // 10 years in ms — beyond Node's 2^31-1 ms setTimeout ceiling, which an + // explicit `print_wait_ceiling_s` can still reach. + const pending = endings.next(10 * 365 * 24 * 3600 * 1000, 1); + // Node clamps a >2^31-1 ms setTimeout to 1ms; the wait must ride out the + // overflow in chunks instead of resolving null at once. + const early = await Promise.race([ + pending, + new Promise<'waiting'>((resolve) => setTimeout(() => { + resolve('waiting'); + }, 50)), + ]); + expect(early).toBe('waiting'); + endings.push(ending(7)); + await expect(pending).resolves.toMatchObject({ turnId: 7 }); + }); +}); + +describe('formatTrustGatedMcpWarning', () => { + it('singularizes the noun for one skipped server', () => { + const text = formatTrustGatedMcpWarning([{ name: 'fs', target: 'stdio: node server.js' }]); + expect(text).toContain('skipped 1 project-level MCP server: fs (stdio: node server.js).'); + expect(text).toContain('"Trust this folder"'); + }); + + it('pluralizes and joins multiple skipped servers', () => { + const text = formatTrustGatedMcpWarning([ + { name: 'api', target: 'http: https://example.com/mcp' }, + { name: 'fs', target: 'stdio: node server.js' }, + ]); + expect(text).toContain('skipped 2 project-level MCP servers:'); + expect(text).toContain('api (http: https://example.com/mcp), fs (stdio: node server.js)'); + }); +}); diff --git a/apps/kimi-code/test/cli/session-flag-picker.test.ts b/apps/kimi-code/test/cli/session-flag-picker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f24560fa11e79ebc3f45e25a8fa557fc2043f3c --- /dev/null +++ b/apps/kimi-code/test/cli/session-flag-picker.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from 'vitest'; + +import { createProgram } from '#/cli/commands'; +import type { CLIOptions } from '#/cli/options'; +import { OptionConflictError, validateOptions } from '#/cli/options'; + +function parse(argv: string[]): CLIOptions { + let captured: CLIOptions | undefined; + const program = createProgram( + '0.0.0-test', + (opts) => { + captured = opts; + }, + () => {}, + ); + program.exitOverride(); + program.configureOutput({ + writeOut: () => {}, + writeErr: () => {}, + }); + program.parse(['node', 'kimi', ...argv]); + if (captured === undefined) { + throw new Error('Main action handler was not called'); + } + return captured; +} + +describe('--session / -r / -S picker routing', () => { + describe('argParser: no-arg forms coerce to empty string', () => { + it('--session with no id → session === ""', () => { + const opts = parse(['--session']); + expect(opts.session).toBe(''); + }); + + it('-S with no id → session === ""', () => { + const opts = parse(['-S']); + expect(opts.session).toBe(''); + }); + + it('-r with no id → session === ""', () => { + const opts = parse(['-r']); + expect(opts.session).toBe(''); + }); + }); + + describe('argParser: id forms keep the id verbatim', () => { + it('--session foo → session === "foo"', () => { + const opts = parse(['--session', 'foo']); + expect(opts.session).toBe('foo'); + }); + + it('-S foo → session === "foo"', () => { + const opts = parse(['-S', 'foo']); + expect(opts.session).toBe('foo'); + }); + + it('-r foo → session === "foo" (hidden alias)', () => { + const opts = parse(['-r', 'foo']); + expect(opts.session).toBe('foo'); + }); + }); + + describe('validateOptions: empty session vs ui mode', () => { + it('empty session + shell mode → OK, session stays ""', () => { + const { options, uiMode } = validateOptions(parse(['--session'])); + expect(uiMode).toBe('shell'); + expect(options.session).toBe(''); + }); + + // Note: --print / --wire are held back from the first release, so + // the "picker + print/wire" combinations can't be constructed via + // Commander anymore. The validateOptions guard still lives in + // source for when those flags return. + }); + + // Silence unused-import warning kept for the preserved guard tests. + void OptionConflictError; +}); diff --git a/apps/kimi-code/test/cli/session.test.ts b/apps/kimi-code/test/cli/session.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5418de9e43aa86703ee8e55cd19c77bb64780af4 --- /dev/null +++ b/apps/kimi-code/test/cli/session.test.ts @@ -0,0 +1,184 @@ +/** + * `kimi session list` + * + * Verifies the CLI layer: scope option handling (--cwd/--all), archived + * pass-through, --limit, --json, and the empty state. + */ + +import { Command } from 'commander'; +import { describe, expect, it } from 'vitest'; + +import { + handleSessionList, + registerSessionCommand, + type SessionListDeps, +} from '#/cli/sub/session'; +import type { ListSessionsOptions, SessionSummary } from '@moonshot-ai/kimi-code-sdk'; + +function summary(overrides: Partial = {}): SessionSummary { + return { + id: 'ses_1', + workDir: '/repo', + sessionDir: '/home/.kimi-code/sessions/wd_repo/ses_1', + createdAt: 1, + updatedAt: new Date('2026-09-01T10:00:00').getTime(), + ...overrides, + }; +} + +interface Captured { + options?: ListSessionsOptions; + out: string; + err: string; + exitCode?: number; +} + +function stubDeps(sessions: readonly SessionSummary[]): { + deps: SessionListDeps; + captured: Captured; +} { + const captured: Captured = { out: '', err: '' }; + const deps: SessionListDeps = { + listSessions: async (options) => { + captured.options = options; + return sessions; + }, + cwd: () => '/repo', + stdout: { + write: (chunk) => { + captured.out += chunk; + return true; + }, + }, + stderr: { + write: (chunk) => { + captured.err += chunk; + return true; + }, + }, + exit: (code) => { + captured.exitCode = code; + throw new Error(`exit ${code}`); + }, + }; + return { deps, captured }; +} + +describe('handleSessionList', () => { + it('lists sessions of the current working directory by default', async () => { + const { deps, captured } = stubDeps([ + summary({ id: 'ses_1', title: 'first' }), + summary({ id: 'ses_2', title: 'second' }), + ]); + + await handleSessionList(deps, { all: false, archived: false, json: false }); + + expect(captured.options).toEqual({ workDir: '/repo', includeArchived: undefined }); + expect(captured.out).toContain('ses_1'); + expect(captured.out).toContain('first'); + expect(captured.out).toContain('ses_2'); + expect(captured.out).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/); + expect(captured.out).not.toContain('/repo\n'); + }); + + it('lists every workspace with --all and shows workDir per row', async () => { + const { deps, captured } = stubDeps([summary({ id: 'ses_1', workDir: '/repo' })]); + + await handleSessionList(deps, { all: true, archived: false, json: false }); + + expect(captured.options).toEqual({ workDir: undefined, includeArchived: undefined }); + expect(captured.out).toContain('/repo'); + }); + + it('uses an explicit --cwd over the current directory', async () => { + const { deps, captured } = stubDeps([summary()]); + + await handleSessionList(deps, { all: false, archived: false, cwd: '/other', json: false }); + + expect(captured.options).toEqual({ workDir: '/other', includeArchived: undefined }); + }); + + it('passes includeArchived through with --archived', async () => { + const { deps, captured } = stubDeps([summary({ archived: true })]); + + await handleSessionList(deps, { all: false, archived: true, json: false }); + + expect(captured.options).toEqual({ workDir: '/repo', includeArchived: true }); + expect(captured.out).toContain('[archived]'); + }); + + it('truncates with --limit', async () => { + const { deps, captured } = stubDeps([ + summary({ id: 'ses_1' }), + summary({ id: 'ses_2' }), + summary({ id: 'ses_3' }), + ]); + + await handleSessionList(deps, { all: false, archived: false, limit: 2, json: false }); + + expect(captured.out).toContain('ses_1'); + expect(captured.out).toContain('ses_2'); + expect(captured.out).not.toContain('ses_3'); + }); + + it('emits the summaries as JSON with --json', async () => { + const sessions = [summary({ id: 'ses_1', title: 'first' })]; + const { deps, captured } = stubDeps(sessions); + + await handleSessionList(deps, { all: false, archived: false, json: true }); + + expect(JSON.parse(captured.out)).toEqual(JSON.parse(JSON.stringify(sessions))); + }); + + it('prints a friendly empty state', async () => { + const { deps, captured } = stubDeps([]); + + await handleSessionList(deps, { all: false, archived: false, json: false }); + + expect(captured.out).toBe('No sessions found.\n'); + }); + + it('strips control characters and line breaks from user-controlled fields', async () => { + const { deps, captured } = stubDeps([ + summary({ + id: 'ses_1', + title: 'line one\nline two \u001b[31mred\u001b[0m', + workDir: '/repo\nevil', + }), + ]); + + await handleSessionList(deps, { all: true, archived: false, json: false }); + + const rows = captured.out.trimEnd().split('\n'); + expect(rows).toHaveLength(1); + expect(rows[0]).not.toContain('\u001b'); + expect(rows[0]).toContain('line one line two [31mred [0m'); + expect(rows[0]).toContain('/repo evil'); + }); +}); + +describe('registerSessionCommand', () => { + it('parses session list options and runs the handler', async () => { + const sessions = [summary({ id: 'ses_1', title: 'first' })]; + const { deps, captured } = stubDeps(sessions); + const program = new Command('kimi'); + registerSessionCommand(program, deps); + + await program.parseAsync(['node', 'kimi', 'session', 'list', '--all', '--json']); + + expect(captured.options).toEqual({ workDir: undefined, includeArchived: undefined }); + expect(JSON.parse(captured.out)).toEqual(JSON.parse(JSON.stringify(sessions))); + expect(captured.exitCode).toBeUndefined(); + }); + + it('rejects a non-numeric --limit', async () => { + const { deps } = stubDeps([]); + const program = new Command('kimi'); + program.exitOverride(); + registerSessionCommand(program, deps); + + await expect( + program.parseAsync(['node', 'kimi', 'session', 'list', '--limit', 'abc']), + ).rejects.toThrow(/positive integer/); + }); +}); diff --git a/apps/kimi-code/test/cli/telemetry.test.ts b/apps/kimi-code/test/cli/telemetry.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..490aa83ec14403c32e0312137912289f2e41065c --- /dev/null +++ b/apps/kimi-code/test/cli/telemetry.test.ts @@ -0,0 +1,119 @@ +/** + * Tests for the CLI telemetry bootstrap helpers, focusing on the + * `kimi web` / `kimi server run` host wiring added in `cli/telemetry.ts`. + */ + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const mocks = vi.hoisted(() => ({ + initializeTelemetry: vi.fn(), + createKimiDeviceId: vi.fn(() => 'device-123'), + resolveKimiHome: vi.fn(() => '/home/.kimi-code'), + resolveConfigPath: vi.fn(() => '/home/.kimi-code/config.toml'), + loadRuntimeConfigSafe: vi.fn( + (): { + config: { defaultModel?: string; telemetry?: boolean }; + fileError: Error | undefined; + } => ({ + config: { defaultModel: 'kimi-k2', telemetry: true }, + fileError: undefined, + }), + ), + getCachedAccessToken: vi.fn(async () => 'tok'), +})); + +vi.mock('@moonshot-ai/kimi-telemetry', () => ({ + initializeTelemetry: mocks.initializeTelemetry, + setTelemetryContext: vi.fn(), + track: vi.fn(), + withTelemetryContext: vi.fn(), +})); + +vi.mock('@moonshot-ai/kimi-code-oauth', async (importOriginal) => { + // Spread the real module: the SDK's v2 client pulls agent-core-v2 into the + // import graph, which subclasses KimiOAuthToolkit from this package. + const actual = await importOriginal(); + return { + ...actual, + createKimiDeviceId: mocks.createKimiDeviceId, + KIMI_CODE_PROVIDER_NAME: 'managed:kimi-code', + }; +}); + +vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + resolveKimiHome: mocks.resolveKimiHome, + resolveConfigPath: mocks.resolveConfigPath, + loadRuntimeConfigSafe: mocks.loadRuntimeConfigSafe, + KimiAuthFacade: vi.fn(function () { + return { getCachedAccessToken: mocks.getCachedAccessToken }; + }), + }; +}); + +describe('initializeServerTelemetry', () => { + beforeEach(() => { + mocks.initializeTelemetry.mockClear(); + mocks.loadRuntimeConfigSafe.mockClear(); + mocks.loadRuntimeConfigSafe.mockReturnValue({ + config: { defaultModel: 'kimi-k2', telemetry: true }, + fileError: undefined, + }); + }); + + it('configures the sink with ui_mode="web" and the CLI product identity', async () => { + const { initializeServerTelemetry } = await import('#/cli/telemetry'); + const client = initializeServerTelemetry({ version: '1.2.3' }); + expect(mocks.initializeTelemetry).toHaveBeenCalledWith( + expect.objectContaining({ + appName: 'kimi-code-cli', + version: '1.2.3', + uiMode: 'web', + model: 'kimi-k2', + enabled: true, + deviceId: 'device-123', + homeDir: '/home/.kimi-code', + }), + ); + // The returned client wraps the module functions so core + the host share + // the same underlying client. + expect(client).toEqual( + expect.objectContaining({ + track: expect.any(Function), + withContext: expect.any(Function), + setContext: expect.any(Function), + }), + ); + // The first dynamic import pulls in the whole SDK/oauth chain (~3s idle, + // more under full-suite transform contention) — give it headroom past the + // 5s default timeout. + }, 20000); + + it('disables telemetry when config.toml sets telemetry = false', async () => { + mocks.loadRuntimeConfigSafe.mockReturnValue({ + config: { defaultModel: 'kimi-k2', telemetry: false }, + fileError: undefined, + }); + const { initializeServerTelemetry } = await import('#/cli/telemetry'); + initializeServerTelemetry({ version: '1.2.3' }); + + expect(mocks.initializeTelemetry).toHaveBeenCalledWith( + expect.objectContaining({ enabled: false }), + ); + }); + + it('degrades to enabled with no model when config is unreadable', async () => { + mocks.loadRuntimeConfigSafe.mockReturnValue({ + config: {}, + fileError: new Error('bad toml'), + }); + const { initializeServerTelemetry } = await import('#/cli/telemetry'); + initializeServerTelemetry({ version: '1.2.3' }); + + expect(mocks.initializeTelemetry).toHaveBeenCalledWith( + expect.objectContaining({ enabled: true, model: undefined }), + ); + }); +}); diff --git a/apps/kimi-code/test/cli/update-download.test.ts b/apps/kimi-code/test/cli/update-download.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..991e250c4904e95da31b23024d521e130d38c727 --- /dev/null +++ b/apps/kimi-code/test/cli/update-download.test.ts @@ -0,0 +1,261 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { createDownloadProgress, runUpdateDownloadCommand } from '#/cli/sub/update-download'; + +const mocks = vi.hoisted(() => ({ + detectNativeInstall: vi.fn(() => true), + tryAcquireUpdateInstallLock: vi.fn(), + readUpdateInstallLockVersion: vi.fn(), + stageNativeUpdate: vi.fn(), + readStagedNativeUpdate: vi.fn(), + promoteStagedUpdateToManual: vi.fn(async () => true), + hashFileSha256: vi.fn(), + stagedExePath: vi.fn(() => '/tmp/staged-exe'), +})); + +vi.mock('#/cli/update/source', () => ({ + detectNativeInstall: mocks.detectNativeInstall, +})); + +vi.mock('#/cli/update/install-lock', () => ({ + tryAcquireUpdateInstallLock: mocks.tryAcquireUpdateInstallLock, + readUpdateInstallLockVersion: mocks.readUpdateInstallLockVersion, +})); + +vi.mock('#/cli/update/native-stage', () => ({ + stageNativeUpdate: mocks.stageNativeUpdate, + readStagedNativeUpdate: mocks.readStagedNativeUpdate, + promoteStagedUpdateToManual: mocks.promoteStagedUpdateToManual, + hashFileSha256: mocks.hashFileSha256, + stagedExePath: mocks.stagedExePath, +})); + +vi.mock('@moonshot-ai/kimi-code-sdk', async () => { + const actual = await vi.importActual( + '@moonshot-ai/kimi-code-sdk', + ); + return { + ...actual, + log: { ...actual.log, warn: vi.fn() }, + }; +}); + +function fakeOut(isTTY: boolean): { readonly out: NodeJS.WriteStream; readonly chunks: string[] } { + const chunks: string[] = []; + const out = { + isTTY, + write(chunk: string) { + chunks.push(chunk); + return true; + }, + } as unknown as NodeJS.WriteStream; + return { out, chunks }; +} + +describe('createDownloadProgress', () => { + it('renders a throttled in-place line on a TTY, with the final frame always shown', () => { + const { out, chunks } = fakeOut(true); + const progress = createDownloadProgress(out, 'Downloading…'); + const total = 100 * 1024 * 1024; + + const nowSpy = vi.spyOn(Date, 'now'); + nowSpy.mockReturnValue(1_000); + progress(10 * 1024 * 1024, total); + nowSpy.mockReturnValue(1_050); // inside the 100 ms throttle window → skipped + progress(20 * 1024 * 1024, total); + nowSpy.mockReturnValue(1_200); + progress(30 * 1024 * 1024, total); + progress(total, total); // final frame is never throttled + + expect(chunks).toEqual([ + '\r\u001B[KDownloading… 10% (10/100 MB)', + '\r\u001B[KDownloading… 30% (30/100 MB)', + '\r\u001B[KDownloading… 100% (100/100 MB)', + ]); + nowSpy.mockRestore(); + }); + + it('prints the label up front and one line per 32 MB when piped', () => { + const { out, chunks } = fakeOut(false); + const progress = createDownloadProgress(out, 'Downloading…'); + const total = 100 * 1024 * 1024; + + progress(10 * 1024 * 1024, total); // below the 32 MB line interval → skipped + progress(40 * 1024 * 1024, total); + progress(total, total); + + expect(chunks).toEqual([ + 'Downloading…\n', + 'Downloading… 40% (40/100 MB)\n', + 'Downloading… 100% (100/100 MB)\n', + ]); + }); + + it('degrades to plain MB counts when Content-Length is unknown', () => { + const { out, chunks } = fakeOut(true); + const progress = createDownloadProgress(out, 'Downloading…'); + progress(5 * 1024 * 1024, null); + expect(chunks).toEqual(['\r\u001B[KDownloading… 5 MB']); + }); +}); + +describe('runUpdateDownloadCommand', () => { + const STAGED_HASH = 'a'.repeat(64); + + beforeEach(() => { + vi.clearAllMocks(); + mocks.detectNativeInstall.mockReturnValue(true); + mocks.tryAcquireUpdateInstallLock.mockResolvedValue({ + filePath: '/tmp/install.lock', + release: vi.fn(async () => {}), + }); + mocks.stageNativeUpdate.mockResolvedValue({ status: 'staged', staged: {} }); + mocks.hashFileSha256.mockResolvedValue(STAGED_HASH); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('refuses on non-native installs', async () => { + mocks.detectNativeInstall.mockReturnValue(false); + const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(1); + expect(mocks.stageNativeUpdate).not.toHaveBeenCalled(); + expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('native build')); + }); + + it('waits for and adopts the result when another instance downloads the same version', async () => { + mocks.tryAcquireUpdateInstallLock.mockResolvedValue(null); + mocks.readUpdateInstallLockVersion.mockResolvedValue('0.7.0'); + // The other worker's staged update is verified on disk on the first poll. + mocks.readStagedNativeUpdate.mockResolvedValue({ version: '0.7.0', sha256: STAGED_HASH }); + const stdoutSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(0); + expect(mocks.stageNativeUpdate).not.toHaveBeenCalled(); + expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining('already in progress')); + // A background waiter's adoption keeps the auto marker. + expect(mocks.promoteStagedUpdateToManual).not.toHaveBeenCalled(); + }); + + it('promotes the adopted stage to manual when an explicit upgrade waited for it', async () => { + mocks.tryAcquireUpdateInstallLock.mockResolvedValue(null); + mocks.readUpdateInstallLockVersion.mockResolvedValue('0.7.0'); + mocks.readStagedNativeUpdate.mockResolvedValue({ version: '0.7.0', sha256: STAGED_HASH }); + vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0', true)).resolves.toBe(0); + expect(mocks.stageNativeUpdate).not.toHaveBeenCalled(); + expect(mocks.promoteStagedUpdateToManual).toHaveBeenCalledTimes(1); + }); + + it('keeps waiting until the manual promotion is confirmed persisted', async () => { + // The first promotion attempt loses a race with a concurrent swap's + // claim/restore cycle; the loop must not report adoption until the + // marker is confirmed. + mocks.tryAcquireUpdateInstallLock.mockResolvedValue(null); + mocks.readUpdateInstallLockVersion.mockResolvedValue('0.7.0'); + mocks.readStagedNativeUpdate.mockResolvedValue({ version: '0.7.0', sha256: STAGED_HASH }); + mocks.promoteStagedUpdateToManual + .mockResolvedValueOnce(false) + .mockResolvedValueOnce(true); + vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0', true)).resolves.toBe(0); + expect(mocks.stageNativeUpdate).not.toHaveBeenCalled(); + expect(mocks.promoteStagedUpdateToManual).toHaveBeenCalledTimes(2); + }); + + it('waits instead of adopting when the recorded payload fails the checksum', async () => { + mocks.tryAcquireUpdateInstallLock.mockResolvedValue(null); + mocks.readUpdateInstallLockVersion.mockResolvedValue('0.7.0'); + mocks.readStagedNativeUpdate.mockResolvedValue({ version: '0.7.0', sha256: STAGED_HASH }); + // First poll: the recorded payload is corrupt (the holder is re-staging + // it — its metadata is only replaced when the repaired generation + // publishes); second poll: the repaired generation verifies. + mocks.hashFileSha256.mockResolvedValueOnce('corrupt').mockResolvedValue(STAGED_HASH); + vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(0); + expect(mocks.stageNativeUpdate).not.toHaveBeenCalled(); + expect(mocks.hashFileSha256).toHaveBeenCalledTimes(2); + }); + + it('takes over when the holder dies leaving a corrupt stage behind', async () => { + const release = vi.fn(async () => {}); + mocks.tryAcquireUpdateInstallLock + .mockResolvedValueOnce(null) // initial acquire: held + .mockResolvedValue({ filePath: '/tmp/install.lock', release }); // in-loop takeover + mocks.readUpdateInstallLockVersion.mockResolvedValueOnce('0.7.0'); + mocks.readStagedNativeUpdate.mockResolvedValue({ version: '0.7.0', sha256: STAGED_HASH }); + // The recorded payload never verifies: the lock poll takes over and + // stageNativeUpdate's own adoption check re-stages it. + mocks.hashFileSha256.mockResolvedValue('corrupt'); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(0); + expect(mocks.stageNativeUpdate).toHaveBeenCalledWith( + expect.objectContaining({ version: '0.7.0' }), + ); + expect(release).toHaveBeenCalledTimes(1); + }); + + it('takes over when the same-version holder finishes without staging', async () => { + const release = vi.fn(async () => {}); + mocks.tryAcquireUpdateInstallLock + .mockResolvedValueOnce(null) // held by the other worker… + .mockResolvedValueOnce({ filePath: '/tmp/install.lock', release }); // …won inside the wait loop + mocks.readUpdateInstallLockVersion.mockResolvedValueOnce('0.7.0'); // the initial holder check + mocks.readStagedNativeUpdate.mockResolvedValue(null); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(0); + expect(mocks.stageNativeUpdate).toHaveBeenCalledWith( + expect.objectContaining({ version: '0.7.0' }), + ); + expect(release).toHaveBeenCalledTimes(1); + }); + + it('fails instead of a false success when the lock holder stages another version', async () => { + mocks.tryAcquireUpdateInstallLock.mockResolvedValue(null); + mocks.readUpdateInstallLockVersion.mockResolvedValue('0.8.0'); + const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(1); + expect(mocks.stageNativeUpdate).not.toHaveBeenCalled(); + expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('0.8.0')); + }); + + it('retries the acquire when the lock vanished between the two reads', async () => { + const release = vi.fn(async () => {}); + mocks.tryAcquireUpdateInstallLock + .mockResolvedValueOnce(null) + .mockResolvedValueOnce({ filePath: '/tmp/install.lock', release }); + mocks.readUpdateInstallLockVersion.mockResolvedValue(undefined); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(0); + expect(mocks.stageNativeUpdate).toHaveBeenCalledWith( + expect.objectContaining({ version: '0.7.0' }), + ); + expect(release).toHaveBeenCalledTimes(1); + }); + + it('stages against the running exe and releases the lock', async () => { + const release = vi.fn(async () => {}); + mocks.tryAcquireUpdateInstallLock.mockResolvedValue({ filePath: '/tmp/install.lock', release }); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(0); + expect(mocks.stageNativeUpdate).toHaveBeenCalledWith( + expect.objectContaining({ version: '0.7.0', exePath: process.execPath }), + ); + expect(release).toHaveBeenCalledTimes(1); + }); + + it('marks the stage as manual when the download answers an explicit upgrade', async () => { + mocks.tryAcquireUpdateInstallLock.mockResolvedValue({ + filePath: '/tmp/install.lock', + release: vi.fn(async () => {}), + }); + await expect(runUpdateDownloadCommand('0.7.0', true)).resolves.toBe(0); + expect(mocks.stageNativeUpdate).toHaveBeenCalledWith( + expect.objectContaining({ version: '0.7.0', manual: true }), + ); + }); + + it('reports staging failures with a non-zero exit code', async () => { + mocks.stageNativeUpdate.mockRejectedValue(new Error('sha256 mismatch')); + const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true); + await expect(runUpdateDownloadCommand('0.7.0')).resolves.toBe(1); + expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('sha256 mismatch')); + }); +}); diff --git a/apps/kimi-code/test/cli/update/cache.test.ts b/apps/kimi-code/test/cli/update/cache.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3009c670901114d27f2a988d2dfdc286811d182a --- /dev/null +++ b/apps/kimi-code/test/cli/update/cache.test.ts @@ -0,0 +1,167 @@ +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { + emptyUpdateInstallState, + readUpdateInstallState, + writeUpdateInstallState, +} from '#/cli/update/install-state'; +import { readUpdateCache, writeUpdateCache } from '#/cli/update/cache'; +import { emptyUpdateCache, type UpdateInstallState } from '#/cli/update/types'; +import { getUpdateInstallStateFile, getUpdateStateFile } from '#/utils/paths'; + +const originalEnv = { ...process.env }; + +let dir: string; + +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-update-cache-')); + process.env['KIMI_CODE_HOME'] = dir; +}); + +afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + process.env = { ...originalEnv }; +}); + +describe('update cache', () => { + it('returns an empty cache when the file is missing', async () => { + await expect(readUpdateCache()).resolves.toEqual(emptyUpdateCache()); + }); + + it('falls back to an empty cache when the file is corrupt', async () => { + mkdirSync(join(dir, 'updates'), { recursive: true }); + writeFileSync(getUpdateStateFile(), '{"broken"', 'utf-8'); + await expect(readUpdateCache()).resolves.toEqual(emptyUpdateCache()); + }); + + it('falls back to an empty cache when the file has the old npm.json shape', async () => { + mkdirSync(join(dir, 'updates'), { recursive: true }); + writeFileSync( + getUpdateStateFile(), + JSON.stringify({ + packageName: '@moonshot-ai/kimi-code', + checkedAt: '2026-04-23T08:00:00.000Z', + distTags: { beta: '0.0.1-beta.1' }, + }), + 'utf-8', + ); + await expect(readUpdateCache()).resolves.toEqual(emptyUpdateCache()); + }); + + it('writes and reads back the cache from updates/latest.json', async () => { + const cache = { + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: '0.5.0', + manifest: null, + } as const; + + await writeUpdateCache(cache); + + expect(getUpdateStateFile()).toBe(join(dir, 'updates', 'latest.json')); + await expect(readUpdateCache()).resolves.toEqual(cache); + }); + + it('writes and reads back a cache carrying a rollout manifest', async () => { + const cache = { + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: '0.5.0', + manifest: { + version: '0.5.0', + publishedAt: '2026-04-23T07:00:00.000Z', + rollout: [ + { percent: 30, delaySeconds: 0 }, + { percent: 30, delaySeconds: 43_200 }, + { percent: 40, delaySeconds: 86_400 }, + ], + }, + } as const; + + await writeUpdateCache(cache); + + await expect(readUpdateCache()).resolves.toEqual(cache); + }); + + it('reads a legacy cache file without a manifest field as manifest null', async () => { + mkdirSync(join(dir, 'updates'), { recursive: true }); + writeFileSync( + getUpdateStateFile(), + JSON.stringify({ + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: '0.5.0', + }), + 'utf-8', + ); + + await expect(readUpdateCache()).resolves.toEqual({ + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: '0.5.0', + manifest: null, + }); + }); + + it('keeps latest and treats a malformed manifest field as null', async () => { + mkdirSync(join(dir, 'updates'), { recursive: true }); + writeFileSync( + getUpdateStateFile(), + JSON.stringify({ + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: '0.5.0', + manifest: { version: 'not-semver', publishedAt: 'nope', rollout: 'bad' }, + }), + 'utf-8', + ); + + await expect(readUpdateCache()).resolves.toEqual({ + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: '0.5.0', + manifest: null, + }); + }); +}); + +describe('update install state', () => { + it('returns an empty install state when the file is missing', async () => { + await expect(readUpdateInstallState()).resolves.toEqual(emptyUpdateInstallState()); + }); + + it('falls back to an empty install state when the file is corrupt', async () => { + mkdirSync(join(dir, 'updates'), { recursive: true }); + writeFileSync(getUpdateInstallStateFile(), '{"broken"', 'utf-8'); + await expect(readUpdateInstallState()).resolves.toEqual(emptyUpdateInstallState()); + }); + + it('writes and reads back the install state from updates/install.json', async () => { + const state: UpdateInstallState = { + active: { + version: '0.5.0', + source: 'npm-global', + startedAt: '2026-04-23T08:00:00.000Z', + }, + lastFailure: { + version: '0.4.0', + failedAt: '2026-04-22T08:00:00.000Z', + attempts: 1, + }, + lastSuccess: { + version: '0.3.0', + installedAt: '2026-04-21T08:00:00.000Z', + notifiedAt: null, + }, + }; + + await writeUpdateInstallState(state); + + expect(getUpdateInstallStateFile()).toBe(join(dir, 'updates', 'install.json')); + await expect(readUpdateInstallState()).resolves.toEqual(state); + }); +}); diff --git a/apps/kimi-code/test/cli/update/cdn.test.ts b/apps/kimi-code/test/cli/update/cdn.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..dae77449f09bc9bfb2a318c430c922698bf00e9c --- /dev/null +++ b/apps/kimi-code/test/cli/update/cdn.test.ts @@ -0,0 +1,261 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { fetchLatestFromCdn, fetchLatestVersionFromCdn } from '#/cli/update/cdn'; +import { kimiCodeCdnLatestJsonUrl, kimiCodeCdnLatestUrl } from '#/constant/app'; + +function mockFetchOk(body: string): typeof fetch { + return vi.fn(async () => ({ + ok: true, + status: 200, + text: async () => body, + })) as unknown as typeof fetch; +} + +function mockFetchStatus(status: number): typeof fetch { + return vi.fn(async () => ({ + ok: status >= 200 && status < 300, + status, + text: async () => '', + })) as unknown as typeof fetch; +} + +type Route = { readonly status?: number; readonly body?: string } | Error; + +/** URL-routed fetch mock: unrouted URLs return 404. */ +function mockRoutedFetch(routes: Record): typeof fetch { + return vi.fn(async (input: string | URL) => { + const route = routes[String(input)]; + if (route === undefined) { + return { ok: false, status: 404, text: async () => '' }; + } + if (route instanceof Error) throw route; + const status = route.status ?? 200; + return { + ok: status >= 200 && status < 300, + status, + text: async () => route.body ?? '', + }; + }) as unknown as typeof fetch; +} + +const MANIFEST_BODY = JSON.stringify({ + schemaVersion: 1, + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + rollout: [ + { percent: 30, delaySeconds: 0 }, + { percent: 30, delaySeconds: 43_200 }, + { percent: 40, delaySeconds: 86_400 }, + ], +}); + +describe('fetchLatestVersionFromCdn', () => { + it('returns the trimmed semver returned by CDN /latest', async () => { + const f = mockFetchOk(' 0.5.0\n'); + await expect(fetchLatestVersionFromCdn(f)).resolves.toBe('0.5.0'); + expect(f).toHaveBeenCalledWith( + kimiCodeCdnLatestUrl(), + expect.objectContaining({ signal: expect.any(AbortSignal) }), + ); + }); + + it('throws when response is non-2xx', async () => { + await expect(fetchLatestVersionFromCdn(mockFetchStatus(404))).rejects.toThrow(/HTTP 404/); + }); + + it('throws when body is not valid semver', async () => { + await expect(fetchLatestVersionFromCdn(mockFetchOk('not-a-version'))).rejects.toThrow( + /invalid semver/, + ); + }); + + it('throws when body is empty', async () => { + await expect(fetchLatestVersionFromCdn(mockFetchOk(' '))).rejects.toThrow(/invalid semver/); + }); + + it('propagates the underlying fetch error', async () => { + const f = vi.fn(async () => { + throw new Error('network down'); + }) as unknown as typeof fetch; + await expect(fetchLatestVersionFromCdn(f)).rejects.toThrow(/network down/); + }); +}); + +describe('fetchLatestFromCdn', () => { + it('parses latest.json and returns the manifest', async () => { + const f = mockRoutedFetch({ [kimiCodeCdnLatestJsonUrl()]: { body: MANIFEST_BODY } }); + await expect(fetchLatestFromCdn(f)).resolves.toEqual({ + latest: '2.0.0', + manifest: { + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + rollout: [ + { percent: 30, delaySeconds: 0 }, + { percent: 30, delaySeconds: 43_200 }, + { percent: 40, delaySeconds: 86_400 }, + ], + }, + }); + expect(f).toHaveBeenCalledWith( + kimiCodeCdnLatestJsonUrl(), + expect.objectContaining({ signal: expect.any(AbortSignal) }), + ); + expect(f).toHaveBeenCalledTimes(1); + }); + + it('ignores unknown manifest fields (lenient parsing)', async () => { + const body = JSON.stringify({ + schemaVersion: 99, + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + rollout: [], + futureField: { nested: true }, + }); + const f = mockRoutedFetch({ [kimiCodeCdnLatestJsonUrl()]: { body } }); + const result = await fetchLatestFromCdn(f); + expect(result.manifest).toEqual({ + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + rollout: [], + }); + }); + + it('defaults a missing rollout to an empty plan (fully rolled out)', async () => { + const body = JSON.stringify({ + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + }); + const f = mockRoutedFetch({ [kimiCodeCdnLatestJsonUrl()]: { body } }); + const result = await fetchLatestFromCdn(f); + expect(result.manifest?.rollout).toEqual([]); + }); + + const fallbackCases: ReadonlyArray = [ + ['latest.json is missing (HTTP 404)', { status: 404 }], + ['latest.json fetch throws', new Error('network down')], + ['body is not valid JSON', { body: 'not json {' }], + ['version is not semver', { body: JSON.stringify({ version: 'nope', publishedAt: '2026-06-12T00:00:00.000Z' }) }], + ['publishedAt is unparseable', { body: JSON.stringify({ version: '2.0.0', publishedAt: 'garbage' }) }], + ['a batch percent is out of range', { + body: JSON.stringify({ + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + rollout: [{ percent: 150, delaySeconds: 0 }], + }), + }], + ['a batch delay is negative', { + body: JSON.stringify({ + version: '2.0.0', + publishedAt: '2026-06-12T00:00:00.000Z', + rollout: [{ percent: 100, delaySeconds: -1 }], + }), + }], + ]; + + for (const [name, route] of fallbackCases) { + it(`falls back to plain /latest when ${name}`, async () => { + const f = mockRoutedFetch({ + [kimiCodeCdnLatestJsonUrl()]: route, + [kimiCodeCdnLatestUrl()]: { body: '1.9.0\n' }, + }); + await expect(fetchLatestFromCdn(f)).resolves.toEqual({ + latest: '1.9.0', + manifest: null, + }); + }); + } + + it('throws when both latest.json and plain /latest fail', async () => { + const f = mockRoutedFetch({ + [kimiCodeCdnLatestJsonUrl()]: { status: 500 }, + [kimiCodeCdnLatestUrl()]: { status: 500 }, + }); + await expect(fetchLatestFromCdn(f)).rejects.toThrow(/HTTP 500/); + }); + + it('propagates the plain /latest error when the fallback also breaks', async () => { + const f = mockRoutedFetch({ + [kimiCodeCdnLatestJsonUrl()]: new Error('json down'), + [kimiCodeCdnLatestUrl()]: { body: 'not-a-version' }, + }); + await expect(fetchLatestFromCdn(f)).rejects.toThrow(/invalid semver/); + }); + + it('falls back to plain /latest when latest.json hangs past the request timeout', async () => { + vi.useFakeTimers(); + try { + const f = vi.fn(async (input: string | URL, init?: RequestInit) => { + if (String(input) === kimiCodeCdnLatestJsonUrl()) { + return new Promise((_resolve, reject) => { + init?.signal?.addEventListener('abort', () => { + reject(new Error('aborted')); + }, { once: true }); + }); + } + if (String(input) === kimiCodeCdnLatestUrl()) { + return { ok: true, status: 200, text: async () => '1.9.0\n' }; + } + return { ok: false, status: 404, text: async () => '' }; + }) as unknown as typeof fetch; + + const result = fetchLatestFromCdn(f); + await vi.advanceTimersByTimeAsync(3_000); + + await expect(result).resolves.toEqual({ + latest: '1.9.0', + manifest: null, + }); + } finally { + vi.useRealTimers(); + } + }); + + it('rejects when plain /latest also hangs past the request timeout', async () => { + vi.useFakeTimers(); + try { + const f = vi.fn(async (_input: string | URL, init?: RequestInit) => { + return new Promise((_resolve, reject) => { + init?.signal?.addEventListener('abort', () => { + reject(new Error('aborted')); + }, { once: true }); + }); + }) as unknown as typeof fetch; + + const result = fetchLatestFromCdn(f); + const expectation = expect(result).rejects.toThrow(/aborted/); + await vi.advanceTimersByTimeAsync(6_000); + + await expectation; + } finally { + vi.useRealTimers(); + } + }); + + it('honors a custom request timeout instead of the background budget', async () => { + vi.useFakeTimers(); + try { + const f = vi.fn(async (_input: string | URL, init?: RequestInit) => { + return new Promise((_resolve, reject) => { + init?.signal?.addEventListener('abort', () => { + reject(new Error('aborted')); + }, { once: true }); + }); + }) as unknown as typeof fetch; + + const result = fetchLatestFromCdn(f, 10_000); + let rejected = false; + void result.catch(() => { + rejected = true; + }); + const expectation = expect(result).rejects.toThrow(/aborted/); + await vi.advanceTimersByTimeAsync(6_000); + expect(rejected).toBe(false); + await vi.advanceTimersByTimeAsync(14_000); + + await expectation; + expect(rejected).toBe(true); + } finally { + vi.useRealTimers(); + } + }); +}); diff --git a/apps/kimi-code/test/cli/update/install-lock.test.ts b/apps/kimi-code/test/cli/update/install-lock.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..63bfbc783ff3e4df9e0c4fa3b54777af1a2aa8f2 --- /dev/null +++ b/apps/kimi-code/test/cli/update/install-lock.test.ts @@ -0,0 +1,218 @@ +import { spawn } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, utimesSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { tryAcquireUpdateInstallLock } from '#/cli/update/install-lock'; +import { getUpdateInstallLockFile } from '#/utils/paths'; + +const fsMocks = vi.hoisted(() => ({ + /** When set, link() throws an error with this code (no hard-link support). */ + linkError: null as string | null, +})); + +vi.mock('node:fs/promises', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + link: async ( + src: Parameters[0], + dst: Parameters[1], + ) => { + if (fsMocks.linkError !== null) { + throw Object.assign(new Error('link() is not supported (mocked)'), { + code: fsMocks.linkError, + }); + } + return actual.link(src, dst); + }, + }; +}); + +const originalEnv = { ...process.env }; + +let dir: string; + +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-update-install-lock-')); + process.env['KIMI_CODE_HOME'] = dir; + fsMocks.linkError = null; +}); + +afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + process.env = { ...originalEnv }; +}); + +describe('update install lock', () => { + it('allows only one holder until the lock is released', async () => { + const first = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + expect(first).not.toBeNull(); + expect(getUpdateInstallLockFile()).toBe(join(dir, 'updates', 'install.lock')); + + const second = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + expect(second).toBeNull(); + + await first?.release(); + + const third = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + expect(third).not.toBeNull(); + await third?.release(); + }); + + it('grants the lock to exactly one of many concurrent acquirers', async () => { + // The lock file must never be observable in an empty/partial state: + // losers of the create race used to sweep the just-created (still empty) + // lock as "corrupt" and also win, breaking exclusivity. + const attempts = await Promise.all( + Array.from({ length: 20 }, () => tryAcquireUpdateInstallLock({ version: '0.5.0' })), + ); + const winners = attempts.filter((handle) => handle !== null); + expect(winners).toHaveLength(1); + const held = JSON.parse(readFileSync(getUpdateInstallLockFile(), 'utf-8')) as { + version: string; + }; + expect(held.version).toBe('0.5.0'); + await winners[0]?.release(); + }); + + it('grants exactly one winner when racing to take over a stale lock', async () => { + // A dead holder's aged lock: every contender classifies it as stale and + // tries to take it over. Compare-and-delete plus post-publish + // verification must leave exactly one survivor. + const child = spawn(process.execPath, ['-e', ''], { stdio: 'ignore' }); + await new Promise((resolve) => child.once('exit', resolve)); + writeAgedLock(child.pid ?? -1); + + const attempts = await Promise.all( + Array.from({ length: 20 }, () => tryAcquireUpdateInstallLock({ version: '0.5.0' })), + ); + const winners = attempts.filter((handle) => handle !== null); + expect(winners).toHaveLength(1); + await winners[0]?.release(); + }); + + it('recovers from a corrupt lock file', async () => { + const filePath = getUpdateInstallLockFile(); + mkdirSync(dirname(filePath), { recursive: true }); + writeFileSync(filePath, '{', 'utf-8'); + // Crash residue is old; a YOUNG unparseable file is treated as a publish + // still in progress (see the publish grace), so age it past the grace. + const old = new Date(Date.now() - 2 * 60 * 1000); + utimesSync(filePath, old, old); + + const lock = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + + expect(lock).not.toBeNull(); + await lock?.release(); + }); + + it('treats a young unparseable lock as a publish in progress', async () => { + // The exclusive-create fallback (filesystems without hard links) is + // observable between create and write; sweeping that window would break + // exclusivity, so young unparseable content is NOT stale. + const filePath = getUpdateInstallLockFile(); + mkdirSync(dirname(filePath), { recursive: true }); + writeFileSync(filePath, '{', 'utf-8'); + + const lock = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + + expect(lock).toBeNull(); + }); + + it('acquires, excludes and releases on filesystems without hard-link support', async () => { + fsMocks.linkError = 'ENOTSUP'; + + const first = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + expect(first).not.toBeNull(); + expect(await tryAcquireUpdateInstallLock({ version: '0.5.0' })).toBeNull(); + + await first?.release(); + const again = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + expect(again).not.toBeNull(); + await again?.release(); + }); + + it('grants exactly one winner under concurrent exclusive-create publishes', async () => { + fsMocks.linkError = 'ENOTSUP'; + + const attempts = await Promise.all( + Array.from({ length: 20 }, () => tryAcquireUpdateInstallLock({ version: '0.5.0' })), + ); + const winners = attempts.filter((handle) => handle !== null); + expect(winners).toHaveLength(1); + await winners[0]?.release(); + }); + + it('takes over a stale lock without hard-link support', async () => { + fsMocks.linkError = 'ENOTSUP'; + const child = spawn(process.execPath, ['-e', ''], { stdio: 'ignore' }); + await new Promise((resolve) => child.once('exit', resolve)); + writeAgedLock(child.pid ?? -1); + + const lock = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + + expect(lock).not.toBeNull(); + await lock?.release(); + }); + + function writeAgedLock(pid: number): void { + const filePath = getUpdateInstallLockFile(); + mkdirSync(dirname(filePath), { recursive: true }); + writeFileSync( + filePath, + `${JSON.stringify({ + version: '0.5.0', + pid, + startedAt: new Date(Date.now() - 60 * 60 * 1000).toISOString(), + })}\n`, + 'utf-8', + ); + } + + it('does not treat an aged lock as stale while its holder process is alive', async () => { + // The holder is this very test process — guaranteed alive. A long native + // download must survive past the 30-minute age threshold. + writeAgedLock(process.pid); + + const lock = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + + expect(lock).toBeNull(); + }); + + it('sweeps an aged lock whose holder process is gone', async () => { + const child = spawn(process.execPath, ['-e', ''], { stdio: 'ignore' }); + await new Promise((resolve) => child.once('exit', resolve)); + writeAgedLock(child.pid ?? -1); + + const lock = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + + expect(lock).not.toBeNull(); + await lock?.release(); + }); + + it('sweeps a young lock whose holder process is gone', async () => { + // A killed holder skips its finally and never releases: the dead pid must + // make the lock stale immediately, not after the 30-minute threshold. + const child = spawn(process.execPath, ['-e', ''], { stdio: 'ignore' }); + await new Promise((resolve) => child.once('exit', resolve)); + const filePath = getUpdateInstallLockFile(); + mkdirSync(dirname(filePath), { recursive: true }); + writeFileSync( + filePath, + `${JSON.stringify({ + version: '0.5.0', + pid: child.pid ?? -1, + startedAt: new Date().toISOString(), + })}\n`, + 'utf-8', + ); + + const lock = await tryAcquireUpdateInstallLock({ version: '0.5.0' }); + + expect(lock).not.toBeNull(); + await lock?.release(); + }); +}); diff --git a/apps/kimi-code/test/cli/update/native-manifest.test.ts b/apps/kimi-code/test/cli/update/native-manifest.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..74f455b5df1ce2a2b0893618e0767a95eda4043f --- /dev/null +++ b/apps/kimi-code/test/cli/update/native-manifest.test.ts @@ -0,0 +1,204 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { + fetchNativeReleaseManifest, + nativeBinaryUrl, + nativeManifestUrl, + selectPlatformEntry, +} from '#/cli/update/native-manifest'; +import { kimiCodeCdnBinariesBase } from '#/constant/app'; + +const VERSION = '0.7.0'; + +function mockFetch(response: { + readonly ok: boolean; + readonly status: number; + readonly body?: string; +}): typeof fetch { + return vi.fn(async () => ({ + ok: response.ok, + status: response.status, + text: async () => response.body ?? '', + })) as unknown as typeof fetch; +} + +const MANIFEST_BODY = JSON.stringify({ + version: VERSION, + tag: `@moonshot-ai/kimi-code@${VERSION}`, + platforms: { + 'win32-x64': { + filename: `kimi-code-win32-x64.zip`, + checksum: 'a'.repeat(64), + }, + 'darwin-arm64': { + filename: `kimi-code-darwin-arm64.zip`, + checksum: 'b'.repeat(64), + }, + }, +}); + +describe('fetchNativeReleaseManifest', () => { + it('fetches and parses the manifest for the given version', async () => { + const f = mockFetch({ ok: true, status: 200, body: MANIFEST_BODY }); + const manifest = await fetchNativeReleaseManifest(VERSION, f); + expect(manifest.version).toBe(VERSION); + expect(Object.keys(manifest.platforms)).toEqual(['win32-x64', 'darwin-arm64']); + expect(f).toHaveBeenCalledWith( + nativeManifestUrl(VERSION), + expect.objectContaining({ signal: expect.any(AbortSignal) }), + ); + }); + + it('ignores unknown fields (lenient parsing)', async () => { + const body = JSON.stringify({ + version: VERSION, + platforms: {}, + futureField: { nested: true }, + }); + const manifest = await fetchNativeReleaseManifest(VERSION, mockFetch({ ok: true, status: 200, body })); + expect(manifest.version).toBe(VERSION); + }); + + it('parses a platform entry carrying a compressed artifact pointer', async () => { + const body = JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { + filename: 'kimi-code-linux-x64', + checksum: 'a'.repeat(64), + compressed: { filename: 'kimi-code-linux-x64.zst', checksum: 'b'.repeat(64) }, + }, + }, + }); + const manifest = await fetchNativeReleaseManifest(VERSION, mockFetch({ ok: true, status: 200, body })); + expect(manifest.platforms['linux-x64']?.compressed).toEqual({ + filename: 'kimi-code-linux-x64.zst', + checksum: 'b'.repeat(64), + }); + }); + + it('parses a platform entry carrying a zstd artifact pointer', async () => { + const body = JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { + filename: 'kimi-code-linux-x64', + checksum: 'a'.repeat(64), + zstd: { file: 'kimi-code-linux-x64.zst', sha256: 'b'.repeat(64) }, + }, + }, + }); + const manifest = await fetchNativeReleaseManifest(VERSION, mockFetch({ ok: true, status: 200, body })); + expect(manifest.platforms['linux-x64']).toEqual({ + filename: 'kimi-code-linux-x64', + checksum: 'a'.repeat(64), + zstd: { file: 'kimi-code-linux-x64.zst', sha256: 'b'.repeat(64) }, + }); + }); + + it.each([ + { file: '', sha256: 'b'.repeat(64) }, + { file: 'kimi-code-linux-x64.zst', sha256: 'invalid' }, + ])('rejects an invalid zstd artifact pointer: %j', async (zstd) => { + const body = JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { filename: 'kimi-code-linux-x64', checksum: 'a'.repeat(64), zstd }, + }, + }); + await expect( + fetchNativeReleaseManifest(VERSION, mockFetch({ ok: true, status: 200, body })), + ).rejects.toThrow(); + }); + + it('rejects a non-semver version argument before hitting the network', async () => { + const f = mockFetch({ ok: true, status: 200, body: MANIFEST_BODY }); + await expect(fetchNativeReleaseManifest('nope', f)).rejects.toThrow(/invalid semver/); + expect(f).not.toHaveBeenCalled(); + }); + + it('rejects a manifest served for a different release', async () => { + // A stale/mispublished endpoint answering with another version's manifest + // must not apply that release's checksums to this version's binary. + const body = JSON.stringify({ version: '0.9.9', platforms: {} }); + await expect( + fetchNativeReleaseManifest(VERSION, mockFetch({ ok: true, status: 200, body })), + ).rejects.toThrow(/0\.9\.9/); + }); + + it('throws on non-2xx', async () => { + await expect( + fetchNativeReleaseManifest(VERSION, mockFetch({ ok: false, status: 404 })), + ).rejects.toThrow(/HTTP 404/); + }); + + it('throws on a malformed checksum', async () => { + const body = JSON.stringify({ + version: VERSION, + platforms: { 'win32-x64': { filename: 'kimi-code-win32-x64.zip', checksum: 'xyz' } }, + }); + await expect( + fetchNativeReleaseManifest(VERSION, mockFetch({ ok: true, status: 200, body })), + ).rejects.toThrow(); + }); + + it('propagates fetch errors', async () => { + const f = vi.fn(async () => { + throw new Error('network down'); + }) as unknown as typeof fetch; + await expect(fetchNativeReleaseManifest(VERSION, f)).rejects.toThrow(/network down/); + }); + + it('rejects when the response body stalls past the request timeout', async () => { + vi.useFakeTimers(); + try { + const f = vi.fn(async (_input: string | URL, init?: RequestInit) => ({ + ok: true, + status: 200, + // Headers arrive, then the body stalls; only the timeout can end this. + text: async () => + new Promise((_, reject) => { + init?.signal?.addEventListener('abort', () => { + reject(new Error('aborted')); + }, { once: true }); + }), + })) as unknown as typeof fetch; + const promise = fetchNativeReleaseManifest(VERSION, f); + const assertion = expect(promise).rejects.toThrow(/aborted/); + await vi.advanceTimersByTimeAsync(11_000); + await assertion; + } finally { + vi.useRealTimers(); + } + }); +}); + +describe('selectPlatformEntry', () => { + const manifest = { + version: VERSION, + platforms: { + 'win32-x64': { filename: 'kimi-code-win32-x64.zip', checksum: 'a'.repeat(64) }, + }, + }; + + it('returns the entry matching platform-arch', () => { + expect(selectPlatformEntry(manifest, 'win32', 'x64')).toEqual( + manifest.platforms['win32-x64'], + ); + }); + + it('throws when the platform is missing', () => { + expect(() => selectPlatformEntry(manifest, 'linux', 'arm64')).toThrow( + /linux-arm64 not found/, + ); + }); +}); + +describe('url helpers', () => { + it('builds the manifest and binary URLs from the binaries base', () => { + expect(nativeManifestUrl(VERSION)).toBe(`${kimiCodeCdnBinariesBase()}/${VERSION}/manifest.json`); + expect(nativeBinaryUrl(VERSION, 'kimi-code-win32-x64.zip')).toBe( + `${kimiCodeCdnBinariesBase()}/${VERSION}/kimi-code-win32-x64.zip`, + ); + }); +}); diff --git a/apps/kimi-code/test/cli/update/native-stage.test.ts b/apps/kimi-code/test/cli/update/native-stage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2aaad60b1e9ad8a6133e3dcb922e272ffd3c5637 --- /dev/null +++ b/apps/kimi-code/test/cli/update/native-stage.test.ts @@ -0,0 +1,991 @@ +import { createHash } from 'node:crypto'; +import { mkdtemp, readdir, readFile, rm, stat, utimes, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { zstdCompressSync } from 'node:zlib'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { nativeBinaryUrl, nativeManifestUrl } from '#/cli/update/native-manifest'; +import { + promoteStagedUpdateToManual, + readStagedNativeUpdate, + stagedExePath, + stageNativeUpdate, +} from '#/cli/update/native-stage'; +import { getNativeStagedStateFile, getNativeStagingDir } from '#/utils/paths'; + +const fsMocks = vi.hoisted(() => ({ + /** Records chmod/rename calls (path-based) so tests can assert ordering. */ + calls: [] as Array<{ readonly op: 'chmod' | 'rename'; readonly path: string; readonly dst?: string }>, + /** When > 0, the next open() wraps its handle so the first write is short. */ + shortWriteBudget: 0, +})); + +vi.mock('node:fs/promises', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + chmod: async ( + path: Parameters[0], + mode: Parameters[1], + ) => { + fsMocks.calls.push({ op: 'chmod', path: String(path) }); + return actual.chmod(path, mode); + }, + rename: async ( + src: Parameters[0], + dst: Parameters[1], + ) => { + fsMocks.calls.push({ op: 'rename', path: String(src), dst: String(dst) }); + return actual.rename(src, dst); + }, + open: async ( + path: Parameters[0], + flags: Parameters[1], + mode: Parameters[2], + ) => { + const handle = await actual.open(path, flags, mode); + if (fsMocks.shortWriteBudget <= 0) return handle; + fsMocks.shortWriteBudget -= 1; + let truncated = false; + return { + // FileHandle methods live on the prototype, so delegate explicitly. + write: async ( + buffer: Buffer, + offset?: number | null, + length?: number | null, + position?: number | null, + ) => { + const off = offset ?? 0; + const len = length ?? buffer.length - off; + // The first write persists only half the requested bytes. + const effectiveLen = !truncated && len > 1 ? Math.floor(len / 2) : len; + truncated = true; + const result = await handle.write(buffer, off, effectiveLen, position ?? null); + return { bytesWritten: result.bytesWritten, buffer: result.buffer }; + }, + close: () => handle.close(), + }; + }, + }; +}); + +const VERSION = '0.7.0'; +const PAYLOAD = Buffer.from('fake-sea-binary-payload'); +// The CDN serves the bare platform binary; the manifest checksum is its sha256. +const BINARY_FILENAME = 'kimi-code-linux-x64'; +const COMPRESSED_FILENAME = 'kimi-code-linux-x64.zst'; + +function sha256Hex(data: Buffer): string { + return createHash('sha256').update(data).digest('hex'); +} + +/** Write a staging artifact old enough for the orphan sweep to reap it. */ +async function agedOrphan(path: string, content: string | Buffer): Promise { + await writeFile(path, content); + const old = new Date(Date.now() - 2 * 60 * 60 * 1000); + await utimes(path, old, old); +} + +interface MockCdnOptions { + readonly version?: string; + readonly payload: Buffer; + readonly checksum?: string; + /** + * When set, the manifest entry advertises a compressed artifact; the .zst + * URL serves `payload` (null → 404, a CDN without the artifact yet). + */ + readonly compressed?: { + readonly payload: Buffer | null; + readonly checksum?: string; + readonly field?: 'compressed' | 'zstd'; + }; +} + +function mockCdnFetch(options: MockCdnOptions): typeof fetch { + const version = options.version ?? VERSION; + const platformEntry: Record = { + filename: BINARY_FILENAME, + checksum: options.checksum ?? sha256Hex(options.payload), + }; + if (options.compressed !== undefined) { + const checksum = + options.compressed.checksum ?? sha256Hex(options.compressed.payload ?? Buffer.alloc(0)); + if (options.compressed.field === 'zstd') { + platformEntry['zstd'] = { file: COMPRESSED_FILENAME, sha256: checksum }; + } else { + platformEntry['compressed'] = { filename: COMPRESSED_FILENAME, checksum }; + } + } + const manifestBody = JSON.stringify({ + version, + tag: `v${version}`, + platforms: { + 'linux-x64': platformEntry, + }, + }); + return vi.fn(async (input: string | URL) => { + const url = String(input); + if (url === nativeManifestUrl(version)) { + return { ok: true, status: 200, text: async () => manifestBody, body: null }; + } + if (url === nativeBinaryUrl(version, BINARY_FILENAME)) { + return { + ok: true, + status: 200, + text: async (): Promise => '', + headers: { + get: (name: string): string | null => + name === 'content-length' ? String(options.payload.length) : null, + }, + body: [options.payload], + }; + } + if (url === nativeBinaryUrl(version, COMPRESSED_FILENAME) && options.compressed?.payload) { + const payload = options.compressed.payload; + return { + ok: true, + status: 200, + text: async (): Promise => '', + headers: { + get: (name: string): string | null => + name === 'content-length' ? String(payload.length) : null, + }, + body: [payload], + }; + } + return { ok: false, status: 404, text: async () => '', body: null }; + }) as unknown as typeof fetch; +} + +describe('stageNativeUpdate', () => { + let workDir: string; + let exePath: string; + + beforeEach(async () => { + workDir = await mkdtemp(join(tmpdir(), 'kimi-stage-test-')); + exePath = join(workDir, 'bin', 'kimi'); + fsMocks.calls.length = 0; + fsMocks.shortWriteBudget = 0; + }); + + afterEach(async () => { + vi.restoreAllMocks(); + await rm(workDir, { recursive: true, force: true }); + }); + + it('downloads, verifies and records the staged metadata', async () => { + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + + expect(result.status).toBe('staged'); + expect(result.staged).toMatchObject({ + version: VERSION, + target: 'linux-x64', + sha256: sha256Hex(PAYLOAD), + exeSize: PAYLOAD.length, + }); + // The published exe name carries a unique per-worker infix: a staged + // executable is never replaced once published, so the pathname a swap + // validates at claim time is stable. + expect(result.staged.exeFileName).toMatch(/^kimi-0\.7\.0\.\d+\.\d+\.\d+$/); + + const stagedOnDisk = await readStagedNativeUpdate(exePath); + expect(stagedOnDisk).toEqual(result.staged); + const exeBytes = await readFile(stagedExePath(exePath, result.staged)); + expect(exeBytes.equals(PAYLOAD)).toBe(true); + // The .part intermediate is gone once the download was promoted. + const leftovers = (await readdir(getNativeStagingDir(exePath))).filter((entry) => + entry.endsWith('.part'), + ); + expect(leftovers).toEqual([]); + }); + + it.each(['compressed', 'zstd'] as const)('downloads the %s artifact and stages the decompressed binary', async (field) => { + const fetchImpl = mockCdnFetch({ + payload: PAYLOAD, + compressed: { payload: zstdCompressSync(PAYLOAD), field }, + }); + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + }); + + expect(result.status).toBe('staged'); + // The metadata records the BARE binary's checksum and size. + expect(result.staged.sha256).toBe(sha256Hex(PAYLOAD)); + expect(result.staged.exeSize).toBe(PAYLOAD.length); + const exeBytes = await readFile(stagedExePath(exePath, result.staged)); + expect(exeBytes.equals(PAYLOAD)).toBe(true); + // The bare binary was never downloaded… + expect(fetchImpl).not.toHaveBeenCalledWith( + nativeBinaryUrl(VERSION, BINARY_FILENAME), + expect.anything(), + ); + // …and the .zst intermediate is gone once decompressed and published. + const leftovers = (await readdir(getNativeStagingDir(exePath))).filter((entry) => + entry.endsWith('.part'), + ); + expect(leftovers).toEqual([]); + }); + + it.each(['compressed', 'zstd'] as const)('falls back to the bare binary when the compressed artifact is missing (%s)', async (field) => { + vi.spyOn(console, 'warn').mockImplementation(() => {}); + const fetchImpl = mockCdnFetch({ + payload: PAYLOAD, + compressed: { payload: null, field }, + }); + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + }); + + expect(result.status).toBe('staged'); + expect(fetchImpl).toHaveBeenCalledWith( + nativeBinaryUrl(VERSION, BINARY_FILENAME), + expect.anything(), + ); + const exeBytes = await readFile(stagedExePath(exePath, result.staged)); + expect(exeBytes.equals(PAYLOAD)).toBe(true); + }); + + it.each(['compressed', 'zstd'] as const)('falls back to the bare binary when the compressed artifact fails verification (%s)', async (field) => { + vi.spyOn(console, 'warn').mockImplementation(() => {}); + const fetchImpl = mockCdnFetch({ + payload: PAYLOAD, + // The .zst bytes do not hash to the advertised compressed checksum. + compressed: { payload: zstdCompressSync(PAYLOAD), checksum: 'f'.repeat(64), field }, + }); + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + }); + + expect(result.status).toBe('staged'); + expect(fetchImpl).toHaveBeenCalledWith( + nativeBinaryUrl(VERSION, BINARY_FILENAME), + expect.anything(), + ); + const exeBytes = await readFile(stagedExePath(exePath, result.staged)); + expect(exeBytes.equals(PAYLOAD)).toBe(true); + }); + + it.each(['compressed', 'zstd'] as const)('falls back to the bare binary when the decompressed content fails verification (%s)', async (field) => { + vi.spyOn(console, 'warn').mockImplementation(() => {}); + // The .zst verifies against its own checksum but inflates to something + // other than the bare binary the manifest checksum covers. + const fetchImpl = mockCdnFetch({ + payload: PAYLOAD, + compressed: { payload: zstdCompressSync(Buffer.from('other-content')), field }, + }); + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + }); + + expect(result.status).toBe('staged'); + expect(result.staged.sha256).toBe(sha256Hex(PAYLOAD)); + const exeBytes = await readFile(stagedExePath(exePath, result.staged)); + expect(exeBytes.equals(PAYLOAD)).toBe(true); + }); + + it('prefers zstd when both manifest formats are present', async () => { + const compressedPayload = zstdCompressSync(PAYLOAD); + const fetchImpl = mockCdnFetch({ + payload: PAYLOAD, + compressed: { payload: compressedPayload, field: 'zstd' }, + }); + vi.mocked(fetchImpl).mockResolvedValueOnce(new Response(JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { + filename: BINARY_FILENAME, + checksum: sha256Hex(PAYLOAD), + zstd: { file: COMPRESSED_FILENAME, sha256: sha256Hex(compressedPayload) }, + compressed: { filename: 'legacy.zst', checksum: 'a'.repeat(64) }, + }, + }, + }))); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + }); + + expect(await readFile(stagedExePath(exePath, result.staged))).toEqual(PAYLOAD); + expect(fetchImpl).toHaveBeenCalledWith( + nativeBinaryUrl(VERSION, COMPRESSED_FILENAME), + expect.anything(), + ); + expect(fetchImpl).not.toHaveBeenCalledWith( + nativeBinaryUrl(VERSION, 'legacy.zst'), + expect.anything(), + ); + expect(fetchImpl).not.toHaveBeenCalledWith( + nativeBinaryUrl(VERSION, BINARY_FILENAME), + expect.anything(), + ); + }); + + it('marks the staged exe executable', async () => { + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + const info = await stat(stagedExePath(exePath, result.staged)); + expect(info.mode & 0o111).not.toBe(0); + }); + + it('records the manual marker when the stage answers an explicit upgrade', async () => { + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + manual: true, + }); + expect(result.staged.manual).toBe(true); + // And it round-trips through the on-disk metadata. + expect((await readStagedNativeUpdate(exePath))?.manual).toBe(true); + }); + + it('makes the download executable before publishing it at the staged name', async () => { + // A concurrent swap may move the staged exe into place the instant it + // appears at its published name, so the chmod must land on the private + // .part file first — a later chmod could hit an already-moved path. + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + const stagedExe = stagedExePath(exePath, result.staged); + const chmodCall = fsMocks.calls.find( + (call) => call.op === 'chmod' && call.path.endsWith('.part'), + ); + const publishCall = fsMocks.calls.find( + (call) => call.op === 'rename' && call.dst === stagedExe, + ); + if (chmodCall === undefined || publishCall === undefined) { + throw new Error('expected chmod(.part) and rename(.part → staged) calls'); + } + // The chmod lands on the very .part file that gets published, before it. + expect(publishCall.path).toBe(chmodCall.path); + expect(fsMocks.calls.indexOf(chmodCall)).toBeLessThan( + fsMocks.calls.indexOf(publishCall), + ); + }); + + it('reports download progress with the Content-Length total', async () => { + const progress: Array = []; + await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + onProgress: (downloaded, total) => { + progress.push([downloaded, total]); + }, + }); + // One frame per chunk; the mock stream delivers the payload in one piece. + expect(progress).toEqual([[PAYLOAD.length, PAYLOAD.length]]); + }); + + it('aborts a stalled download after the idle timeout', async () => { + const manifestBody = JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { filename: BINARY_FILENAME, checksum: 'a'.repeat(64) }, + }, + }); + const fetchImpl = vi.fn(async (input: string | URL, init?: RequestInit) => { + const url = String(input); + if (url === nativeManifestUrl(VERSION)) { + return { ok: true, status: 200, text: async () => manifestBody, body: null }; + } + if (url === nativeBinaryUrl(VERSION, BINARY_FILENAME)) { + const signal = init?.signal; + const body = (async function* (): AsyncGenerator { + yield Buffer.from('first-chunk'); + // Stall forever — only the idle timeout's abort can end this. + await new Promise((_, reject) => { + signal?.addEventListener('abort', () => { + reject(signal.reason instanceof Error ? signal.reason : new Error('aborted')); + }, { once: true }); + }); + })(); + return { + ok: true, + status: 200, + text: async (): Promise => '', + headers: { get: (): string | null => null }, + body, + }; + } + return { ok: false, status: 404, text: async (): Promise => '', body: null }; + }) as unknown as typeof fetch; + + // Real timers with a 50 ms test override — fake timers interact badly + // with async-generator suspension, so the idle timeout is injectable. + await expect( + stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + idleTimeoutMs: 50, + }), + ).rejects.toThrow(/stalled/); + // The failed attempt cleans up after itself. + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + }); + + it('short-circuits when the same version is already staged', async () => { + const firstFetch = mockCdnFetch({ payload: PAYLOAD }); + await stageNativeUpdate({ version: VERSION, exePath, platform: 'linux', arch: 'x64', fetchImpl: firstFetch }); + + const secondFetch = mockCdnFetch({ payload: PAYLOAD }); + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: secondFetch, + }); + + expect(result.status).toBe('already-staged'); + expect(secondFetch).not.toHaveBeenCalled(); + }); + + it('promotes an auto-staged payload to manual when an explicit upgrade adopts it', async () => { + // The passive downloader staged the version first (no manual marker). + await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + manual: true, + }); + + expect(result.status).toBe('already-staged'); + expect(result.staged.manual).toBe(true); + // The promotion persisted to the on-disk metadata. + expect((await readStagedNativeUpdate(exePath))?.manual).toBe(true); + }); + + it('re-stages when the staged exe is corrupted at the same size', async () => { + const first = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + // Same-size corruption after the download: the metadata still validates + // (size matches), but the bytes no longer hash to the recorded checksum. + await writeFile(stagedExePath(exePath, first.staged), Buffer.alloc(PAYLOAD.length)); + // Size-only readers still see the stage as valid… + expect(await readStagedNativeUpdate(exePath)).not.toBeNull(); + + const secondFetch = mockCdnFetch({ payload: PAYLOAD }); + const second = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: secondFetch, + }); + + // …but adoption re-verifies the digest, so the payload is re-downloaded + // and published under a NEW generation name (a published exe is never + // replaced — the damaged one is left for the orphan cleanup). + expect(second.status).toBe('staged'); + expect(secondFetch).toHaveBeenCalled(); + expect(second.staged.exeFileName).not.toBe(first.staged.exeFileName); + const repaired = await readFile(stagedExePath(exePath, second.staged)); + expect(repaired.equals(PAYLOAD)).toBe(true); + }); + + it('re-stages when the staged exe went missing', async () => { + const first = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + // The metadata stays but the exe is deleted → not trustworthy, re-stage. + await rm(stagedExePath(exePath, first.staged)); + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + + const second = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + expect(second.status).toBe('staged'); + }); + + it('keeps the previous staged record when the superseding download fails', async () => { + await stageNativeUpdate({ + version: '0.6.0', + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ version: '0.6.0', payload: Buffer.from('old-payload') }), + }); + + // The superseding download fails verification. The old record must + // survive: deleting it before the replacement is ready could remove a + // concurrent worker's freshly published record, and here it would lose + // a still-valid staged update. + await expect( + stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD, checksum: 'f'.repeat(64) }), + }), + ).rejects.toThrow(/sha256 mismatch/); + + expect((await readStagedNativeUpdate(exePath))?.version).toBe('0.6.0'); + }); + + it('throws on a checksum mismatch and cleans up leftovers', async () => { + await expect( + stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD, checksum: 'f'.repeat(64) }), + }), + ).rejects.toThrow(/sha256 mismatch/); + + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + // Both the staged metadata and the .part download are gone. + await expect(stat(getNativeStagedStateFile(exePath))).rejects.toThrow(); + await expect(stat(getNativeStagingDir(exePath))).rejects.toThrow(); + }); + + it('throws when the platform is missing from the manifest', async () => { + await expect( + stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'win32', + arch: 'arm64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }), + ).rejects.toThrow(/win32-arm64 not found/); + }); + + it('rejects a traversal version before deriving any filesystem path', async () => { + const fetchImpl = mockCdnFetch({ payload: PAYLOAD }); + await expect( + stageNativeUpdate({ + version: 'x/../../kimi', + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl, + }), + ).rejects.toThrow(/invalid semver/); + expect(fetchImpl).not.toHaveBeenCalled(); + // Nothing was created anywhere. + await expect(stat(getNativeStagingDir(exePath))).rejects.toThrow(); + }); + + it('supersedes a staged older version', async () => { + const first = await stageNativeUpdate({ + version: '0.6.0', + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ version: '0.6.0', payload: Buffer.from('old-payload') }), + }); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + + expect(result.status).toBe('staged'); + expect(result.staged.version).toBe(VERSION); + // The older stage's exe is left in place (it may be claim-held by a live + // swap); an unreferenced one is reaped by a later orphan cleanup. + await expect( + stat(join(getNativeStagingDir(exePath), first.staged.exeFileName)), + ).resolves.toBeDefined(); + }); + + it('preserves the exe referenced by the current record during orphan cleanup', async () => { + const first = await stageNativeUpdate({ + version: '0.6.0', + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ version: '0.6.0', payload: Buffer.from('old-payload') }), + }); + // Age the staged exe past the orphan grace period: it is still the + // applicable update (staged.json references it until the final atomic + // write replaces the record), so the cleanup must not reap it. + const oldExe = stagedExePath(exePath, first.staged); + const old = new Date(Date.now() - 2 * 60 * 60 * 1000); + await utimes(oldExe, old, old); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + expect(result.status).toBe('staged'); + + // Referenced at cleanup time → survives this run (a later cleanup reaps + // it once the new record has replaced the old one). + await expect(stat(oldExe)).resolves.toBeDefined(); + }); + + it('cleans orphaned staging files before downloading, preserving live swap claims', async () => { + const stagingDir = getNativeStagingDir(exePath); + const { mkdir } = await import('node:fs/promises'); + await mkdir(stagingDir, { recursive: true }); + // Orphans from interrupted earlier runs: a referenced-by-nothing exe and + // a stale .part download (aged past the orphan grace period). + await agedOrphan(join(stagingDir, 'kimi-9.9.9'), Buffer.from('orphan-exe')); + await agedOrphan(join(stagingDir, 'kimi-9.9.9.part'), Buffer.from('partial')); + // A live swap claim referencing its own staged exe must survive. + const claimExe = 'kimi-8.8.8'; + await writeFile(join(stagingDir, claimExe), Buffer.from('swap-in-progress')); + await writeFile( + join(stagingDir, 'staged.json.swap-1234'), + JSON.stringify({ exeFileName: claimExe }), + ); + // A fresh unreferenced exe is too young to be reaped: a concurrent + // worker may be about to publish its metadata. + const youngExe = 'kimi-7.7.7'; + await writeFile(join(stagingDir, youngExe), Buffer.from('just-published')); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + expect(result.status).toBe('staged'); + + await expect(stat(join(stagingDir, 'kimi-9.9.9'))).rejects.toThrow(); + await expect(stat(join(stagingDir, 'kimi-9.9.9.part'))).rejects.toThrow(); + await expect(stat(join(stagingDir, 'staged.json.swap-1234'))).resolves.toBeDefined(); + await expect(stat(join(stagingDir, claimExe))).resolves.toBeDefined(); + await expect(stat(join(stagingDir, youngExe))).resolves.toBeDefined(); + }); + + it('retries short writes until each chunk is fully persisted', async () => { + // The first write to the .part file persists only half its bytes; the + // write loop must make up the remainder or the staged exe is truncated. + fsMocks.shortWriteBudget = 1; + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + expect(result.status).toBe('staged'); + const exeBytes = await readFile(stagedExePath(exePath, result.staged)); + expect(exeBytes.equals(PAYLOAD)).toBe(true); + }); + + it('leaves foreign files in the staging directory alone', async () => { + const stagingDir = getNativeStagingDir(exePath); + const { mkdir } = await import('node:fs/promises'); + await mkdir(join(stagingDir, 'some-other-tool'), { recursive: true }); + await writeFile(join(stagingDir, 'user-notes.txt'), 'not ours', 'utf-8'); + await writeFile(join(stagingDir, 'some-other-tool', 'cache.bin'), 'not ours either'); + // A genuine updater-owned orphan to prove cleanup still works (aged past + // the orphan grace period). + await agedOrphan(join(stagingDir, 'kimi-9.9.9'), Buffer.from('orphan-exe')); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + expect(result.status).toBe('staged'); + + await expect(stat(join(stagingDir, 'kimi-9.9.9'))).rejects.toThrow(); + await expect(stat(join(stagingDir, 'user-notes.txt'))).resolves.toBeDefined(); + await expect(stat(join(stagingDir, 'some-other-tool', 'cache.bin'))).resolves.toBeDefined(); + }); + + it('cleans orphans with prerelease and build-metadata versions', async () => { + const stagingDir = getNativeStagingDir(exePath); + const { mkdir } = await import('node:fs/promises'); + await mkdir(stagingDir, { recursive: true }); + await agedOrphan(join(stagingDir, 'kimi-1.2.3-rc.1'), Buffer.from('orphan')); + await agedOrphan(join(stagingDir, 'kimi-1.2.3+build.5.exe'), Buffer.from('orphan')); + await agedOrphan(join(stagingDir, 'kimi-1.2.3-rc.1.123.0.part'), Buffer.from('partial')); + // New-style published name with the unique per-worker infix. + await agedOrphan(join(stagingDir, 'kimi-4.5.6.1234.1700000000000.0'), Buffer.from('orphan')); + + const result = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + expect(result.status).toBe('staged'); + + await expect(stat(join(stagingDir, 'kimi-1.2.3-rc.1'))).rejects.toThrow(); + await expect(stat(join(stagingDir, 'kimi-1.2.3+build.5.exe'))).rejects.toThrow(); + await expect(stat(join(stagingDir, 'kimi-1.2.3-rc.1.123.0.part'))).rejects.toThrow(); + await expect(stat(join(stagingDir, 'kimi-4.5.6.1234.1700000000000.0'))).rejects.toThrow(); + }); + + it("preserves another worker's staged result when this attempt fails", async () => { + const stagingDir = getNativeStagingDir(exePath); + const exeFileName = `kimi-${VERSION}`; + const otherPayload = Buffer.from('other-worker-payload'); + const fetchImpl = vi.fn(async (input: string | URL) => { + const url = String(input); + if (url === nativeManifestUrl(VERSION)) { + const manifestBody = JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { filename: BINARY_FILENAME, checksum: sha256Hex(PAYLOAD) }, + }, + }); + return { ok: true, status: 200, text: async () => manifestBody, body: null }; + } + if (url === nativeBinaryUrl(VERSION, BINARY_FILENAME)) { + // A concurrent worker publishes its valid stage mid-download… + const { mkdir } = await import('node:fs/promises'); + await mkdir(stagingDir, { recursive: true }); + await writeFile(join(stagingDir, exeFileName), otherPayload); + await writeFile( + getNativeStagedStateFile(exePath), + `${JSON.stringify({ + version: VERSION, + target: 'linux-x64', + exeFileName, + sha256: sha256Hex(otherPayload), + exeSize: otherPayload.length, + stagedAt: new Date().toISOString(), + })}\n`, + ); + // …then this attempt's download fails. + return { ok: false, status: 503, text: async () => '', body: null }; + } + return { ok: false, status: 404, text: async (): Promise => '', body: null }; + }) as unknown as typeof fetch; + + await expect( + stageNativeUpdate({ version: VERSION, exePath, platform: 'linux', arch: 'x64', fetchImpl }), + ).rejects.toThrow(/503/); + + // The concurrent worker's stage survives this attempt's failure cleanup. + const staged = await readStagedNativeUpdate(exePath); + expect(staged?.version).toBe(VERSION); + const bytes = await readFile(join(stagingDir, exeFileName)); + expect(bytes.equals(otherPayload)).toBe(true); + }); + + it('preserves the staged exe a live swap claim references when this attempt fails', async () => { + const stagingDir = getNativeStagingDir(exePath); + const exeFileName = `kimi-${VERSION}`; + const fetchImpl = vi.fn(async (input: string | URL) => { + const url = String(input); + if (url === nativeManifestUrl(VERSION)) { + const manifestBody = JSON.stringify({ + version: VERSION, + platforms: { + 'linux-x64': { filename: BINARY_FILENAME, checksum: sha256Hex(PAYLOAD) }, + }, + }); + return { ok: true, status: 200, text: async () => manifestBody, body: null }; + } + if (url === nativeBinaryUrl(VERSION, BINARY_FILENAME)) { + // A swap claims the stage mid-download: the metadata is renamed + // aside (invisible to the metadata check), the exe still referenced + // by the live claim. + const { mkdir } = await import('node:fs/promises'); + await mkdir(stagingDir, { recursive: true }); + await writeFile(join(stagingDir, exeFileName), PAYLOAD); + await writeFile( + join(stagingDir, 'staged.json.swap-4321'), + JSON.stringify({ exeFileName }), + ); + // …then this attempt's download fails. + return { ok: false, status: 503, text: async () => '', body: null }; + } + return { ok: false, status: 404, text: async (): Promise => '', body: null }; + }) as unknown as typeof fetch; + + await expect( + stageNativeUpdate({ version: VERSION, exePath, platform: 'linux', arch: 'x64', fetchImpl }), + ).rejects.toThrow(/503/); + + // The exe owned by the live swap survives this attempt's failure cleanup. + const bytes = await readFile(join(stagingDir, exeFileName)); + expect(bytes.equals(PAYLOAD)).toBe(true); + }); +}); + +describe('promoteStagedUpdateToManual', () => { + let workDir: string; + let exePath: string; + + beforeEach(async () => { + workDir = await mkdtemp(join(tmpdir(), 'kimi-promote-test-')); + exePath = join(workDir, 'bin', 'kimi'); + }); + + afterEach(async () => { + await rm(workDir, { recursive: true, force: true }); + }); + + it('promotes the adopted record to manual', async () => { + await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + const adopted = await readStagedNativeUpdate(exePath); + if (adopted === null) throw new Error('expected a staged record'); + + await expect(promoteStagedUpdateToManual(exePath, adopted)).resolves.toBe(true); + expect((await readStagedNativeUpdate(exePath))?.manual).toBe(true); + }); + + it('refuses to promote a record the staged metadata no longer matches', async () => { + await stageNativeUpdate({ + version: '0.6.0', + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ version: '0.6.0', payload: Buffer.from('old-payload') }), + }); + const adopted = await readStagedNativeUpdate(exePath); + if (adopted === null) throw new Error('expected a staged record'); + + // A newer stage is published before the explicit upgrade's promote + // lands: the stale record must not overwrite it. + await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + + await expect(promoteStagedUpdateToManual(exePath, adopted)).resolves.toBe(false); + const current = await readStagedNativeUpdate(exePath); + expect(current?.version).toBe(VERSION); + expect(current?.manual).toBeUndefined(); + }); +}); + +describe('readStagedNativeUpdate', () => { + let workDir: string; + let exePath: string; + + beforeEach(async () => { + workDir = await mkdtemp(join(tmpdir(), 'kimi-staged-read-test-')); + exePath = join(workDir, 'bin', 'kimi'); + }); + + afterEach(async () => { + await rm(workDir, { recursive: true, force: true }); + }); + + it('returns null for malformed staged.json content', async () => { + const { mkdir } = await import('node:fs/promises'); + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + await writeFile(getNativeStagedStateFile(exePath), '{not json', 'utf-8'); + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + }); + + it('returns null when exeFileName is not a plain file name', async () => { + const { mkdir } = await import('node:fs/promises'); + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + await writeFile( + getNativeStagedStateFile(exePath), + JSON.stringify({ + version: '0.7.0', + target: 'linux-x64', + exeFileName: '../../evil', + sha256: 'a'.repeat(64), + exeSize: 42, + stagedAt: new Date().toISOString(), + }), + 'utf-8', + ); + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + }); + + it('returns null when the exe size drifted from the metadata', async () => { + const { staged } = await stageNativeUpdate({ + version: VERSION, + exePath, + platform: 'linux', + arch: 'x64', + fetchImpl: mockCdnFetch({ payload: PAYLOAD }), + }); + await writeFile(stagedExePath(exePath, staged), Buffer.alloc(PAYLOAD.length + 1)); + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + }); +}); diff --git a/apps/kimi-code/test/cli/update/native-swap.test.ts b/apps/kimi-code/test/cli/update/native-swap.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec105abc48eac311549990c830cb548e650aeaed --- /dev/null +++ b/apps/kimi-code/test/cli/update/native-swap.test.ts @@ -0,0 +1,833 @@ +import { createHash } from 'node:crypto'; +import { existsSync, writeFileSync } from 'node:fs'; +import { mkdtemp, mkdir, readdir, readFile, rename, rm, stat, utimes, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { readUpdateInstallState } from '#/cli/update/install-state'; +import { readStagedNativeUpdate, stagedExeFileName } from '#/cli/update/native-stage'; +import { + maybeRelaunchWithStagedNativeUpdate, + type NativeSwapDeps, +} from '#/cli/update/native-swap'; +import { KIMI_CODE_UPDATE_REEXEC_ENV } from '#/constant/app'; +import { getNativeStagedStateFile, getNativeStagingDir } from '#/utils/paths'; + +const fsMocks = vi.hoisted(() => ({ + /** When set, renames matching the predicate fail with an injected error. */ + renameBlocker: null as null | ((src: string, dst: string) => boolean), + /** When set, link() throws an error with this code (no hard-link support). */ + linkError: null as string | null, +})); + +vi.mock('node:fs/promises', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + rename: async ( + src: Parameters[0], + dst: Parameters[1], + ) => { + if (fsMocks.renameBlocker?.(String(src), String(dst)) === true) { + throw new Error('injected rename failure'); + } + return actual.rename(src, dst); + }, + link: async ( + src: Parameters[0], + dst: Parameters[1], + ) => { + if (fsMocks.linkError !== null) { + throw Object.assign(new Error('link() is not supported (mocked)'), { + code: fsMocks.linkError, + }); + } + return actual.link(src, dst); + }, + }; +}); + +const CURRENT_VERSION = '0.6.0'; +const STAGED_VERSION = '0.7.0'; +const STAGED_EXE_SIZE = 42; + +interface FakeChildHandlers { + readonly onEvent: (event: 'error' | 'exit' | 'close', cb: (...args: unknown[]) => void) => void; + readonly child: unknown; +} + +function fakeChild(options: { + readonly code?: number | null; + readonly stdout?: string; + readonly error?: Error; + readonly signal?: NodeJS.Signals | null; +}): FakeChildHandlers { + const listeners = new Map void>(); + const stdoutChunks: string[] = []; + const stdoutListeners: Array<(chunk: Buffer) => void> = []; + const child = { + once(event: string, cb: (...args: unknown[]) => void) { + listeners.set(event, cb); + }, + stdout: { + on(_event: 'data', cb: (chunk: Buffer) => void) { + stdoutListeners.push(cb); + }, + }, + kill: vi.fn(), + }; + queueMicrotask(() => { + if (options.error !== undefined) { + listeners.get('error')?.(options.error); + return; + } + if (options.stdout !== undefined) { + for (const cb of stdoutListeners) cb(Buffer.from(options.stdout)); + } + const code = options.code === undefined ? 0 : options.code; + const signal = options.signal ?? null; + // The smoke check listens on 'close', the re-exec waiter on 'exit'. + listeners.get('close')?.(code, signal); + listeners.get('exit')?.(code, signal); + }); + void stdoutChunks; + return { onEvent: () => {}, child }; +} + +interface SpawnCall { + readonly cmd: string; + readonly args: readonly string[]; + readonly options: Record; +} + +function createSpawnMock(routes: { + readonly smokeCode?: number; + readonly smokeStdout?: string; + readonly reexecCode?: number; + readonly reexecError?: Error; + readonly reexecSignal?: NodeJS.Signals; +}): { readonly calls: SpawnCall[]; readonly spawnImpl: NativeSwapDeps['spawnImpl'] } { + const calls: SpawnCall[] = []; + const spawnImpl = ((cmd: string, args: readonly string[], options: Record) => { + calls.push({ cmd, args, options }); + if (args[0] === '--version') { + return fakeChild({ + code: routes.smokeCode ?? 0, + stdout: routes.smokeStdout ?? `${STAGED_VERSION}\n`, + }).child; + } + return fakeChild({ + code: routes.reexecSignal !== undefined ? null : (routes.reexecCode ?? 0), + error: routes.reexecError, + signal: routes.reexecSignal ?? null, + }).child; + }) as unknown as NativeSwapDeps['spawnImpl']; + return { calls, spawnImpl }; +} + +async function seedStagedUpdate( + exePath: string, + version: string, + options?: { readonly manual?: boolean }, +): Promise { + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + const exeBytes = Buffer.alloc(STAGED_EXE_SIZE, 1); + await writeFile(join(stagingDir, stagedExeFileName(version, 'linux')), exeBytes); + await writeFile( + getNativeStagedStateFile(exePath), + `${JSON.stringify({ + version, + target: 'linux-x64', + exeFileName: stagedExeFileName(version, 'linux'), + // The swap re-verifies the staged bytes against this checksum, so the + // seed must record the payload's real sha256. + sha256: createHash('sha256').update(exeBytes).digest('hex'), + exeSize: STAGED_EXE_SIZE, + stagedAt: new Date().toISOString(), + manual: options?.manual === true ? true : undefined, + }, null, 2)}\n`, + 'utf-8', + ); +} + +function makeDeps( + exePath: string, + overrides: Partial & { readonly spawnImpl: NativeSwapDeps['spawnImpl'] }, +): NativeSwapDeps { + return { + exePath, + argv: ['node', exePath, '--flag', 'value'], + env: { PATH: '/usr/bin' }, + currentVersion: CURRENT_VERSION, + isNative: true, + exitImpl: vi.fn(), + ...overrides, + }; +} + +describe('maybeRelaunchWithStagedNativeUpdate', () => { + let workDir: string; + let exePath: string; + let homeDir: string; + + beforeEach(async () => { + workDir = await mkdtemp(join(tmpdir(), 'kimi-swap-test-')); + homeDir = join(workDir, 'home'); + exePath = join(workDir, 'bin', 'kimi'); + await mkdir(join(workDir, 'bin'), { recursive: true }); + await writeFile(exePath, 'old-binary'); + vi.stubEnv('KIMI_CODE_HOME', homeDir); + fsMocks.renameBlocker = null; + fsMocks.linkError = null; + }); + + afterEach(async () => { + vi.unstubAllEnvs(); + await rm(workDir, { recursive: true, force: true }); + }); + + it('does nothing when the re-exec guard env is set', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({}); + const env = { [KIMI_CODE_UPDATE_REEXEC_ENV]: '1' }; + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl, env }), + ); + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // Read-once: the guard is dropped so children of this session do not inherit it. + expect(env[KIMI_CODE_UPDATE_REEXEC_ENV]).toBeUndefined(); + // Staged files untouched for the "real" next launch. + await expect(stat(getNativeStagedStateFile(exePath))).resolves.toBeDefined(); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('does nothing when not running as a native binary', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl, isNative: false }), + ); + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('does nothing when nothing is staged', async () => { + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + }); + + it('discards a staged update that is not newer than the running version', async () => { + await seedStagedUpdate(exePath, CURRENT_VERSION); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + // The metadata is gone, so future launches do not retry the discard; the + // exe is left for the downloader's orphan cleanup (it may belong to a + // freshly republished stage). + await expect(stat(getNativeStagedStateFile(exePath))).rejects.toThrow(); + await expect( + stat(join(getNativeStagingDir(exePath), stagedExeFileName(CURRENT_VERSION, 'linux'))), + ).resolves.toBeDefined(); + }); + + it('discards staged metadata whose exe is missing', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + await rm(join(getNativeStagingDir(exePath), stagedExeFileName(STAGED_VERSION, 'linux'))); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('swaps in the staged exe, re-execs with the original argv and forwards the exit code', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({ reexecCode: 3 }); + const exitImpl = vi.fn(); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl, exitImpl }), + ); + + expect(relaunched).toBe(true); + // Smoke check + re-exec. + expect(calls).toHaveLength(2); + expect(calls[0]?.args).toEqual(['--version']); + expect(calls[1]?.cmd).toBe(exePath); + expect(calls[1]?.args).toEqual(['--flag', 'value']); + expect((calls[1]?.options['env'] as Record)[KIMI_CODE_UPDATE_REEXEC_ENV]).toBe('1'); + expect(calls[1]?.options['stdio']).toBe('inherit'); + expect(exitImpl).toHaveBeenCalledWith(3); + + // The exe was replaced with the staged payload; backup and staging are gone. + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + await expect(stat(`${exePath}.bak`)).rejects.toThrow(); + await expect(stat(getNativeStagedStateFile(exePath))).rejects.toThrow(); + await expect(stat(getNativeStagingDir(exePath))).rejects.toThrow(); + }); + + it('rolls back when the smoke check fails and records an install failure', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({ smokeCode: 1 }); + const exitImpl = vi.fn(); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl, exitImpl }), + ); + + expect(relaunched).toBe(false); + expect(exitImpl).not.toHaveBeenCalled(); + expect(calls).toHaveLength(1); // smoke only, no re-exec + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + await expect(stat(getNativeStagedStateFile(exePath))).rejects.toThrow(); + // The exe is left for the downloader's orphan cleanup (see the + // not-newer discard test). + + const state = await readUpdateInstallState(); + expect(state.lastFailure).toMatchObject({ version: STAGED_VERSION, attempts: 1 }); + }); + + it('rolls back when the smoke output does not contain the staged version', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { spawnImpl } = createSpawnMock({ smokeStdout: '0.0.0-bogus\n' }); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + expect(relaunched).toBe(false); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('rolls back when the smoke output merely contains the staged version as a substring', async () => { + // `0.7.01` contains `0.7.0` but is a different release — a mispublished + // endpoint could serve exactly that with a matching checksum. + await seedStagedUpdate(exePath, STAGED_VERSION); + const { spawnImpl } = createSpawnMock({ smokeStdout: `${STAGED_VERSION}1\n` }); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + expect(relaunched).toBe(false); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('continues startup with the old in-memory code when the re-exec spawn fails', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { spawnImpl } = createSpawnMock({ reexecError: new Error('spawn EACCES') }); + const exitImpl = vi.fn(); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl, exitImpl }), + ); + expect(relaunched).toBe(false); + expect(exitImpl).not.toHaveBeenCalled(); + // The binary on disk is already the new version; the next launch picks it up. + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + }); + + it('forwards a signal-derived nonzero exit code when the re-exec child is killed', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { spawnImpl } = createSpawnMock({ reexecSignal: 'SIGKILL' }); + const exitImpl = vi.fn(); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl, exitImpl }), + ); + expect(relaunched).toBe(true); + // 128 + 9 (SIGKILL), never a success-looking 0. + expect(exitImpl).toHaveBeenCalledWith(137); + }); + + it('restores the staged metadata when the exe cannot be moved aside', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // rename(exe → bak) fails when the in-service exe is gone. + await rm(exePath); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + // The smoke check runs before anything is moved; only the re-exec is absent. + expect(calls).toHaveLength(1); + expect(calls[0]?.args).toEqual(['--version']); + // The staged update is restored, not dropped: a later launch retries the swap. + const restored = await readStagedNativeUpdate(exePath); + expect(restored).toMatchObject({ version: STAGED_VERSION }); + await expect( + stat(join(getNativeStagingDir(exePath), stagedExeFileName(STAGED_VERSION, 'linux'))), + ).resolves.toBeDefined(); + }); + + it('restores the staged metadata without hard-link support', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // The restore publishes create-if-absent; on filesystems without hard + // links it must fall back to an exclusive create, not drop the stage. + fsMocks.linkError = 'ENOTSUP'; + // rename(exe → bak) fails when the in-service exe is gone. + await rm(exePath); + const { spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + const restored = await readStagedNativeUpdate(exePath); + expect(restored).toMatchObject({ version: STAGED_VERSION }); + }); + + it('retains the claim when the restore hits a transient error', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // rename(exe → bak) fails when the in-service exe is gone. + await rm(exePath); + // ENOSPC is not a hard-link-support error: the restore's create-if-absent + // publish fails transiently, and the claim must be RETAINED for a later + // launch's sweep — dropping it would orphan the staged exe with no newer + // stage to show for it. + fsMocks.linkError = 'ENOSPC'; + const { spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + // The state file was not published, and the claim is still there. + expect(await readStagedNativeUpdate(exePath)).toBeNull(); + const names = await readdir(getNativeStagingDir(exePath)); + expect(names.some((name) => name.startsWith('staged.json.swap-'))).toBe(true); + }); + + it('restores an aged orphaned claim and swaps it on that very launch', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // Simulate a claim left by a dead swap: the record renamed aside and aged + // past the claim-stale threshold. + const claimPath = join(getNativeStagingDir(exePath), 'staged.json.swap-99999'); + await rename(getNativeStagedStateFile(exePath), claimPath); + const old = new Date(Date.now() - 10 * 60 * 1000); + await utimes(claimPath, old, old); + + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + // The sweep restored the claim, and this launch swapped the update in. + expect(relaunched).toBe(true); + expect(calls).toHaveLength(2); + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + }); + + it('defers the swap while another instance holds the swap mutex', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // A fresh swap.lock = another instance in its rename critical section. + await writeFile(join(getNativeStagingDir(exePath), 'swap.lock'), 'other-instance'); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // The stage is untouched for a later launch; the exe is untouched. + expect(await readStagedNativeUpdate(exePath)).toMatchObject({ version: STAGED_VERSION }); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('sweeps an aged swap mutex and proceeds with the swap', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const mutexPath = join(getNativeStagingDir(exePath), 'swap.lock'); + await writeFile(mutexPath, 'crash-residue'); + const old = new Date(Date.now() - 10 * 60 * 1000); + await utimes(mutexPath, old, old); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(true); + expect(calls).toHaveLength(2); + // The mutex was released after the swap. + await expect(stat(mutexPath)).rejects.toThrow(); + }); + + it('puts a young unparseable staged record back instead of destroying it', async () => { + // An in-flight exclusive-create publish (filesystems without hard links) + // is observable mid-write; claiming and discarding it would orphan the + // staged exe while the writer still reports success. + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + const stateFile = getNativeStagedStateFile(exePath); + await writeFile(stateFile, '{', 'utf-8'); + const { spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(await readFile(stateFile, 'utf-8')).toBe('{'); + }); + + it('discards an aged unparseable staged record as crash residue', async () => { + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + const stateFile = getNativeStagedStateFile(exePath); + await writeFile(stateFile, '{', 'utf-8'); + const old = new Date(Date.now() - 10 * 60 * 1000); + await utimes(stateFile, old, old); + const { spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + await expect(stat(stateFile)).rejects.toThrow(); + }); + + it('falls back to a pid-named backup when the plain .bak cannot be removed', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // A directory at `${exePath}.bak` cannot be removed via unlink → pid fallback. + await mkdir(`${exePath}.bak`); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(true); + expect(calls).toHaveLength(2); + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + // The pid-named backup was cleaned after the swap; the directory is untouched. + const names = await readdir(join(workDir, 'bin')); + expect(names.toSorted()).toEqual(['kimi', 'kimi.bak']); + expect((await stat(`${exePath}.bak`)).isDirectory()).toBe(true); + }); + + it('sweeps stale backups from earlier swaps on startup', async () => { + await writeFile(`${exePath}.bak`, 'stale-backup'); + await writeFile(`${exePath}.12345.bak`, 'stale-backup'); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + await expect(stat(`${exePath}.bak`)).rejects.toThrow(); + await expect(stat(`${exePath}.12345.bak`)).rejects.toThrow(); + }); + + it('leaves foreign .bak files alone during backup cleanup', async () => { + await writeFile(`${exePath}.bak`, 'stale-backup'); + await writeFile(`${exePath}.config.bak`, 'user-backup'); + await writeFile(`${exePath}.notes.bak`, 'user-backup'); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // Only the updater-owned exact backup is swept. + await expect(stat(`${exePath}.bak`)).rejects.toThrow(); + expect(await readFile(`${exePath}.config.bak`, 'utf-8')).toBe('user-backup'); + expect(await readFile(`${exePath}.notes.bak`, 'utf-8')).toBe('user-backup'); + }); + + it('leaves every artifact alone while another instance holds a fresh swap claim', async () => { + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + const claimPath = join(stagingDir, 'staged.json.swap-4242'); + await writeFile(claimPath, '{}\n', 'utf-8'); + await writeFile(`${exePath}.bak`, 'in-use-backup'); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // A mid-swap instance owns these: nothing is touched. + await expect(stat(claimPath)).resolves.toBeDefined(); + await expect(stat(`${exePath}.bak`)).resolves.toBeDefined(); + }); + + it('does not claim a newly staged update while another instance is mid-swap', async () => { + // Instance A holds a fresh claim; a downloader has since published a new + // staged.json. Claiming it here would start a second concurrent swap. + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + const claimPath = join(stagingDir, 'staged.json.swap-4242'); + await writeFile(claimPath, '{}\n', 'utf-8'); + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // The staged update and the claim stay put; the launch after the + // in-flight swap ends picks the update up. + await expect(stat(getNativeStagedStateFile(exePath))).resolves.toBeDefined(); + await expect(stat(claimPath)).resolves.toBeDefined(); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('cleans up stale swap claims without touching staged exes', async () => { + const stagingDir = getNativeStagingDir(exePath); + await mkdir(stagingDir, { recursive: true }); + const exeFileName = stagedExeFileName(STAGED_VERSION, 'linux'); + const orphanedExe = join(stagingDir, exeFileName); + await writeFile(orphanedExe, Buffer.alloc(STAGED_EXE_SIZE, 1)); + const claimPath = join(stagingDir, 'staged.json.swap-4242'); + await writeFile( + claimPath, + `${JSON.stringify({ + version: STAGED_VERSION, + target: 'linux-x64', + exeFileName, + sha256: 'a'.repeat(64), + exeSize: STAGED_EXE_SIZE, + stagedAt: new Date(Date.now() - 10 * 60 * 1000).toISOString(), + }, null, 2)}\n`, + 'utf-8', + ); + // Crash residue: the claim is older than the stale window. + const past = new Date(Date.now() - 10 * 60 * 1000); + await utimes(claimPath, past, past); + + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + await expect(stat(claimPath)).rejects.toThrow(); + // The exe the claim referenced is left in place: it may belong to a + // freshly republished stage, and the downloader's orphan cleanup reaps + // it if nothing references it. + await expect(stat(orphanedExe)).resolves.toBeDefined(); + }); + + it('keeps recovery artifacts when both the swap-in rename and the rollback fail', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // Every rename INTO the install path fails: the staged exe cannot move + // in, and the backup cannot move back (transient lock, AV, …). + fsMocks.renameBlocker = (_src, dst) => dst === exePath; + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(1); // smoke check only, no re-exec + // The install path stays absent, but both recovery copies survive: the + // `.bak` IS the old exe, and the staged payload plus its claim are not + // discarded. + await expect(stat(exePath)).rejects.toThrow(); + expect(await readFile(`${exePath}.bak`, 'utf-8')).toBe('old-binary'); + const stagingDir = getNativeStagingDir(exePath); + await expect( + stat(join(stagingDir, stagedExeFileName(STAGED_VERSION, 'linux'))), + ).resolves.toBeDefined(); + await expect( + stat(join(stagingDir, `staged.json.swap-${process.pid}`)), + ).resolves.toBeDefined(); + }); + + it('keeps the exe a fresh staged.json references when sweeping a stale claim', async () => { + // A swap crashed after claiming V (stale claim residue), and a downloader + // has since re-staged V: both records reference the same version-derived + // exe name. Sweeping the claim must not delete the freshly staged exe. + await seedStagedUpdate(exePath, STAGED_VERSION); + const stagingDir = getNativeStagingDir(exePath); + const claimPath = join(stagingDir, 'staged.json.swap-4242'); + await writeFile( + claimPath, + `${JSON.stringify({ + version: STAGED_VERSION, + target: 'linux-x64', + exeFileName: stagedExeFileName(STAGED_VERSION, 'linux'), + sha256: 'a'.repeat(64), + exeSize: STAGED_EXE_SIZE, + stagedAt: new Date(Date.now() - 10 * 60 * 1000).toISOString(), + })}\n`, + 'utf-8', + ); + const past = new Date(Date.now() - 10 * 60 * 1000); + await utimes(claimPath, past, past); + + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + // The stale claim is swept, the fresh stage survives and is swapped in. + await expect(stat(claimPath)).rejects.toThrow(); + expect(relaunched).toBe(true); + expect(calls).toHaveLength(2); // smoke check + re-exec + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + }); + + it('discards a staged update whose exe fails the recorded checksum', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // Same size, different bytes — post-download on-disk damage. + const stagingDir = getNativeStagingDir(exePath); + const stagedExe = join(stagingDir, stagedExeFileName(STAGED_VERSION, 'linux')); + await writeFile(stagedExe, Buffer.alloc(STAGED_EXE_SIZE, 2)); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // The corrupt stage's metadata is discarded so a later cycle re-stages + // it; the exe is left for the downloader's orphan cleanup, and the + // running exe is never touched. + await expect(stat(getNativeStagedStateFile(exePath))).rejects.toThrow(); + await expect(stat(stagedExe)).resolves.toBeDefined(); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('leaves a staged update in place when automatic updates are disabled by env', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { + spawnImpl, + env: { PATH: '/usr/bin', KIMI_CODE_NO_AUTO_UPDATE: '1' }, + }), + ); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + // The payload stays staged for a later launch without the opt-out; the + // running exe is untouched. + await expect(stat(getNativeStagedStateFile(exePath))).resolves.toBeDefined(); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('applies a manually staged update even when automatic updates are disabled by env', async () => { + // The opt-out targets automatic updates; an explicit `kimi upgrade` + // stages with manual: true and must still apply. + await seedStagedUpdate(exePath, STAGED_VERSION, { manual: true }); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { + spawnImpl, + env: { PATH: '/usr/bin', KIMI_CODE_NO_AUTO_UPDATE: '1' }, + }), + ); + + expect(relaunched).toBe(true); + expect(calls).toHaveLength(2); // smoke check + re-exec + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + }); + + it('leaves an automatic stage in place when auto_install is disabled in the tui config', async () => { + await mkdir(homeDir, { recursive: true }); + await writeFile(join(homeDir, 'tui.toml'), '[upgrade]\nauto_install = false\n', 'utf-8'); + await seedStagedUpdate(exePath, STAGED_VERSION); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + expect(calls).toHaveLength(0); + await expect(stat(getNativeStagedStateFile(exePath))).resolves.toBeDefined(); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('applies a manual stage even when auto_install is disabled in the tui config', async () => { + await mkdir(homeDir, { recursive: true }); + await writeFile(join(homeDir, 'tui.toml'), '[upgrade]\nauto_install = false\n', 'utf-8'); + await seedStagedUpdate(exePath, STAGED_VERSION, { manual: true }); + const { calls, spawnImpl } = createSpawnMock({}); + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(true); + expect(calls).toHaveLength(2); // smoke check + re-exec + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + }); + + it('does not overwrite a concurrently published stage when restoring the claim', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // The exe move (step 2) fails. + fsMocks.renameBlocker = (src) => src === exePath; + const v2 = '0.8.0'; + const spawnImpl = ((cmd: string, args: readonly string[]) => { + if (args[0] === '--version') { + // Mid-smoke: a downloader publishes a NEWER stage (the state-file + // path is free — we claimed the older one). + const stagingDir = getNativeStagingDir(exePath); + const v2Exe = stagedExeFileName(v2, 'linux'); + writeFileSync(join(stagingDir, v2Exe), 'newer-binary'); + writeFileSync( + getNativeStagedStateFile(exePath), + `${JSON.stringify({ + version: v2, + target: 'linux-x64', + exeFileName: v2Exe, + sha256: 'b'.repeat(64), + exeSize: Buffer.byteLength('newer-binary'), + stagedAt: new Date().toISOString(), + })}\n`, + ); + return fakeChild({ code: 0, stdout: `${STAGED_VERSION}\n` }).child; + } + return fakeChild({ code: 0 }).child; + }) as unknown as NativeSwapDeps['spawnImpl']; + const relaunched = await maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl })); + + expect(relaunched).toBe(false); + // The newer stage survived; the older claim's metadata was discarded + // instead of clobbering it (its exe is left for the downloader's orphan + // cleanup), and the running exe never moved. + const staged = await readStagedNativeUpdate(exePath); + expect(staged?.version).toBe(v2); + await expect( + stat(join(getNativeStagingDir(exePath), stagedExeFileName(STAGED_VERSION, 'linux'))), + ).resolves.toBeDefined(); + expect(await readFile(exePath, 'utf-8')).toBe('old-binary'); + }); + + it('stamps the claim with a fresh mtime so a concurrent launch does not misread it as stale', async () => { + await seedStagedUpdate(exePath, STAGED_VERSION); + // The metadata may have been staged long before this launch (background + // download finished hours ago); rename alone would keep that old mtime. + const longAgo = new Date(Date.now() - 10 * 60 * 1000); + await utimes(getNativeStagedStateFile(exePath), longAgo, longAgo); + + // Instance A: park inside the smoke check, holding the claim mid-swap. + let releaseSmoke!: () => void; + const smokeGate = new Promise((resolve) => { + releaseSmoke = resolve; + }); + const spawnImplA = ((cmd: string, args: readonly string[]) => { + if (args[0] !== '--version') return fakeChild({ code: 0 }).child; // re-exec + const listeners = new Map void>(); + const stdoutListeners: Array<(chunk: Buffer) => void> = []; + const child = { + once(event: string, cb: (...args: unknown[]) => void) { + listeners.set(event, cb); + }, + stdout: { + on(_event: 'data', cb: (chunk: Buffer) => void) { + stdoutListeners.push(cb); + }, + }, + kill: vi.fn(), + }; + const emitSmokeSuccess = (): void => { + for (const cb of stdoutListeners) cb(Buffer.from(`${STAGED_VERSION}\n`)); + listeners.get('close')?.(0, null); + listeners.get('exit')?.(0, null); + }; + queueMicrotask(() => { + void smokeGate.then(emitSmokeSuccess); + }); + return child; + }) as unknown as NativeSwapDeps['spawnImpl']; + const promiseA = maybeRelaunchWithStagedNativeUpdate(makeDeps(exePath, { spawnImpl: spawnImplA })); + + // Wait until A holds the claim. + const stagingDir = getNativeStagingDir(exePath); + const claimPath = join(stagingDir, `staged.json.swap-${process.pid}`); + await vi.waitFor(() => { + expect(existsSync(claimPath)).toBe(true); + }); + // The claim carries the claim time, not the staged file's old mtime. + expect((await stat(claimPath)).mtimeMs).toBeGreaterThan(Date.now() - 60_000); + + // Instance B: its sweep must treat A's claim as live and touch nothing. + const { calls: callsB, spawnImpl: spawnImplB } = createSpawnMock({}); + const relaunchedB = await maybeRelaunchWithStagedNativeUpdate( + makeDeps(exePath, { spawnImpl: spawnImplB }), + ); + expect(relaunchedB).toBe(false); + expect(callsB).toHaveLength(0); + await expect(stat(claimPath)).resolves.toBeDefined(); + await expect( + stat(join(stagingDir, stagedExeFileName(STAGED_VERSION, 'linux'))), + ).resolves.toBeDefined(); + + // A finishes the swap unharmed. + releaseSmoke(); + await expect(promiseA).resolves.toBe(true); + const newExe = await readFile(exePath); + expect(newExe.equals(Buffer.alloc(STAGED_EXE_SIZE, 1))).toBe(true); + }); +}); diff --git a/apps/kimi-code/test/cli/update/preflight.test.ts b/apps/kimi-code/test/cli/update/preflight.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..fcc57ad6b4a0c6b9166556e95920cc1e84f03db7 --- /dev/null +++ b/apps/kimi-code/test/cli/update/preflight.test.ts @@ -0,0 +1,1278 @@ +import type * as ChildProcess from 'node:child_process'; +import { EventEmitter } from 'node:events'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { readUpdateCache } from '#/cli/update/cache'; +import { + emptyUpdateInstallState, + readUpdateInstallState, + writeUpdateInstallState, +} from '#/cli/update/install-state'; +import { installCommandFor, runUpdatePreflight } from '#/cli/update/preflight'; +import { promptForInstallChoice } from '#/cli/update/prompt'; +import type * as PromptModule from '#/cli/update/prompt'; +import { refreshUpdateCache } from '#/cli/update/refresh'; +import type * as RefreshModule from '#/cli/update/refresh'; +import type * as RolloutModule from '#/cli/update/rollout'; +import { detectInstallSource } from '#/cli/update/source'; +import { + emptyUpdateCache, + type UpdateCache, + type UpdateInstallState, + type UpdateManifest, +} from '#/cli/update/types'; +import type { TuiConfig } from '#/tui/config'; +import { refreshKimiRegion } from '#/utils/region'; + +const mocks = vi.hoisted(() => ({ + readUpdateCache: vi.fn(), + readUpdateInstallState: vi.fn(), + writeUpdateInstallState: vi.fn(), + tryAcquireUpdateInstallLock: vi.fn(), + loadTuiConfig: vi.fn(), + detectInstallSource: vi.fn(), + promptForInstallChoice: vi.fn(), + refreshUpdateCache: vi.fn(), + resolveUpdateDeviceId: vi.fn(), + appendRolloutDecisionLog: vi.fn(), + spawn: vi.fn(), + // Identity by default: resolution is covered by resolve-command.test.ts; + // here we only care which command string reaches spawn(). + resolveCommandPath: vi.fn((cmd: string) => cmd as string | undefined), +})); + +vi.mock('#/utils/process/resolve-command', () => ({ + resolveCommandPath: mocks.resolveCommandPath, +})); + +vi.mock('../../../src/cli/update/cache', () => ({ + readUpdateCache: mocks.readUpdateCache, +})); + +vi.mock('../../../src/cli/update/install-lock', () => ({ + tryAcquireUpdateInstallLock: mocks.tryAcquireUpdateInstallLock, +})); + +vi.mock('../../../src/cli/update/install-state', () => ({ + emptyUpdateInstallState: () => ({ + active: null, + lastFailure: null, + lastSuccess: null, + }), + readUpdateInstallState: mocks.readUpdateInstallState, + writeUpdateInstallState: mocks.writeUpdateInstallState, +})); + +vi.mock('../../../src/tui/config', () => ({ + loadTuiConfig: mocks.loadTuiConfig, + TuiConfigParseError: class TuiConfigParseError extends Error { + readonly fallback: TuiConfig; + + constructor(fallback: TuiConfig) { + super('Invalid client preferences in ~/.kimi-code/tui.toml; using defaults.'); + this.fallback = fallback; + } + }, +})); + +vi.mock('../../../src/cli/update/source', () => ({ + detectInstallSource: mocks.detectInstallSource, +})); + +vi.mock('../../../src/cli/update/prompt', async () => { + const actual = await vi.importActual('../../../src/cli/update/prompt.js'); + return { + ...actual, + promptForInstallChoice: mocks.promptForInstallChoice, + }; +}); + +vi.mock('../../../src/cli/update/refresh', async () => { + const actual = await vi.importActual('../../../src/cli/update/refresh.js'); + return { + ...actual, + refreshUpdateCache: mocks.refreshUpdateCache, + }; +}); + +vi.mock('../../../src/cli/update/rollout', async () => { + const actual = await vi.importActual('../../../src/cli/update/rollout.js'); + return { + ...actual, + resolveUpdateDeviceId: mocks.resolveUpdateDeviceId, + // Stubbed so preflight tests never write a real rollout.log. + appendRolloutDecisionLog: mocks.appendRolloutDecisionLog, + }; +}); + +vi.mock('node:child_process', async () => { + const actual = await vi.importActual('node:child_process'); + return { + ...actual, + spawn: mocks.spawn, + }; +}); + +function cacheWith(version: string): UpdateCache { + return { + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: version, + manifest: null, + }; +} + +function manifestFor(version: string, overrides: Partial = {}): UpdateManifest { + return { + version, + publishedAt: '2020-01-01T00:00:00.000Z', + rollout: [], + ...overrides, + }; +} + +function cacheWithManifest(manifest: UpdateManifest): UpdateCache { + return { + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: manifest.version, + manifest, + }; +} + +/** Every bucket delayed by 24h and the clock just started: nobody is eligible. */ +function heldForEveryone(version: string): UpdateManifest { + return manifestFor(version, { + publishedAt: new Date(Date.now() - 1_000).toISOString(), + rollout: [{ percent: 100, delaySeconds: 86_400 }], + }); +} + +/** Every bucket immediate and publishedAt long past: everybody is eligible. */ +function releasedForEveryone(version: string): UpdateManifest { + return manifestFor(version, { + rollout: [{ percent: 100, delaySeconds: 0 }], + }); +} + +function installState(overrides: Partial = {}): UpdateInstallState { + return { + active: null, + lastFailure: null, + lastSuccess: null, + ...overrides, + }; +} + +function tuiConfig(overrides: Partial = {}): TuiConfig { + return { + theme: 'auto', + disablePasteBurst: false, + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + ...overrides, + }; +} + +function disableAutoInstall(): void { + mocks.loadTuiConfig.mockResolvedValue(tuiConfig({ upgrade: { autoInstall: false } })); +} + +function captureOutput(): { + stdout: string[]; + stderr: string[]; + options: { + stdout: { write(chunk: string): boolean }; + stderr: { write(chunk: string): boolean }; + isTTY: boolean; + }; +} { + const stdout: string[] = []; + const stderr: string[] = []; + return { + stdout, + stderr, + options: { + stdout: { write: (chunk: string) => { stdout.push(chunk); return true; } }, + stderr: { write: (chunk: string) => { stderr.push(chunk); return true; } }, + isTTY: true, + }, + }; +} + +type TestLogFn = ReturnType void>>; + +function captureLogger(): { + info: TestLogFn; + warn: TestLogFn; + error: TestLogFn; + debug: TestLogFn; +} { + return { + info: vi.fn<(message: string, payload?: unknown) => void>(), + warn: vi.fn<(message: string, payload?: unknown) => void>(), + error: vi.fn<(message: string, payload?: unknown) => void>(), + debug: vi.fn<(message: string, payload?: unknown) => void>(), + }; +} + +function mockSpawnExit(code: number, signal: NodeJS.Signals | null = null): void { + mocks.spawn.mockImplementation(() => { + const child = Object.assign(new EventEmitter(), { unref: vi.fn() }); + queueMicrotask(() => { child.emit('exit', code, signal); }); + return child; + }); +} + +async function flushBackgroundInstall(): Promise { + await new Promise((resolve) => { + setImmediate(resolve); + }); +} + +describe('runUpdatePreflight', () => { + beforeEach(() => { + // Pin the experimental flag off so rollout gating is deterministic + // regardless of the host environment (the flag bypasses batch holds). + // Tests that exercise the bypass opt back in with `vi.stubEnv(..., '1')`. + vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', ''); + // Pin the region to cn so address assertions don't follow the dev + // machine's own login/marker state; global tests override below. + vi.stubEnv('KIMI_CODE_OAUTH_HOST', 'https://auth.kimi.com'); + refreshKimiRegion(); + mocks.readUpdateInstallState.mockResolvedValue(emptyUpdateInstallState()); + mocks.writeUpdateInstallState.mockResolvedValue(undefined); + mocks.loadTuiConfig.mockResolvedValue(tuiConfig()); + mocks.resolveUpdateDeviceId.mockReturnValue('test-device'); + mocks.appendRolloutDecisionLog.mockResolvedValue(undefined); + mocks.tryAcquireUpdateInstallLock.mockResolvedValue({ + filePath: '/tmp/kimi-update-install.lock', + release: vi.fn().mockResolvedValue(undefined), + }); + mocks.resolveCommandPath.mockImplementation((cmd: string) => cmd); + }); + + afterEach(() => { vi.clearAllMocks(); vi.unstubAllEnvs(); refreshKimiRegion(); }); + + it('skips all update work when KIMI_CODE_NO_AUTO_UPDATE is set', async () => { + vi.stubEnv('KIMI_CODE_NO_AUTO_UPDATE', '1'); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(readUpdateCache).not.toHaveBeenCalled(); + expect(refreshUpdateCache).not.toHaveBeenCalled(); + expect(detectInstallSource).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('also honors the legacy KIMI_CLI_NO_AUTO_UPDATE alias', async () => { + vi.stubEnv('KIMI_CLI_NO_AUTO_UPDATE', 'true'); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(readUpdateCache).not.toHaveBeenCalled(); + expect(detectInstallSource).not.toHaveBeenCalled(); + }); + + it('starts an automatic update from the first fresh check when the cache is empty', async () => { + mocks.readUpdateCache.mockResolvedValue(emptyUpdateCache()); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(readUpdateCache).toHaveBeenCalledTimes(1); + expect(refreshUpdateCache).toHaveBeenCalledTimes(1); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(detectInstallSource).toHaveBeenCalledTimes(1); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { detached: true, stdio: 'ignore' }, + ); + }); + + it('does not start a fresh-check background install when automatic updates are disabled', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(emptyUpdateCache()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(refreshUpdateCache).toHaveBeenCalledTimes(1); + expect(detectInstallSource).toHaveBeenCalledTimes(1); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('skips when non-interactive', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + const { options } = captureOutput(); + await expect( + runUpdatePreflight('0.4.0', { ...options, isTTY: false }), + ).resolves.toBe('continue'); + expect(detectInstallSource).not.toHaveBeenCalled(); + }); + + it('does not start a fresh-check background install when non-interactive', async () => { + mocks.readUpdateCache.mockResolvedValue(emptyUpdateCache()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + const { options } = captureOutput(); + + await expect( + runUpdatePreflight('0.4.0', { ...options, isTTY: false }), + ).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(refreshUpdateCache).toHaveBeenCalledTimes(1); + expect(detectInstallSource).not.toHaveBeenCalled(); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('npm-global: prompts and spawns npm install -g when automatic updates are disabled', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const { stdout, options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('exit'); + expect(mocks.promptForInstallChoice).toHaveBeenCalledWith( + expect.objectContaining({ + installCommand: 'npm install -g @moonshot-ai/kimi-code@0.5.0', + installSource: 'npm-global', + }), + ); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { stdio: 'inherit' }, + ); + expect(stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.5.0'); + }); + + it('refreshes a stale cached target before showing the foreground install prompt', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.6.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.7.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const { stdout, options } = captureOutput(); + + await expect(runUpdatePreflight('0.5.0', options)).resolves.toBe('exit'); + + expect(refreshUpdateCache).toHaveBeenCalledTimes(1); + expect(mocks.promptForInstallChoice).toHaveBeenCalledWith( + expect.objectContaining({ + target: { version: '0.7.0' }, + installCommand: 'npm install -g @moonshot-ai/kimi-code@0.7.0', + }), + ); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.7.0'], + { stdio: 'inherit' }, + ); + expect(stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.7.0'); + }); + + it('falls back to the cached foreground prompt target when the refresh hangs', async () => { + vi.useFakeTimers(); + try { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.6.0')); + mocks.refreshUpdateCache.mockReturnValue(new Promise(() => {})); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + + const result = runUpdatePreflight('0.5.0', options); + await vi.advanceTimersByTimeAsync(1_000); + + await expect(result).resolves.toBe('continue'); + expect(mocks.promptForInstallChoice).toHaveBeenCalledWith( + expect.objectContaining({ + target: { version: '0.6.0' }, + installCommand: 'npm install -g @moonshot-ai/kimi-code@0.6.0', + }), + ); + } finally { + vi.useRealTimers(); + } + }); + + it('pnpm-global: spawns pnpm add -g', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('pnpm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const { options } = captureOutput(); + await runUpdatePreflight('0.4.0', options); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^pnpm(\.cmd)?$/), + ['add', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { stdio: 'inherit' }, + ); + }); + + it('pnpm-global on win32: spawns pnpm.cmd through a shell', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('pnpm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { value: 'win32' }); + try { + const { options } = captureOutput(); + await runUpdatePreflight('0.4.0', options); + expect(mocks.spawn).toHaveBeenCalledWith( + // Resolved to an absolute path and quoted for the cmd.exe shell. + '"pnpm.cmd"', + ['add', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { stdio: 'inherit', shell: true }, + ); + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + } + }); + + it('yarn-global: spawns yarn global add', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('yarn-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const { options } = captureOutput(); + await runUpdatePreflight('0.4.0', options); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^yarn(\.cmd)?$/), + ['global', 'add', '@moonshot-ai/kimi-code@0.5.0'], + { stdio: 'inherit' }, + ); + }); + + it('bun-global: spawns bun add -g', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('bun-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const { options } = captureOutput(); + await runUpdatePreflight('0.4.0', options); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^bun(\.exe)?$/), + ['add', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { stdio: 'inherit' }, + ); + }); + + it('homebrew: prints manual brew upgrade command, does not spawn', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('homebrew'); + const { stdout, options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(stdout.join('')).toContain('brew upgrade kimi-code'); + expect(stdout.join('')).toContain('Third-party sources may lag behind the official release.'); + expect(stdout.join('')).toContain('https://www.kimi.com/code'); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('native: self-spawns the staged downloader sub-command', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('native'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { value: 'darwin' }); + try { + const { stdout, options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('exit'); + expect(mocks.spawn).toHaveBeenCalledWith( + process.execPath, + ['__update_download', '0.5.0', '--manual'], + expect.objectContaining({ stdio: 'inherit' }), + ); + expect(stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.5.0'); + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + } + }); + + it('native on win32: auto-installs via the staged downloader sub-command', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('native'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(0); + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { value: 'win32' }); + try { + const { stdout, options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('exit'); + expect(mocks.spawn).toHaveBeenCalledWith( + process.execPath, + ['__update_download', '0.5.0', '--manual'], + expect.objectContaining({ stdio: 'inherit' }), + ); + expect(stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.5.0'); + expect(stdout.join('')).not.toContain('Auto-update is not supported'); + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + } + }); + + it('global region: derives install commands and site links from the .ai profile', async () => { + vi.stubEnv('KIMI_CODE_OAUTH_HOST', 'https://auth.kimi.ai'); + refreshKimiRegion(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { value: 'win32' }); + try { + // Native updates self-spawn the staged downloader silently, so the + // region surface there is the manual install command text. + expect(installCommandFor('native', '0.5.0', 'win32')).toBe( + 'irm https://code.kimi.ai/kimi-code/install.ps1 | iex', + ); + + mocks.detectInstallSource.mockResolvedValue('homebrew'); + const brew = captureOutput(); + await expect(runUpdatePreflight('0.4.0', brew.options)).resolves.toBe('continue'); + expect(brew.stdout.join('')).toContain('https://www.kimi.ai/code'); + expect(mocks.spawn).not.toHaveBeenCalled(); + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + refreshKimiRegion(); + } + }); + + it('unsupported: prints fallback npm command', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('unsupported'); + const { stdout, options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(stdout.join('')).toContain('npm install -g @moonshot-ai/kimi-code@0.5.0'); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('declined install continues without spawn', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('warns and continues when spawn exits non-zero, without claiming success', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mockSpawnExit(1); + const { stdout, stderr, options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(stderr.join('')).toContain('warning: failed to install'); + // A failed install must never print the "Updated …" success line. + expect(stdout.join('')).not.toContain('Updated @moonshot-ai/kimi-code'); + }); + + it('spawns the resolved absolute path instead of the bare command name', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + mocks.resolveCommandPath.mockReturnValue('/usr/local/bin/npm'); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('exit'); + + expect(mocks.resolveCommandPath).toHaveBeenCalledWith('npm'); + expect(mocks.spawn).toHaveBeenCalledWith( + '/usr/local/bin/npm', + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { stdio: 'inherit' }, + ); + }); + + it('warns and continues without spawning when the package manager cannot be resolved', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('install'); + // Only resolvable inside the cwd (or missing entirely): refuse to run it. + mocks.resolveCommandPath.mockReturnValue(undefined); + const { stdout, stderr, options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(mocks.spawn).not.toHaveBeenCalled(); + expect(stderr.join('')).toContain('warning: failed to install'); + expect(stdout.join('')).not.toContain('Updated @moonshot-ai/kimi-code'); + }); + + it('records a background install failure without spawning when the package manager cannot be resolved', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.resolveCommandPath.mockReturnValue(undefined); + const { stderr, options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(mocks.spawn).not.toHaveBeenCalled(); + expect(stderr.join('')).toBe(''); + expect(writeUpdateInstallState).toHaveBeenLastCalledWith(expect.objectContaining({ + active: null, + lastFailure: expect.objectContaining({ + version: '0.5.0', + attempts: 1, + }), + lastSuccess: null, + })); + }); + + it('starts an automatic update in the background by default', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { detached: true, stdio: 'ignore' }, + ); + expect(writeUpdateInstallState).toHaveBeenCalledWith(expect.objectContaining({ + active: expect.objectContaining({ + version: '0.5.0', + source: 'npm-global', + startedAt: expect.any(String), + }), + lastFailure: null, + })); + + await flushBackgroundInstall(); + + expect(writeUpdateInstallState).toHaveBeenLastCalledWith(expect.objectContaining({ + active: null, + lastFailure: null, + lastSuccess: expect.objectContaining({ + version: '0.5.0', + installedAt: expect.any(String), + notifiedAt: null, + }), + })); + }); + + it('win32 background auto-update hides the console window', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { value: 'win32' }); + try { + const { options } = captureOutput(); + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(mocks.spawn).toHaveBeenCalledWith( + // Resolved to an absolute path and quoted for the cmd.exe shell. + '"npm.cmd"', + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { detached: true, stdio: 'ignore', shell: true, windowsHide: true }, + ); + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + } + }); + + it('native: retries the background install when an old active record has no live lock', async () => { + // Orphaned `active`: older than the spawn grace window and the lock is + // free (beforeEach default) ⇒ the previous downloader is gone; retry. + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + active: { + version: '0.5.0', + source: 'native', + startedAt: new Date(Date.now() - 120_000).toISOString(), + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('native'); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(mocks.spawn).toHaveBeenCalledWith( + process.execPath, + ['__update_download', '0.5.0'], + expect.objectContaining({ detached: true, stdio: 'ignore' }), + ); + }); + + it('native: does not re-spawn while the install lock is genuinely held', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + active: { + version: '0.5.0', + source: 'native', + startedAt: new Date(Date.now() - 120_000).toISOString(), + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('native'); + // Lock probe fails ⇒ a downloader is actually in flight; trust it. + mocks.tryAcquireUpdateInstallLock.mockResolvedValue(null); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('native: trusts a fresh active record within the spawn grace window', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + active: { + version: '0.5.0', + source: 'native', + startedAt: new Date().toISOString(), + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('native'); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + expect(mocks.spawn).not.toHaveBeenCalled(); + // Inside the grace window the lock is never probed — the freshly spawned + // worker may simply not have reached its self-acquire yet. + expect(mocks.tryAcquireUpdateInstallLock).not.toHaveBeenCalled(); + }); + + it('tracks and logs successful background update installs', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const { options } = captureOutput(); + const track = vi.fn(); + const logger = captureLogger(); + + await expect(runUpdatePreflight('0.4.0', { ...options, track, logger })).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(track).toHaveBeenCalledWith('update_background_install_started', expect.objectContaining({ + current_version: '0.4.0', + target_version: '0.5.0', + source: 'npm-global', + })); + expect(track).toHaveBeenCalledWith('update_background_install_succeeded', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + })); + expect(logger.info).toHaveBeenCalledWith('background update install started', expect.objectContaining({ + currentVersion: '0.4.0', + targetVersion: '0.5.0', + source: 'npm-global', + })); + expect(logger.info).toHaveBeenCalledWith('background update install succeeded', expect.objectContaining({ + targetVersion: '0.5.0', + source: 'npm-global', + })); + }); + + it('defaults to automatic background updates when client preferences cannot be loaded', async () => { + mocks.loadTuiConfig.mockRejectedValue(new Error('broken tui.toml')); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { detached: true, stdio: 'ignore' }, + ); + }); + + it('starts only one background update when two sessions preflight concurrently', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + let acquired = false; + mocks.tryAcquireUpdateInstallLock.mockImplementation(async () => { + if (acquired) return null; + acquired = true; + return { + filePath: '/tmp/kimi-update-install.lock', + release: vi.fn().mockResolvedValue(undefined), + }; + }); + mockSpawnExit(0); + const first = captureOutput(); + const second = captureOutput(); + + await expect(Promise.all([ + runUpdatePreflight('0.4.0', first.options), + runUpdatePreflight('0.4.0', second.options), + ])).resolves.toEqual(['continue', 'continue']); + + expect(mocks.spawn).toHaveBeenCalledTimes(1); + }); + + it('records the first background failure silently so the next launch can retry', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(1); + const { stderr, options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(stderr.join('')).toBe(''); + expect(writeUpdateInstallState).toHaveBeenLastCalledWith(expect.objectContaining({ + active: null, + lastFailure: expect.objectContaining({ + version: '0.5.0', + attempts: 1, + failedAt: expect.any(String), + }), + lastSuccess: null, + })); + }); + + it('tracks and logs background update install failures without writing stderr', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(1); + const { stderr, options } = captureOutput(); + const track = vi.fn(); + const logger = captureLogger(); + + await expect(runUpdatePreflight('0.4.0', { ...options, track, logger })).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(stderr.join('')).toBe(''); + expect(track).toHaveBeenCalledWith('update_background_install_failed', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + attempts: 1, + })); + expect(logger.warn).toHaveBeenCalledWith('background update install failed', expect.objectContaining({ + targetVersion: '0.5.0', + source: 'npm-global', + attempts: 1, + })); + }); + + it('retries automatic update once after the first background failure', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + lastFailure: { + version: '0.5.0', + failedAt: '2026-04-23T08:00:00.000Z', + attempts: 1, + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(1); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).toHaveBeenCalledTimes(1); + expect(writeUpdateInstallState).toHaveBeenLastCalledWith(expect.objectContaining({ + lastFailure: expect.objectContaining({ + version: '0.5.0', + attempts: 2, + }), + })); + }); + + it('prompts for manual foreground install after two background failures', async () => { + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + lastFailure: { + version: '0.5.0', + failedAt: '2026-04-23T08:00:00.000Z', + attempts: 2, + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(promptForInstallChoice).toHaveBeenCalledWith(expect.objectContaining({ + target: { version: '0.5.0' }, + installSource: 'npm-global', + })); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('shows a one-shot notice after a background update succeeds and the new version starts', async () => { + mocks.readUpdateCache.mockResolvedValue(emptyUpdateCache()); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + lastSuccess: { + version: '0.5.0', + installedAt: '2026-04-23T08:00:00.000Z', + notifiedAt: null, + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(emptyUpdateCache()); + const { stdout, options } = captureOutput(); + const track = vi.fn(); + const logger = captureLogger(); + + await expect(runUpdatePreflight('0.5.0', { ...options, track, logger })).resolves.toBe('continue'); + + const rendered = stdout.join(''); + expect(rendered).toContain('Kimi Code updated to v0.5.0'); + expect(rendered).toContain( + 'https://moonshotai.github.io/kimi-code/en/release-notes/changelog.html', + ); + expect(track).toHaveBeenCalledWith('update_success_notice_shown', expect.objectContaining({ + version: '0.5.0', + inferred_from_active: false, + })); + expect(logger.info).toHaveBeenCalledWith('background update success notice shown', expect.objectContaining({ + version: '0.5.0', + inferredFromActive: false, + })); + expect(writeUpdateInstallState).toHaveBeenCalledWith(expect.objectContaining({ + lastSuccess: expect.objectContaining({ + version: '0.5.0', + notifiedAt: expect.any(String), + }), + })); + expect(detectInstallSource).not.toHaveBeenCalled(); + }); + + it('infers a background update success notice when the active install version is now running', async () => { + mocks.readUpdateCache.mockResolvedValue(emptyUpdateCache()); + mocks.readUpdateInstallState.mockResolvedValue(installState({ + active: { + version: '0.5.0', + source: 'npm-global', + startedAt: '2026-04-23T08:00:00.000Z', + }, + })); + mocks.refreshUpdateCache.mockResolvedValue(emptyUpdateCache()); + const { stdout, options } = captureOutput(); + + await expect(runUpdatePreflight('0.5.0', options)).resolves.toBe('continue'); + + expect(stdout.join('')).toContain('Kimi Code updated to v0.5.0'); + expect(writeUpdateInstallState).toHaveBeenCalledWith(expect.objectContaining({ + active: null, + lastFailure: null, + lastSuccess: expect.objectContaining({ + version: '0.5.0', + notifiedAt: expect.any(String), + }), + })); + }); + + it('tracks update_prompted telemetry', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.refreshUpdateCache.mockResolvedValue(cacheWith('0.5.0')); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + const track = vi.fn(); + await runUpdatePreflight('0.4.0', { ...options, track }); + expect(track).toHaveBeenCalledWith('update_prompted', expect.objectContaining({ + current_version: '0.4.0', + target_version: '0.5.0', + decision: 'prompt-install', + source: 'npm-global', + })); + }); + + describe('rollout gating', () => { + it('hides a cached update whose batch is not yet eligible', async () => { + const held = cacheWithManifest(heldForEveryone('0.5.0')); + mocks.readUpdateCache.mockResolvedValue(held); + mocks.refreshUpdateCache.mockResolvedValue(held); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + const { stdout, options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(stdout.join('')).toBe(''); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(detectInstallSource).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + // The launch still refreshes the cache in the background so the device + // flips to eligible purely by time passing. + expect(refreshUpdateCache).toHaveBeenCalledTimes(1); + // Both checks of this launch are recorded in the rollout log. + expect(mocks.appendRolloutDecisionLog).toHaveBeenCalledWith(expect.objectContaining({ + phase: 'startup-cache', + reason: 'held', + current: '0.4.0', + latest: '0.5.0', + bucket: expect.any(Number), + delaySeconds: 86_400, + eligibleAt: expect.any(String), + })); + expect(mocks.appendRolloutDecisionLog).toHaveBeenCalledWith(expect.objectContaining({ + phase: 'background-refresh', + reason: 'held', + })); + }); + + it('starts the background install once the device batch is eligible', async () => { + const released = cacheWithManifest(releasedForEveryone('0.5.0')); + mocks.readUpdateCache.mockResolvedValue(released); + mocks.refreshUpdateCache.mockResolvedValue(released); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const { options } = captureOutput(); + const track = vi.fn(); + + await expect(runUpdatePreflight('0.4.0', { ...options, track })).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { detached: true, stdio: 'ignore' }, + ); + expect(track).toHaveBeenCalledWith('update_background_install_started', expect.objectContaining({ + target_version: '0.5.0', + rollout_bucket: expect.any(Number), + rollout_delay_seconds: 0, + rollout_from_manifest: true, + })); + expect(mocks.appendRolloutDecisionLog).toHaveBeenCalledWith(expect.objectContaining({ + phase: 'startup-cache', + reason: 'eligible', + target: '0.5.0', + })); + }); + + it('prompts with rollout telemetry when eligible and auto-install is disabled', async () => { + disableAutoInstall(); + const released = cacheWithManifest(releasedForEveryone('0.5.0')); + mocks.readUpdateCache.mockResolvedValue(released); + mocks.refreshUpdateCache.mockResolvedValue(released); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + const track = vi.fn(); + + await expect(runUpdatePreflight('0.4.0', { ...options, track })).resolves.toBe('continue'); + + expect(mocks.promptForInstallChoice).toHaveBeenCalledWith( + expect.objectContaining({ target: { version: '0.5.0' } }), + ); + expect(track).toHaveBeenCalledWith('update_prompted', expect.objectContaining({ + target_version: '0.5.0', + rollout_bucket: expect.any(Number), + rollout_delay_seconds: 0, + rollout_from_manifest: true, + })); + }); + + it('uses the refreshed manifest for rollout telemetry when the prompt target changes', async () => { + disableAutoInstall(); + const cached = cacheWithManifest(manifestFor('0.6.0', { + publishedAt: '2020-01-01T00:00:00.000Z', + rollout: [{ percent: 100, delaySeconds: 0 }], + })); + const refreshed = cacheWithManifest(manifestFor('0.7.0', { + publishedAt: '2020-01-01T00:00:00.000Z', + rollout: [{ percent: 100, delaySeconds: 43_200 }], + })); + mocks.readUpdateCache.mockResolvedValue(cached); + mocks.refreshUpdateCache.mockResolvedValue(refreshed); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + const track = vi.fn(); + + await expect(runUpdatePreflight('0.5.0', { ...options, track })).resolves.toBe('continue'); + + expect(mocks.promptForInstallChoice).toHaveBeenCalledWith( + expect.objectContaining({ target: { version: '0.7.0' } }), + ); + expect(track).toHaveBeenCalledWith('update_prompted', expect.objectContaining({ + target_version: '0.7.0', + rollout_bucket: expect.any(Number), + rollout_delay_seconds: 43_200, + rollout_from_manifest: true, + })); + }); + + it('suppresses the manual-command notice while a homebrew device batch is held', async () => { + const held = cacheWithManifest(heldForEveryone('0.5.0')); + mocks.readUpdateCache.mockResolvedValue(held); + mocks.refreshUpdateCache.mockResolvedValue(held); + mocks.detectInstallSource.mockResolvedValue('homebrew'); + const { stdout, options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(stdout.join('')).toBe(''); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('does not start a fresh-check background install while the refreshed manifest is held', async () => { + mocks.readUpdateCache.mockResolvedValue(emptyUpdateCache()); + mocks.refreshUpdateCache.mockResolvedValue(cacheWithManifest(heldForEveryone('0.5.0'))); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(refreshUpdateCache).toHaveBeenCalledTimes(1); + expect(detectInstallSource).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('stays silent when the user-visible refresh reveals a held newer version', async () => { + disableAutoInstall(); + mocks.readUpdateCache.mockResolvedValue(cacheWithManifest(releasedForEveryone('0.6.0'))); + mocks.refreshUpdateCache.mockResolvedValue(cacheWithManifest(heldForEveryone('0.7.0'))); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + const { stdout, options } = captureOutput(); + + await expect(runUpdatePreflight('0.5.0', options)).resolves.toBe('continue'); + + expect(stdout.join('')).toBe(''); + expect(promptForInstallChoice).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('KIMI_CODE_EXPERIMENTAL_FLAG bypasses the rollout: held devices still update', async () => { + vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '1'); + const held = cacheWithManifest(heldForEveryone('0.5.0')); + mocks.readUpdateCache.mockResolvedValue(held); + mocks.refreshUpdateCache.mockResolvedValue(held); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mockSpawnExit(0); + const { options } = captureOutput(); + const track = vi.fn(); + + await expect(runUpdatePreflight('0.4.0', { ...options, track })).resolves.toBe('continue'); + await flushBackgroundInstall(); + + expect(mocks.spawn).toHaveBeenCalledWith( + expect.stringMatching(/^npm(\.cmd)?$/), + ['install', '-g', '@moonshot-ai/kimi-code@0.5.0'], + { detached: true, stdio: 'ignore' }, + ); + expect(track).toHaveBeenCalledWith('update_background_install_started', expect.objectContaining({ + target_version: '0.5.0', + rollout_bypassed: true, + })); + expect(mocks.appendRolloutDecisionLog).toHaveBeenCalledWith(expect.objectContaining({ + phase: 'startup-cache', + reason: 'experimental', + target: '0.5.0', + })); + }); + + it('KIMI_CODE_NO_AUTO_UPDATE still wins over the experimental flag', async () => { + vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '1'); + vi.stubEnv('KIMI_CODE_NO_AUTO_UPDATE', '1'); + mocks.readUpdateCache.mockResolvedValue(cacheWithManifest(releasedForEveryone('0.5.0'))); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(readUpdateCache).not.toHaveBeenCalled(); + expect(mocks.spawn).not.toHaveBeenCalled(); + }); + + it('treats any plan older than 24h as fully rolled out', async () => { + disableAutoInstall(); + const staleRollout = manifestFor('0.5.0', { + publishedAt: new Date(Date.now() - 25 * 3_600 * 1_000).toISOString(), + rollout: [ + { percent: 30, delaySeconds: 0 }, + { percent: 30, delaySeconds: 43_200 }, + { percent: 40, delaySeconds: 86_400 }, + ], + }); + mocks.readUpdateCache.mockResolvedValue(cacheWithManifest(staleRollout)); + mocks.refreshUpdateCache.mockResolvedValue(cacheWithManifest(staleRollout)); + mocks.detectInstallSource.mockResolvedValue('npm-global'); + mocks.promptForInstallChoice.mockResolvedValue('skip'); + const { options } = captureOutput(); + + await expect(runUpdatePreflight('0.4.0', options)).resolves.toBe('continue'); + + expect(mocks.promptForInstallChoice).toHaveBeenCalledWith( + expect.objectContaining({ target: { version: '0.5.0' } }), + ); + }); + }); +}); diff --git a/apps/kimi-code/test/cli/update/prompt.test.ts b/apps/kimi-code/test/cli/update/prompt.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..126440493d9e3735f324caf4899ebc05a20a24c4 --- /dev/null +++ b/apps/kimi-code/test/cli/update/prompt.test.ts @@ -0,0 +1,72 @@ +import { EventEmitter } from 'node:events'; + +import { describe, expect, it } from 'vitest'; + +import { + createInstallPromptChoices, + getDefaultInstallPromptSelection, + moveInstallPromptSelection, + promptForInstallChoice, +} from '#/cli/update/prompt'; + +describe('install prompt helpers', () => { + it('defaults the selection to "Install update now"', () => { + const choices = createInstallPromptChoices({ version: '0.0.2-beta.1' }); + + expect(getDefaultInstallPromptSelection(choices)).toBe(0); + expect(choices[0]).toEqual({ + value: 'install', + label: 'Install update now (0.0.2-beta.1)', + }); + expect(choices[1]).toEqual({ + value: 'skip', + label: 'Continue with current version', + }); + }); + + it('moves selection with arrow directions and clamps at the edges', () => { + expect(moveInstallPromptSelection(1, 'up', 2)).toBe(0); + expect(moveInstallPromptSelection(0, 'up', 2)).toBe(0); + expect(moveInstallPromptSelection(0, 'down', 2)).toBe(1); + expect(moveInstallPromptSelection(1, 'down', 2)).toBe(1); + }); +}); + +describe('promptForInstallChoice', () => { + it('renders changelog hyperlink in the prompt output', async () => { + const CHANGELOG_URL = 'https://moonshotai.github.io/kimi-code/en/release-notes/changelog.html'; + + const input = Object.assign(new EventEmitter(), { + isRaw: false, + setRawMode: () => {}, + resume: () => {}, + off: () => {}, + }) as unknown as NodeJS.ReadStream; + + const outputChunks: string[] = []; + const output = { + write: (chunk: string) => { + outputChunks.push(chunk); + return true; + }, + } as NodeJS.WriteStream; + + const promptPromise = promptForInstallChoice({ + currentVersion: '0.4.0', + target: { version: '0.5.0' }, + installCommand: 'npm install -g @moonshot-ai/kimi-code@0.5.0', + installSource: 'npm-global', + input, + output, + }); + + // Emit keypress to trigger initial render then exit + input.emit('keypress', '', { name: 'escape' }); + + await promptPromise; + + const rendered = outputChunks.join(''); + expect(rendered).toContain(CHANGELOG_URL); + expect(rendered).toContain('View changelog'); + }); +}); diff --git a/apps/kimi-code/test/cli/update/refresh.test.ts b/apps/kimi-code/test/cli/update/refresh.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff5a340de5121187b3ff8908126f4469d7ee88d7 --- /dev/null +++ b/apps/kimi-code/test/cli/update/refresh.test.ts @@ -0,0 +1,99 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { refreshUpdateCache } from '#/cli/update/refresh'; +import type { UpdateManifest } from '#/cli/update/types'; + +const MANIFEST: UpdateManifest = { + version: '0.5.0', + publishedAt: '2026-05-20T12:00:00.000Z', + rollout: [ + { percent: 30, delaySeconds: 0 }, + { percent: 30, delaySeconds: 43_200 }, + { percent: 40, delaySeconds: 86_400 }, + ], +}; + +describe('refreshUpdateCache', () => { + it('writes a fresh cache carrying the manifest on successful fetch', async () => { + const writeCache = vi.fn(async () => {}); + const result = await refreshUpdateCache({ + fetchLatest: async () => ({ latest: '0.5.0', manifest: MANIFEST }), + writeCache, + now: () => new Date('2026-05-20T12:34:56.000Z'), + }); + + expect(result).toEqual({ + source: 'cdn', + checkedAt: '2026-05-20T12:34:56.000Z', + latest: '0.5.0', + manifest: MANIFEST, + }); + expect(writeCache).toHaveBeenCalledWith(result); + }); + + it('writes a null manifest when the fetch fell back to plain text', async () => { + const writeCache = vi.fn(async () => {}); + const result = await refreshUpdateCache({ + fetchLatest: async () => ({ latest: '0.5.0', manifest: null }), + writeCache, + now: () => new Date('2026-05-20T12:34:56.000Z'), + }); + + expect(result).toEqual({ + source: 'cdn', + checkedAt: '2026-05-20T12:34:56.000Z', + latest: '0.5.0', + manifest: null, + }); + expect(writeCache).toHaveBeenCalledWith(result); + }); + + it('propagates fetch errors and skips writeCache so the cache is preserved', async () => { + const writeCache = vi.fn(async () => {}); + await expect( + refreshUpdateCache({ + fetchLatest: async () => { + throw new Error('network down'); + }, + writeCache, + now: () => new Date(), + }), + ).rejects.toThrow(/network down/); + + expect(writeCache).not.toHaveBeenCalled(); + }); + + it('threads timeoutMs into the default CDN fetch', async () => { + vi.useFakeTimers(); + vi.stubGlobal( + 'fetch', + vi.fn(async (_input: string | URL, init?: RequestInit) => { + return new Promise((_resolve, reject) => { + init?.signal?.addEventListener('abort', () => { + reject(new Error('aborted')); + }, { once: true }); + }); + }), + ); + try { + const result = refreshUpdateCache({ + timeoutMs: 10_000, + writeCache: async () => {}, + }); + let rejected = false; + void result.catch(() => { + rejected = true; + }); + const expectation = expect(result).rejects.toThrow(/aborted/); + await vi.advanceTimersByTimeAsync(6_000); + expect(rejected).toBe(false); + await vi.advanceTimersByTimeAsync(14_000); + + await expectation; + expect(rejected).toBe(true); + } finally { + vi.useRealTimers(); + vi.unstubAllGlobals(); + } + }); +}); diff --git a/apps/kimi-code/test/cli/update/rollout.test.ts b/apps/kimi-code/test/cli/update/rollout.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..61590614889c1ab57767236b5e7de1ad628373ed --- /dev/null +++ b/apps/kimi-code/test/cli/update/rollout.test.ts @@ -0,0 +1,366 @@ +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { + appendRolloutDecisionLog, + decidePassiveUpdateTarget, + isRolloutBypassedByExperimentalEnv, + isRolloutEligible, + MAX_ROLLOUT_DELAY_SECONDS, + rolloutBucket, + rolloutDelayForBucket, + rolloutDelaySeconds, + resolveUpdateDeviceId, + selectPassiveUpdateTarget, +} from '#/cli/update/rollout'; +import type { RolloutBatch, UpdateManifest } from '#/cli/update/types'; + +const STANDARD_ROLLOUT: readonly RolloutBatch[] = [ + { percent: 30, delaySeconds: 0 }, + { percent: 30, delaySeconds: 43_200 }, + { percent: 40, delaySeconds: 86_400 }, +]; + +const PUBLISHED_AT = '2026-06-12T00:00:00.000Z'; +const PUBLISHED_AT_MS = Date.parse(PUBLISHED_AT); + +function makeManifest(overrides: Partial = {}): UpdateManifest { + return { + version: '2.0.0', + publishedAt: PUBLISHED_AT, + rollout: STANDARD_ROLLOUT, + ...overrides, + }; +} + +function secondsAfterPublish(seconds: number): Date { + return new Date(PUBLISHED_AT_MS + seconds * 1000); +} + +describe('rolloutBucket', () => { + it('is deterministic and within 0-99', () => { + for (let i = 0; i < 200; i++) { + const bucket = rolloutBucket(`device-${i}`, '2.0.0'); + expect(bucket).toBe(rolloutBucket(`device-${i}`, '2.0.0')); + expect(bucket).toBeGreaterThanOrEqual(0); + expect(bucket).toBeLessThan(100); + expect(Number.isInteger(bucket)).toBe(true); + } + }); + + it('matches pinned vectors (regression guard for the hash layout)', () => { + expect(rolloutBucket('device-a', '1.0.0')).toBe(65); + expect(rolloutBucket('device-b', '1.0.0')).toBe(76); + expect(rolloutBucket('fixed-device', '2.0.0')).toBe(26); + }); + + it('reshuffles buckets when the version changes', () => { + expect(rolloutBucket('device-a', '1.0.1')).toBe(79); + expect(rolloutBucket('device-a', '1.0.1')).not.toBe(rolloutBucket('device-a', '1.0.0')); + }); +}); + +describe('rolloutDelayForBucket', () => { + it('maps buckets to batches at the exact boundaries', () => { + expect(rolloutDelayForBucket(STANDARD_ROLLOUT, 0)).toBe(0); + expect(rolloutDelayForBucket(STANDARD_ROLLOUT, 29)).toBe(0); + expect(rolloutDelayForBucket(STANDARD_ROLLOUT, 30)).toBe(43_200); + expect(rolloutDelayForBucket(STANDARD_ROLLOUT, 59)).toBe(43_200); + expect(rolloutDelayForBucket(STANDARD_ROLLOUT, 60)).toBe(86_400); + expect(rolloutDelayForBucket(STANDARD_ROLLOUT, 99)).toBe(86_400); + }); + + it('clamps oversized delays to 24h', () => { + const rollout: readonly RolloutBatch[] = [{ percent: 100, delaySeconds: 999_999 }]; + expect(rolloutDelayForBucket(rollout, 50)).toBe(MAX_ROLLOUT_DELAY_SECONDS); + }); + + it('assigns buckets not covered by the plan to the slowest cohort', () => { + const rollout: readonly RolloutBatch[] = [{ percent: 30, delaySeconds: 0 }]; + expect(rolloutDelayForBucket(rollout, 29)).toBe(0); + expect(rolloutDelayForBucket(rollout, 30)).toBe(MAX_ROLLOUT_DELAY_SECONDS); + expect(rolloutDelayForBucket(rollout, 99)).toBe(MAX_ROLLOUT_DELAY_SECONDS); + }); + + it('tolerates percents summing past 100', () => { + const rollout: readonly RolloutBatch[] = [ + { percent: 60, delaySeconds: 0 }, + { percent: 60, delaySeconds: 43_200 }, + ]; + expect(rolloutDelayForBucket(rollout, 59)).toBe(0); + expect(rolloutDelayForBucket(rollout, 99)).toBe(43_200); + }); + + it('treats an empty plan as fully rolled out', () => { + expect(rolloutDelayForBucket([], 0)).toBe(0); + expect(rolloutDelayForBucket([], 99)).toBe(0); + }); +}); + +describe('rolloutDelaySeconds', () => { + it('splits 10k devices roughly 30/30/40 across the standard plan', () => { + const counts = new Map([ + [0, 0], + [43_200, 0], + [86_400, 0], + ]); + const manifest = makeManifest(); + for (let i = 0; i < 10_000; i++) { + const delay = rolloutDelaySeconds(manifest, `device-${i}`); + counts.set(delay, (counts.get(delay) ?? 0) + 1); + } + expect(counts.get(0)).toBeGreaterThanOrEqual(2_700); + expect(counts.get(0)).toBeLessThanOrEqual(3_300); + expect(counts.get(43_200)).toBeGreaterThanOrEqual(2_700); + expect(counts.get(43_200)).toBeLessThanOrEqual(3_300); + expect(counts.get(86_400)).toBeGreaterThanOrEqual(3_700); + expect(counts.get(86_400)).toBeLessThanOrEqual(4_300); + }); +}); + +describe('isRolloutEligible', () => { + const delayedForEveryone = makeManifest({ + rollout: [{ percent: 100, delaySeconds: 43_200 }], + }); + + it('is not eligible before publishedAt + delay', () => { + const justBefore = new Date(PUBLISHED_AT_MS + 43_200 * 1000 - 1); + expect(isRolloutEligible(delayedForEveryone, 'device-a', justBefore)).toBe(false); + }); + + it('is eligible exactly at publishedAt + delay', () => { + expect(isRolloutEligible(delayedForEveryone, 'device-a', secondsAfterPublish(43_200))).toBe( + true, + ); + }); + + it('is not eligible while publishedAt is still in the future', () => { + const manifest = makeManifest({ rollout: [] }); + expect(isRolloutEligible(manifest, 'device-a', secondsAfterPublish(-3_600))).toBe(false); + }); + + it('is always eligible 24h after publish regardless of the plan', () => { + const manifest = makeManifest({ rollout: [{ percent: 100, delaySeconds: 999_999 }] }); + expect(isRolloutEligible(manifest, 'device-a', secondsAfterPublish(86_400))).toBe(true); + }); + + it('fails open when publishedAt cannot be parsed', () => { + const manifest = makeManifest({ publishedAt: 'not-a-date' }); + expect(isRolloutEligible(manifest, 'device-a', secondsAfterPublish(-999_999))).toBe(true); + }); +}); + +describe('selectPassiveUpdateTarget', () => { + const now = secondsAfterPublish(60); + + it('falls back to plain latest when manifest is null', () => { + expect(selectPassiveUpdateTarget('1.0.0', '2.0.0', null, 'device-a', now)).toEqual({ + version: '2.0.0', + }); + expect(selectPassiveUpdateTarget('1.0.0', null, null, 'device-a', now)).toBeNull(); + }); + + it('returns null when the manifest version is not newer', () => { + const manifest = makeManifest({ rollout: [] }); + expect(selectPassiveUpdateTarget('2.0.0', '2.0.0', manifest, 'device-a', now)).toBeNull(); + expect(selectPassiveUpdateTarget('3.0.0', '2.0.0', manifest, 'device-a', now)).toBeNull(); + }); + + it('returns the target once the device batch is eligible', () => { + const manifest = makeManifest({ rollout: [{ percent: 100, delaySeconds: 0 }] }); + expect(selectPassiveUpdateTarget('1.0.0', '2.0.0', manifest, 'device-a', now)).toEqual({ + version: '2.0.0', + }); + }); + + it('hides the target while the device batch is not yet eligible', () => { + const manifest = makeManifest({ rollout: [{ percent: 100, delaySeconds: 86_400 }] }); + expect(selectPassiveUpdateTarget('1.0.0', '2.0.0', manifest, 'device-a', now)).toBeNull(); + }); +}); + +describe('decidePassiveUpdateTarget', () => { + const now = secondsAfterPublish(60); + + it('reports no-latest when nothing is known yet', () => { + const decision = decidePassiveUpdateTarget('1.0.0', null, null, 'device-a', now); + expect(decision).toMatchObject({ target: null, reason: 'no-latest' }); + }); + + it('reports not-newer when the known version is not an upgrade', () => { + expect(decidePassiveUpdateTarget('2.0.0', '2.0.0', null, 'device-a', now)).toMatchObject({ + target: null, + reason: 'not-newer', + }); + const manifest = makeManifest({ rollout: [] }); + expect(decidePassiveUpdateTarget('2.0.0', '2.0.0', manifest, 'device-a', now)).toMatchObject({ + target: null, + reason: 'not-newer', + }); + }); + + it('reports no-manifest legacy visibility when only plain latest is known', () => { + const decision = decidePassiveUpdateTarget('1.0.0', '2.0.0', null, 'device-a', now); + expect(decision).toMatchObject({ + target: { version: '2.0.0' }, + reason: 'no-manifest', + bucket: null, + delaySeconds: null, + eligibleAt: null, + }); + }); + + it('reports held with bucket, delay and eligibleAt while the batch is gated', () => { + const manifest = makeManifest({ rollout: [{ percent: 100, delaySeconds: 86_400 }] }); + const decision = decidePassiveUpdateTarget( + '1.0.0', + '2.0.0', + manifest, + 'device-a', + secondsAfterPublish(60), + ); + expect(decision).toMatchObject({ + target: null, + reason: 'held', + bucket: rolloutBucket('device-a', '2.0.0'), + delaySeconds: 86_400, + eligibleAt: new Date(PUBLISHED_AT_MS + 86_400 * 1000).toISOString(), + }); + }); + + it('reports eligible once the batch delay has passed', () => { + const manifest = makeManifest({ rollout: [{ percent: 100, delaySeconds: 43_200 }] }); + const decision = decidePassiveUpdateTarget( + '1.0.0', + '2.0.0', + manifest, + 'device-a', + secondsAfterPublish(43_200), + ); + expect(decision).toMatchObject({ + target: { version: '2.0.0' }, + reason: 'eligible', + delaySeconds: 43_200, + }); + }); +}); + +describe('appendRolloutDecisionLog', () => { + let dir: string; + + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-rollout-log-')); + }); + + afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + }); + + it('appends one JSON line per decision', async () => { + const file = join(dir, 'updates', 'rollout.log'); + await appendRolloutDecisionLog({ phase: 'startup-cache', reason: 'held' }, file); + await appendRolloutDecisionLog({ phase: 'prompt-refresh', reason: 'eligible' }, file); + + const lines = readFileSync(file, 'utf-8').trim().split('\n'); + expect(lines).toHaveLength(2); + expect(JSON.parse(lines[0] ?? '')).toMatchObject({ phase: 'startup-cache', reason: 'held' }); + expect(JSON.parse(lines[1] ?? '')).toMatchObject({ phase: 'prompt-refresh', reason: 'eligible' }); + }); + + it('resets the file once it grows past the size cap', async () => { + const file = join(dir, 'rollout.log'); + writeFileSync(file, 'x'.repeat(300 * 1024), 'utf-8'); + await appendRolloutDecisionLog({ reason: 'eligible' }, file); + + const content = readFileSync(file, 'utf-8'); + expect(content.length).toBeLessThan(1024); + expect(JSON.parse(content.trim())).toMatchObject({ reason: 'eligible' }); + }); + + it('never throws on unwritable paths', async () => { + await expect( + appendRolloutDecisionLog({ reason: 'held' }, '/dev/null/nope/rollout.log'), + ).resolves.toBeUndefined(); + }); +}); + +describe('resolveUpdateDeviceId', () => { + const originalEnv = { ...process.env }; + let dir: string; + + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-rollout-device-id-')); + process.env['KIMI_CODE_HOME'] = dir; + }); + + afterEach(() => { + process.env = { ...originalEnv }; + rmSync(dir, { recursive: true, force: true }); + }); + + it('does not create the telemetry device id file when one is missing', () => { + const deviceId = resolveUpdateDeviceId(); + + expect(deviceId).toMatch(/^[0-9a-f-]+$/); + expect(existsSync(join(dir, 'device_id'))).toBe(false); + }); + + it('reuses an existing telemetry device id without rewriting it', () => { + writeFileSync(join(dir, 'device_id'), 'existing-device-id', 'utf-8'); + + expect(resolveUpdateDeviceId()).toBe('existing-device-id'); + expect(readFileSync(join(dir, 'device_id'), 'utf-8')).toBe('existing-device-id'); + }); +}); + +describe('experimental flag bypass', () => { + const now = secondsAfterPublish(60); + const heldManifest = makeManifest({ rollout: [{ percent: 100, delaySeconds: 86_400 }] }); + + it('bypasses a held rollout and reports experimental', () => { + const decision = decidePassiveUpdateTarget('1.0.0', '2.0.0', heldManifest, 'device-a', now, true); + expect(decision).toMatchObject({ + target: { version: '2.0.0' }, + reason: 'experimental', + bucket: null, + delaySeconds: null, + eligibleAt: null, + }); + }); + + it('still reports not-newer / no-latest under bypass', () => { + expect(decidePassiveUpdateTarget('2.0.0', '2.0.0', heldManifest, 'device-a', now, true)).toMatchObject({ + target: null, + reason: 'not-newer', + }); + expect(decidePassiveUpdateTarget('1.0.0', null, null, 'device-a', now, true)).toMatchObject({ + target: null, + reason: 'no-latest', + }); + }); + + it('marks plain-latest visibility as experimental when bypassing', () => { + expect(decidePassiveUpdateTarget('1.0.0', '2.0.0', null, 'device-a', now, true)).toMatchObject({ + target: { version: '2.0.0' }, + reason: 'experimental', + }); + }); +}); + +describe('isRolloutBypassedByExperimentalEnv', () => { + it('is on for the usual truthy values of KIMI_CODE_EXPERIMENTAL_FLAG', () => { + for (const value of ['1', 'true', 'YES', ' on ']) { + expect(isRolloutBypassedByExperimentalEnv({ KIMI_CODE_EXPERIMENTAL_FLAG: value })).toBe(true); + } + }); + + it('is off when unset, blank, or falsy', () => { + expect(isRolloutBypassedByExperimentalEnv({})).toBe(false); + expect(isRolloutBypassedByExperimentalEnv({ KIMI_CODE_EXPERIMENTAL_FLAG: '' })).toBe(false); + expect(isRolloutBypassedByExperimentalEnv({ KIMI_CODE_EXPERIMENTAL_FLAG: '0' })).toBe(false); + expect(isRolloutBypassedByExperimentalEnv({ KIMI_CODE_EXPERIMENTAL_FLAG: 'off' })).toBe(false); + }); +}); diff --git a/apps/kimi-code/test/cli/update/select.test.ts b/apps/kimi-code/test/cli/update/select.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a616a48673bd105d97e87c43589a6f10b27c3164 --- /dev/null +++ b/apps/kimi-code/test/cli/update/select.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from 'vitest'; + +import { selectUpdateTarget } from '#/cli/update/select'; + +describe('selectUpdateTarget', () => { + it('returns the latest version when it is newer than current', () => { + expect(selectUpdateTarget('0.4.0', '0.5.0')).toEqual({ version: '0.5.0' }); + }); + + it('returns null when latest equals current', () => { + expect(selectUpdateTarget('0.5.0', '0.5.0')).toBeNull(); + }); + + it('returns null when latest is older than current', () => { + expect(selectUpdateTarget('0.6.0', '0.5.0')).toBeNull(); + }); + + it('returns null when latest is null (cache empty)', () => { + expect(selectUpdateTarget('0.5.0', null)).toBeNull(); + }); + + it('returns null when current is not a valid semver', () => { + expect(selectUpdateTarget('not-a-version', '0.5.0')).toBeNull(); + }); + + it('returns null when latest is not a valid semver', () => { + expect(selectUpdateTarget('0.5.0', 'not-a-version')).toBeNull(); + }); + + it('handles prerelease semver comparisons correctly', () => { + expect(selectUpdateTarget('0.5.0-rc.1', '0.5.0')).toEqual({ version: '0.5.0' }); + expect(selectUpdateTarget('0.5.0', '0.5.0-rc.1')).toBeNull(); + }); +}); diff --git a/apps/kimi-code/test/cli/update/source.test.ts b/apps/kimi-code/test/cli/update/source.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..babe509a2069ff1fb9772409823f111f85c0c7a8 --- /dev/null +++ b/apps/kimi-code/test/cli/update/source.test.ts @@ -0,0 +1,199 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { + classifyByPathHeuristic, + classifyInstallSource, + detectInstallSource, +} from '#/cli/update/source'; +import { resolveCommandPath } from '#/utils/process/resolve-command'; + +vi.mock('#/utils/process/resolve-command', () => ({ + resolveCommandPath: vi.fn(), +})); + +describe('classifyByPathHeuristic', () => { + it('returns null for an npm-style global path (handled by classifyInstallSource)', () => { + expect(classifyByPathHeuristic('/usr/local/lib/node_modules/@moonshot-ai/kimi-code')).toBeNull(); + }); + + it('detects pnpm global on macOS', () => { + expect( + classifyByPathHeuristic('/Users/me/Library/pnpm/global/5/node_modules/@moonshot-ai/kimi-code'), + ).toBe('pnpm-global'); + }); + + it('detects pnpm global on Linux', () => { + expect( + classifyByPathHeuristic('/home/me/.local/share/pnpm/global/5/node_modules/@moonshot-ai/kimi-code'), + ).toBe('pnpm-global'); + }); + + it('detects pnpm global on Windows (normalized backslashes)', () => { + expect( + classifyByPathHeuristic('C:\\Users\\me\\AppData\\Local\\pnpm\\global\\5\\node_modules\\@moonshot-ai/kimi-code'), + ).toBe('pnpm-global'); + }); + + it('detects yarn classic global', () => { + expect( + classifyByPathHeuristic('/Users/me/.config/yarn/global/node_modules/@moonshot-ai/kimi-code'), + ).toBe('yarn-global'); + }); + + it('detects yarn berry global (~/.yarn/global)', () => { + expect( + classifyByPathHeuristic('/Users/me/.yarn/global/node_modules/@moonshot-ai/kimi-code'), + ).toBe('yarn-global'); + }); + + it('detects bun global', () => { + expect( + classifyByPathHeuristic('/Users/me/.bun/install/global/node_modules/@moonshot-ai/kimi-code'), + ).toBe('bun-global'); + }); + + it('detects homebrew on macOS (Cellar path)', () => { + expect( + classifyByPathHeuristic('/opt/homebrew/Cellar/kimi-code/0.5.0/libexec/lib/node_modules/@moonshot-ai/kimi-code'), + ).toBe('homebrew'); + }); + + it('detects homebrew on Linux (Linuxbrew)', () => { + expect( + classifyByPathHeuristic('/home/linuxbrew/.linuxbrew/Cellar/kimi-code/0.5.0/libexec/lib/node_modules/@moonshot-ai/kimi-code'), + ).toBe('homebrew'); + }); + + it('does not treat npm-global under Homebrew prefix as homebrew', () => { + expect( + classifyByPathHeuristic('/opt/homebrew/lib/node_modules/@moonshot-ai/kimi-code'), + ).toBeNull(); + }); + + it('returns null for an unknown layout', () => { + expect(classifyByPathHeuristic('/Users/me/dev/@moonshot-ai/kimi-code')).toBeNull(); + }); +}); + +describe('classifyInstallSource (npm prefix matching)', () => { + it('matches a macOS/Linux npm global package path', () => { + expect( + classifyInstallSource('/usr/local/lib/node_modules/@moonshot-ai/kimi-code', '/usr/local', 'darwin'), + ).toBe('npm-global'); + }); + + it('returns unsupported when the package path does not match the prefix', () => { + expect( + classifyInstallSource('/Users/me/dev/@moonshot-ai/kimi-code', '/usr/local', 'darwin'), + ).toBe('unsupported'); + }); +}); + +describe('detectInstallSource', () => { + it('returns pnpm-global when packageRoot matches pnpm heuristic', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => + '/Users/me/Library/pnpm/global/5/node_modules/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('pnpm-global'); + }); + + it('returns yarn-global when packageRoot matches yarn heuristic', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => '/Users/me/.config/yarn/global/node_modules/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('yarn-global'); + }); + + it('returns bun-global when packageRoot matches bun heuristic', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => '/Users/me/.bun/install/global/node_modules/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('bun-global'); + }); + + it('returns npm-global when packageRoot matches npm prefix', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => '/usr/local/lib/node_modules/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('npm-global'); + }); + + it('returns homebrew when packageRoot matches Cellar heuristic', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => + '/opt/homebrew/Cellar/kimi-code/0.5.0/libexec/lib/node_modules/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('homebrew'); + }); + + it('returns native when SEA isSea() is true (highest priority)', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => '/usr/local/lib/node_modules/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => true, + platform: 'darwin', + }), + ).resolves.toBe('native'); + }); + + it('returns unsupported when nothing matches', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => '/Users/me/dev/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => '/usr/local', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('unsupported'); + }); + + it('returns unsupported when npm prefix lookup throws', async () => { + await expect( + detectInstallSource({ + getPackageRoot: () => '/Users/me/dev/@moonshot-ai/kimi-code', + getGlobalPrefix: async () => { + throw new Error('prefix failed'); + }, + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('unsupported'); + }); + + it('returns unsupported when npm cannot be resolved outside the cwd', async () => { + // The default prefix lookup spawns npm; when it can only be found inside + // the current directory (or not at all), detection must degrade to + // 'unsupported' rather than run a planted binary. + vi.mocked(resolveCommandPath).mockReturnValue(undefined); + await expect( + detectInstallSource({ + getPackageRoot: () => '/Users/me/dev/@moonshot-ai/kimi-code', + detectNative: () => false, + platform: 'darwin', + }), + ).resolves.toBe('unsupported'); + expect(resolveCommandPath).toHaveBeenCalledWith('npm'); + }); +}); diff --git a/apps/kimi-code/test/cli/upgrade.test.ts b/apps/kimi-code/test/cli/upgrade.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..db270f94a8d354c465d32721a4308837c6b1b605 --- /dev/null +++ b/apps/kimi-code/test/cli/upgrade.test.ts @@ -0,0 +1,249 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { handleUpgrade } from '#/cli/sub/upgrade'; +import type { InstallPromptChoiceValue } from '#/cli/update/prompt'; +import type { InstallSource, UpdateCache } from '#/cli/update/types'; + +function cacheWith( + version: string | null, + manifest: UpdateCache['manifest'] = null, +): UpdateCache { + return { + source: 'cdn', + checkedAt: '2026-04-23T08:00:00.000Z', + latest: version, + manifest, + }; +} + +function captureOutput(): { + stdout: string[]; + stderr: string[]; + writable: { + stdout: { write(chunk: string): boolean }; + stderr: { write(chunk: string): boolean }; + }; +} { + const stdout: string[] = []; + const stderr: string[] = []; + return { + stdout, + stderr, + writable: { + stdout: { write: (chunk: string) => { stdout.push(chunk); return true; } }, + stderr: { write: (chunk: string) => { stderr.push(chunk); return true; } }, + }, + }; +} + +function createDeps(overrides: { + readonly latest?: string | null; + readonly manifest?: UpdateCache['manifest']; + readonly source?: InstallSource; + readonly isInteractive?: boolean; + readonly promptForInstallChoice?: () => Promise; + readonly installUpdate?: (source: InstallSource, version: string, platform: NodeJS.Platform) => Promise; +} = {}) { + const installUpdate = + overrides.installUpdate ?? + vi.fn<( + source: InstallSource, + version: string, + platform: NodeJS.Platform, + ) => Promise>().mockResolvedValue(undefined); + + return { + refreshUpdateCache: vi + .fn() + .mockResolvedValue(cacheWith(overrides.latest ?? '0.5.0', overrides.manifest ?? null)), + detectInstallSource: vi.fn().mockResolvedValue(overrides.source ?? 'npm-global'), + promptForInstallChoice: + overrides.promptForInstallChoice ?? vi.fn().mockResolvedValue('install'), + installUpdate, + track: vi.fn(), + logger: { + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + debug: vi.fn(), + }, + platform: 'darwin' as NodeJS.Platform, + isInteractive: overrides.isInteractive ?? true, + }; +} + +describe('handleUpgrade', () => { + it('prompts before installing the latest version when the install source supports it', async () => { + const { stdout, stderr, writable } = captureOutput(); + const deps = createDeps({ latest: '0.5.0', source: 'npm-global' }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(0); + + expect(deps.refreshUpdateCache).toHaveBeenCalledTimes(1); + expect(deps.detectInstallSource).toHaveBeenCalledTimes(1); + expect(deps.promptForInstallChoice).toHaveBeenCalledWith({ + currentVersion: '0.4.0', + target: { version: '0.5.0' }, + installCommand: 'npm install -g @moonshot-ai/kimi-code@0.5.0', + installSource: 'npm-global', + }); + expect(deps.installUpdate).toHaveBeenCalledWith('npm-global', '0.5.0', 'darwin'); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_prompted', expect.objectContaining({ + current_version: '0.4.0', + target_version: '0.5.0', + source: 'npm-global', + })); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_install_selected', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + })); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_succeeded', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + })); + expect(deps.logger.info).toHaveBeenCalledWith('manual upgrade install succeeded', expect.objectContaining({ + targetVersion: '0.5.0', + source: 'npm-global', + })); + expect(stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.5.0'); + expect(stderr.join('')).toBe(''); + }); + + it('skips the foreground install when the update prompt is declined', async () => { + const { stdout, writable } = captureOutput(); + const deps = createDeps({ + latest: '0.5.0', + source: 'npm-global', + promptForInstallChoice: vi.fn().mockResolvedValue('skip'), + }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(0); + + expect(deps.promptForInstallChoice).toHaveBeenCalledTimes(1); + expect(deps.installUpdate).not.toHaveBeenCalled(); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_skipped', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + })); + expect(stdout.join('')).toBe(''); + }); + + it('prints up-to-date status without detecting the install source when no newer version exists', async () => { + const { stdout, writable } = captureOutput(); + const deps = createDeps({ latest: '0.4.0' }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(0); + + expect(deps.detectInstallSource).not.toHaveBeenCalled(); + expect(deps.installUpdate).not.toHaveBeenCalled(); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_no_update', expect.objectContaining({ + current_version: '0.4.0', + })); + expect(stdout.join('')).toContain('Kimi Code is already up to date (v0.4.0).'); + }); + + it('prints the manual update command when the install source cannot be auto-installed', async () => { + const { stdout, writable } = captureOutput(); + const deps = createDeps({ latest: '0.5.0', source: 'unsupported' }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(0); + + expect(deps.installUpdate).not.toHaveBeenCalled(); + expect(deps.promptForInstallChoice).not.toHaveBeenCalled(); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_manual_command', expect.objectContaining({ + target_version: '0.5.0', + source: 'unsupported', + })); + expect(stdout.join('')).toContain('To update manually, run: npm install -g @moonshot-ai/kimi-code@0.5.0'); + }); + + it('prints the manual update command without prompting when not interactive, and installs directly with yes', async () => { + const { stdout, writable } = captureOutput(); + const deps = createDeps({ latest: '0.5.0', source: 'npm-global', isInteractive: false }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(0); + + expect(deps.promptForInstallChoice).not.toHaveBeenCalled(); + expect(deps.installUpdate).not.toHaveBeenCalled(); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_manual_command', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + })); + expect(stdout.join('')).toContain('To update manually, run: npm install -g @moonshot-ai/kimi-code@0.5.0'); + + const yesRun = captureOutput(); + const yesDeps = createDeps({ latest: '0.5.0', source: 'npm-global', isInteractive: false }); + + await expect(handleUpgrade('0.4.0', { ...yesDeps, ...yesRun.writable, yes: true })).resolves.toBe(0); + + expect(yesDeps.promptForInstallChoice).not.toHaveBeenCalled(); + expect(yesDeps.installUpdate).toHaveBeenCalledWith('npm-global', '0.5.0', 'darwin'); + expect(yesDeps.track).not.toHaveBeenCalledWith('upgrade_command_prompted', expect.anything()); + expect(yesDeps.track).toHaveBeenCalledWith('upgrade_command_install_selected', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + })); + expect(yesRun.stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.5.0'); + }); + + it('returns a failing exit code when the foreground install fails', async () => { + const { stderr, writable } = captureOutput(); + const deps = createDeps({ + latest: '0.5.0', + source: 'npm-global', + installUpdate: vi.fn().mockRejectedValue(new Error('npm exited with code 1')), + }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(1); + + expect(stderr.join('')).toContain( + 'warning: failed to install @moonshot-ai/kimi-code@0.5.0: npm exited with code 1', + ); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_failed', expect.objectContaining({ + target_version: '0.5.0', + source: 'npm-global', + stage: 'install', + })); + expect(deps.logger.warn).toHaveBeenCalledWith('manual upgrade install failed', expect.objectContaining({ + targetVersion: '0.5.0', + source: 'npm-global', + })); + }); + + it('returns a failing exit code when checking the latest version fails', async () => { + const { stderr, writable } = captureOutput(); + const deps = { + ...createDeps(), + refreshUpdateCache: vi.fn().mockRejectedValue(new Error('cdn unavailable')), + }; + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(1); + + expect(deps.detectInstallSource).not.toHaveBeenCalled(); + expect(deps.installUpdate).not.toHaveBeenCalled(); + expect(deps.track).toHaveBeenCalledWith('upgrade_command_failed', expect.objectContaining({ + current_version: '0.4.0', + stage: 'refresh', + })); + expect(stderr.join('')).toContain('error: failed to check for updates: cdn unavailable'); + }); + + it('ignores rollout gating: installs the latest version while every batch is still held', async () => { + const { stdout, writable } = captureOutput(); + const deps = createDeps({ + latest: '0.5.0', + // Published seconds ago with every device delayed by 24h — passive + // update surfaces would hide this version, manual upgrade must not. + manifest: { + version: '0.5.0', + publishedAt: new Date(Date.now() - 1_000).toISOString(), + rollout: [{ percent: 100, delaySeconds: 86_400 }], + }, + }); + + await expect(handleUpgrade('0.4.0', { ...deps, ...writable })).resolves.toBe(0); + + expect(deps.installUpdate).toHaveBeenCalledWith('npm-global', '0.5.0', 'darwin'); + expect(stdout.join('')).toContain('Updated @moonshot-ai/kimi-code to 0.5.0'); + }); +}); diff --git a/apps/kimi-code/test/cli/v2-run-print.test.ts b/apps/kimi-code/test/cli/v2-run-print.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8dbb10dbaabf655e454aae60e328a9f5d35bf9eb --- /dev/null +++ b/apps/kimi-code/test/cli/v2-run-print.test.ts @@ -0,0 +1,999 @@ +import { mkdtemp, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + IAgentCronService, + IAgentGoalService, + IAgentLifecycleService, + IAgentLoopService, + IAgentPermissionModeService, + IAgentProfileService, + IAgentScopeContext, + IAgentTaskService, + IAuthSummaryService, + IBootstrapService, + IConfigService, + IEventBus, + IEventDispatcher, + IFileSystemStorageService, + IHostFileSystem, + IOAuthToolkit, + ISessionIndex, + ISessionManager, + ITelemetryService, + IWorkspaceInstanceManager, + makeAgentScopeContext, + resolveKimiHome, + type BootstrapInput, + type Event2, +} from '@moonshot-ai/agent-core-v2'; + +import { CLI_SHUTDOWN_TIMEOUT_MS, CLI_USER_AGENT_PRODUCT } from '#/constant/app'; + +import { runV2Print } from '../../src/cli/v2/run-v2-print'; + +const mocks = vi.hoisted(() => ({ + bootstrap: vi.fn(), + ensureMainAgent: vi.fn(), + loadMcpServersDetailed: vi.fn(async () => ({ + servers: {}, + origins: {}, + })), + resolveMcpJsonPaths: vi.fn(async () => ({ + user: '/tmp/kimi-code-test-home/mcp.json', + projectRoot: '/tmp/project/.mcp.json', + project: '/tmp/project/.kimi-code/mcp.json', + })), + createKimiDefaultHeaders: vi.fn(() => ({})), + resolveKimiHome: vi.fn((homeDir?: string) => homeDir ?? '/tmp/kimi-code-test-home'), + createKimiDeviceId: vi.fn(() => 'device-1'), + initializeTelemetry: vi.fn(), + setCrashPhase: vi.fn(), + setTelemetryContext: vi.fn(), + setTelemetryModel: vi.fn(), + shutdownTelemetry: vi.fn(async () => {}), +})); + +vi.mock('@moonshot-ai/agent-core-v2', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + bootstrap: mocks.bootstrap, + ensureMainAgent: mocks.ensureMainAgent, + }; +}); + +vi.mock('@moonshot-ai/agent-core-v2/app/mcpConfig/configLoader', () => ({ + loadMcpServersDetailed: mocks.loadMcpServersDetailed, + resolveMcpJsonPaths: mocks.resolveMcpJsonPaths, +})); + +vi.mock('@moonshot-ai/kimi-code-oauth', async () => { + const actual = await vi.importActual( + '@moonshot-ai/kimi-code-oauth', + ); + return { + ...actual, + createKimiDefaultHeaders: mocks.createKimiDefaultHeaders, + createKimiDeviceId: mocks.createKimiDeviceId, + }; +}); + +vi.mock('@moonshot-ai/kimi-code-sdk', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + resolveKimiHome: mocks.resolveKimiHome, + }; +}); + +vi.mock('@moonshot-ai/kimi-telemetry', async (importOriginal) => { + const actual = await importOriginal(); + return { + // Keep the real `shouldEnableTelemetry` so the tests exercise the actual + // KIMI_DISABLE_TELEMETRY semantics; only the side-effecting entry points + // are stubbed. + ...actual, + initializeTelemetry: mocks.initializeTelemetry, + setCrashPhase: mocks.setCrashPhase, + setTelemetryContext: mocks.setTelemetryContext, + setTelemetryModel: mocks.setTelemetryModel, + shutdownTelemetry: mocks.shutdownTelemetry, + track: vi.fn(), + withTelemetryContext: vi.fn(() => ({ track: vi.fn() })), + }; +}); + +interface FakeScope { + readonly id: string; + readonly accessor: { readonly get: (token: unknown) => unknown }; + readonly dispose: ReturnType; +} + +function fakeScope(id: string, services: Map): FakeScope { + return { + id, + accessor: { + get: (token: unknown) => { + if (!services.has(token)) throw new Error(`unexpected service request: ${String(token)}`); + return services.get(token); + }, + }, + dispose: vi.fn(), + }; +} + +function writer() { + let text = ''; + return { + write: vi.fn((chunk: string) => { + text += chunk; + return true; + }), + text: () => text, + }; +} + +function opts(overrides: Record = {}) { + return { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: 'say hello', + skillsDirs: [], + agent: undefined, + agentFiles: [], + addDirs: [], + ...overrides, + } as const; +} + +function makeFakeHarness() { + // Native event listeners registered on the main agent's IEventBus; the turn + // emits a streaming assistant delta before completing. + const eventListeners = new Set<(event: Event2) => void>(); + const profileState: { profileName: string | undefined } = { profileName: undefined }; + const trustState = { trusted: true }; + + const goal = { createGoal: vi.fn(), getGoal: vi.fn() }; + const agentServices = new Map([ + [ + IAgentProfileService, + { + bind: vi.fn(async () => {}), + setModel: vi.fn(async () => ({ model: 'k2' })), + getModel: () => 'k2', + data: () => ({ profileName: profileState.profileName }), + }, + ], + [IAgentPermissionModeService, { mode: 'auto', setMode: vi.fn() }], + [IAuthSummaryService, { ensureReady: vi.fn(async () => {}) }], + [ + IEventBus, + { + subscribe: vi.fn((handler: (event: Event2) => void) => { + eventListeners.add(handler); + return { dispose: () => eventListeners.delete(handler) }; + }), + }, + ], + [IAgentTaskService, { list: vi.fn(() => []), stopAllOnExit: vi.fn(async () => []) }], + [IAgentCronService, { getNextFireTime: vi.fn(() => null) }], + [IAgentGoalService, goal], + [IEventDispatcher, { flush: vi.fn(async () => {}) }], + [ + IAgentLoopService, + { + submit: vi.fn(() => { + // Emit a native assistant delta on the main agent bus, then complete. + for (const listener of [...eventListeners]) { + listener({ type: 'assistant.delta', turnId: 1, delta: 'hello world' } as unknown as Event2); + } + return { id: 'p1' }; + }), + promptHandle: vi.fn(() => ({ + launched: Promise.resolve({ + id: 1, + result: Promise.resolve({ type: 'completed' }), + }), + })), + snapshot: vi.fn(() => ({ + state: 'idle', + activeTurnId: undefined, + activePromptId: undefined, + queue: [], + notificationCount: 0, + paused: false, + hasPendingRequests: false, + turn: undefined, + activeTraceId: undefined, + })), + cancel: vi.fn(() => false), + settled: vi.fn(async () => {}), + tryAcquireQuiescence: vi.fn(() => ({ dispose: vi.fn() })), + }, + ], + [ + IAgentScopeContext, + makeAgentScopeContext({ agentId: 'main', agentScope: 'agents/main' }), + ], + ]); + const agent = fakeScope('main', agentServices); + + const sessionServices = new Map([ + // drain enumerates agents; empty → no background work to wait on. + [ + IAgentLifecycleService, + { + list: vi.fn(() => []), + handleOf: vi.fn(() => agent), + }, + ], + ]); + const session = fakeScope('ses_v2', sessionServices); + + const appServices = new Map([ + [ + IConfigService, + { + ready: Promise.resolve(), + get: vi.fn((section: string) => (section === 'defaultModel' ? 'k2' : undefined)), + // `applyPrintModeConfigDefaults` inspects each section and fills unset + // keys via the memory layer; an empty section means everything is unset. + inspect: vi.fn(() => ({ value: {} })), + set: vi.fn(async () => {}), + diagnostics: vi.fn(() => []), + }, + ], + [ + ISessionManager, + { + create: vi.fn(async () => session), + resume: vi.fn(async () => session), + get: vi.fn(() => session), + list: vi.fn(() => [session]), + } as unknown as ISessionManager, + ], + [ + ISessionIndex, + { + list: vi.fn(async () => ({ items: [] })), + get: vi.fn(async (id: string) => ({ + id, + workspaceId: 'wd_v2', + cwd: process.cwd(), + createdAt: 1, + updatedAt: 1, + archived: false, + })), + }, + ], + [ISessionIndex, { get: vi.fn(async () => undefined), listRecent: vi.fn(async () => ({ items: [] })) }], + [ + IBootstrapService, + { + platform: 'linux', + arch: 'x64', + clientIdentity: { + productName: 'test-product', + version: '1.2.3-test', + platform: 'test_platform', + }, + osHomeDir: '/home/test', + getEnv: () => undefined, + }, + ], + [IOAuthToolkit, { getCachedAccessToken: vi.fn(async () => undefined) }], + [IFileSystemStorageService, {}], + [IHostFileSystem, {}], + [ + IWorkspaceInstanceManager, + { + getOrCreate: vi.fn(async () => ({ + program: { trust: { get: vi.fn(async () => trustState.trusted) } }, + })), + }, + ], + [ + ITelemetryService, + (() => { + const svc = { + addAppender: vi.fn(() => ({ dispose: vi.fn() })), + setContext: vi.fn(), + track: vi.fn(), + track2: vi.fn(), + shutdown: vi.fn(async () => {}), + withContext: vi.fn(() => svc), + }; + return svc; + })(), + ], + ]); + const app = fakeScope('app', appServices); + return { app, agent, session, agentServices, sessionServices, appServices, profileState, trustState }; +} + +describe('runV2Print', () => { + beforeEach(() => { + vi.stubEnv('KIMI_CODE_EXPERIMENTAL_FLAG', '1'); + vi.stubEnv('KIMI_MODEL_OUTPUT_FORMAT', ''); + // Pin the telemetry kill-switch to "unset" so the host environment cannot + // flip the default telemetry-on path these tests exercise. + vi.stubEnv('KIMI_DISABLE_TELEMETRY', ''); + // `vi.clearAllMocks` keeps implementations, so re-pin the default here. + mocks.loadMcpServersDetailed.mockImplementation(async () => ({ + servers: {}, + origins: {}, + })); + }); + + afterEach(() => { + vi.clearAllMocks(); + vi.unstubAllEnvs(); + }); + + it('submits a prompt, renders native events, awaits completion, and drains', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent, agentServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + const promptService = agentServices.get(IAgentLoopService) as { submit: ReturnType }; + expect(promptService.submit).toHaveBeenCalledWith({ + message: { role: 'user', content: [{ type: 'text', text: 'say hello' }] }, + meta: { origin: { kind: 'user' }, tracked: true }, + }); + // Version banner is first, then the rendered assistant output. + expect(stderr.write).toHaveBeenNthCalledWith(1, 'kimi version 1.2.3-test\n'); + expect(stdout.text()).toContain('hello world'); + expect(app.dispose).toHaveBeenCalled(); + }); + + it('passes explicit skill dirs from --skillsDir into bootstrap args', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts({ skillsDirs: ['/skills'] }) as never, '1.2.3-test', { + stdout, + stderr, + }); + + const input = mocks.bootstrap.mock.calls[0]?.[0] as BootstrapInput; + expect(input.args?.skillDirs).toEqual(['/skills']); + }); + + it('leaves the skill dirs arg unset when --skillsDir is empty', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + const input = mocks.bootstrap.mock.calls[0]?.[0] as BootstrapInput; + expect(input.args?.skillDirs ?? []).toEqual([]); + }); + + it('seeds explicit agent files from --agentFile and binds the --agent profile', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent, appServices, agentServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print( + opts({ agent: 'reviewer', agentFiles: ['/agents/reviewer.md'] }) as never, + '1.2.3-test', + { stdout, stderr }, + ); + + const input = mocks.bootstrap.mock.calls[0]?.[0] as BootstrapInput; + expect(input.args?.agentFiles).toEqual(['/agents/reviewer.md']); + + const sessions = appServices.get(ISessionManager) as { create: ReturnType }; + expect(sessions.create).toHaveBeenCalledWith({ + workDir: process.cwd(), + additionalDirs: undefined, + mainAgentBinding: { profile: 'reviewer', model: 'k2' }, + }); + const profile = agentServices.get(IAgentProfileService) as { bind: ReturnType }; + expect(profile.bind).not.toHaveBeenCalled(); + }); + + it('binds the profile named by --agent-file when --agent is absent', async () => { + const dir = await mkdtemp(join(tmpdir(), 'kimi-agent-file-')); + const agentFile = join(dir, 'reviewer.md'); + await writeFile( + agentFile, + '---\nname: file-reviewer\ndescription: Reviews code.\n---\n\nYou review code.\n', + ); + const stdout = writer(); + const stderr = writer(); + const { app, agent, appServices, agentServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts({ agentFiles: [agentFile] }) as never, '1.2.3-test', { + stdout, + stderr, + }); + + const input = mocks.bootstrap.mock.calls[0]?.[0] as BootstrapInput; + expect(input.args?.agentFiles).toEqual([agentFile]); + + const sessions = appServices.get(ISessionManager) as { create: ReturnType }; + expect(sessions.create).toHaveBeenCalledWith({ + workDir: process.cwd(), + additionalDirs: undefined, + mainAgentBinding: { profile: 'file-reviewer', model: 'k2' }, + }); + const profile = agentServices.get(IAgentProfileService) as { bind: ReturnType }; + expect(profile.bind).not.toHaveBeenCalled(); + }); + + it('does not materialize a main agent after fresh profile binding fails', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, appServices } = makeFakeHarness(); + const sessions = appServices.get(ISessionManager) as { create: ReturnType }; + sessions.create.mockRejectedValueOnce(new Error('Unknown agent profile')); + mocks.bootstrap.mockReturnValue({ app }); + + await expect( + runV2Print(opts({ agent: 'missing' }) as never, '1.2.3-test', { stdout, stderr }), + ).rejects.toThrow('Unknown agent profile'); + + expect(mocks.ensureMainAgent).not.toHaveBeenCalled(); + }); + + it('fails before any turn when --agent-file is invalid', async () => { + const dir = await mkdtemp(join(tmpdir(), 'kimi-agent-file-')); + const agentFile = join(dir, 'broken.md'); + await writeFile(agentFile, '---\nname: broken\n---\n\nbody\n'); + const stdout = writer(); + const stderr = writer(); + const { app, agent, agentServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await expect( + runV2Print(opts({ agentFiles: [agentFile] }) as never, '1.2.3-test', { stdout, stderr }), + ).rejects.toThrow(/Invalid agent file/); + + const profile = agentServices.get(IAgentProfileService) as { + bind: ReturnType; + }; + expect(profile.bind).not.toHaveBeenCalled(); + }); + + it('leaves the agent files arg unset when --agentFile is empty', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + const input = mocks.bootstrap.mock.calls[0]?.[0] as BootstrapInput; + expect(input.args?.agentFiles ?? []).toEqual([]); + }); + + it('passes --agent-file paths through unresolved so the engine can expand ~', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print( + opts({ agent: 'reviewer', agentFiles: ['~/agents/reviewer.md'] }) as never, + '1.2.3-test', + { stdout, stderr }, + ); + + const input = mocks.bootstrap.mock.calls[0]?.[0] as BootstrapInput; + expect(input.args?.agentFiles).toEqual(['~/agents/reviewer.md']); + }); + + it('treats re-selecting the already-bound profile on resume as a no-op', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent, agentServices, appServices, profileState } = makeFakeHarness(); + profileState.profileName = 'reviewer'; + + const index = appServices.get(ISessionIndex) as { get: ReturnType }; + index.get.mockResolvedValue({ id: 'ses_1', cwd: process.cwd() }); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts({ session: 'ses_1', agent: 'reviewer' }) as never, '1.2.3-test', { + stdout, + stderr, + }); + + const profile = agentServices.get(IAgentProfileService) as { + bind: ReturnType; + setModel: ReturnType; + }; + expect(profile.bind).not.toHaveBeenCalled(); + expect(profile.setModel).not.toHaveBeenCalled(); + }); + + it('switches the model when resuming with the already-bound profile and an explicit model', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agent, agentServices, appServices, profileState } = makeFakeHarness(); + profileState.profileName = 'reviewer'; + + const index = appServices.get(ISessionIndex) as { get: ReturnType }; + index.get.mockResolvedValue({ id: 'ses_1', cwd: process.cwd() }); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print( + opts({ session: 'ses_1', agent: 'reviewer', model: 'new-model' }) as never, + '1.2.3-test', + { stdout, stderr }, + ); + + const profile = agentServices.get(IAgentProfileService) as { + bind: ReturnType; + setModel: ReturnType; + }; + expect(profile.bind).not.toHaveBeenCalled(); + expect(profile.setModel).toHaveBeenCalledWith('new-model'); + }); + + it('honors KIMI_DISABLE_TELEMETRY: no cloud appender and no v1 pipeline', async () => { + vi.stubEnv('KIMI_DISABLE_TELEMETRY', '1'); + const stdout = writer(); + const stderr = writer(); + const { app, appServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + const telemetry = appServices.get(ITelemetryService) as { + addAppender: ReturnType; + }; + expect(telemetry.addAppender).not.toHaveBeenCalled(); + expect(mocks.initializeTelemetry).not.toHaveBeenCalled(); + // The run itself is unaffected: the prompt still renders and cleanup runs. + expect(stdout.text()).toContain('hello world'); + expect(app.dispose).toHaveBeenCalled(); + }); + + it('initializes the v1 telemetry pipeline alongside the cloud appender', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, appServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + const telemetry = appServices.get(ITelemetryService) as { + addAppender: ReturnType; + }; + expect(telemetry.addAppender).toHaveBeenCalledTimes(1); + expect(mocks.initializeTelemetry).toHaveBeenCalledTimes(1); + expect(mocks.initializeTelemetry).toHaveBeenCalledWith({ + homeDir: resolveKimiHome(), + deviceId: 'device-1', + appName: CLI_USER_AGENT_PRODUCT, + version: '1.2.3-test', + uiMode: 'print', + model: 'k2', + endpoint: expect.any(Function), + getAccessToken: expect.any(Function), + onUnexpectedError: expect.any(Function), + }); + // The resolved session id is synced onto the v1 client so crash events and + // system metrics carry it; the sink model is reconciled too (same value + // here, since the fresh session uses the configured default). + expect(mocks.setTelemetryContext).toHaveBeenCalledWith({ sessionId: 'ses_v2' }); + expect(mocks.setTelemetryModel).toHaveBeenCalledWith('k2'); + expect(mocks.setCrashPhase).toHaveBeenCalledWith('runtime'); + expect(mocks.setCrashPhase).toHaveBeenCalledWith('shutdown'); + expect(mocks.shutdownTelemetry).toHaveBeenCalledWith({ + timeoutMs: CLI_SHUTDOWN_TIMEOUT_MS, + }); + }); + + it('reconciles the v1 sink model with the resumed session model', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, appServices, agentServices } = makeFakeHarness(); + + // The resumed session's stored model differs from the configured default. + const profile = agentServices.get(IAgentProfileService) as { getModel: () => string }; + profile.getModel = () => 'resumed-model'; + const index = appServices.get(ISessionIndex) as { get: ReturnType }; + index.get.mockResolvedValue({ id: 'ses_1', cwd: process.cwd() }); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts({ session: 'ses_1' }) as never, '1.2.3-test', { stdout, stderr }); + + // The v1 pipeline was initialized up front with the best-known model, so + // crash events during session resolution still reach a sink... + expect(mocks.initializeTelemetry).toHaveBeenCalledTimes(1); + expect(mocks.initializeTelemetry).toHaveBeenCalledWith( + expect.objectContaining({ model: 'k2' }), + ); + // ...and the sink's model was reconciled to the resumed session's real + // model only after the session resolved. + expect(mocks.setTelemetryModel).toHaveBeenCalledWith('resumed-model'); + const initOrder = mocks.initializeTelemetry.mock.invocationCallOrder[0]; + const reconcileOrder = mocks.setTelemetryModel.mock.invocationCallOrder[0]; + expect(initOrder).toBeDefined(); + expect(reconcileOrder).toBeGreaterThan(initOrder!); + }); + + it('flushes the wire journal before disposing the app', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agentServices } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + const dispatcher = agentServices.get(IEventDispatcher) as { + flush: ReturnType; + }; + expect(dispatcher.flush).toHaveBeenCalled(); + const flushOrder = dispatcher.flush.mock.invocationCallOrder[0]; + const disposeOrder = app.dispose.mock.invocationCallOrder[0]; + expect(flushOrder).toBeDefined(); + expect(disposeOrder).toBeGreaterThan(flushOrder!); + }); + + it('flushes the wire journal when the turn fails', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agentServices } = makeFakeHarness(); + + const promptService = agentServices.get(IAgentLoopService) as { + promptHandle: ReturnType; + }; + promptService.promptHandle.mockReturnValueOnce({ + launched: Promise.resolve({ + id: 1, + result: Promise.resolve({ + type: 'failed', + error: { code: 'provider.overloaded', message: 'llm request failed' }, + }), + }), + }); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await expect(runV2Print(opts() as never, '1.2.3-test', { stdout, stderr })).rejects.toThrow( + 'provider.overloaded: llm request failed', + ); + + const dispatcher = agentServices.get(IEventDispatcher) as { + flush: ReturnType; + }; + expect(dispatcher.flush).toHaveBeenCalled(); + const flushOrder = dispatcher.flush.mock.invocationCallOrder[0]; + const disposeOrder = app.dispose.mock.invocationCallOrder[0]; + expect(disposeOrder).toBeGreaterThan(flushOrder!); + }); + + it('does not let a wire flush failure mask the turn outcome', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agentServices } = makeFakeHarness(); + + const promptService = agentServices.get(IAgentLoopService) as { + promptHandle: ReturnType; + }; + promptService.promptHandle.mockReturnValueOnce({ + launched: Promise.resolve({ + id: 1, + result: Promise.resolve({ + type: 'failed', + error: { code: 'provider.overloaded', message: 'llm request failed' }, + }), + }), + }); + const dispatcher = agentServices.get(IEventDispatcher) as { + flush: ReturnType; + }; + dispatcher.flush.mockRejectedValueOnce(new Error('disk full')); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await expect(runV2Print(opts() as never, '1.2.3-test', { stdout, stderr })).rejects.toThrow( + 'provider.overloaded: llm request failed', + ); + expect(app.dispose).toHaveBeenCalled(); + }); + + it('cancels and settles the active turn before flushing on a termination signal', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, agentServices } = makeFakeHarness(); + + const order: string[] = []; + const loop = agentServices.get(IAgentLoopService) as { + snapshot: ReturnType; + cancel: ReturnType; + settled: ReturnType; + tryAcquireQuiescence: ReturnType; + }; + loop.snapshot.mockReturnValue({ + state: 'running', + activeTurnId: undefined, + activePromptId: undefined, + queue: [], + notificationCount: 0, + paused: false, + hasPendingRequests: false, + turn: undefined, + activeTraceId: undefined, + }); + loop.cancel.mockImplementation(() => { + if (!order.includes('cancel')) order.push('cancel'); + return true; + }); + loop.settled = vi.fn(async () => { + if (!order.includes('settled')) order.push('settled'); + }); + const guardDispose = vi.fn(); + loop.tryAcquireQuiescence = vi.fn(() => ({ dispose: guardDispose })); + const taskService = agentServices.get(IAgentTaskService) as { + stopAllOnExit: ReturnType; + }; + taskService.stopAllOnExit = vi.fn(async () => { + if (!order.includes('stop')) order.push('stop'); + return []; + }); + const dispatcher = agentServices.get(IEventDispatcher) as { + flush: ReturnType; + }; + dispatcher.flush = vi.fn(async () => { + order.push('flush'); + }); + + // A turn still in flight when the signal arrives: the queue snapshot reports + // the pending item, then the running prompt, then goes empty. + const promptService = agentServices.get(IAgentLoopService) as { + promptHandle: ReturnType; + snapshot: ReturnType; + cancel: ReturnType; + }; + let settleTurn!: (result: unknown) => void; + promptService.promptHandle.mockReturnValueOnce({ + launched: Promise.resolve({ + id: 1, + result: new Promise((resolve) => { + settleTurn = resolve; + }), + }), + }); + let promptPhase: 'launching' | 'active' | 'empty' = 'launching'; + promptService.snapshot = vi.fn(() => { + if (promptPhase === 'launching') { + return { + state: 'running', + activeTurnId: undefined, + activePromptId: undefined, + queue: [{ id: 'p1', message: { role: 'user', content: [] } }], + notificationCount: 0, + paused: false, + hasPendingRequests: true, + turn: undefined, + activeTraceId: undefined, + }; + } + if (promptPhase === 'active') { + return { + state: 'running', + activeTurnId: 1, + activePromptId: 'p1', + queue: [], + notificationCount: 0, + paused: false, + hasPendingRequests: false, + turn: undefined, + activeTraceId: undefined, + }; + } + return { + state: 'idle', + activeTurnId: undefined, + activePromptId: undefined, + queue: [], + notificationCount: 0, + paused: false, + hasPendingRequests: false, + turn: undefined, + activeTraceId: undefined, + }; + }); + + const handlers = new Map Promise>(); + const fakeProcess = { + once: (signal: string, handler: () => Promise) => { + handlers.set(signal, handler); + }, + off: () => {}, + exit: vi.fn((code?: number) => { + order.push(`exit:${code}`); + }), + }; + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + const run = runV2Print(opts() as never, '1.2.3-test', { + stdout, + stderr, + process: fakeProcess as never, + }); + const outcome = run.catch((error: unknown) => error); + for (let i = 0; i < 100 && !handlers.has('SIGINT'); i++) { + await new Promise((resolve) => setTimeout(resolve, 5)); + } + const onSigint = handlers.get('SIGINT')!; + settleTurn({ type: 'cancelled', steps: 0, reason: new Error('aborted') }); + const sigintRun = onSigint(); + // The flush must wait for the prompt queue to empty, even with idle loops. + for (let i = 0; i < 100 && !order.includes('settled'); i++) { + await new Promise((resolve) => setTimeout(resolve, 5)); + } + await new Promise((resolve) => setTimeout(resolve, 30)); + expect(promptService.cancel).toHaveBeenCalled(); + expect(order).toEqual(['stop', 'cancel', 'settled']); + promptPhase = 'active'; + await new Promise((resolve) => setTimeout(resolve, 30)); + expect(order).toEqual(['stop', 'cancel', 'settled']); + promptPhase = 'empty'; + await sigintRun; + + expect(order).toEqual(['stop', 'cancel', 'settled', 'flush', 'exit:130']); + // The guard taken during quiesce is only released after app.dispose(). + expect(loop.tryAcquireQuiescence).toHaveBeenCalled(); + const lastGuardRelease = guardDispose.mock.invocationCallOrder.at(-1); + const appDisposeOrder = app.dispose.mock.invocationCallOrder[0]; + expect(lastGuardRelease).toBeGreaterThan(appDisposeOrder!); + expect(await outcome).toBeInstanceOf(Error); + }); + + it('warns on stderr when workspace trust skips project-level MCP servers', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, trustState } = makeFakeHarness(); + trustState.trusted = false; + mocks.loadMcpServersDetailed.mockResolvedValue({ + servers: { + fs: { transport: 'stdio', command: 'node', args: ['server.js'] }, + api: { transport: 'http', url: 'https://example.com/mcp' }, + }, + origins: { + fs: '/tmp/project/.mcp.json', + api: '/tmp/project/.kimi-code/mcp.json', + }, + }); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + expect(stderr.text()).toContain( + 'Warning: this folder is not trusted; skipped 2 project-level MCP servers: ' + + 'api (http: https://example.com/mcp), fs (stdio: node server.js).', + ); + expect(stderr.text()).toContain('"Trust this folder"'); + // The warning is advisory only — the run itself is unaffected. + expect(stdout.text()).toContain('hello world'); + }); + + it('does not read mcp.json for the trust warning when the folder is trusted', async () => { + const stdout = writer(); + const stderr = writer(); + const { app } = makeFakeHarness(); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + expect(mocks.loadMcpServersDetailed).not.toHaveBeenCalled(); + expect(stderr.text()).not.toContain('not trusted'); + }); + + it('stays silent when untrusted but no project-level MCP servers are declared', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, trustState } = makeFakeHarness(); + trustState.trusted = false; + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + expect(mocks.loadMcpServersDetailed).toHaveBeenCalled(); + expect(stderr.text()).not.toContain('not trusted'); + }); + + it('warns for a project server that overrides a same-named user server', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, trustState } = makeFakeHarness(); + trustState.trusted = false; + mocks.loadMcpServersDetailed.mockResolvedValue({ + servers: { + github: { transport: 'stdio', command: './project-github' }, + toString: { transport: 'http', url: 'https://example.com/mcp' }, + }, + origins: { + github: '/tmp/project/.mcp.json', + toString: '/tmp/project/.kimi-code/mcp.json', + }, + }); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + expect(stderr.text()).toContain('github (stdio: ./project-github)'); + expect(stderr.text()).toContain('toString (http: https://example.com/mcp)'); + }); + + it('still runs when the trust-gated MCP probe fails', async () => { + const stdout = writer(); + const stderr = writer(); + const { app, appServices, trustState } = makeFakeHarness(); + trustState.trusted = false; + const workspaces = appServices.get(IWorkspaceInstanceManager) as { + getOrCreate: ReturnType; + }; + workspaces.getOrCreate.mockRejectedValueOnce(new Error('trust store unavailable')); + + mocks.bootstrap.mockReturnValue({ app }); + mocks.ensureMainAgent.mockResolvedValue({ agentId: 'main', generation: 1 }); + + await runV2Print(opts() as never, '1.2.3-test', { stdout, stderr }); + + expect(stdout.text()).toContain('hello world'); + }); +}); diff --git a/apps/kimi-code/test/cli/version.test.ts b/apps/kimi-code/test/cli/version.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5451262205a2dc9d7f23d6aaa00a18a5b6ff59c4 --- /dev/null +++ b/apps/kimi-code/test/cli/version.test.ts @@ -0,0 +1,26 @@ +import { readFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; + +import { describe, expect, it } from 'vitest'; + +import { + createKimiCodeUserAgent, + getHostPackageJsonPath, + getHostPackageRoot, + getVersion, +} from '#/cli/version'; + +describe('cli version helpers', () => { + it('resolves the host package manifest near apps/kimi-code and reads its version', () => { + const pkgPath = getHostPackageJsonPath(); + const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string }; + + expect(pkgPath.endsWith(join('apps', 'kimi-code', 'package.json'))).toBe(true); + expect(getHostPackageRoot()).toBe(dirname(pkgPath)); + expect(getVersion()).toBe(pkg.version); + }); + + it('builds the product user-agent for ad-hoc fetches', () => { + expect(createKimiCodeUserAgent('1.2.3')).toBe('kimi-code-cli/1.2.3'); + }); +}); diff --git a/apps/kimi-code/test/cli/vis.test.ts b/apps/kimi-code/test/cli/vis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b611e6a372a4213b1605259b06b236984706b3b6 --- /dev/null +++ b/apps/kimi-code/test/cli/vis.test.ts @@ -0,0 +1,114 @@ +/** + * `kimi vis` + * + * Verifies the CLI layer for the session visualizer: home + auto-port + * resolution, browser open vs `--no-open`, and the session deep-link path. + * Uses injected deps so no real port is bound and the real vis server is + * never started. + */ + +import { describe, it, expect, vi } from 'vitest'; + +import { handleVis, type VisDeps } from '#/cli/sub/vis'; + +function makeDeps(over: Partial = {}): { + deps: VisDeps; + opened: string[]; + out: string[]; +} { + const opened: string[] = []; + const out: string[] = []; + const deps: VisDeps = { + getHomeDir: () => '/home/k', + startVisServer: vi.fn(async (o) => ({ + port: 41234, + host: '127.0.0.1', + url: 'http://127.0.0.1:41234/', + close: async () => {}, + _opts: o, + })) as unknown as VisDeps['startVisServer'], + openUrl: async (u: string) => { + opened.push(u); + }, + waitForShutdown: async () => {}, + stdout: { + write: (s: string) => { + out.push(s); + return true; + }, + }, + stderr: { write: () => true }, + exit: vi.fn() as unknown as VisDeps['exit'], + ...over, + }; + return { deps, opened, out }; +} + +describe('handleVis', () => { + it('starts the server with the home dir + auto port and opens the browser', async () => { + const { deps, opened, out } = makeDeps(); + await handleVis(deps, { open: true }); + expect(deps.startVisServer).toHaveBeenCalledWith( + expect.objectContaining({ homeDir: '/home/k', port: 0 }), + ); + expect(opened).toEqual(['http://127.0.0.1:41234/']); + expect(out.join('')).toContain('http://127.0.0.1:41234/'); + }); + + it('does not open the browser when open is false', async () => { + const { deps, opened } = makeDeps(); + await handleVis(deps, { open: false }); + expect(opened).toEqual([]); + }); + + it('deep-links to a session when sessionId is given', async () => { + const { deps, opened } = makeDeps(); + await handleVis(deps, { open: true, sessionId: 'sess_abc' }); + expect(opened[0]).toBe('http://127.0.0.1:41234/sessions/sess_abc'); + }); + + it('uses the explicit port when provided', async () => { + const { deps } = makeDeps(); + await handleVis(deps, { open: false, port: 4321 }); + expect(deps.startVisServer).toHaveBeenCalledWith( + expect.objectContaining({ homeDir: '/home/k', port: 4321 }), + ); + }); + + it('closes the server after shutdown', async () => { + const close = vi.fn(async () => {}); + const { deps } = makeDeps({ + startVisServer: vi.fn(async () => ({ + port: 41234, + host: '127.0.0.1', + url: 'http://127.0.0.1:41234/', + close, + })) as unknown as VisDeps['startVisServer'], + }); + await handleVis(deps, { open: false }); + expect(close).toHaveBeenCalledOnce(); + }); + + it('reports a clean error and exits when the server fails to start', async () => { + const errored: string[] = []; + const { deps, opened } = makeDeps({ + startVisServer: vi.fn(async () => { + throw new Error('listen EADDRINUSE: address already in use 127.0.0.1:4321'); + }) as unknown as VisDeps['startVisServer'], + stderr: { + write: (s: string) => { + errored.push(s); + return true; + }, + }, + waitForShutdown: vi.fn(async () => {}), + }); + await handleVis(deps, { open: true, port: 4321 }); + expect(errored.join('')).toContain('Failed to start kimi vis'); + expect(errored.join('')).toContain('EADDRINUSE'); + expect(deps.exit).toHaveBeenCalledWith(1); + // Nothing past the failed start should run. + expect(opened).toEqual([]); + expect(deps.waitForShutdown).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/cli/web/remote-control.test.ts b/apps/kimi-code/test/cli/web/remote-control.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc0f8ba9c786017cf53c44de6fff63e41d038744 --- /dev/null +++ b/apps/kimi-code/test/cli/web/remote-control.test.ts @@ -0,0 +1,65 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { + formatRemoteControlOutput, + formatRemoteControlStatus, +} from '#/cli/sub/web/remote-control'; + +afterEach(() => { + vi.unstubAllEnvs(); +}); + +describe('Remote Control output', () => { + const outputOptions = { + url: 'https://example.test/devices/example-device/?rc=1&from=kimi_code_cli', + localOrigin: 'http://127.0.0.1:1234', + localServerToken: 'example-token', + deviceName: 'example-device', + qrCode: 'QR\n', + pngPath: '/tmp/example-qr.png', + }; + + it('shows the full URL as the clickable link text alongside the setup contract', () => { + vi.stubEnv('FORCE_HYPERLINK', '1'); + const output = formatRemoteControlOutput(outputOptions); + const url = outputOptions.url; + expect(output).toContain('Use Kimi Code on this machine'); + expect(output).toContain('1.'); + expect(output).toContain('2.'); + expect(output).toContain('3.'); + expect(output).toContain(`\u001B]8;;${url}`); + const plain = output + .replaceAll(/\u001B\]8;;.*?\u0007/g, '') + .replaceAll(/\u001B\[[0-9;]*m/g, ''); + expect(plain).toContain(`open ${url}`); + expect(plain).not.toContain('exampl…'); + expect(plain).toContain('http://127.0.0.1:1234/#token=example-token'); + expect(output).toContain('#token=example-token'); + expect(output).toContain('Connected to example.test'); + expect(output).toContain('This device:'); + expect(output).not.toContain('Manage devices'); + expect(output).toContain('PNG:'); + expect(output).toContain('\n QR'); + expect(output).toContain('grants control of this machine'); + expect(output).toContain('docs'); + expect(output).toContain('feedback'); + expect(output).toContain('Logs: off'); + expect(output).not.toContain('stream-1'); + }); + + it('prints the full URL as plain text when the terminal cannot render hyperlinks', () => { + vi.stubEnv('FORCE_HYPERLINK', '0'); + const output = formatRemoteControlOutput(outputOptions); + expect(output).toContain(`open ${outputOptions.url}`); + expect(output).toContain('#token=example-token'); + expect(output).not.toContain('exampl…vice'); + expect(output).not.toContain('Manage devices'); + }); + + it('formats relay and device lifecycle states', () => { + expect(formatRemoteControlStatus('relay_connected').toLowerCase()).toContain('connected'); + expect(formatRemoteControlStatus('relay_disconnected')).toContain('disconnected'); + expect(formatRemoteControlStatus('device_connected').toLowerCase()).toContain('connected'); + expect(formatRemoteControlStatus('device_disconnected')).toContain('disconnected'); + }); +}); diff --git a/apps/kimi-code/test/cli/web/web.test.ts b/apps/kimi-code/test/cli/web/web.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..816f5d7871fbdc086bd355e0dddd506c6a4f16b0 --- /dev/null +++ b/apps/kimi-code/test/cli/web/web.test.ts @@ -0,0 +1,1166 @@ +/** + * Tests for the `kimi web` Commander wiring and its subcommands. + * + * These tests don't actually start the server — the foreground runner is + * injected, so they verify option parsing, the ready banner / one-line ready + * output, browser opening, and the rotate-token / deprecated `kimi server kill` + * subcommands against fake deps. + */ + +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import chalk, { Chalk } from 'chalk'; +import { Command } from 'commander'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { resetCapabilitiesCache, setCapabilities } from '@moonshot-ai/pi-tui'; + +import { registerWebCommand } from '#/cli/sub/web'; +import type { LegacyKillDeps } from '#/cli/sub/web/legacy-kill'; +import type { WebCommandDeps } from '#/cli/sub/web/run'; +import type { ParsedServerOptions } from '#/cli/sub/web/shared'; +import { darkColors } from '#/tui/theme/colors'; + +vi.mock('node:child_process', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, spawn: vi.fn() }; +}); + +function stripAnsi(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +function makeProgram(): Command { + // `commander` exitOverride avoids killing the test runner when --help/error fires. + const program = new Command('kimi').exitOverride(); + registerWebCommand(program); + return program; +} + +type ForegroundRunner = NonNullable; + +/** + * Fake foreground runner: records the parsed options and fires `onReady` with + * a fixed origin, then returns (the real runner blocks until SIGINT/SIGTERM). + */ +function makeRunner(origin = 'http://127.0.0.1:58627'): { + runner: ForegroundRunner; + calls: { options: ParsedServerOptions | undefined }; +} { + const calls: { options: ParsedServerOptions | undefined } = { options: undefined }; + const runner: ForegroundRunner = async (options, hooks) => { + calls.options = options; + await hooks?.onReady?.(origin); + return undefined as never; + }; + return { runner, calls }; +} + +/** Capturing stdout/stderr pair for `WebCommandDeps`. */ +function makeIo(): { + stdout: Pick; + stderr: Pick; + readStdout(): string; +} { + let out = ''; + return { + stdout: { + write(chunk: string | Uint8Array) { + out += String(chunk); + return true; + }, + }, + stderr: { + write() { + return true; + }, + }, + readStdout: () => out, + }; +} + +describe('kimi web', () => { + it('registers the `web` command with only the rotate-token subcommand', () => { + const program = makeProgram(); + const web = program.commands.find((c) => c.name() === 'web'); + expect(web).toBeDefined(); + const subs = web?.commands.map((c) => c.name()).toSorted(); + // Foreground servers stop with Ctrl+C, so there is no kill/ps. + expect(subs).toEqual(['rotate-token']); + }); + + it('exposes the foreground server options on `web` itself', () => { + const program = makeProgram(); + const web = program.commands.find((c) => c.name() === 'web'); + expect(web).toBeDefined(); + const longs = web!.options.map((o) => o.long).filter(Boolean); + expect(longs).toContain('--port'); + expect(longs).toContain('--host'); + expect(longs).toContain('--allowed-host'); + expect(longs).toContain('--insecure-no-tls'); + expect(longs).toContain('--allow-remote-shutdown'); + expect(longs).toContain('--dangerous-bypass-auth'); + expect(longs).toContain('--log-level'); + expect(longs).toContain('--debug-endpoints'); + expect(longs).toContain('--web-title'); + const remoteControl = web!.options.find((option) => option.long === '--remote-control'); + expect(remoteControl?.short).toBe('--rc'); + // web opens the browser by default → the option is the negative --no-open. + expect(longs).toContain('--no-open'); + // The background/daemon era flags are gone: the server always runs in the + // foreground. + expect(longs).not.toContain('--foreground'); + expect(longs).not.toContain('--keep-alive'); + expect(longs).not.toContain('--daemon'); + expect(longs).not.toContain('--idle-grace-ms'); + expect(longs).not.toContain('--allow-remote-terminals'); + }); + + it('routes `kimi server` and any legacy subcommand to a deprecation notice', async () => { + for (const argv of [ + ['node', 'kimi', 'server'], + ['node', 'kimi', 'server', 'run', '--port', '1'], + ['node', 'kimi', 'server', 'status'], + ['node', 'kimi', 'server', 'ps', '--json'], + ]) { + const program = makeProgram(); + let stderr = ''; + const exitCalls: number[] = []; + const errSpy = vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => { + stderr += String(chunk); + return true; + }); + const exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code?: number) => { + exitCalls.push(code ?? 0); + return undefined; + }) as never); + + await program.parseAsync(argv); + errSpy.mockRestore(); + exitSpy.mockRestore(); + + expect(exitCalls).toEqual([1]); + expect(stderr).toContain('`kimi server` has been deprecated and no longer works.'); + expect(stderr).toContain('kimi web'); + expect(stderr).toContain('kimi server kill'); + expect(stderr).toContain('0.28.0'); + expect(stderr).toContain('next major version'); + } + }); +}); + +describe('`kimi web` ready banner', () => { + it('prints the TUI-style ready panel once listening', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + // The runner reports the actual bound origin — the banner must take the + // port from it, not from the requested --port. + const { runner } = makeRunner('http://127.0.0.1:58628'); + const { stdout, stderr, readStdout } = makeIo(); + + await handleWebCommand( + { port: '58627', open: false }, + { + startServerForeground: runner, + resolveToken: () => 'tok', + openUrl: vi.fn(), + stdout, + stderr, + }, + ); + + const plain = stripAnsi(readStdout()); + expect(plain).toContain('Kimi server ready'); + expect(plain).toContain('Local:'); + expect(plain).toContain('http://127.0.0.1:58628/#token=tok'); + expect(plain).toContain('Token:'); + // Loopback bind shows a Network hint for enabling network access. + expect(plain).toContain('Network:'); + expect(plain).toContain('use --host to enable'); + expect(plain).toContain('Logs:'); + expect(plain).toContain('off'); + expect(plain).toContain('Stop:'); + expect(plain).toContain('Ctrl+C'); + // No bordered panel (the token URL must print in full for copying), but + // the Kimi sprite stays next to the title. + expect(plain).not.toContain('╭'); + expect(plain).not.toContain('╰'); + expect(plain).toContain('▐█▛█▛█▌'); + expect(plain).toContain('▐█████▌'); + expect(plain).not.toContain('Kimi server:'); + + // Title is above the URLs; Logs/Stop are at the bottom. + expect(plain.indexOf('Kimi server ready')).toBeLessThan(plain.indexOf('Local:')); + expect(plain.indexOf('Logs:')).toBeLessThan(plain.indexOf('Stop:')); + }); + + it('uses the TUI dark palette for the ready banner', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr, readStdout } = makeIo(); + const previousChalkLevel = chalk.level; + chalk.level = 3; + + try { + await handleWebCommand( + { port: '58627', host: '127.0.0.1', open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + } finally { + chalk.level = previousChalkLevel; + } + + const out = readStdout(); + const color = new Chalk({ level: 3 }); + expect(out).toContain(color.hex(darkColors.primary)('▐█▛█▛█▌')); + expect(out).toContain(color.bold.hex(darkColors.primary)('Kimi server ready')); + expect(out).toContain(color.hex(darkColors.accent)('http://127.0.0.1:58627/')); + expect(out).toContain(color.bold.hex(darkColors.textDim)('Local: ')); + expect(out).toContain(color.hex(darkColors.textMuted)('off')); + }); + + it('renders the bypass danger notice in the error color', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr, readStdout } = makeIo(); + const previousChalkLevel = chalk.level; + chalk.level = 3; + + try { + await handleWebCommand( + { port: '58627', dangerousBypassAuth: true, open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + } finally { + chalk.level = previousChalkLevel; + } + + const color = new Chalk({ level: 3 }); + expect(readStdout()).toContain( + color.bold.hex(darkColors.error)( + '⚠ DANGER: authentication is DISABLED (--dangerous-bypass-auth).', + ), + ); + }); + + it('prints the danger notice and suppresses the token when auth is bypassed', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr, readStdout } = makeIo(); + const openUrl = vi.fn(); + + await handleWebCommand( + { port: '58627', host: '127.0.0.1', dangerousBypassAuth: true, open: true }, + { + startServerForeground: runner, + resolveToken: () => 'tok', + openUrl, + stdout, + stderr, + }, + ); + + const plain = stripAnsi(readStdout()); + // Red, impossible-to-miss danger notice. + expect(plain).toContain('DANGER: authentication is DISABLED'); + expect(plain).toContain('--dangerous-bypass-auth'); + expect(plain).toContain('Ctrl+C'); + // The token is irrelevant when bypassed — neither printed nor carried in + // any URL (so it cannot leak via copy/paste of the banner). + expect(plain).not.toContain('tok'); + expect(plain).not.toContain('#token='); + // The opened browser URL carries no token fragment either. + expect(openUrl).toHaveBeenCalledWith('http://127.0.0.1:58627'); + }); +}); + +describe('ready banner reflects the bind class', () => { + it('lists Local + Network addresses for a 0.0.0.0 bind (Vite-style)', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner('http://0.0.0.0:58627'); + const { stdout, stderr, readStdout } = makeIo(); + + await handleWebCommand( + { host: '0.0.0.0', open: false }, + { + startServerForeground: runner, + resolveToken: () => 'tok-xyz', + networkAddresses: [ + { address: '192.0.2.66', family: 'IPv4' }, + { address: '198.51.100.216', family: 'IPv4' }, + ], + openUrl: vi.fn(), + stdout, + stderr, + }, + ); + + const raw = stripAnsi(readStdout()); + expect(raw).toContain('Kimi server ready'); + expect(raw).toContain('Local:'); + expect(raw).toContain('Network:'); + // Full token-bearing URLs are printed plainly (no box, no truncation) so + // they are easy to copy. + expect(raw).toContain('http://localhost:58627/#token=tok-xyz'); + expect(raw).toContain('http://192.0.2.66:58627/#token=tok-xyz'); + expect(raw).toContain('http://198.51.100.216:58627/#token=tok-xyz'); + expect(raw).toContain('Token:'); + expect(raw).toContain('tok-xyz'); + expect(raw).not.toContain('╭'); + }); + + it('lists only the Local URL for a 127.0.0.1 bind', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner('http://127.0.0.1:58627'); + const { stdout, stderr, readStdout } = makeIo(); + + await handleWebCommand( + { host: '127.0.0.1', open: false }, + { + startServerForeground: runner, + resolveToken: () => 'tok-loop', + // Injected interface addresses must NOT leak into a loopback banner. + networkAddresses: [{ address: '192.0.2.66', family: 'IPv4' }], + openUrl: vi.fn(), + stdout, + stderr, + }, + ); + + const raw = stripAnsi(readStdout()); + expect(raw).toContain('Kimi server ready'); + expect(raw).toContain('Local:'); + expect(raw).toContain('http://127.0.0.1:58627/#token=tok-loop'); + expect(raw).toContain('Token:'); + expect(raw).toContain('tok-loop'); + // No network URLs on a loopback bind — just the "off" hint. + expect(raw).toContain('use --host to enable'); + expect(raw).not.toContain('Network: http'); + expect(raw).not.toContain('192.0.2.66'); + expect(raw).not.toContain('╭'); + }); +}); + +describe('`kimi web` opens the browser', () => { + afterEach(() => { + vi.unstubAllEnvs(); + resetCapabilitiesCache(); + }); + + it('opens the Web UI URL with the #token= fragment by default', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr } = makeIo(); + const openUrl = vi.fn(); + + await handleWebCommand( + { port: '58627', open: true }, + { + startServerForeground: runner, + resolveToken: () => 'tok-xyz', + openUrl, + stdout, + stderr, + }, + ); + + expect(openUrl).toHaveBeenCalledWith('http://127.0.0.1:58627/#token=tok-xyz'); + }); + + it('opens the plain origin when no token is resolvable', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr } = makeIo(); + const openUrl = vi.fn(); + + await handleWebCommand( + { port: '58627', open: true }, + { + startServerForeground: runner, + resolveToken: () => undefined, + openUrl, + stdout, + stderr, + }, + ); + + expect(openUrl).toHaveBeenCalledWith('http://127.0.0.1:58627'); + }); + + it('opens localhost rather than the wildcard bind address', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner('http://0.0.0.0:58627'); + const { stdout, stderr } = makeIo(); + const openUrl = vi.fn(); + + await handleWebCommand( + { host: '0.0.0.0', open: true }, + { + startServerForeground: runner, + resolveToken: () => 'tok-xyz', + openUrl, + stdout, + stderr, + }, + ); + + expect(openUrl).toHaveBeenCalledWith('http://localhost:58627/#token=tok-xyz'); + }); + + it('opens localhost for a wildcard IPv6 bind', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner('http://:::58627'); + const { stdout, stderr } = makeIo(); + const openUrl = vi.fn(); + + await handleWebCommand( + { host: '::', open: true }, + { + startServerForeground: runner, + resolveToken: () => undefined, + openUrl, + stdout, + stderr, + }, + ); + + expect(openUrl).toHaveBeenCalledWith('http://localhost:58627'); + }); + + it('does not open the browser when open is false', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner('http://127.0.0.1:9000'); + const { stdout, stderr } = makeIo(); + const openUrl = vi.fn(); + + await handleWebCommand( + { port: '58627', open: false }, + { startServerForeground: runner, openUrl, stdout, stderr }, + ); + + expect(openUrl).not.toHaveBeenCalled(); + }); + + it('maps --remote-control and --rc to the same option', () => { + for (const flag of ['--remote-control', '--rc']) { + const program = makeProgram(); + const web = program.commands.find((command) => command.name() === 'web')!; + web.parseOptions([flag]); + expect(web.opts()).toMatchObject({ remoteControl: true }); + } + }); + + it('rejects Remote Control on a non-loopback host', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await expect( + handleWebCommand( + { remoteControl: true, host: '0.0.0.0', open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ), + ).rejects.toThrow('--remote-control requires a loopback host.'); + }); + + it('shows --remote-control in help', () => { + const remoteControlOption = makeProgram() + .commands.find((command) => command.name() === 'web')! + .options.find((option) => option.long === '--remote-control'); + expect(remoteControlOption?.hidden).toBeFalsy(); + }); +}); + +describe('kimi rc', () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + + it('registers `rc` with the `remote` alias and the web server options, without a --remote-control flag', () => { + const program = makeProgram(); + const rc = program.commands.find((c) => c.name() === 'rc'); + expect(rc).toBeDefined(); + expect(rc!.alias()).toBe('remote'); + const longs = rc!.options.map((o) => o.long).filter(Boolean); + expect(longs).toContain('--port'); + expect(longs).toContain('--host'); + expect(longs).toContain('--no-open'); + expect(longs).not.toContain('--remote-control'); + }); + + it('shows `rc` in help', () => { + expect(makeProgram().helpInformation()).toContain('rc|remote'); + }); + + it('forces Remote Control for both `rc` and `remote`', async () => { + for (const name of ['rc', 'remote']) { + const program = makeProgram(); + let stderr = ''; + const errSpy = vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => { + stderr += String(chunk); + return true; + }); + const exitSpy = vi + .spyOn(process, 'exit') + .mockImplementation(() => undefined as never); + try { + await program.parseAsync(['node', 'kimi', name, '--host', '0.0.0.0']); + } finally { + errSpy.mockRestore(); + exitSpy.mockRestore(); + } + // The loopback check only runs when remoteControl was forced on. + expect(stderr).toContain('--remote-control requires a loopback host.'); + } + }); +}); + +describe('`kimi web` option threading', () => { + it('threads the CLI flags into the foreground runner options', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner, calls } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await handleWebCommand( + { + port: '59000', + host: '0.0.0.0', + insecureNoTls: true, + allowedHost: ['.example.com'], + dangerousBypassAuth: true, + debugEndpoints: true, + allowRemoteShutdown: true, + open: false, + }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + + expect(calls.options).toEqual({ + host: '0.0.0.0', + port: 59000, + logLevel: 'silent', + debugEndpoints: true, + insecureNoTls: true, + allowRemoteShutdown: true, + dangerousBypassAuth: true, + allowedHosts: ['.example.com'], + }); + }); + + it('defaults the host to 127.0.0.1 and insecureNoTls to true', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner, calls } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await handleWebCommand( + { port: '58627', open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + + expect(calls.options).toMatchObject({ + host: '127.0.0.1', + insecureNoTls: true, + logLevel: 'silent', + }); + }); + + it('maps a bare --host to the default LAN host', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner, calls } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await handleWebCommand( + { port: '58627', host: true, open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + + expect(calls.options).toMatchObject({ host: '0.0.0.0', insecureNoTls: true }); + }); + + it('passes --log-level through to the runner', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner, calls } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await handleWebCommand( + { port: '58627', logLevel: 'debug', open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + + expect(calls.options).toMatchObject({ logLevel: 'debug' }); + }); + + it('passes --web-title through to the runner', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner, calls } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await handleWebCommand( + { port: '58627', webTitle: 'My Dev Box', open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + + expect(calls.options).toMatchObject({ webTitle: 'My Dev Box' }); + }); + + it('leaves webTitle undefined when --web-title is not passed', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner, calls } = makeRunner(); + const { stdout, stderr } = makeIo(); + + await handleWebCommand( + { port: '58627', open: false }, + { startServerForeground: runner, openUrl: vi.fn(), stdout, stderr }, + ); + + expect(calls.options?.webTitle).toBeUndefined(); + }); + + it('rejects an invalid --log-level before calling the runner', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const startServerForeground = vi.fn(async () => undefined as never); + const { stdout, stderr } = makeIo(); + + await expect( + handleWebCommand( + { logLevel: 'shout', open: false }, + { startServerForeground, openUrl: vi.fn(), stdout, stderr }, + ), + ).rejects.toThrow(/invalid --log-level/); + expect(startServerForeground).not.toHaveBeenCalled(); + }); + + it('prints the one-line ready line instead of the full banner with a non-default --log-level', async () => { + const { handleWebCommand } = await import('#/cli/sub/web/run'); + const { runner } = makeRunner(); + const { stdout, stderr, readStdout } = makeIo(); + + await handleWebCommand( + { port: '58627', logLevel: 'info', open: false }, + { + startServerForeground: runner, + resolveToken: () => 'tok', + openUrl: vi.fn(), + stdout, + stderr, + }, + ); + + const plain = stripAnsi(readStdout()); + expect(plain).toContain('Kimi server: http://127.0.0.1:58627/#token=tok'); + expect(plain).not.toContain('Kimi server ready'); + expect(plain).not.toContain('Local:'); + }); + + it('parses comma-separated --allowed-host values', async () => { + const { parseAllowedHostArgs } = await import('#/cli/sub/web/shared'); + expect(parseAllowedHostArgs(['.example.com, app.example.com'])).toEqual([ + '.example.com', + 'app.example.com', + ]); + }); +}); + +describe('shared parsers stay strict', () => { + it('rejects out-of-range --port', async () => { + const { parsePort } = await import('#/cli/sub/web/shared'); + expect(() => parsePort('99999', '--port', 58627)).toThrow(/invalid --port/); + expect(() => parsePort('-1', '--port', 58627)).toThrow(/invalid --port/); + expect(parsePort(undefined, '--port', 58627)).toBe(58627); + expect(parsePort('8080', '--port', 58627)).toBe(8080); + }); + + it('rejects unknown --log-level values', async () => { + const { parseLogLevel } = await import('#/cli/sub/web/shared'); + expect(() => parseLogLevel('shout')).toThrow(/invalid --log-level/); + expect(parseLogLevel(undefined)).toBe('info'); + expect(parseLogLevel('debug')).toBe('debug'); + }); +}); + +describe('server web asset directory resolution', () => { + it('uses extracted SEA web assets when available', async () => { + const { resolveServerWebAssetsDir } = await import('#/cli/sub/web/run'); + expect(resolveServerWebAssetsDir('/cache/kimi/dist-web')).toBe('/cache/kimi/dist-web'); + }); + + it('falls back to package dist-web outside SEA mode', async () => { + const { resolveServerWebAssetsDir } = await import('#/cli/sub/web/run'); + expect(resolveServerWebAssetsDir(null)).toMatch(/[/\\]dist-web$/); + }); + + it('returns the assets dir when it is built, dev mode or not', async () => { + const { serverWebAssetsDir } = await import('#/cli/sub/web/run'); + const dir = mkdtempSync(join(tmpdir(), 'kimi-web-assets-')); + try { + writeFileSync(join(dir, 'index.html'), ''); + expect(serverWebAssetsDir({}, dir)).toBe(dir); + expect(serverWebAssetsDir({ KIMI_CODE_DEV_SERVER: '1' }, dir)).toBe(dir); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('requires built assets outside dev mode', async () => { + const { serverWebAssetsDir } = await import('#/cli/sub/web/run'); + const dir = mkdtempSync(join(tmpdir(), 'kimi-web-assets-')); + try { + expect(serverWebAssetsDir({}, dir)).toBe(dir); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('tolerates missing assets in dev mode (API-only server)', async () => { + const { serverWebAssetsDir } = await import('#/cli/sub/web/run'); + const dir = mkdtempSync(join(tmpdir(), 'kimi-web-assets-')); + try { + expect(serverWebAssetsDir({ KIMI_CODE_DEV_SERVER: '1' }, dir)).toBeUndefined(); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +}); + +function makeLegacyKillDeps(overrides: Partial = {}): { + deps: LegacyKillDeps; + writes: string[]; + errors: string[]; + signals: Array<{ pid: number; signal: NodeJS.Signals }>; + state: { shutdownCalls: number; removeCalls: number }; + clock: { t: number }; +} { + const writes: string[] = []; + const errors: string[] = []; + const signals: Array<{ pid: number; signal: NodeJS.Signals }> = []; + const state = { shutdownCalls: 0, removeCalls: 0 }; + const clock = { t: 0 }; + const deps: LegacyKillDeps = { + readLock: async () => undefined, + removeLock: async () => { + state.removeCalls += 1; + }, + requestShutdown: async () => { + state.shutdownCalls += 1; + }, + resolveToken: () => undefined, + signalPid: (pid, signal) => { + signals.push({ pid, signal }); + return true; + }, + pidAlive: () => false, + sleep: async (ms) => { + clock.t += ms; + }, + stdout: { + write(chunk: string | Uint8Array) { + writes.push(String(chunk)); + return true; + }, + }, + stderr: { + write(chunk: string | Uint8Array) { + errors.push(String(chunk)); + return true; + }, + }, + now: () => clock.t, + ...overrides, + }; + return { deps, writes, errors, signals, state, clock }; +} + +describe('`kimi server kill` (deprecated, legacy servers only)', () => { + const legacyLock = { pid: 1234, host: '127.0.0.1', port: 58627 }; + + it('is registered as the only working subcommand of the deprecated `server` command', () => { + const program = makeProgram(); + const server = program.commands.find((c) => c.name() === 'server'); + expect(server).toBeDefined(); + expect(server?.commands.map((c) => c.name())).toEqual(['kill']); + }); + + it('prints a deprecation notice naming the 0.28.0 cutoff on every run', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps, errors } = makeLegacyKillDeps(); + + await handleLegacyKillCommand(deps); + + const notice = errors.join(''); + expect(notice).toContain('deprecated'); + expect(notice).toContain('0.28.0'); + expect(notice).toContain('Ctrl+C'); + }); + + it('prints "No running legacy Kimi server." and sends no signal when no lock exists', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps, writes, signals } = makeLegacyKillDeps({ readLock: async () => undefined }); + + await handleLegacyKillCommand(deps); + + expect(writes.join('')).toContain('No running legacy Kimi server.'); + expect(signals).toEqual([]); + }); + + it('sweeps a stale lock whose pid is already dead', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps, writes, signals, state } = makeLegacyKillDeps({ + readLock: async () => legacyLock, + pidAlive: () => false, + }); + + await handleLegacyKillCommand(deps); + + expect(writes.join('')).toContain('No running legacy Kimi server.'); + expect(signals).toEqual([]); + expect(state.shutdownCalls).toBe(0); + expect(state.removeCalls).toBe(1); + }); + + it('attempts the API shutdown, then stops after SIGTERM when the pid exits promptly', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps, writes, signals, state, clock } = makeLegacyKillDeps({ + readLock: async () => legacyLock, + pidAlive: () => clock.t < 50, + }); + + await handleLegacyKillCommand(deps); + + expect(state.shutdownCalls).toBe(1); + expect(signals).toEqual([{ pid: 1234, signal: 'SIGTERM' }]); + expect(writes.join('')).toContain('pid 1234'); + expect(writes.join('')).toContain('stopped.'); + // The lock is removed once the pid is confirmed dead. + expect(state.removeCalls).toBe(1); + }); + + it('escalates to SIGKILL when the pid survives SIGTERM', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps, writes, signals, clock } = makeLegacyKillDeps({ + readLock: async () => ({ ...legacyLock, pid: 5678 }), + // Survives the 3s SIGTERM grace, dies during the 2s SIGKILL grace. + pidAlive: () => clock.t < 3100, + }); + + await handleLegacyKillCommand(deps); + + expect(signals.map((s) => s.signal)).toEqual(['SIGTERM', 'SIGKILL']); + expect(writes.join('')).toContain('pid 5678'); + expect(writes.join('')).toContain('killed.'); + }); + + it('throws a permissions error when the pid survives SIGKILL', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps } = makeLegacyKillDeps({ + readLock: async () => ({ ...legacyLock, pid: 9999 }), + pidAlive: () => true, + }); + + await expect(handleLegacyKillCommand(deps)).rejects.toThrow(/insufficient permissions/); + }); + + it('skips the API path when the lock records no port', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + const { deps, signals, state, clock } = makeLegacyKillDeps({ + readLock: async () => ({ pid: 1234 }), + // Alive at the initial check, dead when the SIGTERM grace polls. + pidAlive: () => clock.t < 50, + }); + + await handleLegacyKillCommand(deps); + + expect(state.shutdownCalls).toBe(0); + expect(signals).toEqual([{ pid: 1234, signal: 'SIGTERM' }]); + }); + + it('passes the resolved token to requestShutdown', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + let seenToken: string | undefined = 'unset'; + const { deps, clock } = makeLegacyKillDeps({ + readLock: async () => legacyLock, + resolveToken: () => 'tok-123', + requestShutdown: async (_origin, token) => { + seenToken = token; + }, + pidAlive: () => clock.t < 50, + }); + + await handleLegacyKillCommand(deps); + + expect(seenToken).toBe('tok-123'); + }); + + it('passes undefined when the token cannot be read (best-effort)', async () => { + const { handleLegacyKillCommand } = await import('#/cli/sub/web/legacy-kill'); + let seenToken: string | undefined = 'unset'; + const { deps, clock } = makeLegacyKillDeps({ + readLock: async () => legacyLock, + resolveToken: () => undefined, + requestShutdown: async (_origin, token) => { + seenToken = token; + }, + pidAlive: () => clock.t < 50, + }); + + await handleLegacyKillCommand(deps); + + expect(seenToken).toBeUndefined(); + }); +}); + +describe('readLegacyLock', () => { + let dir: string; + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-legacy-lock-')); + }); + afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + }); + + it('parses a lock written by an old build', async () => { + const { readLegacyLock } = await import('#/cli/sub/web/legacy-kill'); + const lockPath = join(dir, 'lock'); + writeFileSync( + lockPath, + JSON.stringify({ pid: 1234, started_at: '2026-01-01T00:00:00.000Z', port: 58627 }), + ); + + await expect(readLegacyLock(lockPath)).resolves.toEqual({ + pid: 1234, + host: undefined, + port: 58627, + }); + }); + + it('rejects a corrupt lock whose pid is not a positive integer', async () => { + const { readLegacyLock } = await import('#/cli/sub/web/legacy-kill'); + const lockPath = join(dir, 'lock'); + // pid 0 / negative pids have process-group semantics on POSIX — the lock + // must be treated as unusable rather than signaled. + for (const pid of [0, -1, 1.5, '1234']) { + writeFileSync(lockPath, JSON.stringify({ pid, port: 58627 })); + await expect(readLegacyLock(lockPath)).resolves.toBeUndefined(); + } + }); + + it('returns undefined when the lock file is missing or unparseable', async () => { + const { readLegacyLock } = await import('#/cli/sub/web/legacy-kill'); + await expect(readLegacyLock(join(dir, 'missing'))).resolves.toBeUndefined(); + const lockPath = join(dir, 'lock'); + writeFileSync(lockPath, 'not json'); + await expect(readLegacyLock(lockPath)).resolves.toBeUndefined(); + }); +}); + +describe('resolveServerToken', () => { + let dir: string; + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-server-token-')); + }); + afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + }); + + it('reads the token from /server.token', async () => { + const { resolveServerToken } = await import('#/cli/sub/web/shared'); + writeFileSync(join(dir, 'server.token'), 'secret-token\n'); + expect(resolveServerToken(dir)).toBe('secret-token'); + }); + + it('trims surrounding whitespace', async () => { + const { resolveServerToken } = await import('#/cli/sub/web/shared'); + writeFileSync(join(dir, 'server.token'), ' tok \n'); + expect(resolveServerToken(dir)).toBe('tok'); + }); + + it('throws a clear error when the token file is missing', async () => { + const { resolveServerToken } = await import('#/cli/sub/web/shared'); + expect(() => resolveServerToken(dir)).toThrow(/unable to read server token/); + }); +}); + +describe('authHeaders', () => { + it('builds a Bearer Authorization header', async () => { + const { authHeaders } = await import('#/cli/sub/web/shared'); + expect(authHeaders('abc')).toEqual({ Authorization: 'Bearer abc' }); + }); +}); + +describe('buildWebUrl', () => { + it('carries the token in the URL fragment (not path or query)', async () => { + const { buildWebUrl } = await import('#/cli/sub/web/run'); + const url = buildWebUrl('http://127.0.0.1:58627', 'abc123'); + expect(url).toBe('http://127.0.0.1:58627/#token=abc123'); + const parsed = new URL(url); + expect(parsed.hash).toBe('#token=abc123'); + // The token is client-side only: it must NOT appear in the path or query + // (which WOULD be sent to the server and logged). + expect(parsed.pathname).not.toContain('abc123'); + expect(parsed.search).not.toContain('abc123'); + }); + + it('normalizes a trailing slash', async () => { + const { buildWebUrl } = await import('#/cli/sub/web/run'); + expect(buildWebUrl('http://127.0.0.1:58627/', 't')).toBe( + 'http://127.0.0.1:58627/#token=t', + ); + }); +}); + +describe('accessUrlLines', () => { + it('returns Local + Network lines for a wildcard bind', async () => { + const { accessUrlLines } = await import('#/cli/sub/web/access-urls'); + const lines = accessUrlLines('0.0.0.0', 58627, 'tok', [ + { address: '192.168.1.5', family: 'IPv4' }, + ]); + expect(lines).toEqual([ + { label: 'Local: ', url: 'http://localhost:58627/#token=tok' }, + { label: 'Network: ', url: 'http://192.168.1.5:58627/#token=tok' }, + ]); + }); + + it('returns a single Local line for a loopback bind', async () => { + const { accessUrlLines } = await import('#/cli/sub/web/access-urls'); + const lines = accessUrlLines('127.0.0.1', 58627, 'tok'); + expect(lines).toEqual([ + { label: 'Local: ', url: 'http://127.0.0.1:58627/#token=tok' }, + ]); + }); + + it('returns a single URL line for a specific host (no token)', async () => { + const { accessUrlLines } = await import('#/cli/sub/web/access-urls'); + const lines = accessUrlLines('192.168.1.5', 58627, undefined); + expect(lines).toEqual([{ label: 'URL: ', url: 'http://192.168.1.5:58627/' }]); + }); + + it('splitTokenFragment splits off the #token= fragment', async () => { + const { splitTokenFragment } = await import('#/cli/sub/web/access-urls'); + expect(splitTokenFragment('http://h:1/#token=abc')).toEqual(['http://h:1/', '#token=abc']); + expect(splitTokenFragment('http://h:1/')).toEqual(['http://h:1/', '']); + }); +}); + +describe('browserOpenOrigin', () => { + it('rewrites wildcard bind hosts to localhost on the same port', async () => { + const { browserOpenOrigin } = await import('#/cli/sub/web/access-urls'); + expect(browserOpenOrigin('http://0.0.0.0:58627')).toBe('http://localhost:58627'); + expect(browserOpenOrigin('http://:::58627')).toBe('http://localhost:58627'); + }); + + it('keeps navigable origins unchanged', async () => { + const { browserOpenOrigin } = await import('#/cli/sub/web/access-urls'); + expect(browserOpenOrigin('http://127.0.0.1:58627')).toBe('http://127.0.0.1:58627'); + expect(browserOpenOrigin('http://192.168.1.5:58627')).toBe('http://192.168.1.5:58627'); + expect(browserOpenOrigin('http://[::1]:58627')).toBe('http://[::1]:58627'); + }); +}); + +describe('`kimi web rotate-token`', () => { + let dir: string; + let prevHome: string | undefined; + + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-rotate-')); + prevHome = process.env['KIMI_CODE_HOME']; + process.env['KIMI_CODE_HOME'] = dir; + vi.resetModules(); + }); + + afterEach(() => { + if (prevHome === undefined) { + delete process.env['KIMI_CODE_HOME']; + } else { + process.env['KIMI_CODE_HOME'] = prevHome; + } + rmSync(dir, { recursive: true, force: true }); + }); + + it('writes a new token to server.token and prints it', async () => { + const { registerWebCommand } = await import('#/cli/sub/web'); + const program = new Command('kimi').exitOverride(); + registerWebCommand(program); + let stdout = ''; + const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => { + stdout += String(chunk); + return true; + }); + + await program.parseAsync(['node', 'kimi', 'web', 'rotate-token']); + writeSpy.mockRestore(); + + const token = readFileSync(join(dir, 'server.token'), 'utf8').trim(); + expect(token.length).toBeGreaterThan(20); + expect(stdout).toContain('New server token'); + expect(stdout).toContain(token); + }); + + it('re-prints the access links with the new token when a server is running', async () => { + const { registerWebCommand } = await import('#/cli/sub/web'); + const { mkdirSync, writeFileSync: writeSync } = await import('node:fs'); + // Fake a live instance-registry entry pointing at this (alive) process so + // getLiveServerInstance() finds the running server and the command can + // re-print its links. + mkdirSync(join(dir, 'server', 'instances'), { recursive: true }); + writeSync( + join(dir, 'server', 'instances', '01JTEST0000000000000000000.json'), + JSON.stringify({ + server_id: '01JTEST0000000000000000000', + pid: process.pid, + host: '127.0.0.1', + port: 58627, + started_at: Date.now(), + heartbeat_at: Date.now(), + }), + ); + + const program = new Command('kimi').exitOverride(); + registerWebCommand(program); + let stdout = ''; + const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => { + stdout += String(chunk); + return true; + }); + + await program.parseAsync(['node', 'kimi', 'web', 'rotate-token']); + writeSpy.mockRestore(); + + const token = readFileSync(join(dir, 'server.token'), 'utf8').trim(); + expect(stdout).toContain('New server token'); + expect(stdout).toContain(`http://127.0.0.1:58627/#token=${token}`); + // Token line sits between the note and the links. + expect(stdout.indexOf('picks up the new token')).toBeLessThan( + stdout.indexOf('New server token'), + ); + expect(stdout.indexOf('New server token')).toBeLessThan( + stdout.indexOf(`http://127.0.0.1:58627/#token=${token}`), + ); + }); +}); + +describe('formatHostForUrl', () => { + it('bracket-wraps IPv6 and leaves IPv4 as-is', async () => { + const { formatHostForUrl } = await import('#/cli/sub/web/networks'); + expect(formatHostForUrl('192.168.1.5', 'IPv4')).toBe('192.168.1.5'); + expect(formatHostForUrl('fe80::1', 'IPv6')).toBe('[fe80::1]'); + }); +}); + +describe('filterDisplayAddresses', () => { + it('drops IPv6 link-local, de-duplicates, and orders IPv4 before IPv6', async () => { + const { filterDisplayAddresses } = await import('#/cli/sub/web/networks'); + const out = filterDisplayAddresses([ + { address: 'fe80::ecf3:c2ff:fe9c:11c3', family: 'IPv6' }, + { address: '192.168.1.5', family: 'IPv4' }, + { address: 'fe80::ecf3:c2ff:fe9c:11c3', family: 'IPv6' }, + { address: '10.0.0.1', family: 'IPv4' }, + { address: 'fe80::1', family: 'IPv6' }, + { address: '2001:db8::1', family: 'IPv6' }, + ]); + expect(out).toEqual([ + { address: '192.168.1.5', family: 'IPv4' }, + { address: '10.0.0.1', family: 'IPv4' }, + { address: '2001:db8::1', family: 'IPv6' }, + ]); + }); +}); diff --git a/apps/kimi-code/test/e2e/local-logging-export.e2e.test.ts b/apps/kimi-code/test/e2e/local-logging-export.e2e.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d89bbde2ebe445cd721e700df44b40e2f9997cb0 --- /dev/null +++ b/apps/kimi-code/test/e2e/local-logging-export.e2e.test.ts @@ -0,0 +1,158 @@ +import { readFile, mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import * as zlib from 'node:zlib'; + +import { Command } from 'commander'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { registerExportCommand } from '#/cli/sub/export'; +import { createKimiCodeHostIdentity } from '#/cli/version'; +import { createKimiHarness } from '@moonshot-ai/kimi-code-sdk'; + +const GLOBAL_LOG = 'logs/global/kimi-code.log'; +const MAIN_WIRE = 'agents/main/wire.jsonl'; +const ENABLED = process.env['KIMI_E2E'] === '1'; + +let homeDir: string; +let workDir: string; +let oldHome: string | undefined; +let oldLogLevel: string | undefined; + +beforeEach(async () => { + homeDir = await mkdtemp(join(tmpdir(), 'kimi-cli-log-home-')); + workDir = await mkdtemp(join(tmpdir(), 'kimi-cli-log-work-')); + oldHome = process.env['KIMI_CODE_HOME']; + oldLogLevel = process.env['KIMI_LOG_LEVEL']; + process.env['KIMI_CODE_HOME'] = homeDir; + process.env['KIMI_LOG_LEVEL'] = 'info'; +}); + +afterEach(async () => { + if (oldHome === undefined) { + delete process.env['KIMI_CODE_HOME']; + } else { + process.env['KIMI_CODE_HOME'] = oldHome; + } + if (oldLogLevel === undefined) { + delete process.env['KIMI_LOG_LEVEL']; + } else { + process.env['KIMI_LOG_LEVEL'] = oldLogLevel; + } + await rm(homeDir, { recursive: true, force: true }); + await rm(workDir, { recursive: true, force: true }); +}); + +describe.skipIf(!ENABLED)('local logging export e2e', () => { + it('exports the main wire and global log by default, and allows skipping global log', async () => { + const harness = createKimiHarness({ + homeDir, + identity: createKimiCodeHostIdentity('0.1.1'), + }); + try { + await harness.setConfig({ + providers: { + local: { + type: 'openai', + baseUrl: 'https://model.example.test/v1', + apiKey: 'sk-test', + }, + }, + models: { + 'fake-model': { + provider: 'local', + model: 'fake-model', + maxContextSize: 262144, + }, + }, + defaultModel: 'fake-model', + }); + const session = await harness.createSession({ + id: 'ses_cli_logging_export', + workDir, + model: 'fake-model', + }); + + const defaultZip = join(workDir, 'default.zip'); + await runKimiExport([session.id, '-o', defaultZip]); + const defaultEntries = readZipEntries(await readFile(defaultZip)); + expect(defaultEntries.has(MAIN_WIRE)).toBe(true); + expect(defaultEntries.has(GLOBAL_LOG)).toBe(true); + expect(defaultEntries.get(GLOBAL_LOG)!.toString('utf-8').length).toBeGreaterThan(0); + const defaultManifest = JSON.parse( + defaultEntries.get('manifest.json')!.toString('utf-8'), + ) as Record; + expect(defaultManifest['globalLogPath']).toBe(GLOBAL_LOG); + + const noGlobalZip = join(workDir, 'no-global.zip'); + await runKimiExport([session.id, '-o', noGlobalZip, '--no-include-global-log']); + const noGlobalEntries = readZipEntries(await readFile(noGlobalZip)); + expect(noGlobalEntries.has(GLOBAL_LOG)).toBe(false); + const noGlobalManifest = JSON.parse( + noGlobalEntries.get('manifest.json')!.toString('utf-8'), + ) as Record; + expect(noGlobalManifest['globalLogPath']).toBeUndefined(); + } finally { + await harness.close().catch(() => {}); + } + }, 15_000); +}); + +async function runKimiExport(args: string[]): Promise { + const program = new Command('kimi'); + const stdout: string[] = []; + const stderr: string[] = []; + registerExportCommand(program, { + stdout: { + write: (chunk) => { + stdout.push(chunk); + return true; + }, + }, + stderr: { + write: (chunk) => { + stderr.push(chunk); + return true; + }, + }, + exit: (code: number): never => { + throw new Error(`kimi export exited ${code}: ${stderr.join('')}`); + }, + }); + await program.parseAsync(['node', 'kimi', 'export', ...args]); +} + +function readZipEntries(buf: Buffer): Map { + let eocd = -1; + for (let i = buf.length - 22; i >= Math.max(0, buf.length - 65_557); i--) { + if (buf.readUInt32LE(i) === 0x06054b50) { + eocd = i; + break; + } + } + if (eocd === -1) throw new Error('zip eocd not found'); + const entryCount = buf.readUInt16LE(eocd + 10); + const cdOffset = buf.readUInt32LE(eocd + 16); + const entries = new Map(); + let pos = cdOffset; + for (let i = 0; i < entryCount; i++) { + if (buf.readUInt32LE(pos) !== 0x02014b50) throw new Error('bad cd entry'); + const method = buf.readUInt16LE(pos + 10); + const compressedSize = buf.readUInt32LE(pos + 20); + const fnameLen = buf.readUInt16LE(pos + 28); + const extraLen = buf.readUInt16LE(pos + 30); + const commentLen = buf.readUInt16LE(pos + 32); + const lfhOffset = buf.readUInt32LE(pos + 42); + const filename = buf.toString('utf8', pos + 46, pos + 46 + fnameLen); + if (buf.readUInt32LE(lfhOffset) !== 0x04034b50) throw new Error('bad lfh'); + const lfhFnameLen = buf.readUInt16LE(lfhOffset + 26); + const lfhExtraLen = buf.readUInt16LE(lfhOffset + 28); + const dataStart = lfhOffset + 30 + lfhFnameLen + lfhExtraLen; + const compressed = buf.subarray(dataStart, dataStart + compressedSize); + const data = method === 0 ? compressed : method === 8 ? zlib.inflateRawSync(compressed) : null; + if (data === null) throw new Error('unsupported compression'); + entries.set(filename, data); + pos += 46 + fnameLen + extraLen + commentLen; + } + return entries; +} diff --git a/apps/kimi-code/test/e2e/real-llm-smoke.e2e.test.ts b/apps/kimi-code/test/e2e/real-llm-smoke.e2e.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b31faefd084034d4360a1ceaab8d48df43cc291f --- /dev/null +++ b/apps/kimi-code/test/e2e/real-llm-smoke.e2e.test.ts @@ -0,0 +1,81 @@ +/** + * Real-LLM smoke. Opt-in only — runs when `KIMI_E2E_REAL=1` is set, so + * `make test` / CI never touches the network. Goes through the SDK's + * `KimiHarness` entry and round-trips one real prompt. Requires provider + * credentials on disk. + * + * Env knobs: + * KIMI_E2E_REAL — set to "1" to enable this suite + * KIMI_E2E_MODEL — model alias override (default: config's default) + * KIMI_E2E_PROMPT — prompt text (default: "Reply with a single word: hi") + * KIMI_E2E_WORKDIR — workspace directory (default: /tmp/kimi-e2e) + */ + +import { mkdirSync } from 'node:fs'; +import process from 'node:process'; + +import { createKimiHarness, type Event } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, test } from 'vitest'; + +import { createKimiCodeHostIdentity, getVersion } from '#/cli/version'; + +const DEFAULT_PROMPT = 'Reply with a single word: hi'; +const DEFAULT_WORKDIR = '/tmp/kimi-e2e'; +const TURN_TIMEOUT_MS = 60_000; + +const ENABLED = process.env['KIMI_E2E_REAL'] === '1'; +type TurnEndedEvent = Extract; + +describe.skipIf(!ENABLED)('SDK e2e — real LLM smoke', () => { + test( + 'round-trips a single prompt through KimiHarness', + async () => { + const workDir = process.env['KIMI_E2E_WORKDIR'] ?? DEFAULT_WORKDIR; + const prompt = process.env['KIMI_E2E_PROMPT'] ?? DEFAULT_PROMPT; + const modelAlias = process.env['KIMI_E2E_MODEL']; + mkdirSync(workDir, { recursive: true }); + + const version = getVersion(); + process.stderr.write( + `[smoke] workDir=${workDir}${modelAlias !== undefined ? ` model=${modelAlias}` : ''}\n` + + `[smoke] prompt=${JSON.stringify(prompt)}\n`, + ); + + const harness = createKimiHarness({ + identity: createKimiCodeHostIdentity(version), + }); + + try { + const session = await harness.createSession({ + workDir, + model: modelAlias, + }); + process.stderr.write(`[smoke] session created: ${session.id}\n`); + + const turnEnded = new Promise((resolve) => { + const off = session.onEvent((event) => { + const payload = JSON.stringify(event).slice(0, 500); + process.stdout.write(`[smoke][event:${event.type}] ${payload}\n`); + if (event.type === 'turn.ended') { + off(); + resolve(event); + } + }); + }); + + await session.prompt(prompt); + process.stderr.write('[smoke] prompt dispatched\n'); + + const event = await turnEnded; + process.stderr.write(`[smoke] turn.ended reason=${event.reason}\n`); + if (event.error !== undefined) { + process.stderr.write(`[smoke] error=${event.error.message}\n`); + } + expect(event.reason).toBe('completed'); + } finally { + await harness.close().catch(() => {}); + } + }, + TURN_TIMEOUT_MS + 10_000, + ); +}); diff --git a/apps/kimi-code/test/feedback/codebase-upload/codebase-upload.test.ts b/apps/kimi-code/test/feedback/codebase-upload/codebase-upload.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8903d162689b300f822d7e9ab1b7cf77987971da --- /dev/null +++ b/apps/kimi-code/test/feedback/codebase-upload/codebase-upload.test.ts @@ -0,0 +1,406 @@ +import { execFile } from 'node:child_process'; +import { randomBytes } from 'node:crypto'; +import { mkdtemp, mkdir, rm, stat, utimes, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { promisify } from 'node:util'; + +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { removeStaleFeedbackUploads } from '../../../src/feedback/archive'; +import { packageCodebase, scanCodebase } from '../../../src/feedback/codebase'; +import { uploadArchive } from '../../../src/feedback/upload'; + +const execFileAsync = promisify(execFile); + +afterEach(() => { + vi.unstubAllGlobals(); + vi.useRealTimers(); +}); + +describe('uploadArchive', () => { + it('requests upload parts, PUTs each part, and completes with etags', async () => { + const workRoot = await mkdtemp(join(tmpdir(), 'feedback-upload-direct-')); + const archivePath = join(workRoot, 'repo.zip'); + await writeFile(archivePath, 'hello'); + + const fetchMock = vi.fn( + async () => new Response('', { status: 200, headers: { ETag: '"etag-1"' } }), + ); + vi.stubGlobal('fetch', fetchMock); + const api = { + createUploadUrl: vi.fn(async () => ({ + uploadId: 28, + parts: [{ partNumber: 1, url: 'https://example.test/part1', method: 'PUT', size: 5 }], + })), + completeUpload: vi.fn(async () => {}), + }; + + try { + await uploadArchive( + api, + { + path: archivePath, + size: 5, + sha256: 'hash', + fingerprint: 'fingerprint', + fileCount: 1, + }, + 3, + { filename: 'repo.zip' }, + ); + + expect(api.createUploadUrl).toHaveBeenCalledWith({ + feedbackId: 3, + filename: 'repo.zip', + size: 5, + sha256: 'hash', + }); + expect(fetchMock).toHaveBeenCalledOnce(); + const [url, init] = fetchMock.mock.calls[0] as unknown as [string, RequestInit]; + expect(url).toBe('https://example.test/part1'); + expect(init.method).toBe('PUT'); + expect(init.body).toBeInstanceOf(ReadableStream); + expect((init as { duplex?: string }).duplex).toBe('half'); + expect(new Headers(init.headers).get('content-length')).toBe('5'); + // Drain the stream so the underlying file handle is released. + expect(await new Response(init.body as ReadableStream).text()).toBe('hello'); + expect(api.completeUpload).toHaveBeenCalledWith({ + uploadId: 28, + parts: [{ partNumber: 1, etag: '"etag-1"' }], + }); + } finally { + await rm(workRoot, { recursive: true, force: true }); + } + }); + + it('uses the backend-provided part upload method', async () => { + const workRoot = await mkdtemp(join(tmpdir(), 'feedback-upload-method-')); + const archivePath = join(workRoot, 'repo.zip'); + await writeFile(archivePath, 'hello'); + + const fetchMock = vi.fn( + async () => new Response('', { status: 200, headers: { ETag: '"etag-1"' } }), + ); + vi.stubGlobal('fetch', fetchMock); + const api = { + createUploadUrl: vi.fn(async () => ({ + uploadId: 28, + parts: [{ partNumber: 1, url: 'https://example.test/part1', method: 'POST', size: 5 }], + })), + completeUpload: vi.fn(async () => {}), + }; + + try { + await uploadArchive( + api, + { + path: archivePath, + size: 5, + sha256: 'hash', + fingerprint: 'fingerprint', + fileCount: 1, + }, + 3, + { filename: 'repo.zip' }, + ); + + const [, init] = fetchMock.mock.calls[0] as unknown as [string, RequestInit]; + expect(init.method).toBe('POST'); + expect(await new Response(init.body as ReadableStream).text()).toBe('hello'); + } finally { + await rm(workRoot, { recursive: true, force: true }); + } + }); + + it('aborts a stalled part PUT and does not mark upload complete', async () => { + const workRoot = await mkdtemp(join(tmpdir(), 'feedback-upload-stalled-')); + const archivePath = join(workRoot, 'repo.zip'); + await writeFile(archivePath, 'hello'); + + const fetchMock = vi.fn((_url: string, init?: RequestInit) => + new Promise((_resolve, reject) => { + const signal = init?.signal; + if (signal?.aborted) { + reject(Object.assign(new Error('aborted'), { name: 'AbortError' })); + return; + } + signal?.addEventListener( + 'abort', + () => { + reject(Object.assign(new Error('aborted'), { name: 'AbortError' })); + }, + { once: true }, + ); + }), + ); + vi.stubGlobal('fetch', fetchMock); + const api = { + createUploadUrl: vi.fn(async () => ({ + uploadId: 28, + parts: [{ partNumber: 1, url: 'https://example.test/part1', method: 'PUT', size: 5 }], + })), + completeUpload: vi.fn(async () => {}), + }; + + vi.useFakeTimers(); + try { + const upload = uploadArchive( + api, + { + path: archivePath, + size: 5, + sha256: 'hash', + fingerprint: 'fingerprint', + fileCount: 1, + }, + 3, + { filename: 'repo.zip', timeoutMs: 25, maxRetries: 0 }, + ); + const expectation = expect(upload).rejects.toThrow(/timed out/); + await vi.advanceTimersByTimeAsync(25); + await expectation; + expect(api.completeUpload).not.toHaveBeenCalled(); + } finally { + vi.useRealTimers(); + await rm(workRoot, { recursive: true, force: true }); + } + }); + + it('retries a failed part and completes once it succeeds', async () => { + const workRoot = await mkdtemp(join(tmpdir(), 'feedback-upload-retry-')); + const archivePath = join(workRoot, 'repo.zip'); + await writeFile(archivePath, 'hello'); + + let attempt = 0; + const fetchMock = vi.fn(async () => { + attempt += 1; + if (attempt === 1) return new Response('server error', { status: 500 }); + return new Response('', { status: 200, headers: { ETag: '"etag-1"' } }); + }); + vi.stubGlobal('fetch', fetchMock); + const api = { + createUploadUrl: vi.fn(async () => ({ + uploadId: 28, + parts: [{ partNumber: 1, url: 'https://example.test/part1', method: 'PUT', size: 5 }], + })), + completeUpload: vi.fn(async () => {}), + }; + + vi.useFakeTimers(); + try { + const upload = uploadArchive( + api, + { + path: archivePath, + size: 5, + sha256: 'hash', + fingerprint: 'fingerprint', + fileCount: 1, + }, + 3, + { filename: 'repo.zip', timeoutMs: 10_000 }, + ); + await vi.advanceTimersByTimeAsync(1_000); + await upload; + expect(fetchMock).toHaveBeenCalledTimes(2); + expect(api.completeUpload).toHaveBeenCalledWith({ + uploadId: 28, + parts: [{ partNumber: 1, etag: '"etag-1"' }], + }); + } finally { + vi.useRealTimers(); + await rm(workRoot, { recursive: true, force: true }); + } + }); +}); + +describe('packageCodebase', () => { + it('rejects empty codebase archives instead of uploading an empty zip', async () => { + const archivePath = join(tmpdir(), 'feedback-empty-codebase.zip'); + try { + await expect( + packageCodebase( + { + root: tmpdir(), + files: [], + fingerprint: 'empty-codebase', + usedGitIgnore: false, + }, + archivePath, + ), + ).rejects.toThrow(/empty/i); + await expect(stat(archivePath)).rejects.toThrow(); + } finally { + await rm(archivePath, { force: true }); + } + }); +}); + + +describe('scanCodebase filtering', () => { + it('rejects when the scan signal is already aborted', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-aborted-')); + const controller = new AbortController(); + controller.abort(); + try { + await expect(scanCodebase(root, { signal: controller.signal })).rejects.toMatchObject({ + name: 'AbortError', + }); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('skips dependency and build directories outside a git work tree', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-no-git-')); + try { + await mkdir(join(root, 'node_modules', 'pkg'), { recursive: true }); + await mkdir(join(root, 'dist')); + await writeFile(join(root, 'node_modules', 'pkg', 'index.js'), 'module.exports = 1;\n'); + await writeFile(join(root, 'dist', 'bundle.js'), 'built\n'); + await writeFile(join(root, 'keep.ts'), 'export const keep = 1;\n'); + + const scan = await scanCodebase(root); + expect(scan.usedGitIgnore).toBe(false); + expect(scan.files.map((file) => file.path)).toEqual(['keep.ts']); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('filters sensitive files even when tracked by git', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-git-')); + try { + await writeFile(join(root, '.env'), 'SECRET=1\n'); + await writeFile(join(root, '.envrc'), 'export AWS_SECRET_ACCESS_KEY=secret\n'); + await writeFile(join(root, '.npmrc'), '//registry.npmjs.org/:_authToken=secret\n'); + await writeFile(join(root, '.yarnrc.yml'), 'npmAuthToken: secret\n'); + await writeFile(join(root, 'id_rsa'), 'private-key\n'); + await writeFile(join(root, 'app.ts'), 'export const app = 1;\n'); + await execFileAsync('git', ['init'], { cwd: root }); + await execFileAsync('git', ['add', '-A'], { cwd: root }); + + const scan = await scanCodebase(root); + expect(scan.usedGitIgnore).toBe(true); + const paths = scan.files.map((file) => file.path); + expect(paths).toContain('app.ts'); + expect(paths).not.toContain('.env'); + expect(paths).not.toContain('.envrc'); + expect(paths).not.toContain('.npmrc'); + expect(paths).not.toContain('.yarnrc.yml'); + expect(paths).not.toContain('id_rsa'); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('filters sensitive files by glob outside a git work tree', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-sensitive-')); + try { + await mkdir(join(root, '.ssh')); + await writeFile(join(root, '.env.production'), 'SECRET=1\n'); + await writeFile(join(root, 'tls.pem'), 'cert\n'); + await writeFile(join(root, '.ssh', 'config'), 'Host *\n'); + await writeFile(join(root, 'keep.ts'), 'export const keep = 1;\n'); + + const scan = await scanCodebase(root); + expect(scan.files.map((file) => file.path)).toEqual(['keep.ts']); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('skips individual files larger than the per-file limit', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-large-file-')); + try { + await writeFile(join(root, 'big.bin'), randomBytes(256)); + await writeFile(join(root, 'small.txt'), 'hello\n'); + + const scan = await scanCodebase(root, { limits: { maxFileSize: 128 } }); + expect(scan.files.map((file) => file.path)).toEqual(['small.txt']); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('skips tracked files that were deleted from the working tree', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-deleted-')); + try { + await writeFile(join(root, 'keep.ts'), 'export const keep = 1;\n'); + await writeFile(join(root, 'deleted.ts'), 'export const gone = 1;\n'); + await execFileAsync('git', ['init'], { cwd: root }); + await execFileAsync('git', ['add', '-A'], { cwd: root }); + // Remove only from the working tree; the index still lists it, so + // `git ls-files` reports a path that no longer exists on disk. + await rm(join(root, 'deleted.ts')); + + const scan = await scanCodebase(root); + expect(scan.usedGitIgnore).toBe(true); + expect(scan.files.map((file) => file.path)).toEqual(['keep.ts']); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('marks exceedsLimit when file count reaches the limit', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-limit-')); + try { + await writeFile(join(root, 'a.txt'), 'a\n'); + await writeFile(join(root, 'b.txt'), 'b\n'); + await writeFile(join(root, 'c.txt'), 'c\n'); + + const scan = await scanCodebase(root, { limits: { maxFiles: 2 } }); + expect(scan.files).toHaveLength(2); + expect(scan.exceedsLimit).toEqual({ reason: 'file-count', limit: 2 }); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('marks exceedsLimit when cumulative file size reaches the archive limit', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-scan-total-size-')); + try { + await writeFile(join(root, 'a.txt'), 'a'.repeat(100)); + await writeFile(join(root, 'b.txt'), 'b'.repeat(100)); + await writeFile(join(root, 'c.txt'), 'c'.repeat(100)); + + // 250 bytes fits any two files (200) but not the third (300). + const scan = await scanCodebase(root, { limits: { maxArchiveSize: 250 } }); + expect(scan.files).toHaveLength(2); + expect(scan.exceedsLimit).toEqual({ reason: 'total-size', limit: 250 }); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); +}); + +describe('removeStaleFeedbackUploads', () => { + it('removes archive dirs older than the cutoff and keeps recent ones', async () => { + const root = await mkdtemp(join(tmpdir(), 'feedback-uploads-gc-')); + try { + const staleDir = join(root, 'stale'); + const freshDir = join(root, 'fresh'); + await mkdir(staleDir); + await mkdir(freshDir); + await writeFile(join(staleDir, 'repo.zip'), 'old'); + await writeFile(join(freshDir, 'repo.zip'), 'new'); + + const now = Date.now(); + const twoDaysAgoSec = (now - 2 * 24 * 60 * 60 * 1000) / 1000; + await utimes(staleDir, twoDaysAgoSec, twoDaysAgoSec); + + await removeStaleFeedbackUploads({ now, dir: root }); + + await expect(stat(staleDir)).rejects.toThrow(); + await expect(stat(freshDir)).resolves.toBeDefined(); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it('is a no-op when the cache dir does not exist', async () => { + const missing = join(tmpdir(), 'feedback-uploads-gc-missing-' + String(Date.now())); + await expect(removeStaleFeedbackUploads({ dir: missing })).resolves.toBeUndefined(); + }); +}); diff --git a/apps/kimi-code/test/helpers/process.ts b/apps/kimi-code/test/helpers/process.ts new file mode 100644 index 0000000000000000000000000000000000000000..1da718facb8bd701e855616acd7b0003711f40fd --- /dev/null +++ b/apps/kimi-code/test/helpers/process.ts @@ -0,0 +1,32 @@ +import { vi } from 'vitest'; + +export class ExitCalled extends Error { + constructor(public readonly code: number) { + super(`exit(${code})`); + } +} + +export function mockProcessExit() { + return vi.spyOn(process, 'exit').mockImplementation(((code?: string | number | null) => { + throw new ExitCalled(Number(code ?? 0)); + }) as never); +} + +export function captureProcessWrite(stream: 'stdout' | 'stderr'): { + readonly chunks: string[]; + readonly text: () => string; + readonly restore: () => void; +} { + const chunks: string[] = []; + const target = process[stream]; + const spy = vi.spyOn(target, 'write').mockImplementation(((chunk: string | Uint8Array) => { + chunks.push(typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8')); + return true; + }) as never); + + return { + chunks, + text: () => chunks.join(''), + restore: () =>{ spy.mockRestore(); }, + }; +} diff --git a/apps/kimi-code/test/migration/badge.test.ts b/apps/kimi-code/test/migration/badge.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..68fb72bf30df419ceda0a89d2d4be346855795b1 --- /dev/null +++ b/apps/kimi-code/test/migration/badge.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from 'vitest'; + +import { formatSessionLabel } from '#/migration/badge'; + +describe('formatSessionLabel', () => { + it('prepends [imported] when metadata.imported_from_kimi_cli === true', () => { + const label = formatSessionLabel({ + title: 'Refactor sessions list', + metadata: { imported_from_kimi_cli: true }, + }); + expect(label).toBe('[imported] Refactor sessions list'); + }); + + it('does not prepend [imported] when metadata is missing', () => { + const label = formatSessionLabel({ title: 'Plain session' }); + expect(label).toBe('Plain session'); + }); + + it('does not prepend [imported] when metadata is empty', () => { + const label = formatSessionLabel({ title: 'Plain session', metadata: {} }); + expect(label).toBe('Plain session'); + }); + + it('only triggers on the literal boolean true (not truthy values)', () => { + const label = formatSessionLabel({ + title: 'truthy but not true', + metadata: { imported_from_kimi_cli: 'yes' as unknown }, + }); + expect(label).toBe('truthy but not true'); + }); + + it('does not prepend [imported] when flag is false', () => { + const label = formatSessionLabel({ + title: 'native session', + metadata: { imported_from_kimi_cli: false }, + }); + expect(label).toBe('native session'); + }); + + it('preserves the title even when it is empty', () => { + const label = formatSessionLabel({ + title: '', + metadata: { imported_from_kimi_cli: true }, + }); + expect(label).toBe('[imported] '); + }); +}); diff --git a/apps/kimi-code/test/migration/command.test.ts b/apps/kimi-code/test/migration/command.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab70534b019d06109edd968f1e9a449402c80736 --- /dev/null +++ b/apps/kimi-code/test/migration/command.test.ts @@ -0,0 +1,42 @@ +import { Command } from 'commander'; +import { describe, expect, it, vi } from 'vitest'; + +import { registerMigrateCommand } from '#/migration/command'; + +describe('registerMigrateCommand', () => { + it('adds a migrate subcommand with --run and --config-only options', () => { + const program = new Command('kimi'); + registerMigrateCommand(program, () => {}); + const sub = program.commands.find((c) => c.name() === 'migrate'); + expect(sub).toBeDefined(); + expect(sub!.description()).toContain('Migrate'); + const flags = sub!.options.map((o) => o.long); + expect(flags).toEqual(['--run', '--config-only']); + }); + + it('invokes the host handler with both flags false by default', () => { + const program = new Command('kimi'); + const onMigrate = vi.fn(); + registerMigrateCommand(program, onMigrate); + program.parse(['migrate'], { from: 'user' }); + expect(onMigrate).toHaveBeenCalledWith({ run: false, configOnly: false }); + }); + + it('parses --run and --config-only', () => { + const program = new Command('kimi'); + const onMigrate = vi.fn(); + registerMigrateCommand(program, onMigrate); + program.parse(['migrate', '--run', '--config-only'], { from: 'user' }); + expect(onMigrate).toHaveBeenCalledWith({ run: true, configOnly: true }); + }); + + it('is not shadowed by a same-named parent option', () => { + const program = new Command('kimi'); + program.option('--yes', 'legacy alias', false); + program.option('-y, --yolo', 'yolo', false); + const onMigrate = vi.fn(); + registerMigrateCommand(program, onMigrate); + program.parse(['migrate', '--run'], { from: 'user' }); + expect(onMigrate).toHaveBeenCalledWith({ run: true, configOnly: false }); + }); +}); diff --git a/apps/kimi-code/test/migration/detect-pending.test.ts b/apps/kimi-code/test/migration/detect-pending.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff02e4ebffac23220cbb5a57e2ffe78c7a400f72 --- /dev/null +++ b/apps/kimi-code/test/migration/detect-pending.test.ts @@ -0,0 +1,142 @@ +import { describe, expect, it, beforeEach, afterEach } from 'vitest'; +import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { detectPendingMigration } from '#/migration/detect-pending'; + +let src: string; +let tgt: string; +beforeEach(async () => { + src = await mkdtemp(join(tmpdir(), 'detect-pending-src-')); + tgt = await mkdtemp(join(tmpdir(), 'detect-pending-tgt-')); +}); +afterEach(async () => { + await rm(src, { recursive: true, force: true }); + await rm(tgt, { recursive: true, force: true }); +}); + +describe('detectPendingMigration', () => { + it('returns null when source dir does not exist', async () => { + const plan = await detectPendingMigration({ sourceHome: join(src, 'nope'), targetHome: tgt }); + expect(plan).toBeNull(); + }); + + it('returns null when the migrated marker exists', async () => { + await writeFile(join(src, '.migrated-to-kimi-code'), '{}', 'utf-8'); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).toBeNull(); + }); + + it('returns null when the skip marker exists in target', async () => { + await writeFile(join(src, 'config.toml'), '', 'utf-8'); + await writeFile(join(tgt, '.skip-migration-from-kimi-cli'), '', 'utf-8'); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).toBeNull(); + }); + + it('returns null when source has nothing worth migrating', async () => { + // empty source dir, no config/mcp/credentials/sessions + const plan = await detectPendingMigration({ + sourceHome: src, + targetHome: tgt, + plansSourceHome: tgt, + }); + expect(plan).toBeNull(); + }); + + it('returns null when the only source data is OAuth credentials', async () => { + // OAuth credentials are deliberately never migrated. An install whose + // only legacy data is `credentials/*.json` therefore has nothing to + // offer the migration screen — kimi-code's own /login flow handles + // re-auth on first use. + await mkdir(join(src, 'credentials'), { recursive: true }); + await writeFile( + join(src, 'credentials', 'kimi-code.json'), + JSON.stringify({ + access_token: 'a', + refresh_token: 'r', + expires_at: 1, + scope: 's', + token_type: 'Bearer', + }), + 'utf-8', + ); + const plan = await detectPendingMigration({ + sourceHome: src, + targetHome: tgt, + plansSourceHome: tgt, + }); + expect(plan).toBeNull(); + }); + + it('returns a MigrationPlan when source has migratable data', async () => { + await writeFile(join(src, 'config.toml'), 'default_thinking = true\n', 'utf-8'); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).not.toBeNull(); + expect(plan?.hasConfig).toBe(true); + }); + + it('returns a MigrationPlan when source has only user-history', async () => { + await mkdir(join(src, 'user-history'), { recursive: true }); + await writeFile(join(src, 'user-history', 'shell.txt'), 'ls\n', 'utf-8'); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).not.toBeNull(); + expect(plan?.hasUserHistory).toBe(true); + }); + + it('does not suppress when the marker targeted a different home', async () => { + await writeFile(join(src, 'config.toml'), 'default_thinking = true\n', 'utf-8'); + await writeFile( + join(src, '.migrated-to-kimi-code'), + JSON.stringify({ version: 1, target_path: '/some/other/home' }), + 'utf-8', + ); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).not.toBeNull(); // this target was never migrated → still offer + }); + + it('suppresses when the marker targeted this home', async () => { + await writeFile(join(src, 'config.toml'), 'default_thinking = true\n', 'utf-8'); + await writeFile( + join(src, '.migrated-to-kimi-code'), + JSON.stringify({ version: 1, target_path: tgt }), + 'utf-8', + ); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).toBeNull(); + }); + + it('returns a MigrationPlan when source has only skills', async () => { + await mkdir(join(src, 'skills', 'mine'), { recursive: true }); + await writeFile(join(src, 'skills', 'mine', 'SKILL.md'), '# skill', 'utf-8'); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).not.toBeNull(); + expect(plan?.hasSkills).toBe(true); + }); + + it('returns a MigrationPlan when source has only session scan failures', async () => { + const bucket = join(src, 'sessions', '11111111111111111111111111111111'); + await mkdir(join(bucket, 'legacy-session'), { recursive: true }); + const plan = await detectPendingMigration({ sourceHome: src, targetHome: tgt }); + expect(plan).not.toBeNull(); + expect(plan?.sessionScanFailures?.length).toBeGreaterThan(0); + }); + + it('detects skills from skillsSourceHome when it differs from the source home', async () => { + const skillsHome = await mkdtemp(join(tmpdir(), 'detect-pending-skills-')); + try { + await mkdir(join(skillsHome, 'skills', 'mine'), { recursive: true }); + await writeFile(join(skillsHome, 'skills', 'mine', 'SKILL.md'), '# skill', 'utf-8'); + const plan = await detectPendingMigration({ + sourceHome: src, + skillsSourceHome: skillsHome, + targetHome: tgt, + }); + expect(plan).not.toBeNull(); + expect(plan?.hasSkills).toBe(true); + expect(plan?.skillsSourceHome).toBe(skillsHome); + } finally { + await rm(skillsHome, { recursive: true, force: true }); + } + }); +}); diff --git a/apps/kimi-code/test/migration/legacy-source.test.ts b/apps/kimi-code/test/migration/legacy-source.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..73e49243005a07b5dbdc0cb2bbc635b252b99aa1 --- /dev/null +++ b/apps/kimi-code/test/migration/legacy-source.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from 'vitest'; +import { join } from 'node:path'; +import { resolveLegacySourceHome, sameLegacyPath } from '#/migration/legacy-source'; + +const HOME = '/home/user'; +const CWD = '/work/project'; + +describe('resolveLegacySourceHome', () => { + it('defaults to ~/.kimi when KIMI_SHARE_DIR is unset', () => { + const r = resolveLegacySourceHome({}, HOME, CWD); + expect(r).toEqual({ sourceHome: join(HOME, '.kimi'), origin: 'default' }); + }); + + it('defaults to ~/.kimi when KIMI_SHARE_DIR is empty or blank', () => { + expect(resolveLegacySourceHome({ KIMI_SHARE_DIR: '' }, HOME, CWD).origin).toBe('default'); + expect(resolveLegacySourceHome({ KIMI_SHARE_DIR: ' ' }, HOME, CWD).origin).toBe('default'); + }); + + it('uses an absolute KIMI_SHARE_DIR verbatim', () => { + const r = resolveLegacySourceHome({ KIMI_SHARE_DIR: '/data/kimi' }, HOME, CWD); + expect(r.sourceHome).toBe('/data/kimi'); + expect(r.origin).toBe('share-dir'); + }); + + it('resolves a relative KIMI_SHARE_DIR against the process CWD (old-CLI rule)', () => { + const r = resolveLegacySourceHome({ KIMI_SHARE_DIR: 'relative/kimi' }, HOME, CWD); + expect(r.sourceHome).toBe(join(CWD, 'relative', 'kimi')); + expect(r.origin).toBe('share-dir'); + }); + + it('does not expand ~ in KIMI_SHARE_DIR (old-CLI rule)', () => { + const r = resolveLegacySourceHome({ KIMI_SHARE_DIR: '~/custom' }, HOME, CWD); + expect(r.sourceHome).toBe(join(CWD, '~/custom')); + }); + + it('resolves skills from ~/.kimi when the share dir is redirected', () => { + const r = resolveLegacySourceHome({ KIMI_SHARE_DIR: '/data/kimi' }, HOME, CWD); + expect(r.skillsSourceHome).toBe(join(HOME, '.kimi')); + }); + + it('keeps a single source when KIMI_SHARE_DIR points at ~/.kimi itself', () => { + const r = resolveLegacySourceHome({ KIMI_SHARE_DIR: join(HOME, '.kimi') }, HOME, CWD); + expect(r.skillsSourceHome).toBeUndefined(); + }); +}); + +describe('sameLegacyPath', () => { + it('matches identical and redundant forms', () => { + expect(sameLegacyPath('/a/b', '/a/b')).toBe(true); + expect(sameLegacyPath('/a/b/', '/a/b')).toBe(true); + expect(sameLegacyPath('/a/./b', '/a/b')).toBe(true); + }); + + it('rejects different paths', () => { + expect(sameLegacyPath('/a/b', '/a/c')).toBe(false); + }); +}); diff --git a/apps/kimi-code/test/migration/migration-screen.test.ts b/apps/kimi-code/test/migration/migration-screen.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b508e889d4e223dd79c13d50c11d16aa72949d0 --- /dev/null +++ b/apps/kimi-code/test/migration/migration-screen.test.ts @@ -0,0 +1,626 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + MigrationScreenComponent, + type MigrationScreenResult, +} from '#/migration/migration-screen'; +import { darkColors } from '#/tui/theme/colors'; +import type { + MigrationPlan, + MigrationReport, + RunMigrationInput, +} from '@moonshot-ai/migration-legacy'; + +function makePlan(over: Partial = {}): MigrationPlan { + return { + sourceHome: '/x/.kimi', + hasConfig: true, + hasMcp: true, + hasUserHistory: true, + hasSkills: false, + hasPlans: false, + oauthCredentials: ['kimi-code'], + workdirs: [], + detectedPlugins: [], + detectedMcpOauthServers: [], + totalSessions: 1365, + ...over, + }; +} + +function render(c: MigrationScreenComponent): string { + return c.render(80).join('\n'); +} + +describe('MigrationScreenComponent — ask phase', () => { + it('ask1 renders the intro block and three options', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + const out = render(c); + expect(out).toContain('Migrate from kimi-cli'); + expect(out).toContain('1365 sessions'); + expect(out).toContain('Migrate now'); + expect(out).toContain('Ask me later'); + expect(out).toContain('Never ask again'); + }); + + it('ask1 summary does not mention kimi-cli login (oauth is not a migrated kind)', async () => { + // OAuth credentials are deliberately never migrated, so the pre-migration + // summary must not list "kimi-cli login" alongside the real migratable + // data classes — that framing makes users believe their session will + // carry over, which it does not. + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + const out = render(c); + expect(out).not.toContain('kimi-cli login'); + expect(out).not.toContain('/login'); + }); + + it('picking "Ask me later" at ask1 completes with decision=later', () => { + let result: { decision: string } | undefined; + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: (r) => { + result = r; + }, + }); + c.handleInput('\u001B[B'); // Down -> "Ask me later" + c.handleInput('\r'); // Enter + expect(result?.decision).toBe('later'); + }); + + it('"Migrate now" -> "Config only" advances ask1 -> ask2 and resolves scope.sessions=false', async () => { + let captured: RunMigrationInput | undefined; + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + runMigration: async (input) => { + captured = input; + return makeReport(); + }, + onComplete: () => {}, + }); + c.handleInput('\r'); // ask1: "Migrate now" + c.handleInput('\r'); // ask2: "Config only" (first option) + await new Promise((r) => setTimeout(r, 0)); + expect(captured?.scope.sessions).toBe(false); + }); + + it('"Migrate now" -> "Config + sessions" begins migration immediately with sessions=true', async () => { + let captured: RunMigrationInput | undefined; + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + runMigration: async (input) => { + captured = input; + return makeReport(); + }, + onComplete: () => {}, + }); + c.handleInput('\r'); // ask1: Migrate now + c.handleInput('\u001B[B'); // ask2: down -> Also migrate sessions + c.handleInput('\r'); // ask2 select -> "Config + N sessions" begins migration immediately + await new Promise((r) => setTimeout(r, 0)); + expect(captured?.scope.sessions).toBe(true); + }); + + it('ask2 shows the detected session count alongside the "config only" option', () => { + const c = new MigrationScreenComponent({ + plan: makePlan({ totalSessions: 1365 }), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c.handleInput('\r'); // ask1: Migrate now -> ask2 + const out = render(c); + expect(out).toContain('Config only'); + // Concrete count so the user sees the cost of "+ sessions" up front. + expect(out).toContain('Config + 1365 sessions'); + expect(out).not.toContain('Most recent'); + expect(out).not.toContain('Migrate now'); + }); + + it('ask2 falls back to "Config + all sessions" when no sessions were detected', () => { + const c = new MigrationScreenComponent({ + plan: makePlan({ totalSessions: 0 }), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c.handleInput('\r'); // ask1 -> ask2 + const out = render(c); + expect(out).toContain('Config + all sessions'); + // "Config + 0 sessions" would read as an obvious dead-end. + expect(out).not.toContain('Config + 0 sessions'); + }); + + it('skipDecisionStep starts at the scope question with the now/later/never gate hidden', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + skipDecisionStep: true, + onComplete: () => {}, + }); + const out = render(c); + expect(out).toContain('Migrate chat sessions too?'); + expect(out).not.toContain('Migrate now'); + expect(out).not.toContain('Never ask again'); + }); + + it('skipDecisionStep -> "Config only" resolves scope without the decision step', async () => { + let captured: RunMigrationInput | undefined; + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + skipDecisionStep: true, + runMigration: async (input) => { + captured = input; + return makeReport(); + }, + onComplete: () => {}, + }); + c.handleInput('\r'); // ask2: "Config only" (first option) — no ask1 gate + await new Promise((r) => setTimeout(r, 0)); + expect(captured?.scope.sessions).toBe(false); + }); +}); + +describe('MigrationScreenComponent — progress phase', () => { + it('renders a step checklist and the session counter when in progress', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + // expose progress rendering via the test hook (see Step 5.2) + c._testEnterProgress(); + c._testUpdateStep('config done'); + c._testUpdateSessionProgress(32, 50); + const out = c.render(80).join('\n'); + expect(out).toContain('Migrating from kimi-cli'); + expect(out).toContain('32 / 50'); + expect(out).toContain('Config'); + }); + + it('animates the progress spinner while a migration step runs', async () => { + vi.useFakeTimers(); + try { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + skipDecisionStep: true, + // A migration that never settles keeps the screen in the progress + // phase so the spinner animation can be observed. + runMigration: () => new Promise(() => {}), + onComplete: () => {}, + }); + c.handleInput('\r'); // ask2: "Config only" -> migration begins + c._testUpdateSessionProgress(1, 3); // surface the spinner line + const before = c.render(80).join('\n'); + vi.advanceTimersByTime(400); // several spinner frames + const after = c.render(80).join('\n'); + // Before the fix nothing advanced the spinner — the frame, and the whole + // progress render, stayed frozen on the first braille glyph. + expect(after).not.toBe(before); + } finally { + vi.useRealTimers(); + } + }); + + it('tracks Config and MCP as independent steps', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testEnterProgress(); + c._testUpdateStep('config done'); // config finished; MCP has not started + const out = c.render(80).join('\n'); + // Four checklist rows (config, mcp, user-history, sessions). With only + // config done, exactly one shows ✓ and the other three show ◐ — MCP is + // its own step and stays pending. + expect((out.match(/✓/g) ?? []).length).toBe(1); + expect((out.match(/◐/g) ?? []).length).toBe(3); + }); +}); + +function makeReport( + over: Partial = {}, + summaryOver: Partial = {}, + noticesOver: Partial = {}, +): MigrationReport { + return { + startedAt: 's', + completedAt: 'e', + migratorVersion: '0.1.1', + source: '/x/.kimi', + target: '/y/.kimi-code', + summary: { + config: { + migrated: true, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: [], + wroteSiblingDueToConflict: false, + wroteTuiSibling: false, + migratedHooks: 0, + droppedHooks: 0, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { providers: [], models: [], hooks: 0 }, + }, + mcp: { mergedServers: [], keptNewForConflicts: [], droppedServers: [], wroteSiblingDueToConflict: false, sourceUnreadable: false }, + userHistory: { copied: 12, skippedExisting: 0 }, + skills: { copied: 0, skippedExisting: 0 }, + plans: { copied: 0, skippedExisting: 0 }, + sessions: { + scope: 'all', + bucketsScanned: 0, + bucketsSkippedNonlocalKaos: 0, + bucketsSkippedNoWorkdirFound: 0, + sessionsAttempted: 50, + sessionsMigrated: 50, + sessionsAlreadyMigrated: 0, + sessionsSkippedPlaceholder: 0, + sessionsSkippedEmpty: 0, + sessionsSkippedMalformed: 0, + sessionsFailed: [], + sessionsConflicts: [], + ...over, + }, + ...summaryOver, + }, + notices: { + mcpOauthServersRequiringReauth: [], + oauthLoginsRequiringRelogin: [], + detectedPlugins: ['p1', 'p2'], + configConflictNotice: null, + tuiConflictNotice: null, + plansCopiedNotice: null, + ...noticesOver, + }, + }; +} + +describe('MigrationScreenComponent — result phase', () => { + it('renders the report summary including plugin notices', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult(makeReport()); + const out = c.render(80).join('\n'); + expect(out).toContain('Migration complete'); + expect(out).toContain('50 sessions migrated'); + expect(out).toContain('2 kimi-cli plugins'); + }); + + it('renders nothing-needed-migrating when every counter is zero', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult( + makeReport( + { sessionsAttempted: 0, sessionsMigrated: 0 }, + { + config: { + migrated: false, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: [], + wroteSiblingDueToConflict: false, + wroteTuiSibling: false, + migratedHooks: 0, + droppedHooks: 0, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { providers: [], models: [], hooks: 0 }, + }, + userHistory: { copied: 0, skippedExisting: 0 }, + }, + ), + ); + const out = c.render(80).join('\n'); + expect(out).toContain('Nothing needed migrating'); + }); + + it('renders migrated hooks in the ✓ line and dropped hooks as a warning', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult( + makeReport( + {}, + { + config: { + migrated: true, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: [], + wroteSiblingDueToConflict: false, + wroteTuiSibling: false, + migratedHooks: 2, + droppedHooks: 1, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { providers: [], models: [], hooks: 0 }, + }, + }, + ), + ); + const out = c.render(80).join('\n'); + expect(out).toContain('· hooks'); // appears in the ✓ migrated-kinds line + expect(out).toContain('1 hooks dropped'); + }); + + it('Enter on the result screen completes with the prior decision', () => { + let result: MigrationScreenResult | undefined; + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: (r) => { + result = r; + }, + }); + c._testShowResult(makeReport()); + c.handleInput('\r'); + expect(result?.decision).toBe('now'); + expect(result?.migrated).toBe(true); + }); + + it('omits a data class from the result when it was not migrated', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + // config skipped (e.g. a malformed legacy config.toml). + c._testShowResult( + makeReport( + {}, + { + config: { + migrated: false, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: [], + wroteSiblingDueToConflict: false, + wroteTuiSibling: false, + migratedHooks: 0, + droppedHooks: 0, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { providers: [], models: [], hooks: 0 }, + }, + }, + ), + ); + const out = c.render(80).join('\n'); + // REPL history (copied) is still shown... + expect(out).toContain('REPL history'); + // ...but config must not be claimed as migrated. + expect(out).not.toContain('config'); + }); + + it('surfaces conflict and failure warnings on the result screen', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult( + makeReport( + { sessionsFailed: [{ sourcePath: '/s', reason: 'bad' }] }, + { + config: { + migrated: true, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: [], + wroteSiblingDueToConflict: true, + wroteTuiSibling: false, + migratedHooks: 0, + droppedHooks: 0, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { providers: [], models: [], hooks: 0 }, + }, + mcp: { mergedServers: ['m'], keptNewForConflicts: [], droppedServers: [], wroteSiblingDueToConflict: true, sourceUnreadable: false }, + }, + ), + ); + const out = c.render(80).join('\n'); + expect(out).toContain('config.migrated-from-kimi-cli.toml'); + expect(out).toContain('mcp.migrated-from-kimi-cli.json'); + expect(out).toContain('1 sessions failed'); + }); + + it('lists sibling-file contents in the config-fallback warning so the user knows what to merge', () => { + // When the target's `config.toml` could not be parsed and migration writes + // to `config.migrated-from-kimi-cli.toml` instead, the result screen must + // (a) name the sibling, (b) say what's in it so the user knows what to + // merge by hand, and (c) describe the trigger accurately (parse failure, + // not "unreadable"). Otherwise users have to crack the file open to find + // out — and they may not realize hooks landed in there at all. + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult( + makeReport( + {}, + { + config: { + migrated: true, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: [], + wroteSiblingDueToConflict: true, + wroteTuiSibling: false, + migratedHooks: 0, + droppedHooks: 0, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { + providers: ['openai', 'managed:kimi-code'], + models: ['gpt4'], + hooks: 3, + }, + }, + }, + ), + ); + const out = c.render(80).join('\n'); + expect(out).toContain('config.migrated-from-kimi-cli.toml'); + // Accurate trigger description (file parses, not "unreadable"). + expect(out).toContain('could not be parsed'); + // Enumeration of what's inside the sibling. + expect(out).toContain('2 providers'); + expect(out).toContain('1 model'); + expect(out).toContain('3 hooks'); + }); + + it('shows skipped empty sessions as a muted line, not a failure', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult(makeReport({ sessionsSkippedEmpty: 3 })); + const out = c.render(80).join('\n'); + expect(out).toContain('3 empty sessions skipped'); + // It is informational, not a failure. + expect(out).not.toContain('3 sessions failed'); + }); + + it('lists kept config settings on the result screen when kimi-cli differed', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult( + makeReport( + {}, + { + config: { + migrated: true, + tuiExtracted: false, + droppedProviders: [], + droppedModels: [], + droppedKeys: [], + configConflicts: ['default_model', 'providers.kimi'], + wroteSiblingDueToConflict: false, + wroteTuiSibling: false, + migratedHooks: 0, + droppedHooks: 0, + sourceUnreadable: false, + deviceIdCopied: false, + siblingContents: { providers: [], models: [], hooks: 0 }, + }, + }, + ), + ); + const out = c.render(80).join('\n'); + expect(out).toContain('2 config conflicts kept yours'); + expect(out).toContain('default_model · providers.kimi'); + }); + + it('surfaces MCP servers that need re-authentication', () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + }); + c._testShowResult(makeReport({}, {}, { mcpOauthServersRequiringReauth: ['srv-a', 'srv-b'] })); + const out = c.render(80).join('\n'); + expect(out).toContain('2 MCP servers need re-authentication'); + }); +}); + +describe('MigrationScreenComponent — execution wiring', () => { + it('runs migration after the ask phase and lands on the result phase', async () => { + const fakeReport = makeReport(); + let onCompleteResult: MigrationScreenResult | undefined; + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: (r) => { + onCompleteResult = r; + }, + // injected runner for testability — no filesystem access + runMigration: async (_input) => fakeReport, + }); + c.handleInput('\r'); // ask1: Migrate now + c.handleInput('\r'); // ask2: Config only -> begins migration + // migration is async; wait a tick + await new Promise((res) => setTimeout(res, 0)); + expect(c.render(80).join('\n')).toContain('Migration complete'); + c.handleInput('\r'); // dismiss result + expect(onCompleteResult?.decision).toBe('now'); + expect(onCompleteResult?.migrated).toBe(true); + }); + + it('lands on the failure screen with the runner rejection reason', async () => { + const c = new MigrationScreenComponent({ + plan: makePlan(), + sourceHome: '/x/.kimi', + targetHome: '/y/.kimi-code', + onComplete: () => {}, + runMigration: async () => { + throw new Error('boom'); + }, + }); + c.handleInput('\r'); // ask1: Migrate now + c.handleInput('\r'); // ask2: Config only -> begins migration + await new Promise((res) => setTimeout(res, 0)); + const out = c.render(80).join('\n'); + expect(out).toContain('Migration failed'); + expect(out).toContain('Reason: boom'); + }); +}); diff --git a/apps/kimi-code/test/migration/run-headless.test.ts b/apps/kimi-code/test/migration/run-headless.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..87ed5c7f778521c72ac2f15a315902fa85e4f879 --- /dev/null +++ b/apps/kimi-code/test/migration/run-headless.test.ts @@ -0,0 +1,153 @@ +import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { createHash } from 'node:crypto'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { MIGRATE_HEADLESS_EXIT, runHeadlessMigrate } from '#/migration/run-headless'; + +let home: string; +let target: string; +let lines: string[]; + +const write = (line: string): void => { + lines.push(line); +}; + +beforeEach(async () => { + home = await mkdtemp(join(tmpdir(), 'migrate-headless-home-')); + target = await mkdtemp(join(tmpdir(), 'migrate-headless-target-')); + lines = []; +}); + +afterEach(async () => { + await rm(home, { recursive: true, force: true }); + await rm(target, { recursive: true, force: true }); +}); + +function sourceHome(): string { + return join(home, '.kimi'); +} + +async function writeLegacyConfig(): Promise { + await mkdir(sourceHome(), { recursive: true }); + await writeFile(join(sourceHome(), 'config.toml'), 'default_thinking = true\n', 'utf-8'); +} + +async function writeRealSession(workdir: string, uuid: string): Promise { + await mkdir(workdir, { recursive: true }); + const bucket = createHash('md5').update(workdir).digest('hex'); + const sessionDir = join(sourceHome(), 'sessions', bucket, uuid); + await mkdir(sessionDir, { recursive: true }); + await writeFile( + join(sourceHome(), 'kimi.json'), + JSON.stringify({ work_dirs: [{ path: workdir, kaos: 'local', last_session_id: uuid }] }), + 'utf-8', + ); + await writeFile( + join(sessionDir, 'context.jsonl'), + '{"role":"_system_prompt","content":"hi"}\n{"role":"user","content":"hello"}\n', + 'utf-8', + ); +} + +describe('runHeadlessMigrate', () => { + it('reports nothing to migrate for an empty source', async () => { + await mkdir(sourceHome(), { recursive: true }); + const code = await runHeadlessMigrate( + { configOnly: false }, + { env: {}, userHome: home, targetHome: target, write }, + ); + expect(code).toBe(MIGRATE_HEADLESS_EXIT.success); + expect(lines.join('\n')).toContain('nothing to migrate'); + }); + + it('refuses when source and target are the same directory', async () => { + const code = await runHeadlessMigrate( + { configOnly: false }, + { env: {}, userHome: home, targetHome: sourceHome(), write }, + ); + expect(code).toBe(MIGRATE_HEADLESS_EXIT.error); + expect(lines.join('\n')).toContain('refusing to migrate'); + }); + + it('migrates config and sessions, writes the report and the completion marker', async () => { + await writeLegacyConfig(); + await writeRealSession(join(home, 'proj'), '11111111-aaaa-4bbb-8ccc-111111111111'); + const code = await runHeadlessMigrate( + { configOnly: false }, + { env: {}, userHome: home, targetHome: target, write }, + ); + expect(code).toBe(MIGRATE_HEADLESS_EXIT.success); + const out = lines.join('\n'); + expect(out).toContain('detected: 1 sessions'); + expect(out).toContain('step: config done'); + expect(out).toContain('sessions: translating 1/1'); + expect(out).toContain('migrated=1'); + expect(out).toContain('result: complete'); + const report = JSON.parse(await readFile(join(target, 'migration-report.json'), 'utf-8')); + expect(report.summary.sessions.sessionsMigrated).toBe(1); + expect(report.summary.config.migrated).toBe(true); + const marker = JSON.parse( + await readFile(join(sourceHome(), '.migrated-to-kimi-code'), 'utf-8'), + ); + expect(marker.target_path).toBe(target); + }); + + it('skips sessions in config-only mode', async () => { + await writeLegacyConfig(); + await writeRealSession(join(home, 'proj'), '11111111-aaaa-4bbb-8ccc-111111111111'); + const code = await runHeadlessMigrate( + { configOnly: true }, + { env: {}, userHome: home, targetHome: target, write }, + ); + expect(code).toBe(MIGRATE_HEADLESS_EXIT.success); + expect(lines.join('\n')).toContain('scope: config-only'); + const report = JSON.parse(await readFile(join(target, 'migration-report.json'), 'utf-8')); + expect(report.summary.sessions.scope).toBe('config-only'); + expect(report.summary.sessions.sessionsMigrated).toBe(0); + expect(report.summary.config.migrated).toBe(true); + }); + + it('exits incomplete and writes no marker when a session fails', async () => { + await writeLegacyConfig(); + const workdir = join(home, 'proj'); + await writeRealSession(workdir, '11111111-aaaa-4bbb-8ccc-111111111111'); + const bucket = createHash('md5').update(workdir).digest('hex'); + await writeFile( + join(sourceHome(), 'sessions', bucket, '11111111-aaaa-4bbb-8ccc-111111111111', 'context.jsonl'), + '"broken\x00line\nnot json at all\n', + 'utf-8', + ); + const code = await runHeadlessMigrate( + { configOnly: false }, + { env: {}, userHome: home, targetHome: target, write }, + ); + expect(code).toBe(MIGRATE_HEADLESS_EXIT.incomplete); + const out = lines.join('\n'); + expect(out).toContain('failed='); + expect(out).toContain('result: incomplete'); + await expect( + readFile(join(sourceHome(), '.migrated-to-kimi-code'), 'utf-8'), + ).rejects.toThrow(); + }); + + it('honors KIMI_SHARE_DIR as the source and keeps skills on the default home', async () => { + const shareDir = join(home, 'share'); + await mkdir(join(shareDir), { recursive: true }); + await writeFile(join(shareDir, 'config.toml'), 'default_thinking = true\n', 'utf-8'); + await mkdir(join(sourceHome(), 'skills', 'mine'), { recursive: true }); + await writeFile(join(sourceHome(), 'skills', 'mine', 'SKILL.md'), '# skill', 'utf-8'); + const code = await runHeadlessMigrate( + { configOnly: false }, + { env: { KIMI_SHARE_DIR: shareDir }, userHome: home, targetHome: target, write }, + ); + expect(code).toBe(MIGRATE_HEADLESS_EXIT.success); + const out = lines.join('\n'); + expect(out).toContain(`source: ${shareDir} (KIMI_SHARE_DIR)`); + expect(out).toContain('skills: copied=1'); + const report = JSON.parse(await readFile(join(target, 'migration-report.json'), 'utf-8')); + expect(report.summary.config.migrated).toBe(true); + }); +}); diff --git a/apps/kimi-code/test/native/cache-base.test.ts b/apps/kimi-code/test/native/cache-base.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..896aefabcd2f25fae8816f390cbfc78d150f1789 --- /dev/null +++ b/apps/kimi-code/test/native/cache-base.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, it } from 'vitest'; + +import { getNativeCacheBase } from '#/native/native-assets'; + +describe('getNativeCacheBase precedence', () => { + const baseOptions = { homeDir: '/home/u' }; + + it('uses KIMI_CODE_CACHE_DIR when set (highest precedence)', () => { + const got = getNativeCacheBase({ + ...baseOptions, + env: { KIMI_CODE_CACHE_DIR: '/custom/cache' }, + }); + expect(got).toBe('/custom/cache'); + }); + + it('ignores KIMI_CODE_HOME (no longer affects native cache)', () => { + const got = getNativeCacheBase({ + ...baseOptions, + env: { KIMI_CODE_HOME: '/legacy' }, + platform: 'darwin', + }); + expect(got).toBe('/home/u/Library/Caches/kimi-code'); + }); + + it('uses platform default on macOS when no env set', () => { + const got = getNativeCacheBase({ + ...baseOptions, + env: {}, + platform: 'darwin', + }); + expect(got).toBe('/home/u/Library/Caches/kimi-code'); + }); + + it('uses XDG_CACHE_HOME on Linux when set', () => { + const got = getNativeCacheBase({ + ...baseOptions, + env: { XDG_CACHE_HOME: '/xdg' }, + platform: 'linux', + }); + expect(got).toBe('/xdg/kimi-code'); + }); + + it('uses LOCALAPPDATA on Windows when set', () => { + const got = getNativeCacheBase({ + ...baseOptions, + env: { LOCALAPPDATA: 'C:\\Users\\u\\AppData\\Local' }, + platform: 'win32', + }); + expect(got).toBe('C:\\Users\\u\\AppData\\Local\\kimi-code'); + }); +}); diff --git a/apps/kimi-code/test/native/cache-gc.test.ts b/apps/kimi-code/test/native/cache-gc.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f9203a15f3aebf4de4acf3691ae9f382de7bd47 --- /dev/null +++ b/apps/kimi-code/test/native/cache-gc.test.ts @@ -0,0 +1,103 @@ +import { mkdirSync, statSync, utimesSync, writeFileSync, readdirSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { cleanupStaleNativeCache } from '#/native/native-assets'; + +describe('cleanupStaleNativeCache', () => { + let root: string; + + beforeEach(() => { + root = mkdtempSync(join(tmpdir(), 'kimi-cache-gc-')); + }); + + afterEach(() => { + rmSync(root, { recursive: true, force: true }); + }); + + function makeHashDir(version: string, target: string, hash: string, mtimeOffset = 0): string { + const dir = join(root, 'native', version, target, hash); + mkdirSync(dir, { recursive: true }); + writeFileSync(join(dir, 'marker.txt'), hash); + const now = Math.floor(Date.now() / 1000); + utimesSync(dir, now + mtimeOffset, now + mtimeOffset); + return dir; + } + + it('keeps currentRoot + most recently modified sibling, deletes the rest', () => { + const v = '1.0.0'; + const t = 'darwin-arm64'; + const oldest = makeHashDir(v, t, 'aaaa', -300); + const middle = makeHashDir(v, t, 'bbbb', -200); + const recent = makeHashDir(v, t, 'cccc', -100); + const current = makeHashDir(v, t, 'dddd', 0); + + const result = cleanupStaleNativeCache({ + cacheBase: root, + version: v, + target: t, + currentRoot: current, + }); + + expect(result.kept.toSorted()).toEqual([recent, current].toSorted()); + expect(result.removed.toSorted()).toEqual([oldest, middle].toSorted()); + + expect(readdirSync(join(root, 'native', v, t)).toSorted()).toEqual(['cccc', 'dddd']); + }); + + it('no-op when only currentRoot exists', () => { + const v = '1.0.0'; + const t = 'darwin-arm64'; + const current = makeHashDir(v, t, 'dddd'); + + const result = cleanupStaleNativeCache({ + cacheBase: root, + version: v, + target: t, + currentRoot: current, + }); + + expect(result.kept).toEqual([current]); + expect(result.removed).toEqual([]); + }); + + it('no-op when target dir does not exist', () => { + const result = cleanupStaleNativeCache({ + cacheBase: root, + version: '1.0.0', + target: 'darwin-arm64', + currentRoot: join(root, 'native', '1.0.0', 'darwin-arm64', 'absent'), + }); + expect(result.kept).toEqual([]); + expect(result.removed).toEqual([]); + }); + + it('does not touch other targets or versions', () => { + const current = makeHashDir('1.0.0', 'darwin-arm64', 'dddd'); + const otherTarget = makeHashDir('1.0.0', 'linux-x64', 'eeee'); + const otherVersion = makeHashDir('0.9.0', 'darwin-arm64', 'ffff'); + + cleanupStaleNativeCache({ + cacheBase: root, + version: '1.0.0', + target: 'darwin-arm64', + currentRoot: current, + }); + + expect(statSync(otherTarget).isDirectory()).toBe(true); + expect(statSync(otherVersion).isDirectory()).toBe(true); + }); + + it('errors array is empty on clean run', () => { + const current = makeHashDir('1.0.0', 'darwin-arm64', 'dddd'); + const result = cleanupStaleNativeCache({ + cacheBase: root, + version: '1.0.0', + target: 'darwin-arm64', + currentRoot: current, + }); + expect(result.errors).toEqual([]); + }); +}); diff --git a/apps/kimi-code/test/native/native-assets.test.ts b/apps/kimi-code/test/native/native-assets.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c2cce2ecb116ec25c042d79c0842634e1620f69 --- /dev/null +++ b/apps/kimi-code/test/native/native-assets.test.ts @@ -0,0 +1,336 @@ +import { createHash } from 'node:crypto'; +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, describe, expect, it } from 'vitest'; +import { + getTextBuildWorkerRuntimeState, + resetTextBuildWorkerRuntime, +} from '@moonshot-ai/minidb/worker-runtime'; + +import { + getEmbeddedNativeAssetManifest, + getMinidbTextBuildWorkerFile, + getNativeCacheBase, + getNativePackageRoot, + NATIVE_ASSET_MANIFEST_VERSION, + type NativeAssetManifest, + type NativeAssetSource, +} from '#/native/native-assets'; +import { installMinidbTextBuildWorker } from '#/native/minidb-worker'; +import { loadNativePackage } from '#/native/native-require'; + +function sha256(bytes: Buffer | string): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +function fakeManifest(files: Record, workerContent?: string): { + manifest: NativeAssetManifest; + source: NativeAssetSource; +} { + const assetEntries = Object.entries(files).map(([relativePath, content]) => { + const assetKey = `native/test-target/${relativePath}`; + return { + assetKey, + relativePath, + sha256: sha256(content), + }; + }); + const manifestKey = 'native/test-target/manifest.json'; + const workerAssetKey = 'native/test-target/runtime/minidb-text-build-worker'; + const manifest: NativeAssetManifest = { + version: NATIVE_ASSET_MANIFEST_VERSION, + target: 'test-target', + packages: [ + { + name: 'fake-native', + root: 'node_modules/fake-native', + files: assetEntries, + }, + ], + runtimeFiles: + workerContent === undefined + ? [] + : [ + { + key: 'minidb-text-build-worker', + assetKey: workerAssetKey, + relativePath: 'runtime/minidb/text-build-worker.mjs', + sha256: sha256(workerContent), + mode: 0o644, + }, + ], + }; + const assets = new Map([ + [manifestKey, Buffer.from(JSON.stringify(manifest))], + ...Object.entries(files).map(([relativePath, content]) => [ + `native/test-target/${relativePath}`, + Buffer.from(content), + ] as const), + ...(workerContent === undefined + ? [] + : [[workerAssetKey, Buffer.from(workerContent)] as const]), + ]); + return { + manifest, + source: { + getAssetKeys: () => [...assets.keys()], + getRawAsset: (assetKey) => { + const asset = assets.get(assetKey); + if (asset === undefined) throw new Error(`missing test asset: ${assetKey}`); + return asset; + }, + }, + }; +} + +function sourceForManifest(manifest: unknown): NativeAssetSource { + const key = 'native/test-target/manifest.json'; + return { + getAssetKeys: () => [key], + getRawAsset: (assetKey) => { + if (assetKey !== key) throw new Error(`missing test asset: ${assetKey}`); + return Buffer.from(JSON.stringify(manifest)); + }, + }; +} + +afterEach(() => { + resetTextBuildWorkerRuntime(); +}); + +describe('native assets', () => { + it('uses KIMI_CODE_CACHE_DIR as the native cache base when present', () => { + expect( + getNativeCacheBase({ + env: { KIMI_CODE_CACHE_DIR: '/tmp/kimi-cache' }, + homeDir: '/home/kimi', + platform: 'linux', + }), + ).toBe('/tmp/kimi-cache'); + }); + + it('extracts package assets and repairs corrupted cache files', () => { + const dir = mkdtempSync(join(tmpdir(), 'kimi-native-assets-')); + try { + const { manifest, source } = fakeManifest({ + 'node_modules/fake-native/package.json': '{"main":"index.js"}', + 'node_modules/fake-native/index.js': "module.exports = { value: 'ok' };\n", + }); + + const packageRoot = getNativePackageRoot('fake-native', { + cacheBase: dir, + manifest, + source, + version: 'test', + }); + expect(packageRoot).toBe(join(dir, 'native', 'test', 'test-target', sha256(JSON.stringify(manifest)), 'node_modules', 'fake-native')); + expect(readFileSync(join(packageRoot ?? '', 'index.js'), 'utf-8')).toContain("value: 'ok'"); + + writeFileSync(join(packageRoot ?? '', 'index.js'), 'broken'); + const repairedRoot = getNativePackageRoot('fake-native', { + cacheBase: dir, + manifest, + source, + version: 'test', + }); + expect(repairedRoot).toBe(packageRoot); + expect(readFileSync(join(repairedRoot ?? '', 'index.js'), 'utf-8')).toContain("value: 'ok'"); + expect(existsSync(join(dir, 'native', 'test', 'test-target'))).toBe(true); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('loads a package from extracted native assets', () => { + const dir = mkdtempSync(join(tmpdir(), 'kimi-native-require-')); + try { + const { manifest, source } = fakeManifest({ + 'node_modules/fake-native/package.json': '{"main":"index.js"}', + 'node_modules/fake-native/index.js': "module.exports = { value: 'ok' };\n", + }); + + const pkg = loadNativePackage<{ value: string }>('fake-native', { + cacheBase: dir, + manifest, + source, + version: 'test', + }); + + expect(pkg).toEqual({ value: 'ok' }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('extracts, reuses, and repairs the runtime worker in the unified cache tree', () => { + const dir = mkdtempSync(join(tmpdir(), 'kimi-native-worker-')); + try { + const worker = 'export const worker = true;\n'; + const { manifest, source } = fakeManifest( + { 'node_modules/fake-native/package.json': '{"main":"index.js"}' }, + worker, + ); + const options = { cacheBase: dir, manifest, source, version: 'test' }; + const first = getMinidbTextBuildWorkerFile(options); + const packageRoot = getNativePackageRoot('fake-native', options); + expect(first).toBe( + join( + dir, + 'native', + 'test', + 'test-target', + sha256(JSON.stringify(manifest)), + 'runtime', + 'minidb', + 'text-build-worker.mjs', + ), + ); + expect(packageRoot?.startsWith(join(dir, 'native', 'test', 'test-target'))).toBe(true); + expect(getMinidbTextBuildWorkerFile(options)).toBe(first); + + writeFileSync(first!, 'corrupt'); + expect(getMinidbTextBuildWorkerFile(options)).toBe(first); + expect(readFileSync(first!, 'utf-8')).toBe(worker); + + const installed = installMinidbTextBuildWorker(options); + expect(installed).toMatchObject({ status: 'installed', assetSha256: sha256(worker) }); + expect(getTextBuildWorkerRuntimeState()).toMatchObject({ + configured: true, + entry: { kind: 'packaged', path: first }, + }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('reports missing and corrupt runtime worker assets without configuring MiniDb', () => { + const dir = mkdtempSync(join(tmpdir(), 'kimi-native-worker-fail-')); + try { + const missing = fakeManifest({}); + expect( + installMinidbTextBuildWorker({ + cacheBase: dir, + manifest: missing.manifest, + source: missing.source, + version: 'test', + }), + ).toEqual({ status: 'asset-missing' }); + + const corrupt = fakeManifest({}, 'worker'); + const corruptSource: NativeAssetSource = { + getAssetKeys: () => corrupt.source.getAssetKeys(), + getRawAsset: (key) => + key.endsWith('/runtime/minidb-text-build-worker') + ? Buffer.from('wrong') + : corrupt.source.getRawAsset(key), + }; + expect( + installMinidbTextBuildWorker({ + cacheBase: dir, + manifest: corrupt.manifest, + source: corruptSource, + version: 'test', + }), + ).toMatchObject({ status: 'failed', errorCode: 'Error' }); + expect(getTextBuildWorkerRuntimeState()).toEqual({ configured: false }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('rejects unsupported or structurally incomplete native manifest versions', () => { + const valid = fakeManifest({}, 'worker').manifest; + const cases: Array<{ manifest: unknown; error: RegExp }> = [ + { manifest: { ...valid, version: 1 }, error: /Unsupported native asset manifest version: 1/ }, + { + manifest: { version: NATIVE_ASSET_MANIFEST_VERSION, target: 'test-target', runtimeFiles: [] }, + error: /packages must be an array/, + }, + { + manifest: { version: NATIVE_ASSET_MANIFEST_VERSION, target: 'test-target', packages: [] }, + error: /runtimeFiles must be an array/, + }, + { manifest: { ...valid, packages: {} }, error: /packages must be an array/ }, + { manifest: { ...valid, runtimeFiles: {} }, error: /runtimeFiles must be an array/ }, + ]; + + for (const item of cases) { + expect(() => + getEmbeddedNativeAssetManifest(sourceForManifest(item.manifest), 'test-target'), + ).toThrow(item.error); + } + }); + + it('rejects unsafe paths, invalid file metadata, and duplicate manifest keys', () => { + const valid = fakeManifest({}, 'worker').manifest; + const worker = valid.runtimeFiles[0]!; + const invalidRuntimeFiles: Array<{ file: Record; error: RegExp }> = [ + { file: { ...worker, relativePath: '/tmp/worker.mjs' }, error: /safe relative path/ }, + { file: { ...worker, relativePath: '../worker.mjs' }, error: /safe relative path/ }, + { file: { ...worker, relativePath: 'runtime\\..\\worker.mjs' }, error: /safe relative path/ }, + { file: { ...worker, sha256: 'not-a-sha' }, error: /64 lowercase hex/ }, + { file: { ...worker, mode: 0o1000 }, error: /mode must be an integer/ }, + { file: { ...worker, assetKey: 42 }, error: /assetKey must be a non-empty string/ }, + ]; + for (const item of invalidRuntimeFiles) { + expect(() => + getEmbeddedNativeAssetManifest( + sourceForManifest({ ...valid, runtimeFiles: [item.file] }), + 'test-target', + ), + ).toThrow(item.error); + } + + const validPackage = valid.packages[0]!; + expect(() => + getEmbeddedNativeAssetManifest( + sourceForManifest({ + ...valid, + packages: [{ ...validPackage, root: '../node_modules/fake-native' }], + }), + 'test-target', + ), + ).toThrow(/safe relative path/); + expect(() => + getEmbeddedNativeAssetManifest( + sourceForManifest({ + ...valid, + packages: [{ ...validPackage, files: {} }], + }), + 'test-target', + ), + ).toThrow(/files must be an array/); + + expect(() => + getEmbeddedNativeAssetManifest( + sourceForManifest({ + ...valid, + runtimeFiles: [ + worker, + { ...worker, assetKey: 'native/test-target/runtime/other', relativePath: 'runtime/other.mjs' }, + ], + }), + 'test-target', + ), + ).toThrow(/duplicate runtime key/); + + expect(() => + getEmbeddedNativeAssetManifest( + sourceForManifest({ + ...valid, + runtimeFiles: [ + worker, + { + ...worker, + key: 'other', + relativePath: 'runtime/other.mjs', + }, + ], + }), + 'test-target', + ), + ).toThrow(/duplicate assetKey/); + }); +}); diff --git a/apps/kimi-code/test/native/web-assets.test.ts b/apps/kimi-code/test/native/web-assets.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..abe3801feeca2338b8322113edead5cbe93651dc --- /dev/null +++ b/apps/kimi-code/test/native/web-assets.test.ts @@ -0,0 +1,113 @@ +import { createHash } from 'node:crypto'; +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { describe, expect, it } from 'vitest'; + +import { + getNativeWebAssetsDir, + getWebAssetCacheRoot, + WEB_ASSET_MANIFEST_VERSION, + type WebAssetManifest, + type WebAssetSource, +} from '#/native/web-assets'; + +function sha256(bytes: Buffer | string): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +function fakeWebAssets(files: Record): { + manifest: WebAssetManifest; + source: WebAssetSource; +} { + const manifest: WebAssetManifest = { + version: WEB_ASSET_MANIFEST_VERSION, + target: 'test-target', + root: 'dist-web', + files: Object.entries(files).map(([relativePath, content]) => ({ + assetKey: `web/test-target/dist-web/${relativePath}`, + relativePath, + sha256: sha256(content), + })), + }; + const assets = new Map([ + ['web/test-target/manifest.json', Buffer.from(JSON.stringify(manifest))], + ...Object.entries(files).map(([relativePath, content]) => [ + `web/test-target/dist-web/${relativePath}`, + Buffer.from(content), + ] as const), + ]); + return { + manifest, + source: { + getAssetKeys: () => [...assets.keys()], + getRawAsset: (assetKey) => { + const asset = assets.get(assetKey); + if (asset === undefined) throw new Error(`missing test asset: ${assetKey}`); + return asset; + }, + }, + }; +} + +describe('web assets', () => { + it('extracts embedded web assets into a dist-web cache directory', () => { + const dir = mkdtempSync(join(tmpdir(), 'kimi-web-assets-runtime-')); + try { + const { manifest, source } = fakeWebAssets({ + 'index.html': '
\n', + 'assets/app.js': 'console.log("ok");\n', + }); + + const webDir = getNativeWebAssetsDir({ + cacheBase: dir, + manifest, + source, + version: 'test', + }); + + expect(webDir).toBe(getWebAssetCacheRoot(manifest, { cacheBase: dir, version: 'test' })); + expect(readFileSync(join(webDir ?? '', 'index.html'), 'utf-8')).toBe('
\n'); + expect(readFileSync(join(webDir ?? '', 'assets', 'app.js'), 'utf-8')).toBe( + 'console.log("ok");\n', + ); + expect(existsSync(join(dir, 'web', 'test', 'test-target'))).toBe(true); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('repairs corrupted extracted files on the next lookup', () => { + const dir = mkdtempSync(join(tmpdir(), 'kimi-web-assets-repair-')); + try { + const { manifest, source } = fakeWebAssets({ + 'index.html': '', + }); + + const webDir = getNativeWebAssetsDir({ + cacheBase: dir, + manifest, + source, + version: 'test', + }); + writeFileSync(join(webDir ?? '', 'index.html'), 'broken'); + + const repairedDir = getNativeWebAssetsDir({ + cacheBase: dir, + manifest, + source, + version: 'test', + }); + + expect(repairedDir).toBe(webDir); + expect(readFileSync(join(repairedDir ?? '', 'index.html'), 'utf-8')).toBe(''); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('returns null when no SEA web asset source is available', () => { + expect(getNativeWebAssetsDir({ source: null })).toBeNull(); + }); +}); diff --git a/apps/kimi-code/test/postinstall/takeover.test.ts b/apps/kimi-code/test/postinstall/takeover.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1919aa70b2f2bf736dfcc89d411a0704e5be5d52 --- /dev/null +++ b/apps/kimi-code/test/postinstall/takeover.test.ts @@ -0,0 +1,316 @@ +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { chmod, mkdir, mkdtemp, readFile, realpath, rm, symlink, writeFile } from 'node:fs/promises'; +import { existsSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { + executeTakeover, + planTakeover, + verifyTakeover, +} from '../../scripts/postinstall/takeover.mjs'; +import { + detectPackageManager, + isGlobalInstall, + ownPackageRoot, +} from '../../scripts/postinstall/reach.mjs'; +import { renameTargetFor, isSystemOwnedDir } from '../../scripts/postinstall/migrate.mjs'; +import { executableCandidates } from '../../scripts/postinstall/platform.mjs'; + +const POSIX = process.platform !== 'win32'; +const DELIM = POSIX ? ':' : ';'; +const PLATFORM = process.platform; + +let root: string; +beforeEach(async () => { + root = await mkdtemp(join(tmpdir(), 'postinstall-')); +}); +afterEach(async () => { + await rm(root, { recursive: true, force: true }); + for (const key of [ + 'npm_config_global', + 'pnpm_config_global', + 'npm_config_location', + 'npm_config_user_agent', + 'npm_config_argv', + ]) { + delete process.env[key]; + } +}); + +interface TestEnv { + ownRoot: string; + ownBin: string; + path: (...dirs: string[]) => string; +} + +async function makeEnv(): Promise { + const ownRoot = join(root, 'ownpkg'); + const ownBin = join(root, 'ownbin'); + await mkdir(ownRoot, { recursive: true }); + await mkdir(ownBin, { recursive: true }); + await writeFile(join(ownRoot, 'package.json'), '{"name":"@moonshot-ai/kimi-code"}', 'utf-8'); + await writeFile(join(ownRoot, 'main.mjs'), '// kimi-code\n', 'utf-8'); + await chmod(join(ownRoot, 'main.mjs'), 0o755); + await symlink(join(ownRoot, 'main.mjs'), join(ownBin, 'kimi')); + return { + ownRoot: await realpath(ownRoot), + ownBin, + path: (...dirs) => dirs.join(DELIM), + }; +} + +async function makeLegacyShim(dirName: string): Promise<{ dir: string; shim: string }> { + const dir = join(root, dirName); + await mkdir(dir, { recursive: true }); + const shim = join(dir, 'kimi'); + await writeFile(shim, '#!/bin/sh\n# setuptools entry point for kimi_cli\n', 'utf-8'); + await chmod(shim, 0o755); + return { dir, shim }; +} + +describe.runIf(POSIX)('shim takeover (POSIX fixtures)', () => { + it('renames a single legacy shim to kimi-legacy and verifies the takeover', async () => { + const env = await makeEnv(); + const legacy = await makeLegacyShim('uvbin'); + const detection = env.path(env.ownBin, legacy.dir); + const reachability = env.path(env.ownBin, legacy.dir); + + const plan = await planTakeover(env.ownRoot, detection, reachability, PLATFORM); + expect(plan.kind).toBe('proceed'); + if (plan.kind !== 'proceed') return; + + const outcomes = await executeTakeover(plan.classifications); + expect(outcomes.renames).toHaveLength(1); + expect(outcomes.errors).toHaveLength(0); + expect(existsSync(join(legacy.dir, 'kimi-legacy'))).toBe(true); + expect(existsSync(legacy.shim)).toBe(false); + await expect(readFile(join(legacy.dir, 'kimi-legacy'), 'utf-8')).resolves.toContain( + 'kimi_cli', + ); + + const verify = await verifyTakeover( + env.ownRoot, + reachability, + plan.classifications.map((c) => c.shimPath), + PLATFORM, + ); + expect(verify.kind).toBe('own'); + }); + + it('preserves the first of two legacy shims and deletes the second', async () => { + const env = await makeEnv(); + const first = await makeLegacyShim('uvbin'); + const second = await makeLegacyShim('pipxbin'); + const detection = env.path(env.ownBin, first.dir, second.dir); + const reachability = env.path(env.ownBin, first.dir, second.dir); + + const plan = await planTakeover(env.ownRoot, detection, reachability, PLATFORM); + expect(plan.kind).toBe('proceed'); + if (plan.kind !== 'proceed') return; + + const outcomes = await executeTakeover(plan.classifications); + expect(outcomes.renames.map((c) => c.shimPath)).toEqual([first.shim]); + expect(outcomes.deletes.map((c) => c.shimPath)).toEqual([second.shim]); + expect(existsSync(join(first.dir, 'kimi-legacy'))).toBe(true); + expect(existsSync(join(second.dir, 'kimi'))).toBe(false); + expect(existsSync(join(second.dir, 'kimi-legacy'))).toBe(false); + }); + + it('consolidates onto an existing legacy kimi-legacy', async () => { + const env = await makeEnv(); + const legacy = await makeLegacyShim('uvbin'); + await writeFile( + join(legacy.dir, 'kimi-legacy'), + '#!/bin/sh\n# older kimi_cli entry point\n', + 'utf-8', + ); + + const plan = await planTakeover(env.ownRoot, env.path(env.ownBin, legacy.dir), env.path(env.ownBin, legacy.dir), PLATFORM); + expect(plan.kind).toBe('proceed'); + if (plan.kind !== 'proceed') return; + + const outcomes = await executeTakeover(plan.classifications); + expect(outcomes.consolidates).toHaveLength(1); + expect(existsSync(legacy.shim)).toBe(false); + await expect(readFile(join(legacy.dir, 'kimi-legacy'), 'utf-8')).resolves.toContain( + 'older kimi_cli', + ); + }); + + it('leaves a user-managed kimi-legacy untouched (delete-only)', async () => { + const env = await makeEnv(); + const legacy = await makeLegacyShim('uvbin'); + await writeFile(join(legacy.dir, 'kimi-legacy'), 'my own wrapper\n', 'utf-8'); + + const plan = await planTakeover(env.ownRoot, env.path(env.ownBin, legacy.dir), env.path(env.ownBin, legacy.dir), PLATFORM); + expect(plan.kind).toBe('proceed'); + if (plan.kind !== 'proceed') return; + + const outcomes = await executeTakeover(plan.classifications); + expect(outcomes.skippedForeignTarget).toHaveLength(1); + expect(outcomes.preserved).toBe(false); + expect(existsSync(legacy.shim)).toBe(false); + await expect(readFile(join(legacy.dir, 'kimi-legacy'), 'utf-8')).resolves.toBe( + 'my own wrapper\n', + ); + }); + + it('a failed preserve attempt gives the next shim its own preserve attempt', async () => { + const env = await makeEnv(); + const first = await makeLegacyShim('uvbin'); + const second = await makeLegacyShim('pipxbin'); + + const outcomes = await executeTakeover([ + { + kind: 'renameable', + shimPath: join(root, 'gone', 'kimi'), + target: join(root, 'gone', 'kimi-legacy'), + detection: { shimPath: join(root, 'gone', 'kimi'), realPath: '' }, + }, + { + kind: 'renameable', + shimPath: second.shim, + target: join(second.dir, 'kimi-legacy'), + detection: { shimPath: second.shim, realPath: second.shim }, + }, + ]); + + expect(outcomes.errors).toHaveLength(1); + expect(outcomes.renames.map((c) => c.shimPath)).toEqual([second.shim]); + expect(outcomes.deletes).toHaveLength(0); + expect(outcomes.preserved).toBe(true); + expect(existsSync(join(second.dir, 'kimi-legacy'))).toBe(true); + }); + + it('reports the takeover as not held when a shim survives ahead of ours', async () => { + const env = await makeEnv(); + const legacy = await makeLegacyShim('uvbin'); + const reachability = env.path(legacy.dir, env.ownBin); + + const plan = await planTakeover(env.ownRoot, env.path(legacy.dir, env.ownBin), reachability, PLATFORM); + expect(plan.kind).toBe('proceed'); + if (plan.kind !== 'proceed') return; + + const verify = await verifyTakeover( + env.ownRoot, + reachability, + plan.classifications.map((c) => c.shimPath), + PLATFORM, + ); + expect(verify.kind).toBe('blocked-legacy'); + }); + + it('aborts with kind=blocked when the shim dir is not writable', async () => { + if (process.getuid?.() === 0) return; + const env = await makeEnv(); + const legacy = await makeLegacyShim('sysbin'); + await chmod(legacy.dir, 0o555); + try { + const plan = await planTakeover(env.ownRoot, env.path(env.ownBin, legacy.dir), env.path(legacy.dir, env.ownBin), PLATFORM); + expect(plan.kind).toBe('blocked'); + expect(existsSync(legacy.shim)).toBe(true); + } finally { + await chmod(legacy.dir, 0o755); + } + }); + + it('aborts with kind=foreign when an unrecognized kimi wins resolution', async () => { + const env = await makeEnv(); + const foreignDir = join(root, 'homebin'); + await mkdir(foreignDir, { recursive: true }); + await writeFile(join(foreignDir, 'kimi'), '#!/bin/sh\necho mine\n', 'utf-8'); + await chmod(join(foreignDir, 'kimi'), 0o755); + const legacy = await makeLegacyShim('uvbin'); + + const plan = await planTakeover( + env.ownRoot, + env.path(foreignDir, legacy.dir, env.ownBin), + env.path(foreignDir, legacy.dir, env.ownBin), + PLATFORM, + ); + expect(plan.kind).toBe('foreign'); + expect(existsSync(legacy.shim)).toBe(true); + }); + + it('aborts with kind=not-on-path when our shim is not reachable', async () => { + const env = await makeEnv(); + const legacy = await makeLegacyShim('uvbin'); + + const plan = await planTakeover(env.ownRoot, env.path(env.ownBin, legacy.dir), env.path(legacy.dir), PLATFORM); + expect(plan.kind).toBe('not-on-path'); + expect(existsSync(legacy.shim)).toBe(true); + }); + + it('returns noop when no legacy shim exists', async () => { + const env = await makeEnv(); + const plan = await planTakeover(env.ownRoot, env.path(env.ownBin), env.path(env.ownBin), PLATFORM); + expect(plan.kind).toBe('noop'); + }); + + it('verifies none when every kimi is gone after execution', async () => { + const env = await makeEnv(); + const verify = await verifyTakeover(env.ownRoot, env.path(join(root, 'emptybin')), [], PLATFORM); + expect(verify.kind).toBe('none'); + }); +}); + +describe('package-manager and own-root detection', () => { + it('detects the package manager from npm_config_user_agent', () => { + process.env['npm_config_user_agent'] = 'pnpm/9.1.0 npm/? node/v22.0.0 darwin arm64'; + expect(detectPackageManager()).toBe('pnpm'); + process.env['npm_config_user_agent'] = 'yarn/1.22.22 npm/? node/v22.0.0 darwin arm64'; + expect(detectPackageManager()).toBe('yarn'); + process.env['npm_config_user_agent'] = 'npm/11.0.0 node/v22.0.0 darwin arm64'; + expect(detectPackageManager()).toBe('npm'); + }); + + it('gates on the documented global-install signals', () => { + expect(isGlobalInstall()).toBe(false); + process.env['npm_config_global'] = 'true'; + expect(isGlobalInstall()).toBe(true); + delete process.env['npm_config_global']; + process.env['npm_config_location'] = 'global'; + expect(isGlobalInstall()).toBe(true); + delete process.env['npm_config_location']; + process.env['pnpm_config_global'] = 'true'; + expect(isGlobalInstall()).toBe(true); + }); + + it('locates the own package root from a nested start dir', async () => { + const pkg = join(root, 'pkgroot'); + await mkdir(join(pkg, 'scripts', 'postinstall'), { recursive: true }); + await writeFile(join(pkg, 'package.json'), '{}', 'utf-8'); + expect(await ownPackageRoot(join(pkg, 'scripts', 'postinstall'))).toBe(await realpath(pkg)); + }); +}); + +describe('windows forms (platform injection, host-agnostic)', () => { + it('expands PATHEXT candidates for kimi', () => { + const candidates = executableCandidates('kimi', 'win32'); + expect(candidates).toContain('kimi'); + expect(candidates).toContain('kimi.exe'); + expect(candidates).toContain('kimi.cmd'); + expect(executableCandidates('kimi', 'linux')).toEqual(['kimi']); + }); + + it('preserves the extension in the rename target', () => { + expect(renameTargetFor('C:\\Users\\me\\.local\\bin\\kimi.exe', 'win32')).toBe( + 'C:\\Users\\me\\.local\\bin\\kimi-legacy.exe', + ); + expect(renameTargetFor('C:\\Users\\me\\.local\\bin\\kimi', 'win32')).toBe( + 'C:\\Users\\me\\.local\\bin\\kimi-legacy', + ); + expect(renameTargetFor('/home/me/.local/bin/kimi', 'linux')).toBe( + '/home/me/.local/bin/kimi-legacy', + ); + }); + + it('classifies system-owned dirs from drive-letter and UNC forms', async () => { + await expect(isSystemOwnedDir('C:\\Program Files\\kimi\\kimi.exe', 'win32')).resolves.toBe(true); + await expect(isSystemOwnedDir('c:\\programdata\\uv\\kimi.exe', 'win32')).resolves.toBe(true); + await expect(isSystemOwnedDir('C:\\Users\\me\\.local\\bin\\kimi.exe', 'win32')).resolves.toBe(false); + await expect(isSystemOwnedDir('D:\\tools\\kimi.exe', 'win32')).resolves.toBe(false); + await expect(isSystemOwnedDir('\\\\server\\share\\tools\\kimi.exe', 'win32')).resolves.toBe(false); + }); +}); diff --git a/apps/kimi-code/test/scripts/build-plugin-marketplace-cdn.test.ts b/apps/kimi-code/test/scripts/build-plugin-marketplace-cdn.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b011094a1d547f6cb4b5f9956033d3f47070774 --- /dev/null +++ b/apps/kimi-code/test/scripts/build-plugin-marketplace-cdn.test.ts @@ -0,0 +1,55 @@ +import { access, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, describe, expect, it } from 'vitest'; + +import { buildPluginMarketplaceCdn } from '../../scripts/build-plugin-marketplace-cdn.mjs'; + +const tempRoots: string[] = []; + +afterEach(async () => { + await Promise.all( + tempRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })), + ); +}); + +describe('buildPluginMarketplaceCdn', () => { + it('packages WebBridge without publishing other unlisted official directories', async () => { + const root = await mkdtemp(join(tmpdir(), 'kimi-plugin-cdn-build-')); + tempRoots.push(root); + const pluginsRoot = join(root, 'plugins'); + const outDir = join(root, 'out'); + + await writePlugin(pluginsRoot, 'listed-plugin'); + await writePlugin(pluginsRoot, 'kimi-webbridge'); + await writePlugin(pluginsRoot, 'not-listed'); + await writeFile( + join(pluginsRoot, 'marketplace.json'), + JSON.stringify({ + version: '1', + plugins: [{ id: 'listed-plugin', source: './official/listed-plugin' }], + }), + 'utf8', + ); + + await buildPluginMarketplaceCdn({ pluginsRoot, outDir }); + + await expect(access(join(outDir, 'official/listed-plugin.zip'))).resolves.toBeUndefined(); + await expect(access(join(outDir, 'official/kimi-webbridge.zip'))).resolves.toBeUndefined(); + await expect(access(join(outDir, 'official/not-listed.zip'))).rejects.toThrow(); + const marketplace = JSON.parse(await readFile(join(outDir, 'marketplace.json'), 'utf8')); + expect(marketplace.plugins).toHaveLength(1); + expect(marketplace.plugins[0].id).toBe('listed-plugin'); + }); +}); + +async function writePlugin(pluginsRoot: string, id: string): Promise { + const pluginDir = join(pluginsRoot, 'official', id); + await mkdir(pluginDir, { recursive: true }); + await writeFile( + join(pluginDir, 'kimi.plugin.json'), + JSON.stringify({ name: id, version: '1.0.0' }), + 'utf8', + ); +} diff --git a/apps/kimi-code/test/scripts/native/exec.test.ts b/apps/kimi-code/test/scripts/native/exec.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..87f5811916b1c1ee4c0870bc085fda740ab87bf2 --- /dev/null +++ b/apps/kimi-code/test/scripts/native/exec.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest'; + +import { commandForExecFile } from '../../../scripts/native/exec.mjs'; + +describe('commandForExecFile', () => { + it('returns command as-is on non-Windows', () => { + const result = commandForExecFile('postject', ['kimi', 'NODE_SEA_BLOB', './blob'], 'darwin'); + expect(result).toEqual({ command: 'postject', args: ['kimi', 'NODE_SEA_BLOB', './blob'] }); + }); + + it('returns command as-is on Windows for non-batch files', () => { + const result = commandForExecFile('postject.exe', ['kimi.exe'], 'win32'); + expect(result).toEqual({ command: 'postject.exe', args: ['kimi.exe'] }); + }); + + it('wraps .cmd files through cmd.exe on Windows', () => { + const result = commandForExecFile('postject.cmd', ['kimi.exe', 'NODE_SEA_BLOB'], 'win32', { + ComSpec: 'C:\\Windows\\System32\\cmd.exe', + }); + expect(result.command).toBe('C:\\Windows\\System32\\cmd.exe'); + expect(result.args).toEqual([ + '/d', + '/s', + '/c', + '""postject.cmd" "kimi.exe" "NODE_SEA_BLOB""', + ]); + expect(result.options?.windowsVerbatimArguments).toBe(true); + }); + + it('wraps .bat files through cmd.exe on Windows', () => { + const result = commandForExecFile('foo.bat', [], 'win32', { ComSpec: 'cmd.exe' }); + expect(result.command).toBe('cmd.exe'); + }); + + it('escapes embedded double quotes in args', () => { + const result = commandForExecFile('foo.cmd', ['hello "world"'], 'win32', { + ComSpec: 'cmd.exe', + }); + expect(result.args[3]).toBe('""foo.cmd" "hello ""world""""'); + }); + + it('falls back to cmd.exe when ComSpec missing', () => { + const result = commandForExecFile('foo.cmd', [], 'win32', {}); + expect(result.command).toBe('cmd.exe'); + }); +}); diff --git a/apps/kimi-code/test/scripts/native/manifest.test.ts b/apps/kimi-code/test/scripts/native/manifest.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f8b6892fd22bff8b1e9257effbf4e5db25c8967 --- /dev/null +++ b/apps/kimi-code/test/scripts/native/manifest.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from 'vitest'; + +import { + NATIVE_ASSET_MANIFEST_VERSION, + buildManifestKey, + isManifestVersionSupported, +} from '../../../scripts/native/manifest.mjs'; + +describe('NATIVE_ASSET_MANIFEST_VERSION', () => { + it('is a positive integer', () => { + expect(Number.isInteger(NATIVE_ASSET_MANIFEST_VERSION)).toBe(true); + expect(NATIVE_ASSET_MANIFEST_VERSION).toBeGreaterThan(0); + }); +}); + +describe('buildManifestKey', () => { + it('namespaces by target', () => { + expect(buildManifestKey('darwin-arm64')).toBe('native/darwin-arm64/manifest.json'); + expect(buildManifestKey('linux-x64')).toBe('native/linux-x64/manifest.json'); + }); +}); + +describe('isManifestVersionSupported', () => { + it('accepts current version', () => { + expect(isManifestVersionSupported(NATIVE_ASSET_MANIFEST_VERSION)).toBe(true); + }); + + it('rejects other versions', () => { + expect(isManifestVersionSupported(NATIVE_ASSET_MANIFEST_VERSION + 1)).toBe(false); + expect(isManifestVersionSupported(0)).toBe(false); + }); +}); diff --git a/apps/kimi-code/test/scripts/native/native-deps.test.ts b/apps/kimi-code/test/scripts/native/native-deps.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b0893fabea3df593770e4946a1c1d220154ec0c --- /dev/null +++ b/apps/kimi-code/test/scripts/native/native-deps.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, it } from 'vitest'; + +import { + nativeDeps, + resolveTargetDeps, + isSupportedTarget, + SUPPORTED_TARGETS, +} from '../../../scripts/native/native-deps.mjs'; + +describe('SUPPORTED_TARGETS', () => { + it('contains the six published targets', () => { + expect([...SUPPORTED_TARGETS].toSorted()).toEqual( + [ + 'darwin-arm64', + 'darwin-x64', + 'linux-arm64', + 'linux-x64', + 'win32-arm64', + 'win32-x64', + ].toSorted(), + ); + }); +}); + +describe('isSupportedTarget', () => { + it('accepts every supported target', () => { + for (const t of SUPPORTED_TARGETS) { + expect(isSupportedTarget(t)).toBe(true); + } + }); + + it('rejects unknown targets', () => { + expect(isSupportedTarget('linux-x64-musl')).toBe(false); + expect(isSupportedTarget('darwin-arm')).toBe(false); + }); +}); + +describe('resolveTargetDeps', () => { + it('returns one descriptor per package for darwin-arm64', () => { + const deps = resolveTargetDeps('darwin-arm64'); + const names = deps.map((d) => d.resolvedName); + expect(names).toContain('@mariozechner/clipboard'); + expect(names).toContain('@mariozechner/clipboard-darwin-arm64'); + expect(names).toContain('@moonshot-ai/pi-tui'); + }); + + it('picks the right clipboard subpackage per target', () => { + expect( + resolveTargetDeps('linux-x64').map((d) => d.resolvedName), + ).toContain('@mariozechner/clipboard-linux-x64-gnu'); + expect( + resolveTargetDeps('win32-x64').map((d) => d.resolvedName), + ).toContain('@mariozechner/clipboard-win32-x64-msvc'); + expect( + resolveTargetDeps('win32-arm64').map((d) => d.resolvedName), + ).toContain('@mariozechner/clipboard-win32-arm64-msvc'); + }); + + it('encodes pi-tui native file path per target', () => { + const linuxPiTui = resolveTargetDeps('linux-arm64').find( + (d) => d.resolvedName === '@moonshot-ai/pi-tui', + ); + expect(linuxPiTui?.nativeFileRelatives).toEqual([ + 'native/linux/prebuilds/linux-arm64/linux-platform-x11.node', + ]); + const macPiTui = resolveTargetDeps('darwin-x64').find( + (d) => d.resolvedName === '@moonshot-ai/pi-tui', + ); + expect(macPiTui?.nativeFileRelatives).toEqual([ + 'native/darwin/prebuilds/darwin-x64/darwin-platform.node', + ]); + const winArmPiTui = resolveTargetDeps('win32-arm64').find( + (d) => d.resolvedName === '@moonshot-ai/pi-tui', + ); + expect(winArmPiTui?.nativeFileRelatives).toEqual([ + 'native/win32/prebuilds/win32-arm64/win32-platform.node', + ]); + }); + + it('throws on unsupported target', () => { + expect(() => resolveTargetDeps('linux-x64-musl')).toThrow(/unsupported/i); + }); +}); + +describe('nativeDeps registry shape', () => { + it('has clipboard host (collect=js-only)', () => { + const host = nativeDeps.find((d) => d.id === 'clipboard-host'); + expect(host?.collect).toBe('js-only'); + }); + + it('has clipboard-target (collect=native-files, parent=clipboard-host)', () => { + const target = nativeDeps.find((d) => d.id === 'clipboard-target'); + expect(target?.collect).toBe('native-files'); + expect(target?.parent).toBe('clipboard-host'); + }); + + it('has pi-tui (collect=native-file-only, no parent)', () => { + const piTui = nativeDeps.find((d) => d.id === 'pi-tui'); + expect(piTui?.collect).toBe('native-file-only'); + expect(piTui?.parent).toBe(null); + }); +}); diff --git a/apps/kimi-code/test/scripts/native/paths.test.ts b/apps/kimi-code/test/scripts/native/paths.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..826ade0bacab090311a89cd63b883ae42c5ba2b4 --- /dev/null +++ b/apps/kimi-code/test/scripts/native/paths.test.ts @@ -0,0 +1,107 @@ +import { resolve } from 'node:path'; + +import { describe, expect, it } from 'vitest'; + +import { + appRoot, + executableName, + nativeIntermediatesDir, + nativeBinDir, + nativeBinPath, + nativeBlobPath, + nativeJsBundlePath, + nativeManifestKey, + nativeSeaConfigPath, + targetTriple, + nativeDistRoot, + nativeManifestDir, + nativeArtifactsDir, + nativeSmokeHome, + SEA_SENTINEL_FUSE, +} from '../../../scripts/native/paths.mjs'; + +// paths.mjs builds every path with node:path.resolve (backslashes on Windows). +// Build expectations the same way so they match on every platform. +const p = (...segments: string[]): string => resolve(appRoot, ...segments); + +describe('targetTriple', () => { + it('returns platform-arch when env unset', () => { + expect(targetTriple({ platform: 'darwin', arch: 'arm64', env: {} })).toBe('darwin-arm64'); + expect(targetTriple({ platform: 'linux', arch: 'x64', env: {} })).toBe('linux-x64'); + expect(targetTriple({ platform: 'win32', arch: 'x64', env: {} })).toBe('win32-x64'); + }); + + it('honors KIMI_CODE_BUILD_TARGET override', () => { + expect( + targetTriple({ + platform: 'darwin', + arch: 'arm64', + env: { KIMI_CODE_BUILD_TARGET: 'linux-arm64' }, + }), + ).toBe('linux-arm64'); + }); +}); + +describe('executableName', () => { + it('returns kimi.exe on win32', () => { + expect(executableName('win32')).toBe('kimi.exe'); + }); + + it('returns kimi on other platforms', () => { + expect(executableName('darwin')).toBe('kimi'); + expect(executableName('linux')).toBe('kimi'); + }); +}); + +describe('path helpers', () => { + it('returns absolute intermediates dir under app root', () => { + expect(nativeIntermediatesDir()).toBe(p('dist-native/intermediates')); + }); + + it('returns absolute bin dir per target', () => { + expect(nativeBinDir('darwin-arm64')).toBe(p('dist-native/bin/darwin-arm64')); + }); + + it('returns absolute bin path with executable name', () => { + expect(nativeBinPath('darwin-arm64', 'darwin')).toBe( + p('dist-native/bin/darwin-arm64/kimi'), + ); + expect(nativeBinPath('win32-x64', 'win32')).toBe( + p('dist-native/bin/win32-x64/kimi.exe'), + ); + }); + + it('returns intermediate artifact paths', () => { + expect(nativeJsBundlePath()).toBe(p('dist-native/intermediates/main.cjs')); + expect(nativeBlobPath()).toBe(p('dist-native/intermediates/kimi.blob')); + expect(nativeSeaConfigPath()).toBe( + p('dist-native/intermediates/sea-config.json'), + ); + }); + + it('returns manifest key for target', () => { + expect(nativeManifestKey('darwin-arm64')).toBe('native/darwin-arm64/manifest.json'); + }); + + it('returns native dist root', () => { + expect(nativeDistRoot()).toBe(p('dist-native')); + }); + + it('returns manifest dir for target', () => { + expect(nativeManifestDir('darwin-arm64')).toBe( + p('dist-native/intermediates/native-assets/darwin-arm64'), + ); + }); + + it('returns artifacts dir', () => { + expect(nativeArtifactsDir()).toBe(p('dist-native/artifacts')); + }); + + it('returns smoke home', () => { + expect(nativeSmokeHome()).toBe(p('dist-native/smoke-home')); + }); + + it('has correct SEA sentinel fuse value', () => { + expect(SEA_SENTINEL_FUSE).toBe('NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2'); + }); +}); diff --git a/apps/kimi-code/test/scripts/native/release-artifacts.test.ts b/apps/kimi-code/test/scripts/native/release-artifacts.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b4586eab3401c5b2b9549b358c115b35e7a443f --- /dev/null +++ b/apps/kimi-code/test/scripts/native/release-artifacts.test.ts @@ -0,0 +1,217 @@ +import { createHash } from 'node:crypto'; +import { createWriteStream, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdtemp, readFile, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { execFile } from 'node:child_process'; +import { pipeline } from 'node:stream/promises'; +import { promisify } from 'node:util'; +import { inflateRawSync, zstdDecompressSync } from 'node:zlib'; + +import { afterEach, describe, expect, it } from 'vitest'; +import { ZipFile } from 'yazl'; + +import { appRoot } from '../../../scripts/native/paths.mjs'; + +const execFileAsync = promisify(execFile); +const packageScript = resolve(appRoot, 'scripts/native/package.mjs'); +const manifestScript = resolve(appRoot, 'scripts/native/produce-manifest.mjs'); +const artifactsDir = resolve(appRoot, 'dist-native/artifacts'); +const target = 'test-zip-artifact'; +const executableName = process.platform === 'win32' ? 'kimi.exe' : 'kimi'; +const fakeBinary = resolve(appRoot, 'dist-native/bin', target, executableName); + +function sha256(bytes: Buffer | string): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +function zipEntryNames(zipPath: string): readonly string[] { + const zip = readFileSync(zipPath); + const eocdOffset = findEndOfCentralDirectory(zip); + const entryCount = zip.readUInt16LE(eocdOffset + 10); + let offset = zip.readUInt32LE(eocdOffset + 16); + const names: string[] = []; + + for (let i = 0; i < entryCount; i += 1) { + expect(zip.readUInt32LE(offset)).toBe(0x02014b50); + const nameLength = zip.readUInt16LE(offset + 28); + const extraLength = zip.readUInt16LE(offset + 30); + const commentLength = zip.readUInt16LE(offset + 32); + names.push(zip.subarray(offset + 46, offset + 46 + nameLength).toString('utf-8')); + offset += 46 + nameLength + extraLength + commentLength; + } + + return names; +} + +function readZipEntry(zipPath: string, expectedName: string): Buffer { + const zip = readFileSync(zipPath); + const eocdOffset = findEndOfCentralDirectory(zip); + const entryCount = zip.readUInt16LE(eocdOffset + 10); + let offset = zip.readUInt32LE(eocdOffset + 16); + + for (let i = 0; i < entryCount; i += 1) { + expect(zip.readUInt32LE(offset)).toBe(0x02014b50); + const method = zip.readUInt16LE(offset + 10); + const compressedSize = zip.readUInt32LE(offset + 20); + const nameLength = zip.readUInt16LE(offset + 28); + const extraLength = zip.readUInt16LE(offset + 30); + const commentLength = zip.readUInt16LE(offset + 32); + const localHeaderOffset = zip.readUInt32LE(offset + 42); + const name = zip.subarray(offset + 46, offset + 46 + nameLength).toString('utf-8'); + if (name === expectedName) { + return readLocalEntry(zip, localHeaderOffset, method, compressedSize); + } + offset += 46 + nameLength + extraLength + commentLength; + } + + throw new Error(`zip entry not found: ${expectedName}`); +} + +function readLocalEntry( + zip: Buffer, + localHeaderOffset: number, + method: number, + compressedSize: number, +): Buffer { + expect(zip.readUInt32LE(localHeaderOffset)).toBe(0x04034b50); + const nameLength = zip.readUInt16LE(localHeaderOffset + 26); + const extraLength = zip.readUInt16LE(localHeaderOffset + 28); + const dataStart = localHeaderOffset + 30 + nameLength + extraLength; + const compressed = zip.subarray(dataStart, dataStart + compressedSize); + if (method === 0) return compressed; + if (method === 8) return inflateRawSync(compressed); + throw new Error(`unsupported zip compression method: ${String(method)}`); +} + +function findEndOfCentralDirectory(zip: Buffer): number { + for (let offset = zip.length - 22; offset >= 0; offset -= 1) { + if (zip.readUInt32LE(offset) === 0x06054b50) return offset; + } + throw new Error('end of central directory not found'); +} + +describe('native release artifacts', () => { + afterEach(() => { + rmSync(resolve(appRoot, 'dist-native/bin', target), { recursive: true, force: true }); + for (const name of [ + `kimi-code-${target}.zip`, + `kimi-code-${target}.zip.sha256`, + `kimi-code-${target}.zst`, + `kimi-code-${target}.zst.sha256`, + `kimi-code-${target}.tar.gz`, + `kimi-code-${target}.tar.gz.sha256`, + 'manifest.json', + ]) { + rmSync(resolve(artifactsDir, name), { force: true }); + } + }); + + it('packages the native binary as a zip archive and checksums the archive', async () => { + const binaryContent = 'native binary payload\n'; + mkdirSync(resolve(appRoot, 'dist-native/bin', target), { recursive: true }); + writeFileSync(fakeBinary, binaryContent, { mode: 0o755 }); + + await execFileAsync(process.execPath, [packageScript], { + cwd: appRoot, + env: { ...process.env, KIMI_CODE_BUILD_TARGET: target }, + }); + + const archivePath = resolve(artifactsDir, `kimi-code-${target}.zip`); + const checksumPath = `${archivePath}.sha256`; + expect(existsSync(archivePath)).toBe(true); + expect(existsSync(checksumPath)).toBe(true); + expect(zipEntryNames(archivePath)).toEqual([executableName]); + expect(readZipEntry(archivePath, executableName).toString('utf-8')).toBe(binaryContent); + expect(readFileSync(checksumPath, 'utf-8')).toBe( + `${sha256(readFileSync(archivePath))} kimi-code-${target}.zip\n`, + ); + }); + + it('produces compressed artifacts and a manifest paired with the bare binary', async () => { + const binaryContent = 'native binary payload\n'; + mkdirSync(resolve(appRoot, 'dist-native/bin', target), { recursive: true }); + writeFileSync(fakeBinary, binaryContent, { mode: 0o755 }); + await execFileAsync(process.execPath, [packageScript], { + cwd: appRoot, + env: { ...process.env, KIMI_CODE_BUILD_TARGET: target }, + }); + + await execFileAsync(process.execPath, [manifestScript, artifactsDir, '@moonshot-ai/kimi-code@0.5.0']); + + const zstBytes = readFileSync(resolve(artifactsDir, `kimi-code-${target}.zst`)); + expect(zstdDecompressSync(zstBytes).toString('utf-8')).toBe(binaryContent); + const tarballPath = resolve(artifactsDir, `kimi-code-${target}.tar.gz`); + expect(existsSync(tarballPath)).toBe(true); + expect(readFileSync(`${tarballPath}.sha256`, 'utf-8')).toBe( + `${sha256(readFileSync(tarballPath))} kimi-code-${target}.tar.gz\n`, + ); + + const manifest = JSON.parse( + readFileSync(resolve(artifactsDir, 'manifest.json'), 'utf-8'), + ) as { + version: string; + tag: string; + platforms: Record< + string, + { filename: string; checksum: string; compressed: { filename: string; checksum: string } } + >; + }; + expect(manifest).toEqual({ + version: '0.5.0', + tag: '@moonshot-ai/kimi-code@0.5.0', + platforms: { + [target]: { + filename: `kimi-code-${target}`, + checksum: sha256(Buffer.from(binaryContent)), + compressed: { filename: `kimi-code-${target}.zst`, checksum: sha256(zstBytes) }, + }, + }, + }); + }); + + it('keeps the .exe suffix in Windows manifest filenames', async () => { + const releaseDir = await mkdtemp(join(tmpdir(), 'kimi-manifest-win32-')); + try { + const binaryContent = Buffer.from('fake windows binary'); + const zip = new ZipFile(); + zip.addBuffer(binaryContent, 'kimi.exe'); + zip.end(); + await pipeline( + zip.outputStream, + createWriteStream(join(releaseDir, 'kimi-code-win32-x64.zip')), + ); + await writeFile( + join(releaseDir, 'kimi-code-win32-x64.zip.sha256'), + `${'b'.repeat(64)} kimi-code-win32-x64.zip\n`, + ); + + await execFileAsync(process.execPath, [manifestScript, releaseDir, 'v0.5.0']); + + const manifest = JSON.parse(await readFile(join(releaseDir, 'manifest.json'), 'utf-8')) as { + platforms: Record< + string, + { filename: string; checksum: string; compressed: { filename: string } } + >; + }; + const entry = manifest.platforms['win32-x64']; + if (entry === undefined) throw new Error('missing win32-x64 manifest entry'); + expect(entry.filename).toBe('kimi-code-win32-x64.exe'); + expect(entry.checksum).toBe(sha256(binaryContent)); + expect(entry.compressed.filename).toBe('kimi-code-win32-x64.zst'); + } finally { + rmSync(releaseDir, { recursive: true, force: true }); + } + }); + + it('fails when no zip sidecars exist', async () => { + const releaseDir = await mkdtemp(join(tmpdir(), 'kimi-manifest-empty-')); + try { + await expect( + execFileAsync(process.execPath, [manifestScript, releaseDir, 'v0.5.0']), + ).rejects.toThrow(); + } finally { + rmSync(releaseDir, { recursive: true, force: true }); + } + }); +}); diff --git a/apps/kimi-code/test/scripts/native/sign-args.test.ts b/apps/kimi-code/test/scripts/native/sign-args.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..803f1820a2e7193185f46b4b06c7140f3e61362b --- /dev/null +++ b/apps/kimi-code/test/scripts/native/sign-args.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, it } from 'vitest'; + +import { buildCodesignArgs } from '../../../scripts/native/04-sign.mjs'; + +describe('buildCodesignArgs', () => { + it('returns ad-hoc args for identity "-"', () => { + const args = buildCodesignArgs({ + identity: '-', + executable: '/path/kimi', + entitlementsPath: '/path/entitlements.plist', + keychainPath: null, + }); + expect(args).toEqual(['--sign', '-', '/path/kimi']); + }); + + it('returns hardened-runtime args for Developer ID identity', () => { + const args = buildCodesignArgs({ + identity: 'Developer ID Application: Moonshot AI (ABCD1234)', + executable: '/path/kimi', + entitlementsPath: '/path/entitlements.plist', + keychainPath: '/tmp/sign.keychain-db', + }); + expect(args).toEqual([ + '--sign', + 'Developer ID Application: Moonshot AI (ABCD1234)', + '--options', + 'runtime', + '--entitlements', + '/path/entitlements.plist', + '--timestamp', + '--keychain', + '/tmp/sign.keychain-db', + '--force', + '/path/kimi', + ]); + }); + + it('omits --keychain when keychainPath is null but uses Developer ID otherwise', () => { + const args = buildCodesignArgs({ + identity: 'Developer ID Application: Moonshot AI (ABCD1234)', + executable: '/path/kimi', + entitlementsPath: '/path/entitlements.plist', + keychainPath: null, + }); + expect(args).toContain('--entitlements'); + expect(args).not.toContain('--keychain'); + }); +}); diff --git a/apps/kimi-code/test/scripts/native/web-assets.test.ts b/apps/kimi-code/test/scripts/native/web-assets.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b5bfa9204cd225e31c92786bf4d3ea6eaed0bb2 --- /dev/null +++ b/apps/kimi-code/test/scripts/native/web-assets.test.ts @@ -0,0 +1,89 @@ +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { describe, expect, it } from 'vitest'; + +import { + collectWebAssets, + webAssetManifestKey, + WEB_ASSET_MANIFEST_VERSION, +} from '../../../scripts/native/web-assets.mjs'; + +function sha256(bytes: Buffer | string): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +describe('collectWebAssets', () => { + it('collects dist-web files into deterministic SEA asset keys', async () => { + const appRoot = mkdtempSync(join(tmpdir(), 'kimi-web-assets-build-')); + try { + mkdirSync(join(appRoot, 'dist-web', 'assets'), { recursive: true }); + writeFileSync(join(appRoot, 'dist-web', 'index.html'), '
\n'); + writeFileSync(join(appRoot, 'dist-web', 'assets', 'app.js'), 'console.log("ok");\n'); + + const { manifest, manifestJson, assets } = await collectWebAssets({ + appRoot, + target: 'test-target', + }); + + expect(webAssetManifestKey('test-target')).toBe('web/test-target/manifest.json'); + expect(manifest).toEqual({ + version: WEB_ASSET_MANIFEST_VERSION, + target: 'test-target', + root: 'dist-web', + files: [ + { + assetKey: 'web/test-target/dist-web/assets/app.js', + relativePath: 'assets/app.js', + sha256: sha256('console.log("ok");\n'), + }, + { + assetKey: 'web/test-target/dist-web/index.html', + relativePath: 'index.html', + sha256: sha256('
\n'), + }, + ], + }); + expect(JSON.parse(manifestJson) as unknown).toEqual(manifest); + expect(assets).toEqual({ + 'web/test-target/dist-web/assets/app.js': join(appRoot, 'dist-web', 'assets', 'app.js'), + 'web/test-target/dist-web/index.html': join(appRoot, 'dist-web', 'index.html'), + }); + } finally { + rmSync(appRoot, { recursive: true, force: true }); + } + }); + + it('fails clearly when dist-web has not been built', async () => { + const appRoot = mkdtempSync(join(tmpdir(), 'kimi-web-assets-missing-')); + try { + await expect(collectWebAssets({ appRoot, target: 'test-target' })).rejects.toThrow( + /Kimi web build output was not found/, + ); + } finally { + rmSync(appRoot, { recursive: true, force: true }); + } + }); + + it('keeps manifest JSON parseable and stable', async () => { + const appRoot = mkdtempSync(join(tmpdir(), 'kimi-web-assets-json-')); + try { + mkdirSync(join(appRoot, 'dist-web'), { recursive: true }); + writeFileSync(join(appRoot, 'dist-web', 'index.html'), ''); + + const { manifestJson } = await collectWebAssets({ appRoot, target: 'test-target' }); + + expect(readFileSync(join(appRoot, 'dist-web', 'index.html'), 'utf-8')).toBe(''); + expect(manifestJson.endsWith('\n')).toBe(true); + expect(JSON.parse(manifestJson)).toMatchObject({ + version: WEB_ASSET_MANIFEST_VERSION, + target: 'test-target', + root: 'dist-web', + }); + } finally { + rmSync(appRoot, { recursive: true, force: true }); + } + }); +}); diff --git a/apps/kimi-code/test/tui/activity-pane.test.ts b/apps/kimi-code/test/tui/activity-pane.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1501d65e44c2c18c604b4451dac9ce9464e8d2d3 --- /dev/null +++ b/apps/kimi-code/test/tui/activity-pane.test.ts @@ -0,0 +1,221 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { AgentSwarmProgressComponent } from '#/tui/components/messages/agent-swarm-progress'; +import type { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { KimiTUI, type KimiTUIStartupInput, type TUIState } from '#/tui/kimi-tui'; + +interface ActivityDriver { + state: TUIState; + sessionEventHandler: SessionEventHandler; + updateActivityPane(): void; +} + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function makeStartupInput(): KimiTUIStartupInput { + return { + cliOptions: { + session: undefined, + continue: false, + yolo: false, + auto: false, + plan: false, + model: undefined, + outputFormat: undefined, + prompt: undefined, + skillsDirs: [], + agent: undefined, + agentFiles: [], + }, + tuiConfig: { + theme: 'dark', + disablePasteBurst: false, + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + }, + version: '0.0.0-test', + workDir: '/tmp/proj-a', + }; +} + +function makeDriverWithTerminalProgress(): { + driver: ActivityDriver; + state: TUIState; + setProgress: ReturnType void>>; +} { + const setProgress = vi.fn<(active: boolean) => void>(); + const driver = new KimiTUI({} as never, makeStartupInput()) as unknown as ActivityDriver; + vi.spyOn(driver.state.ui, 'requestRender').mockImplementation(() => {}); + driver.state.terminal = { columns: 80, setProgress } as unknown as TUIState['terminal']; + driver.state.terminalState.supportsProgress = true; + return { driver, state: driver.state, setProgress }; +} + +function startSwarmProgress(driver: ActivityDriver, state: TUIState): AgentSwarmProgressComponent { + const handler = driver.sessionEventHandler.subAgentEventHandler; + handler.handleAgentSwarmToolCallStarted('call_swarm', { + description: 'Review changed files', + }); + handler.handleLifecycleEvent({ + type: 'subagent.spawned', + subagentId: 'agent-1', + subagentName: 'coder', + parentToolCallId: 'call_swarm', + description: 'Review changed files #1 (coder)', + swarmIndex: 1, + runInBackground: false, + } as Parameters[0]); + handler.handleLifecycleEvent({ + type: 'subagent.started', + subagentId: 'agent-1', + } as Parameters[0]); + + const progress = state.transcriptContainer.children.find( + (child): child is AgentSwarmProgressComponent => child instanceof AgentSwarmProgressComponent, + ); + if (progress === undefined) throw new Error('expected AgentSwarm progress'); + return progress; +} + +describe('updateActivityPane terminal progress', () => { + it('toggles terminal progress when the activity pane enters and leaves work mode', () => { + vi.useFakeTimers(); + try { + const { driver, state, setProgress } = makeDriverWithTerminalProgress(); + + state.livePane = { ...state.livePane, mode: 'waiting' }; + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(1); + expect(setProgress).toHaveBeenLastCalledWith(true); + expect(state.terminalState.progressActive).toBe(true); + + state.livePane = { ...state.livePane, mode: 'idle' }; + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(2); + expect(setProgress).toHaveBeenLastCalledWith(false); + expect(state.terminalState.progressActive).toBe(false); + } finally { + vi.useRealTimers(); + } + }); + + it('never emits terminal progress when the terminal does not support OSC 9;4', () => { + vi.useFakeTimers(); + try { + const { driver, state, setProgress } = makeDriverWithTerminalProgress(); + state.terminalState.supportsProgress = false; + + state.livePane = { ...state.livePane, mode: 'waiting' }; + driver.updateActivityPane(); + state.livePane = { ...state.livePane, mode: 'idle' }; + driver.updateActivityPane(); + + expect(setProgress).not.toHaveBeenCalled(); + expect(state.terminalState.progressActive).toBe(false); + } finally { + vi.useRealTimers(); + } + }); + + it('keeps compaction visible as terminal progress even though the pane is hidden', () => { + const { driver, state, setProgress } = makeDriverWithTerminalProgress(); + state.appState.isCompacting = true; + state.appState.streamingPhase = 'waiting'; + + driver.updateActivityPane(); + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(1); + expect(setProgress).toHaveBeenLastCalledWith(true); + + state.appState.isCompacting = false; + state.appState.streamingPhase = 'idle'; + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(2); + expect(setProgress).toHaveBeenLastCalledWith(false); + }); + + it('keeps terminal progress active without showing a thinking spinner', () => { + vi.useFakeTimers(); + try { + const { driver, state, setProgress } = makeDriverWithTerminalProgress(); + state.livePane = { ...state.livePane, mode: 'idle' }; + state.appState.streamingPhase = 'thinking'; + + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(1); + expect(setProgress).toHaveBeenLastCalledWith(true); + expect(state.activitySpinner).toBeNull(); + expect(state.activityContainer.children).toHaveLength(0); + + state.appState.streamingPhase = 'idle'; + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(2); + expect(setProgress).toHaveBeenLastCalledWith(false); + expect(state.activitySpinner).toBeNull(); + } finally { + vi.useRealTimers(); + } + }); + + it('moves the moon spinner into the AgentSwarm progress row while active', () => { + vi.useFakeTimers(); + try { + const { driver, state, setProgress } = makeDriverWithTerminalProgress(); + const progress = startSwarmProgress(driver, state); + state.livePane = { ...state.livePane, mode: 'tool' }; + + driver.updateActivityPane(); + + expect(setProgress).toHaveBeenCalledTimes(1); + expect(setProgress).toHaveBeenLastCalledWith(true); + expect(state.activitySpinner).not.toBeNull(); + expect(state.activityContainer.children).toHaveLength(0); + expect(strip(progress.render(80).join('\n'))).toContain('🌑 Working…'); + + state.activitySpinner?.instance.stop(); + driver.sessionEventHandler.clearAgentSwarmProgress(); + } finally { + vi.useRealTimers(); + } + }); + + it('keeps ended AgentSwarm progress on a placeholder instead of the moon spinner', () => { + vi.useFakeTimers(); + try { + const { driver, state } = makeDriverWithTerminalProgress(); + const progress = startSwarmProgress(driver, state); + driver.sessionEventHandler.subAgentEventHandler.handleAgentSwarmToolResult( + 'call_swarm', + { + tool_call_id: 'call_swarm', + output: 'Done', + is_error: false, + }, + false, + ); + state.livePane = { ...state.livePane, mode: 'tool' }; + + driver.updateActivityPane(); + + expect(state.activitySpinner).not.toBeNull(); + expect(state.activityContainer.children).toHaveLength(1); + const output = strip(progress.render(80).join('\n')); + expect(output).toContain(' Working…'); + expect(output).not.toContain('🌑 Working…'); + + state.activitySpinner?.instance.stop(); + driver.sessionEventHandler.clearAgentSwarmProgress(); + } finally { + vi.useRealTimers(); + } + }); +}); diff --git a/apps/kimi-code/test/tui/background-task-status.test.ts b/apps/kimi-code/test/tui/background-task-status.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b7981ac6b775ec24829da480d6789e3b14f176d --- /dev/null +++ b/apps/kimi-code/test/tui/background-task-status.test.ts @@ -0,0 +1,122 @@ +import type { BackgroundTaskInfo, BackgroundTaskStatus } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it } from 'vitest'; + +import { formatBackgroundTaskTranscript } from '@/tui/utils/background-task-status'; + +function task(overrides: Partial = {}): BackgroundTaskInfo { + const taskId = overrides.taskId ?? 'bash-abcd1234'; + const kind = overrides.kind ?? (taskId.startsWith('agent-') ? 'agent' : 'process'); + const base = { + taskId, + kind, + description: 'dev server', + status: 'running', + startedAt: Date.now() - 1000, + endedAt: null, + ...overrides, + }; + if (kind === 'agent') { + return { + ...base, + kind: 'agent', + agentId: 'agent-child', + subagentType: 'coder', + ...overrides, + } as BackgroundTaskInfo; + } + return { + ...base, + kind: 'process', + command: 'npm run dev', + pid: 1234, + exitCode: null, + ...overrides, + } as BackgroundTaskInfo; +} + +describe('formatBackgroundTaskTranscript', () => { + it('renders a bash started entry', () => { + const data = formatBackgroundTaskTranscript(task({ status: 'running' })); + expect(data.phase).toBe('started'); + expect(data.headline).toContain('bash task started'); + expect(data.detail).toBe('dev server'); + }); + + it('renders an agent started entry', () => { + const data = formatBackgroundTaskTranscript( + task({ taskId: 'agent-deadbeef', status: 'running' }), + ); + expect(data.headline).toContain('agent task started'); + }); + + it('renders a question started entry', () => { + const data = formatBackgroundTaskTranscript( + task({ + taskId: 'question-deadbeef', + kind: 'question', + questionCount: 1, + status: 'running', + }), + ); + expect(data.headline).toContain('question task started'); + }); + + it('renders a completed entry with exit code in detail', () => { + const data = formatBackgroundTaskTranscript( + task({ status: 'completed', exitCode: 0, endedAt: Date.now() }), + ); + expect(data.phase).toBe('completed'); + expect(data.headline).toContain('completed'); + expect(data.detail).toContain('exit 0'); + }); + + it('renders a failed entry with non-zero exit', () => { + const data = formatBackgroundTaskTranscript( + task({ status: 'failed', exitCode: 2, endedAt: Date.now() }), + ); + expect(data.phase).toBe('failed'); + expect(data.headline).toContain('failed'); + expect(data.detail).toContain('exit 2'); + }); + + it('renders a killed entry with stop reason', () => { + const data = formatBackgroundTaskTranscript( + task({ status: 'killed', stopReason: 'user', endedAt: Date.now() }), + ); + expect(data.phase).toBe('failed'); + expect(data.headline).toContain('stopped'); + expect(data.detail).toContain('user'); + }); + + it('renders a lost entry with restart note', () => { + const data = formatBackgroundTaskTranscript(task({ status: 'lost', endedAt: Date.now() })); + expect(data.phase).toBe('failed'); + expect(data.headline).toContain('lost'); + expect(data.detail).toContain('session restarted'); + }); + + it('surfaces timeout stop reason for agent deadlines', () => { + const data = formatBackgroundTaskTranscript( + task({ + taskId: 'agent-aaaaaaaa', + status: 'timed_out', + endedAt: Date.now(), + }), + ); + expect(data.detail).toContain('timed out'); + }); + + it('handles every BackgroundTaskStatus without throwing', () => { + const statuses: BackgroundTaskStatus[] = [ + 'running', + 'completed', + 'failed', + 'timed_out', + 'killed', + 'lost', + ]; + for (const status of statuses) { + expect(() => formatBackgroundTaskTranscript(task({ status }))).not.toThrow(); + } + }); +}); diff --git a/apps/kimi-code/test/tui/banner/banner-provider.test.ts b/apps/kimi-code/test/tui/banner/banner-provider.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..12f8573ca1b8100781970ae9c1e9e1b8c173346f --- /dev/null +++ b/apps/kimi-code/test/tui/banner/banner-provider.test.ts @@ -0,0 +1,780 @@ +import { describe, expect, it } from 'vitest'; + +import { + selectBannerState, + selectDisplayableBanner, + shouldDisplayBanner, +} from '#/tui/banner/banner-provider'; +import type { BannerState } from '#/tui/types'; + +describe('selectBannerState', () => { + const now = new Date('2026-06-15T12:00:00+08:00'); + + function expectAlwaysBanner( + result: BannerState | null, + expected: Pick, + ): BannerState { + expect(result).not.toBeNull(); + const banner = result!; + expect(banner).toMatchObject({ ...expected, display: 'always' }); + expect(banner.key).toEqual(expect.any(String)); + expect(banner.ttlHours).toBeUndefined(); + return banner; + } + + it('returns the active banner when enabled and no time window is set', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_title: 'New', + banner_maintext: 'Active', + banner_subtext: 'Details', + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: 'New', mainText: 'Active', subText: 'Details' }); + }); + + it('returns null when the active banner is outside its time window', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_title: 'Old', + banner_maintext: 'Expired', + banner_start_time: '2026-05-01T00:00:00+08:00', + banner_end_time: '2026-05-31T00:00:00+08:00', + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toBeNull(); + }); + + it('filters out the active banner when the client version is too low', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'New', + banner_min_version: '0.15.0', + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toBeNull(); + }); + + it('shows the active banner only below banner_max_version', () => { + const json = { + banner_enabled: true, + banner_maintext: 'Upgrade', + banner_max_version: '0.15.0', + }; + expect(selectBannerState(json, '0.14.0', now, () => 0)).toMatchObject({ + mainText: 'Upgrade', + }); + expect(selectBannerState(json, '0.15.0', now, () => 0)).toBeNull(); + expect(selectBannerState(json, '0.16.0', now, () => 0)).toBeNull(); + }); + + it('shows the active banner only on the exact banner_version', () => { + const json = { + banner_enabled: true, + banner_maintext: 'Pinned', + banner_version: '0.14.0', + }; + expect(selectBannerState(json, '0.14.0', now, () => 0)).toMatchObject({ + mainText: 'Pinned', + }); + expect(selectBannerState(json, '0.14.1', now, () => 0)).toBeNull(); + expect(selectBannerState(json, '0.13.9', now, () => 0)).toBeNull(); + }); + + it('combines min and max version as an inclusive-exclusive range', () => { + const json = { + banner_enabled: true, + banner_maintext: 'Range', + banner_min_version: '0.13.0', + banner_max_version: '0.15.0', + }; + expect(selectBannerState(json, '0.12.9', now, () => 0)).toBeNull(); + expect(selectBannerState(json, '0.13.0', now, () => 0)).not.toBeNull(); + expect(selectBannerState(json, '0.14.9', now, () => 0)).not.toBeNull(); + expect(selectBannerState(json, '0.15.0', now, () => 0)).toBeNull(); + }); + + it('filters out the banner when a version constraint is not valid semver', () => { + for (const constraint of [ + { banner_max_version: 'not-a-version' }, + { banner_version: 'not-a-version' }, + ]) { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'Broken', + ...constraint, + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toBeNull(); + } + }); + + it('picks a random enabled fallback when the active banner is not shown', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { enabled: true, banner_title: 'Tip', banner_maintext: 'First' }, + { enabled: true, banner_title: 'Tip', banner_maintext: 'Second' }, + ], + }, + '0.14.0', + now, + () => 0.75, + ); + expectAlwaysBanner(result, { tag: 'Tip', mainText: 'Second', subText: null }); + }); + + it('filters out fallback entries when the client version is too low', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { enabled: true, banner_maintext: 'Old tip' }, + { enabled: true, banner_maintext: 'New tip', banner_min_version: '0.15.0' }, + ], + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Old tip', subText: null }); + }); + + it('filters out fallback entries by max and exact version', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { enabled: true, banner_maintext: 'Too new', banner_max_version: '0.14.0' }, + { enabled: true, banner_maintext: 'Other version', banner_version: '0.13.0' }, + { enabled: true, banner_maintext: 'Matching', banner_version: '0.14.0' }, + ], + }, + '0.14.0', + now, + () => 0.99, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Matching', subText: null }); + }); + + it('returns null when no enabled fallback entries exist', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [{ enabled: false, banner_maintext: 'Hidden' }], + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toBeNull(); + }); + + it('returns null for malformed input fields', () => { + expect(selectBannerState({ weird: true }, '0.14.0', now, () => 0)).toBeNull(); + }); + + it('falls back to the fallback list when banner_enabled is missing', () => { + const result = selectBannerState( + { + banner_fallback_enabled: true, + banner_fallback_list: [{ enabled: true, banner_maintext: 'Fallback' }], + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Fallback', subText: null }); + }); + + it('treats an empty tag as null while still showing the banner', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_title: '', + banner_maintext: 'No tag', + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'No tag', subText: null }); + }); + + it('makes the active banner unavailable when mainText is empty', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_title: 'New', + banner_maintext: '', + banner_fallback_enabled: true, + banner_fallback_list: [{ enabled: true, banner_maintext: 'Fallback' }], + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Fallback', subText: null }); + }); + + it('treats missing subtext as null', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'Main only', + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Main only', subText: null }); + }); + + it('treats empty time fields as always valid', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'Always on', + banner_start_time: '', + banner_end_time: null, + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Always on', subText: null }); + }); + + it('falls back to UTC when timestamps have no timezone', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'UTC fallback', + banner_start_time: '2026-06-15T04:00:00', + banner_end_time: '2026-06-15T20:00:00', + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'UTC fallback', subText: null }); + }); + + it('returns null when the fallback list is empty', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [], + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toBeNull(); + }); + + it('returns null when the fallback list is missing', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toBeNull(); + }); + + it('uses banner_id as the banner key when present', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_id: 'active-1', + banner_maintext: 'Active', + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toMatchObject({ key: 'active-1', display: 'always' }); + }); + + it('generates a stable hash key when banner_id is missing', () => { + const json = { + banner_enabled: true, + banner_title: 'New', + banner_maintext: 'Active', + banner_subtext: 'Details', + }; + + const first = selectBannerState(json, '0.14.0', now, () => 0); + const second = selectBannerState(json, '0.14.0', now, () => 0); + const changedDisplay = selectBannerState( + { + ...json, + banner_display: 'cooldown', + banner_display_ttl_hours: 72, + }, + '0.14.0', + now, + () => 0, + ); + + expect(first).not.toBeNull(); + expect(second).not.toBeNull(); + expect(changedDisplay).not.toBeNull(); + expect(first!.key).toMatch(/^[0-9a-f]{32}$/); + expect(second!.key).toBe(first!.key); + expect(changedDisplay!.key).not.toBe(first!.key); + }); + + it('parses cooldown display and ttl hours', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_id: 'active-1', + banner_maintext: 'Active', + banner_display: 'cooldown', + banner_display_ttl_hours: 72, + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toMatchObject({ + key: 'active-1', + display: 'cooldown', + ttlHours: 72, + }); + }); + + it('falls back to 24 hours when cooldown ttl is invalid', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_id: 'active-1', + banner_maintext: 'Active', + banner_display: 'cooldown', + banner_display_ttl_hours: 0, + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toMatchObject({ display: 'cooldown', ttlHours: 24 }); + }); + + it('falls back to always for unknown display values', () => { + const result = selectBannerState( + { + banner_enabled: true, + banner_id: 'active-1', + banner_maintext: 'Active', + banner_display: '24h', + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toMatchObject({ display: 'always' }); + expect(result?.ttlHours).toBeUndefined(); + }); + + it('supports fallback display and ttl fields', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { + enabled: true, + banner_id: 'fallback-1', + banner_maintext: 'Fallback', + banner_display: 'cooldown', + banner_display_ttl_hours: 168, + }, + ], + }, + '0.14.0', + now, + () => 0, + ); + expect(result).toMatchObject({ + key: 'fallback-1', + display: 'cooldown', + ttlHours: 168, + }); + }); + + it('shows the banner when banner_platform is missing, empty, all, or cli', () => { + for (const banner_platform of [undefined, null, '', ' ', 'all', 'cli', 'ALL', ' CLI ']) { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'Active', + banner_platform, + }, + '0.14.0', + now, + () => 0, + ); + expect(result, `platform=${String(banner_platform)}`).not.toBeNull(); + } + }); + + it('skips the active banner when banner_platform targets other platforms', () => { + for (const banner_platform of ['desktop', 'web']) { + const result = selectBannerState( + { + banner_enabled: true, + banner_maintext: 'Active', + banner_platform, + banner_fallback_enabled: true, + banner_fallback_list: [{ enabled: true, banner_maintext: 'Fallback' }], + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Fallback', subText: null }); + } + }); + + it('filters fallback entries by banner_platform', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { enabled: true, banner_maintext: 'Desktop tip', banner_platform: 'desktop' }, + { enabled: true, banner_maintext: 'Web tip', banner_platform: 'web' }, + { enabled: true, banner_maintext: 'Cli tip', banner_platform: 'cli' }, + ], + }, + '0.14.0', + now, + () => 0.99, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Cli tip', subText: null }); + }); + + it('filters fallback entries by their time window', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { + enabled: true, + banner_maintext: 'Expired tip', + banner_end_time: '2026-06-01T00:00:00+08:00', + }, + { + enabled: true, + banner_maintext: 'Future tip', + banner_start_time: '2026-07-01T00:00:00+08:00', + }, + { + enabled: true, + banner_maintext: 'Current tip', + banner_start_time: '2026-06-01T00:00:00+08:00', + banner_end_time: '2026-06-30T00:00:00+08:00', + }, + ], + }, + '0.14.0', + now, + () => 0.99, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'Current tip', subText: null }); + }); + + it('treats fallback entries without time fields as always valid', () => { + const result = selectBannerState( + { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { enabled: true, banner_maintext: 'No window', banner_start_time: '', banner_end_time: null }, + ], + }, + '0.14.0', + now, + () => 0, + ); + expectAlwaysBanner(result, { tag: null, mainText: 'No window', subText: null }); + }); +}); + +describe('shouldDisplayBanner', () => { + const now = new Date('2026-06-16T12:00:00.000Z'); + + const banner: BannerState = { + key: 'always', + tag: null, + mainText: 'Always', + subText: null, + display: 'always', + }; + + it('returns true for always banners even when they were shown before', () => { + expect( + shouldDisplayBanner( + banner, + { + version: 1, + shown: { + always: { lastShownAt: '2026-06-16T11:59:59.000Z' }, + }, + }, + now, + ), + ).toBe(true); + }); + + it('returns true for once banners without a shown record', () => { + expect(shouldDisplayBanner({ ...banner, key: 'once', display: 'once' }, { version: 1, shown: {} }, now)).toBe( + true, + ); + }); + + it('returns false for once banners with a shown record', () => { + expect( + shouldDisplayBanner( + { ...banner, key: 'once', display: 'once' }, + { + version: 1, + shown: { + once: { lastShownAt: '2026-06-16T11:59:59.000Z' }, + }, + }, + now, + ), + ).toBe(false); + }); + + it('treats an invalid shown record as not shown', () => { + expect( + shouldDisplayBanner( + { ...banner, key: 'once', display: 'once' }, + { + version: 1, + shown: { + once: { lastShownAt: 'not-a-date' }, + }, + }, + now, + ), + ).toBe(true); + }); + + it('returns false during cooldown ttl', () => { + expect( + shouldDisplayBanner( + { ...banner, key: 'cooldown', display: 'cooldown', ttlHours: 24 }, + { + version: 1, + shown: { + cooldown: { lastShownAt: '2026-06-16T00:00:00.000Z' }, + }, + }, + now, + ), + ).toBe(false); + }); + + it('returns true at the cooldown ttl boundary', () => { + expect( + shouldDisplayBanner( + { ...banner, key: 'cooldown', display: 'cooldown', ttlHours: 24 }, + { + version: 1, + shown: { + cooldown: { lastShownAt: '2026-06-15T12:00:00.000Z' }, + }, + }, + now, + ), + ).toBe(true); + }); + + it('supports custom cooldown ttl values', () => { + expect( + shouldDisplayBanner( + { ...banner, key: 'cooldown', display: 'cooldown', ttlHours: 1 }, + { + version: 1, + shown: { + cooldown: { lastShownAt: '2026-06-16T11:30:00.000Z' }, + }, + }, + now, + ), + ).toBe(false); + expect( + shouldDisplayBanner( + { ...banner, key: 'cooldown', display: 'cooldown', ttlHours: 168 }, + { + version: 1, + shown: { + cooldown: { lastShownAt: '2026-06-09T12:00:01.000Z' }, + }, + }, + now, + ), + ).toBe(false); + }); +}); + +describe('selectDisplayableBanner', () => { + const now = new Date('2026-06-16T12:00:00.000Z'); + + it('falls back when the active once banner was already shown', () => { + const result = selectDisplayableBanner({ + json: { + banner_enabled: true, + banner_id: 'active', + banner_maintext: 'Active', + banner_display: 'once', + banner_fallback_enabled: true, + banner_fallback_list: [ + { + enabled: true, + banner_id: 'fallback', + banner_maintext: 'Fallback', + banner_display: 'once', + }, + ], + }, + clientVersion: '0.14.0', + now, + random: () => 0, + state: { + version: 1, + shown: { + active: { lastShownAt: '2026-06-16T00:00:00.000Z' }, + }, + }, + }); + + expect(result).toMatchObject({ key: 'fallback', display: 'once' }); + }); + + it('falls back when active cooldown is within ttl', () => { + const result = selectDisplayableBanner({ + json: { + banner_enabled: true, + banner_id: 'active', + banner_maintext: 'Active', + banner_display: 'cooldown', + banner_display_ttl_hours: 1, + banner_fallback_enabled: true, + banner_fallback_list: [ + { + enabled: true, + banner_id: 'fallback', + banner_maintext: 'Fallback', + }, + ], + }, + clientVersion: '0.14.0', + now, + random: () => 0, + state: { + version: 1, + shown: { + active: { lastShownAt: '2026-06-16T11:30:00.000Z' }, + }, + }, + }); + + expect(result).toMatchObject({ key: 'fallback', display: 'always' }); + }); + + it('returns active cooldown after ttl instead of fallback', () => { + const result = selectDisplayableBanner({ + json: { + banner_enabled: true, + banner_id: 'active', + banner_maintext: 'Active', + banner_display: 'cooldown', + banner_display_ttl_hours: 24, + banner_fallback_enabled: true, + banner_fallback_list: [ + { + enabled: true, + banner_id: 'fallback', + banner_maintext: 'Fallback', + }, + ], + }, + clientVersion: '0.14.0', + now, + random: () => 0, + state: { + version: 1, + shown: { + active: { lastShownAt: '2026-06-15T12:00:00.000Z' }, + }, + }, + }); + + expect(result).toMatchObject({ key: 'active', display: 'cooldown', ttlHours: 24 }); + }); + + it('randomly chooses only displayable fallback candidates', () => { + const result = selectDisplayableBanner({ + json: { + banner_enabled: false, + banner_fallback_enabled: true, + banner_fallback_list: [ + { + enabled: true, + banner_id: 'fallback-once', + banner_maintext: 'Fallback once', + banner_display: 'once', + }, + { + enabled: true, + banner_id: 'fallback-always', + banner_maintext: 'Fallback always', + }, + ], + }, + clientVersion: '0.14.0', + now, + random: () => 0, + state: { + version: 1, + shown: { + 'fallback-once': { lastShownAt: '2026-06-16T00:00:00.000Z' }, + }, + }, + }); + + expect(result).toMatchObject({ key: 'fallback-always', display: 'always' }); + }); +}); diff --git a/apps/kimi-code/test/tui/banner/state.test.ts b/apps/kimi-code/test/tui/banner/state.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0824e6fd98d0fdce6376c8c11e2e4d61d41d8a7c --- /dev/null +++ b/apps/kimi-code/test/tui/banner/state.test.ts @@ -0,0 +1,88 @@ +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { + emptyBannerDisplayState, + readBannerDisplayState, + writeBannerDisplayState, +} from '#/tui/banner/state'; +import { getBannerStateFile } from '#/utils/paths'; + +const originalEnv = { ...process.env }; + +let dir: string; + +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'kimi-banner-state-')); + process.env['KIMI_CODE_HOME'] = dir; +}); + +afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + process.env = { ...originalEnv }; +}); + +describe('banner display state cache', () => { + it('returns an empty state when the file is missing', async () => { + await expect(readBannerDisplayState()).resolves.toEqual(emptyBannerDisplayState()); + }); + + it('falls back to an empty state when the file is corrupt', async () => { + mkdirSync(join(dir, 'cache', 'banner'), { recursive: true }); + writeFileSync(getBannerStateFile(), '{"broken"', 'utf-8'); + await expect(readBannerDisplayState()).resolves.toEqual(emptyBannerDisplayState()); + }); + + it('falls back to an empty state for an unknown future version', async () => { + mkdirSync(join(dir, 'cache', 'banner'), { recursive: true }); + writeFileSync( + getBannerStateFile(), + JSON.stringify({ + version: 2, + shown: {}, + }), + 'utf-8', + ); + await expect(readBannerDisplayState()).resolves.toEqual(emptyBannerDisplayState()); + }); + + it('writes and reads back the state from cache/banner/state.json', async () => { + const state = { + version: 1 as const, + shown: { + active: { lastShownAt: '2026-06-16T00:00:00.000Z' }, + }, + }; + + await writeBannerDisplayState(state); + + expect(getBannerStateFile()).toBe(join(dir, 'cache', 'banner', 'state.json')); + await expect(readBannerDisplayState()).resolves.toEqual(state); + }); + + it('drops invalid shown records when reading', async () => { + mkdirSync(join(dir, 'cache', 'banner'), { recursive: true }); + writeFileSync( + getBannerStateFile(), + JSON.stringify({ + version: 1, + shown: { + valid: { lastShownAt: '2026-06-16T00:00:00.000Z' }, + invalid: { lastShownAt: 'not-a-date' }, + malformed: { shownAt: '2026-06-16T00:00:00.000Z' }, + }, + }), + 'utf-8', + ); + + await expect(readBannerDisplayState()).resolves.toEqual({ + version: 1, + shown: { + valid: { lastShownAt: '2026-06-16T00:00:00.000Z' }, + }, + }); + }); +}); diff --git a/apps/kimi-code/test/tui/chalk-named-color-guard.test.ts b/apps/kimi-code/test/tui/chalk-named-color-guard.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e37a118710af5552821b5efe99252141336e4ed9 --- /dev/null +++ b/apps/kimi-code/test/tui/chalk-named-color-guard.test.ts @@ -0,0 +1,74 @@ +import { readFileSync, readdirSync } from 'node:fs'; +import { join, relative } from 'node:path'; + +import { describe, expect, it } from 'vitest'; + +const SRC_ROOT = join(__dirname, '..', '..', 'src'); + +const NAMED_COLORS = [ + 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', + 'white', 'gray', 'grey', 'black', + 'blackBright', 'whiteBright', 'redBright', 'greenBright', + 'yellowBright', 'blueBright', 'magentaBright', 'cyanBright', +]; + +const CHALK_NAMED_PATTERN = new RegExp( + `chalk\\.(${NAMED_COLORS.join('|')})\\(`, +); + +function walk(dir: string, files: string[] = []): string[] { + try { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const p = join(dir, entry.name); + if (entry.isDirectory()) { + walk(p, files); + } else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts') && !entry.name.endsWith('.spec.ts')) { + files.push(p); + } + } + } catch { /* skip */ } + return files; +} + +describe('chalk named color guard', () => { + it('forbids chalk named colors in production source code', () => { + const offenders: { file: string; line: number; snippet: string }[] = []; + const files = walk(SRC_ROOT); + let inBlockComment = false; + for (const file of files) { + const content = readFileSync(file, 'utf8'); + const lines = content.split('\n'); + for (let i = 0; i < lines.length; i++) { + const line = lines[i] ?? ''; + const trimmed = line.trimStart(); + + if (inBlockComment) { + if (trimmed.includes('*/')) inBlockComment = false; + continue; + } + + if (trimmed.startsWith('/*')) { + if (!trimmed.includes('*/')) inBlockComment = true; + continue; + } + + if (trimmed.startsWith('//') || trimmed.startsWith('*')) continue; + + CHALK_NAMED_PATTERN.lastIndex = 0; + const m = CHALK_NAMED_PATTERN.exec(line); + if (m) { + offenders.push({ + file: relative(SRC_ROOT, file), + line: i + 1, + snippet: line.trim(), + }); + } + } + } + expect( + offenders, + `Found chalk named color usages. Use chalk.hex(colors.) or theme styles instead.\n` + + offenders.map((o) => ` ${o.file}:${String(o.line)} ${o.snippet}`).join('\n'), + ).toEqual([]); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/add-dir.test.ts b/apps/kimi-code/test/tui/commands/add-dir.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..222314ffdbadbab08766bf8d5de92a0b6938d593 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/add-dir.test.ts @@ -0,0 +1,211 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { handleAddDirCommand } from '#/tui/commands/add-dir'; +import { dispatchInput, type SlashCommandHost } from '#/tui/commands/dispatch'; + +type MountedPanel = { + handleInput: (data: string) => void; + render: (width: number) => string[]; +}; + +const ANSI_SGR = /\u001B\[[0-9;]*m/g; + +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function makeHost(additionalDirs: readonly string[] = []) { + const state = { + appState: { + additionalDirs, + streamingPhase: 'idle', + isCompacting: false, + }, + }; + let mountedPanel: MountedPanel | null = null; + const session = { + id: 'session-1', + summary: { + additionalDirs, + }, + addAdditionalDir: vi.fn(async (path: string, options: { persist: boolean }) => ({ + additionalDirs: [...additionalDirs, path], + projectRoot: '/repo', + configPath: '/repo/.kimi-code/local.toml', + persisted: options.persist, + })), + }; + const host = { + state, + session, + skillCommandMap: new Map(), + setAppState: vi.fn((patch: Record) => Object.assign(state.appState, patch)), + refreshSlashCommandAutocomplete: vi.fn(), + appendTranscriptEntry: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + sendNormalUserInput: vi.fn(), + track: vi.fn(), + mountEditorReplacement: vi.fn((panel: MountedPanel) => { + mountedPanel = panel; + }), + restoreEditor: vi.fn(() => { + mountedPanel = null; + }), + } as unknown as SlashCommandHost & { + session: typeof session; + state: typeof state; + setAppState: ReturnType; + refreshSlashCommandAutocomplete: ReturnType; + appendTranscriptEntry: ReturnType; + showError: ReturnType; + showStatus: ReturnType; + sendNormalUserInput: ReturnType; + mountEditorReplacement: ReturnType; + restoreEditor: ReturnType; + }; + return { + host, + session, + getMountedPanel: () => mountedPanel, + }; +} + +describe('handleAddDirCommand', () => { + it('shows the empty message when no additional dirs are configured', async () => { + const { host } = makeHost(); + + await handleAddDirCommand(host, ''); + + expect(host.showStatus).toHaveBeenCalledWith('No additional directories configured.'); + }); + + it('lists current additional dirs for no args', async () => { + const { host } = makeHost(['/repo/shared', '/repo/docs']); + + await handleAddDirCommand(host, ''); + + expect(host.showStatus).toHaveBeenCalledWith( + 'Additional directories:\n /repo/shared\n /repo/docs', + ); + }); + + it('lists current additional dirs for the list subcommand', async () => { + const { host } = makeHost(['/repo/shared']); + + await handleAddDirCommand(host, 'list'); + + expect(host.showStatus).toHaveBeenCalledWith('Additional directories:\n /repo/shared'); + }); + + it('renders the add-dir confirmation without option descriptions', async () => { + const { host, getMountedPanel } = makeHost(); + + await handleAddDirCommand(host, '../shared'); + + const rendered = getMountedPanel()?.render(120).map(strip).join('\n') ?? ''; + expect(rendered).toContain('Add directory to workspace: ../shared'); + expect(rendered).toContain('Yes, for this session'); + expect(rendered).toContain('Yes, and remember this directory'); + expect(rendered).toContain('No'); + expect(rendered).not.toContain('Use this directory in the current session only'); + expect(rendered).not.toContain('Save this directory to the project workspace config'); + expect(rendered).not.toContain('Do not add this directory.'); + }); + + it('adds a workspace dir for this session only after confirmation', async () => { + const { host, session, getMountedPanel } = makeHost(); + + await handleAddDirCommand(host, '../shared'); + getMountedPanel()?.handleInput(' '); + + await vi.waitFor(() => { + expect(session.addAdditionalDir).toHaveBeenCalledWith('../shared', { persist: false }); + }); + expect(host.restoreEditor).toHaveBeenCalledOnce(); + expect(host.setAppState).toHaveBeenCalledWith({ + additionalDirs: ['../shared'], + }); + expect(host.refreshSlashCommandAutocomplete).toHaveBeenCalledOnce(); + await vi.waitFor(() => { + expect(host.showStatus).toHaveBeenCalledWith( + 'Added workspace directory:\n ../shared\n For this session only', + 'success', + ); + }); + expect(host.appendTranscriptEntry).not.toHaveBeenCalled(); + }); + + it('adds a remembered workspace dir after confirmation', async () => { + const { host, session, getMountedPanel } = makeHost(); + + await handleAddDirCommand(host, '../shared'); + getMountedPanel()?.handleInput('\u001B[B'); + getMountedPanel()?.handleInput(' '); + + await vi.waitFor(() => { + expect(session.addAdditionalDir).toHaveBeenCalledWith('../shared', { persist: true }); + }); + await vi.waitFor(() => { + expect(host.showStatus).toHaveBeenCalledWith( + 'Added workspace directory:\n ../shared\n Saved to:\n /repo/.kimi-code/local.toml', + 'success', + ); + }); + expect(host.appendTranscriptEntry).not.toHaveBeenCalled(); + }); + + it('does not add a workspace dir when the confirmation is cancelled', async () => { + const { host, session, getMountedPanel } = makeHost(); + + await handleAddDirCommand(host, '../shared'); + getMountedPanel()?.handleInput('\u001B[B'); + getMountedPanel()?.handleInput('\u001B[B'); + getMountedPanel()?.handleInput(' '); + + expect(session.addAdditionalDir).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith('Did not add ../shared as a working directory.'); + }); + + it('routes /add-dir errors through the slash-command dispatcher error handler', async () => { + const { host, session, getMountedPanel } = makeHost(); + session.addAdditionalDir.mockRejectedValueOnce(new Error('workspace.additional_dir must exist and be a directory')); + + dispatchInput(host, '/add-dir ../other'); + await vi.waitFor(() => { + expect(getMountedPanel()).not.toBeNull(); + }); + getMountedPanel()?.handleInput(' '); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith( + 'workspace.additional_dir must exist and be a directory', + ); + }); + + expect(host.setAppState).not.toHaveBeenCalled(); + expect(host.refreshSlashCommandAutocomplete).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('re-checks the busy gate after lazy session creation (v2)', async () => { + const { host, session, getMountedPanel } = makeHost(); + // Session-less v2: the path-adding form lazy-creates via ensureSession. + Object.assign(host, { + session: undefined, + ensureSession: vi.fn(async () => { + // A first prompt starts a turn while the session is being created. + host.state.appState.streamingPhase = 'waiting'; + return session; + }), + }); + + await handleAddDirCommand(host, '../shared'); + + expect(host.showError).toHaveBeenCalledWith( + 'Cannot /add-dir while streaming — press Esc or Ctrl-C first.', + ); + expect(getMountedPanel()).toBeNull(); + expect(session.addAdditionalDir).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/copy.test.ts b/apps/kimi-code/test/tui/commands/copy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e980aa5ff444cd299cd1948b2eb1435f1dbde8d --- /dev/null +++ b/apps/kimi-code/test/tui/commands/copy.test.ts @@ -0,0 +1,142 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { findLastAssistantText, handleCopyCommand } from '#/tui/commands/copy'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import { findBuiltInSlashCommand, resolveSlashCommandAvailability } from '#/tui/commands/index'; +import type { TranscriptEntry } from '#/tui/types'; + +const mocks = vi.hoisted(() => ({ + copyTextToClipboard: vi.fn(), +})); + +vi.mock('#/utils/clipboard/clipboard-text', () => ({ + copyTextToClipboard: mocks.copyTextToClipboard, +})); + +let nextEntryId = 0; + +function entry(kind: TranscriptEntry['kind'], content: string): TranscriptEntry { + return { + id: `entry-${String(nextEntryId++)}`, + kind, + renderMode: 'markdown', + content, + }; +} + +function assistantEntry(content: string): TranscriptEntry { + return { ...entry('assistant', content), modelText: true }; +} + +function makeHost(entries: TranscriptEntry[]) { + const host = { + state: { transcriptEntries: entries }, + showStatus: vi.fn(), + showError: vi.fn(), + } as unknown as SlashCommandHost & { + showStatus: ReturnType; + showError: ReturnType; + }; + return host; +} + +describe('copy slash command', () => { + it('is registered as an idle-only built-in', () => { + const command = findBuiltInSlashCommand('copy'); + expect(command).toBeDefined(); + expect(resolveSlashCommandAvailability(command!, '')).toBe('idle-only'); + }); +}); + +describe('findLastAssistantText', () => { + it('returns an empty string for an empty transcript', () => { + expect(findLastAssistantText([])).toBe(''); + }); + + it('returns the newest assistant entry across later non-assistant entries', () => { + const entries = [ + assistantEntry('first answer'), + entry('user', 'follow-up question'), + assistantEntry('second answer'), + entry('user', 'typing…'), + entry('status', 'Working…'), + ]; + + expect(findLastAssistantText(entries)).toBe('second answer'); + }); + + it('skips assistant entries with empty or whitespace-only content', () => { + const entries = [assistantEntry('real answer'), assistantEntry(' \n ')]; + + expect(findLastAssistantText(entries)).toBe('real answer'); + }); + + it('ignores thinking and other non-visible-reply kinds', () => { + const entries = [ + assistantEntry('visible reply'), + entry('thinking', 'hidden reasoning'), + entry('tool_call', 'Bash ls'), + ]; + + expect(findLastAssistantText(entries)).toBe('visible reply'); + }); + + it('skips synthetic assistant cards like hook results and goal completions', () => { + const entries = [ + assistantEntry('real reply'), + entry('assistant', '*PostToolUse hook* ran something'), + entry('assistant', 'Goal completed: shipped the feature'), + ]; + + expect(findLastAssistantText(entries)).toBe('real reply'); + }); +}); + +describe('handleCopyCommand', () => { + beforeEach(() => { + vi.clearAllMocks(); + mocks.copyTextToClipboard.mockResolvedValue('native'); + }); + + it('copies the last visible assistant text and reports the character count', async () => { + const host = makeHost([entry('user', 'hi'), assistantEntry('final summary')]); + + await handleCopyCommand(host); + + expect(mocks.copyTextToClipboard).toHaveBeenCalledWith('final summary'); + expect(host.showStatus).toHaveBeenCalledWith( + `Copied to clipboard (${String('final summary'.length)} characters).`, + ); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('marks the copy as unverified when only the terminal escape delivered it', async () => { + mocks.copyTextToClipboard.mockResolvedValue('osc52'); + const host = makeHost([entry('user', 'hi'), assistantEntry('final summary')]); + + await handleCopyCommand(host); + + expect(host.showStatus).toHaveBeenCalledWith( + `Copied via terminal escape sequence (unverified, ${String('final summary'.length)} characters).`, + ); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('warns when there is no assistant message to copy', async () => { + const host = makeHost([entry('user', 'hi')]); + + await handleCopyCommand(host); + + expect(mocks.copyTextToClipboard).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith('No assistant message to copy.', 'warning'); + }); + + it('shows an error when the clipboard write fails', async () => { + mocks.copyTextToClipboard.mockRejectedValue(new Error('pbcopy exited')); + const host = makeHost([assistantEntry('final summary')]); + + await handleCopyCommand(host); + + expect(host.showError).toHaveBeenCalledWith('Failed to copy to clipboard: pbcopy exited'); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/experiments.test.ts b/apps/kimi-code/test/tui/commands/experiments.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ec02ae037900f6ad85028a2e2a8a12ecd305968 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/experiments.test.ts @@ -0,0 +1,177 @@ +import type { ExperimentalFeatureState } from '@moonshot-ai/kimi-code-sdk'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import type { SlashCommandHost } from '#/tui/commands'; +import { applyExperimentalFeatureChanges } from '#/tui/commands/config'; +import { + isExperimentalFlagEnabled, + setExperimentalFeatures, +} from '#/tui/commands/experimental-flags'; +import { darkColors } from '#/tui/theme/colors'; + +function feature(overrides: Partial = {}): ExperimentalFeatureState { + return { + id: 'micro_compaction', + title: 'Micro compaction', + description: 'Trim older tool results.', + surface: 'core', + env: 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION', + defaultEnabled: true, + enabled: true, + source: 'default', + ...overrides, + }; +} + +function makeHost() { + const session = { + id: 'ses-experiments', + reloadSession: vi.fn(async () => ({})), + }; + const host = { + state: { + theme: { palette: darkColors }, + ui: { requestRender: vi.fn() }, + }, + harness: { + setConfig: vi.fn(async () => ({ providers: {} })), + getExperimentalFeatures: vi.fn(async () => [ + feature({ enabled: false, source: 'config', configValue: false }), + ]), + reloadSession: vi.fn(async () => session), + }, + session, + refreshSlashCommandAutocomplete: vi.fn(), + reloadCurrentSessionView: vi.fn(async () => {}), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + showStatus: vi.fn(), + showError: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + } as unknown as SlashCommandHost & { + harness: { + setConfig: ReturnType; + getExperimentalFeatures: ReturnType; + reloadSession: ReturnType; + }; + refreshSlashCommandAutocomplete: ReturnType; + reloadCurrentSessionView: ReturnType; + mountEditorReplacement: ReturnType; + restoreEditor: ReturnType; + showStatus: ReturnType; + showError: ReturnType; + track: ReturnType; + session: typeof session; + }; + return host; +} + +describe('experimental feature command handlers', () => { + afterEach(() => { + setExperimentalFeatures([]); + }); + + it('persists config overrides, refreshes command flags, closes the panel, and reloads', async () => { + const host = makeHost(); + + await applyExperimentalFeatureChanges(host, [{ id: 'micro_compaction', enabled: false }]); + + expect(host.harness.setConfig).toHaveBeenCalledWith({ + experimental: { micro_compaction: false }, + }); + expect(host.harness.getExperimentalFeatures).toHaveBeenCalledOnce(); + expect(isExperimentalFlagEnabled('micro_compaction')).toBe(false); + expect(host.refreshSlashCommandAutocomplete).toHaveBeenCalled(); + expect(host.restoreEditor).toHaveBeenCalled(); + expect(host.harness.reloadSession).toHaveBeenCalledWith({ id: host.session.id }); + expect(host.session.reloadSession).not.toHaveBeenCalled(); + expect(host.reloadCurrentSessionView).toHaveBeenCalledWith( + host.session, + 'Experimental features updated. Session reloaded.', + ); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + expect(host.track).toHaveBeenCalledWith('experimental_features_apply', { + changed: 1, + flags: '', + }); + expect(host.showStatus).not.toHaveBeenCalledWith( + 'Experimental features updated.', + darkColors.success, + ); + }); + + it.each([true, false])( + 'toggles notification display without reloading the session: %s', + async (enabled) => { + const host = makeHost(); + host.harness.getExperimentalFeatures.mockResolvedValue([ + feature({ id: 'notify_user', enabled }), + ]); + await applyExperimentalFeatureChanges(host, [{ id: 'notify_user', enabled }]); + expect(host.harness.setConfig).toHaveBeenCalledWith({ + experimental: { notify_user: enabled }, + }); + expect(isExperimentalFlagEnabled('notify_user')).toBe(enabled); + expect(host.refreshSlashCommandAutocomplete).toHaveBeenCalledOnce(); + expect(host.harness.reloadSession).not.toHaveBeenCalled(); + expect(host.reloadCurrentSessionView).not.toHaveBeenCalled(); + expect(host.showError).not.toHaveBeenCalled(); + }, + ); + + it('still reloads when another experimental feature changes alongside notifications', async () => { + const host = makeHost(); + await applyExperimentalFeatureChanges(host, [ + { id: 'notify_user', enabled: false }, + { id: 'micro_compaction', enabled: false }, + ]); + expect(host.harness.reloadSession).toHaveBeenCalledOnce(); + }); + + it('reports the post-apply enabled flag set in telemetry', async () => { + const host = makeHost(); + host.harness.getExperimentalFeatures.mockResolvedValue([ + feature({ id: 'wait_for', enabled: true }), + feature({ id: 'subagent_fork', enabled: true }), + feature({ id: 'tower', enabled: false }), + ]); + + await applyExperimentalFeatureChanges(host, [{ id: 'subagent_fork', enabled: true }]); + + expect(host.track).toHaveBeenCalledWith('experimental_features_apply', { + changed: 1, + flags: 'subagent_fork,wait_for', + }); + }); + + it('does not write config when there are no drafted changes', async () => { + const host = makeHost(); + + await applyExperimentalFeatureChanges(host, []); + + expect(host.harness.setConfig).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith( + 'No experimental feature changes to apply.', + 'textMuted', + ); + }); + + it('notices that tower mode needs a restart when the tower flag changes', async () => { + const host = makeHost(); + + await applyExperimentalFeatureChanges(host, [{ id: 'tower', enabled: true }]); + + expect(host.showNotice).toHaveBeenCalledWith( + 'Tower mode takes effect after restarting Kimi Code.', + ); + }); + + it('does not show the restart notice for non-tower changes', async () => { + const host = makeHost(); + + await applyExperimentalFeatureChanges(host, [{ id: 'micro_compaction', enabled: false }]); + + expect(host.showNotice).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/goal.test.ts b/apps/kimi-code/test/tui/commands/goal.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5553a0ffecb8509818f519656d234ef983564074 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/goal.test.ts @@ -0,0 +1,969 @@ +import { ErrorCodes, KimiError } from '@moonshot-ai/kimi-code-sdk'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + dispatchInput, + goalArgumentCompletions, + goalObjectiveLengthWarning, + handleGoalCommand, + parseGoalCommand, + setExperimentalFeatures, +} from '#/tui/commands/index'; +import { + appendGoalQueueItem, + moveGoalQueueItem, + readGoalQueue, + removeGoalQueueItem, + updateGoalQueueItem, +} from '#/tui/goal-queue-store'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import { getBuiltInPalette } from '#/tui/theme'; +import { PERMISSION_MODE_DESCRIPTIONS } from '#/tui/utils/permission-mode'; + +vi.mock('#/tui/goal-queue-store', () => ({ + appendGoalQueueItem: vi.fn(async () => ({ + goals: [{ id: 'q1', objective: 'obj', createdAt: '', updatedAt: '' }], + })), + readGoalQueue: vi.fn(async () => ({ + goals: [ + { id: 'q1', objective: 'First queued goal', createdAt: '', updatedAt: '' }, + { id: 'q2', objective: 'Second queued goal', createdAt: '', updatedAt: '' }, + ], + })), + moveGoalQueueItem: vi.fn(async () => ({ + goals: [ + { id: 'q2', objective: 'Second queued goal', createdAt: '', updatedAt: '' }, + { id: 'q1', objective: 'First queued goal', createdAt: '', updatedAt: '' }, + ], + })), + removeGoalQueueItem: vi.fn(async () => ({ + goals: [{ id: 'q2', objective: 'Second queued goal', createdAt: '', updatedAt: '' }], + })), + updateGoalQueueItem: vi.fn(async () => ({ + goals: [ + { id: 'q1', objective: 'First queued goal updated', createdAt: '', updatedAt: '' }, + { id: 'q2', objective: 'Second queued goal', createdAt: '', updatedAt: '' }, + ], + })), +})); + +const ENTER = '\r'; +const ESCAPE = '\u001B'; +const UP = '\u001B[A'; +const DOWN = '\u001B[B'; + +function fakeSnapshot() { + return { + goalId: 'g1', + objective: 'obj', + status: 'active' as const, + turnsUsed: 0, + tokensUsed: 0, + wallClockMs: 0, + budget: { + tokenBudget: null, + turnBudget: 20, + wallClockBudgetMs: null, + remainingTokens: null, + remainingTurns: 20, + remainingWallClockMs: null, + tokenBudgetReached: false, + turnBudgetReached: false, + wallClockBudgetReached: false, + overBudget: false, + }, + }; +} + +function stripAnsi(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function makeHost( + overrides: { + model?: string; + hasSession?: boolean; + streaming?: boolean; + permissionMode?: 'manual' | 'auto' | 'yolo'; + } = {}, +) { + const session = { + setPermission: vi.fn(async () => {}), + createGoal: vi.fn(async () => fakeSnapshot()), + getGoal: vi.fn(async (): Promise<{ goal: ReturnType | null }> => ({ + goal: null, + })), + pauseGoal: vi.fn(async () => fakeSnapshot()), + resumeGoal: vi.fn(async () => fakeSnapshot()), + cancelGoal: vi.fn(async () => fakeSnapshot()), + cancel: vi.fn(async () => {}), + }; + const hasSession = overrides.hasSession ?? true; + const transcriptContainer = { addChild: vi.fn() }; + const host = { + state: { + appState: { + model: overrides.model ?? 'kimi-model', + permissionMode: overrides.permissionMode ?? 'auto', + streamingPhase: overrides.streaming ? 'streaming' : 'idle', + isCompacting: false, + }, + editor: { getText: vi.fn(() => '') }, + transcriptContainer, + ui: { requestRender: vi.fn() }, + theme: { palette: getBuiltInPalette('dark') }, + }, + session: hasSession ? session : undefined, + skillCommandMap: new Map(), + requireSession: () => session, + setAppState: vi.fn((patch: Record) => Object.assign(host.state.appState, patch)), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + sendNormalUserInput: vi.fn(), + requestQueuedGoalPromotion: vi.fn(), + cancelInFlight: vi.fn(), + track: vi.fn(), + } as unknown as SlashCommandHost; + return { host, session }; +} + +interface TestPicker { + handleInput(data: string): void; + render(width: number): string[]; +} + +function mountedPicker(host: SlashCommandHost): TestPicker { + const mock = host.mountEditorReplacement as ReturnType; + return mock.mock.calls[0]?.[0] as TestPicker; +} + +function latestMountedPicker(host: SlashCommandHost): TestPicker { + const mock = host.mountEditorReplacement as ReturnType; + return mock.mock.calls.at(-1)?.[0] as TestPicker; +} + +describe('parseGoalCommand', () => { + it('treats empty and status as status', () => { + expect(parseGoalCommand('')).toEqual({ kind: 'status' }); + expect(parseGoalCommand('status')).toEqual({ kind: 'status' }); + }); + + it('parses control subcommands', () => { + expect(parseGoalCommand('pause')).toEqual({ kind: 'pause' }); + expect(parseGoalCommand('resume')).toEqual({ kind: 'resume' }); + expect(parseGoalCommand('cancel')).toEqual({ kind: 'cancel' }); + }); + + it('treats `clear` as an objective, not a subcommand (cancel is the remove action)', () => { + expect(parseGoalCommand('clear')).toMatchObject({ kind: 'create', objective: 'clear' }); + }); + + it('parses a plain objective', () => { + expect(parseGoalCommand('Ship feature X')).toMatchObject({ + kind: 'create', + objective: 'Ship feature X', + replace: false, + }); + }); + + it('keeps option-looking tokens as part of the objective (no goal flags)', () => { + // Goal command flags are not parsed after `/goal`; stop conditions go in the + // objective as natural language, so option-looking text stays objective text. + expect(parseGoalCommand('--retry-strategy Ship feature X')).toMatchObject({ + kind: 'create', + objective: '--retry-strategy Ship feature X', + }); + }); + + it('treats text after -- as the objective', () => { + expect(parseGoalCommand('-- --leading-option is part of the goal')).toMatchObject({ + kind: 'create', + objective: '--leading-option is part of the goal', + }); + expect(parseGoalCommand('-- cancel')).toMatchObject({ kind: 'create', objective: 'cancel' }); + }); + + it('parses replace as the first argument', () => { + expect(parseGoalCommand('replace Ship feature Y')).toMatchObject({ + kind: 'create', + objective: 'Ship feature Y', + replace: true, + }); + }); + + it('parses next as an upcoming-goal command', () => { + expect(parseGoalCommand('next Ship release notes')).toEqual({ + kind: 'next-add', + objective: 'Ship release notes', + }); + expect(parseGoalCommand('next manage')).toEqual({ kind: 'next-manage' }); + expect(parseGoalCommand('next -- manage release notes')).toEqual({ + kind: 'next-add', + objective: 'manage release notes', + }); + }); + + it('shows a hint for /goal next without an objective', () => { + expect(parseGoalCommand('next')).toEqual({ + kind: 'error', + severity: 'hint', + message: + 'Provide an upcoming goal objective, e.g. `/goal next Ship feature X`, or use `/goal next manage`.', + }); + }); + + it('rejects objectives longer than 4000 characters with a file-reference hint', () => { + expect(parseGoalCommand('x'.repeat(4001))).toEqual({ + kind: 'error', + restoreInput: true, + message: + 'Goal objective is too long (max 4000 characters). Put long content in a file and reference the file path.', + }); + expect(parseGoalCommand(`next ${'x'.repeat(4001)}`)).toEqual({ + kind: 'error', + restoreInput: true, + message: + 'Goal objective is too long (max 4000 characters). Put long content in a file and reference the file path.', + }); + }); +}); + +describe('goalObjectiveLengthWarning', () => { + it('warns once the typed /goal objective exceeds the limit', () => { + const warning = goalObjectiveLengthWarning(`/goal ${'x'.repeat(4001)}`); + expect(warning).toContain('(4001/4000 characters)'); + expect(warning).toContain('reference the file path'); + }); + + it('ignores leading whitespace because submitted text is trimmed', () => { + expect(goalObjectiveLengthWarning(` /goal ${'x'.repeat(4001)}`)).toBeDefined(); + }); + + it('warns for over-limit /goal next and /goal replace objectives', () => { + expect(goalObjectiveLengthWarning(`/goal next ${'x'.repeat(4001)}`)).toBeDefined(); + expect(goalObjectiveLengthWarning(`/goal replace ${'x'.repeat(4001)}`)).toBeDefined(); + expect(goalObjectiveLengthWarning(`/goal -- ${'x'.repeat(4001)}`)).toBeDefined(); + }); + + it('stays quiet for valid objectives and non-goal input', () => { + expect(goalObjectiveLengthWarning(`/goal ${'x'.repeat(4000)}`)).toBeUndefined(); + expect(goalObjectiveLengthWarning('/goal Ship feature X')).toBeUndefined(); + expect(goalObjectiveLengthWarning('Ship feature X')).toBeUndefined(); + }); + + it('stays quiet for control forms and lookalike commands', () => { + expect(goalObjectiveLengthWarning('/goal')).toBeUndefined(); + expect(goalObjectiveLengthWarning('/goal status')).toBeUndefined(); + expect(goalObjectiveLengthWarning('/goal pause')).toBeUndefined(); + expect(goalObjectiveLengthWarning('/goal next manage')).toBeUndefined(); + expect(goalObjectiveLengthWarning(`/goalie ${'x'.repeat(4001)}`)).toBeUndefined(); + }); + + it('stays quiet when the boundary is a newline or tab (dispatch sends those as plain messages)', () => { + expect(goalObjectiveLengthWarning(`/goal\n${'x'.repeat(4001)}`)).toBeUndefined(); + expect(goalObjectiveLengthWarning(`/goal\t${'x'.repeat(4001)}`)).toBeUndefined(); + }); + + it('still warns for multiline objectives after a literal-space boundary', () => { + const objective = `${'x'.repeat(2000)}\n${'x'.repeat(2001)}`; + expect(goalObjectiveLengthWarning(`/goal ${objective}`)).toBeDefined(); + }); +}); + +describe('handleGoalCommand', () => { + let host: SlashCommandHost; + let session: ReturnType['session']; + + beforeEach(() => { + const made = makeHost(); + host = made.host; + session = made.session; + vi.mocked(appendGoalQueueItem).mockClear(); + vi.mocked(readGoalQueue).mockClear(); + vi.mocked(moveGoalQueueItem).mockClear(); + vi.mocked(removeGoalQueueItem).mockClear(); + vi.mocked(updateGoalQueueItem).mockClear(); + }); + + it('/goal calls getGoal and does not send input', async () => { + await handleGoalCommand(host, ''); + expect(session.getGoal).toHaveBeenCalledOnce(); + expect(host.track).toHaveBeenCalledWith('goal_status', { status: 'none' }); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('/goal status calls getGoal and does not send input', async () => { + await handleGoalCommand(host, 'status'); + expect(session.getGoal).toHaveBeenCalledOnce(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('/goal creates a goal and sends the objective as input', async () => { + await handleGoalCommand(host, 'Ship feature X'); + expect(session.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X', replace: false }), + ); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + expect(host.sendNormalUserInput).not.toHaveBeenCalledWith('/goal Ship feature X'); + }); + + it('/goal keeps the sendNormalUserInput host receiver', async () => { + const calls: Array<{ receiver: unknown; text: string }> = []; + host.sendNormalUserInput = function (this: unknown, text: string): void { + calls.push({ receiver: this, text }); + }; + + await handleGoalCommand(host, 'Ship feature X'); + + expect(calls).toEqual([{ receiver: host, text: 'Ship feature X' }]); + }); + + it('rejects an over-limit objective before sending and restores the typed input', async () => { + const args = 'x'.repeat(4001); + await handleGoalCommand(host, args); + + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(host.showError).toHaveBeenCalledWith( + 'Goal objective is too long (max 4000 characters). Put long content in a file and reference the file path.', + ); + expect(host.restoreInputText).toHaveBeenCalledWith(`/goal ${args}`); + }); + + it('does not restore input for the empty-objective usage hint', async () => { + await handleGoalCommand(host, 'replace'); + + expect(host.showStatus).toHaveBeenCalled(); + expect(host.restoreInputText).not.toHaveBeenCalled(); + }); + + it('does not restore over a draft typed while validation was pending', async () => { + vi.mocked(host.state.editor.getText).mockReturnValue('a newer draft'); + + await handleGoalCommand(host, 'x'.repeat(4001)); + + expect(host.showError).toHaveBeenCalled(); + expect(host.restoreInputText).not.toHaveBeenCalled(); + }); + + it('asks before starting a goal in Manual mode', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'Ship feature X'); + + expect(manualHost.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(s.createGoal).not.toHaveBeenCalled(); + expect(manualHost.sendNormalUserInput).not.toHaveBeenCalled(); + const text = stripAnsi(mountedPicker(manualHost).render(80).join('\n')); + expect(text).toContain('Always Ask mode is not suitable for unattended goal work'); + expect(text).toContain('Return to the input box with your goal command'); + }); + + it('defaults to Auto when confirming a Manual-mode goal start', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'Ship feature X'); + mountedPicker(manualHost).handleInput(ENTER); + + await vi.waitFor(() => { + expect(s.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X' }), + ); + }); + expect(s.setPermission).toHaveBeenCalledWith('auto'); + expect(manualHost.setAppState).toHaveBeenCalledWith({ permissionMode: 'auto' }); + expect(manualHost.showNotice).toHaveBeenCalledWith('Permission mode: Never Ask'); + expect(manualHost.showStatus).toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.auto, 'warning'); + expect(manualHost.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + + it('can start a Manual-mode goal without changing permission', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'Ship feature X'); + const picker = mountedPicker(manualHost); + picker.handleInput(DOWN); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + await vi.waitFor(() => { + expect(s.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X' }), + ); + }); + expect(s.setPermission).not.toHaveBeenCalled(); + expect(manualHost.showNotice).not.toHaveBeenCalled(); + expect(manualHost.showStatus).not.toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.auto, 'warning'); + expect(manualHost.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + + it('can switch to YOLO when starting a Manual-mode goal', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'Ship feature X'); + const picker = mountedPicker(manualHost); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + await vi.waitFor(() => { + expect(s.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X' }), + ); + }); + expect(s.setPermission).toHaveBeenCalledWith('yolo'); + expect(manualHost.setAppState).toHaveBeenCalledWith({ permissionMode: 'yolo' }); + expect(manualHost.showNotice).toHaveBeenCalledWith('Permission mode: Ask When Needed'); + expect(manualHost.showStatus).toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.yolo, 'warning'); + }); + + it('restores the previous permission mode when the goal fails to start', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + s.createGoal = vi.fn(async () => { + throw new KimiError(ErrorCodes.GOAL_ALREADY_EXISTS, 'A goal already exists'); + }); + + await handleGoalCommand(manualHost, 'Ship feature X'); + const picker = mountedPicker(manualHost); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + await vi.waitFor(() => { + // Switched to YOLO to run the goal, then restored to Manual on failure. + expect(s.setPermission).toHaveBeenLastCalledWith('manual'); + }); + expect(s.setPermission).toHaveBeenCalledWith('yolo'); + expect(manualHost.setAppState).toHaveBeenLastCalledWith({ permissionMode: 'manual' }); + // The permissive-mode notice is deferred until the goal starts, so a failed + // start leaves no stale notice behind. + expect(manualHost.showNotice).not.toHaveBeenCalled(); + expect(manualHost.showStatus).not.toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.yolo, 'warning'); + }); + + it('returns the command to the input box when a Manual-mode goal start is cancelled', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'Ship feature X'); + mountedPicker(manualHost).handleInput(ESCAPE); + + expect(manualHost.restoreInputText).toHaveBeenCalledWith('/goal Ship feature X'); + expect(manualHost.showStatus).toHaveBeenCalledWith('Goal not started.'); + expect(s.createGoal).not.toHaveBeenCalled(); + }); + + it('returns the command to the input box when Do not start is selected', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'replace Ship feature Y'); + const picker = mountedPicker(manualHost); + picker.handleInput(DOWN); + picker.handleInput(DOWN); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + expect(manualHost.restoreInputText).toHaveBeenCalledWith('/goal replace Ship feature Y'); + expect(s.createGoal).not.toHaveBeenCalled(); + }); + + it('asks before starting a goal in YOLO mode', async () => { + const { host: yoloHost, session: s } = makeHost({ permissionMode: 'yolo' }); + + await handleGoalCommand(yoloHost, 'Ship feature X'); + + expect(yoloHost.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(s.createGoal).not.toHaveBeenCalled(); + expect(yoloHost.sendNormalUserInput).not.toHaveBeenCalled(); + const text = stripAnsi(mountedPicker(yoloHost).render(80).join('\n')); + expect(text).toContain('Ask When Needed mode can still stop for questions'); + expect(text).toContain('Keep Ask When Needed and start'); + expect(text).not.toContain('Start in Always Ask'); + }); + + it('defaults to Auto when confirming a YOLO-mode goal start', async () => { + const { host: yoloHost, session: s } = makeHost({ permissionMode: 'yolo' }); + + await handleGoalCommand(yoloHost, 'Ship feature X'); + mountedPicker(yoloHost).handleInput(ENTER); + + await vi.waitFor(() => { + expect(s.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X' }), + ); + }); + expect(s.setPermission).toHaveBeenCalledWith('auto'); + expect(yoloHost.setAppState).toHaveBeenCalledWith({ permissionMode: 'auto' }); + expect(yoloHost.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + + it('can keep YOLO when starting a YOLO-mode goal', async () => { + const { host: yoloHost, session: s } = makeHost({ permissionMode: 'yolo' }); + + await handleGoalCommand(yoloHost, 'Ship feature X'); + const picker = mountedPicker(yoloHost); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + await vi.waitFor(() => { + expect(s.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X' }), + ); + }); + expect(s.setPermission).not.toHaveBeenCalled(); + expect(yoloHost.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + + it('returns the command to the input box when a YOLO-mode goal start is cancelled', async () => { + const { host: yoloHost, session: s } = makeHost({ permissionMode: 'yolo' }); + + await handleGoalCommand(yoloHost, 'replace Ship feature Y'); + const picker = mountedPicker(yoloHost); + picker.handleInput(DOWN); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + expect(yoloHost.restoreInputText).toHaveBeenCalledWith('/goal replace Ship feature Y'); + expect(s.createGoal).not.toHaveBeenCalled(); + }); + + it('does not pass budget limits (flags were removed)', async () => { + await handleGoalCommand(host, 'Ship feature X'); + const arg = (session.createGoal as ReturnType).mock.calls[0]?.[0] as Record< + string, + unknown + >; + expect(arg).not.toHaveProperty('budgetLimits'); + }); + + it('rejects too-long objectives before any SDK call', async () => { + await handleGoalCommand(host, 'x'.repeat(4001)); + expect(host.showError).toHaveBeenCalled(); + expect(session.createGoal).not.toHaveBeenCalled(); + }); + + it('/goal replace passes replace: true', async () => { + await handleGoalCommand(host, 'replace Ship feature Y'); + expect(session.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature Y', replace: true }), + ); + }); + + it('/goal next queues an upcoming goal and does not send it to the agent', async () => { + session.getGoal.mockResolvedValueOnce({ goal: fakeSnapshot() }); + + await handleGoalCommand(host, 'next Ship release notes'); + + expect(session.getGoal).toHaveBeenCalledOnce(); + expect(appendGoalQueueItem).toHaveBeenCalledWith(session, { + objective: 'Ship release notes', + }); + expect(host.track).toHaveBeenCalledWith('goal_queue_append'); + expect(host.showStatus).not.toHaveBeenCalledWith( + 'Upcoming goal added. It will start after the current goal is complete.', + ); + const addChild = host.state.transcriptContainer.addChild as ReturnType; + const message = addChild.mock.calls[0]?.[0] as { render(width: number): string[] }; + expect(stripAnsi(message.render(80).join('\n'))).toBe( + '\n● Upcoming goal added. It will start after the current goal is complete.', + ); + expect(host.state.ui.requestRender).toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(session.createGoal).not.toHaveBeenCalled(); + }); + + it('/goal next starts immediately when there is no current goal', async () => { + await handleGoalCommand(host, 'next Ship release notes'); + + expect(session.getGoal).toHaveBeenCalledOnce(); + expect(appendGoalQueueItem).not.toHaveBeenCalled(); + expect(session.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship release notes', replace: false }), + ); + expect(host.showStatus).toHaveBeenCalledWith( + 'No active goal. Starting this goal now.', + ); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship release notes'); + }); + + it('/goal next queues instead of starting immediately while streaming with no current goal', async () => { + const { host: streamingHost, session: s } = makeHost({ streaming: true }); + + await handleGoalCommand(streamingHost, 'next Ship release notes'); + + expect(s.getGoal).toHaveBeenCalledOnce(); + expect(appendGoalQueueItem).toHaveBeenCalledWith(s, { + objective: 'Ship release notes', + }); + expect(streamingHost.requestQueuedGoalPromotion).toHaveBeenCalledOnce(); + expect(s.createGoal).not.toHaveBeenCalled(); + expect(streamingHost.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('/goal next follows the normal goal-start prompt when there is no current goal', async () => { + const { host: manualHost, session: s } = makeHost({ permissionMode: 'manual' }); + + await handleGoalCommand(manualHost, 'next Ship release notes'); + + expect(s.getGoal).toHaveBeenCalledOnce(); + expect(appendGoalQueueItem).not.toHaveBeenCalled(); + expect(manualHost.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(s.createGoal).not.toHaveBeenCalled(); + + mountedPicker(manualHost).handleInput(ESCAPE); + expect(manualHost.restoreInputText).toHaveBeenCalledWith('/goal next Ship release notes'); + }); + + it('/goal next does not require a configured model when queueing after a current goal', async () => { + const { host: noModelHost, session: s } = makeHost({ model: '' }); + s.getGoal.mockResolvedValueOnce({ goal: fakeSnapshot() }); + + await handleGoalCommand(noModelHost, 'next Ship release notes'); + + expect(appendGoalQueueItem).toHaveBeenCalledWith(s, { + objective: 'Ship release notes', + }); + expect(noModelHost.showError).not.toHaveBeenCalled(); + }); + + it('/goal next requires a configured model when it starts immediately', async () => { + const { host: noModelHost, session: s } = makeHost({ model: '' }); + + await handleGoalCommand(noModelHost, 'next Ship release notes'); + + expect(s.getGoal).toHaveBeenCalledOnce(); + expect(appendGoalQueueItem).not.toHaveBeenCalled(); + expect(s.createGoal).not.toHaveBeenCalled(); + expect(noModelHost.showError).toHaveBeenCalled(); + }); + + it('/goal next manage opens the upcoming goal manager without sending input', async () => { + await handleGoalCommand(host, 'next manage'); + + expect(readGoalQueue).toHaveBeenCalledWith(session); + expect(host.track).toHaveBeenCalledWith('goal_queue_manage'); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + const text = stripAnsi(mountedPicker(host).render(100).join('\n')); + expect(text).toContain('Upcoming goals'); + expect(text).toContain('First queued goal'); + expect(text).toContain('Second queued goal'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(session.createGoal).not.toHaveBeenCalled(); + }); + + it('/goal next manage reorders goals through the queue store', async () => { + await handleGoalCommand(host, 'next manage'); + const manager = mountedPicker(host); + + manager.handleInput(DOWN); + manager.handleInput(' '); + manager.handleInput(UP); + + await vi.waitFor(() => { + expect(moveGoalQueueItem).toHaveBeenCalledWith(session, { + goalId: 'q2', + direction: 'up', + }); + }); + }); + + it('/goal next manage removes goals through the queue store', async () => { + await handleGoalCommand(host, 'next manage'); + + mountedPicker(host).handleInput('d'); + + await vi.waitFor(() => { + expect(removeGoalQueueItem).toHaveBeenCalledWith(session, { goalId: 'q1' }); + }); + }); + + it('/goal next manage edits goals through the queue store', async () => { + await handleGoalCommand(host, 'next manage'); + + mountedPicker(host).handleInput('e'); + await vi.waitFor(() => { + expect(host.mountEditorReplacement).toHaveBeenCalledTimes(2); + }); + const editDialog = latestMountedPicker(host); + editDialog.handleInput(' updated'); + editDialog.handleInput(ENTER); + + await vi.waitFor(() => { + expect(updateGoalQueueItem).toHaveBeenCalledWith(session, { + goalId: 'q1', + objective: 'First queued goal updated', + }); + }); + }); + + it('surfaces duplicate-goal errors with replace guidance', async () => { + session.createGoal.mockRejectedValueOnce( + new KimiError(ErrorCodes.GOAL_ALREADY_EXISTS, 'exists'), + ); + await handleGoalCommand(host, 'Ship feature X'); + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('/goal replace')); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('/goal pause calls pauseGoal and does not send input', async () => { + await handleGoalCommand(host, 'pause'); + expect(session.pauseGoal).toHaveBeenCalledOnce(); + expect(host.track).toHaveBeenCalledWith('goal_pause'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('/goal pause cancels an active stream', async () => { + const { host: streamingHost, session: s } = makeHost({ streaming: true }); + await handleGoalCommand(streamingHost, 'pause'); + expect(s.pauseGoal).toHaveBeenCalledOnce(); + expect(s.cancel).toHaveBeenCalledOnce(); + }); + + it('/goal resume calls resumeGoal and sends a resume input', async () => { + await handleGoalCommand(host, 'resume'); + expect(session.resumeGoal).toHaveBeenCalledOnce(); + expect(host.track).toHaveBeenCalledWith('goal_resume'); + expect(host.showStatus).not.toHaveBeenCalledWith('Goal resumed.'); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Resume the active goal.'); + }); + + it('/goal cancel calls cancelGoal and does not send input', async () => { + await handleGoalCommand(host, 'cancel'); + expect(session.cancelGoal).toHaveBeenCalledOnce(); + expect(host.track).toHaveBeenCalledWith('goal_cancel'); + expect(host.showNotice).toHaveBeenCalledWith('Goal cancelled.'); + expect(host.showStatus).not.toHaveBeenCalledWith('Goal cancelled.'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('/goal cancel cancels an active stream', async () => { + const { host: streamingHost, session: s } = makeHost({ streaming: true }); + await handleGoalCommand(streamingHost, 'cancel'); + expect(s.cancelGoal).toHaveBeenCalledOnce(); + expect(s.cancel).toHaveBeenCalledOnce(); + }); + + // No-goal control commands all read as calm status messages, never red errors. + it('pausing with no goal shows a friendly status, not an error', async () => { + session.pauseGoal.mockRejectedValueOnce(new KimiError(ErrorCodes.GOAL_NOT_FOUND, 'No current goal')); + await handleGoalCommand(host, 'pause'); + expect(host.showStatus).toHaveBeenCalledWith('No goal to pause.'); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('resuming with no goal shows a friendly status, not an error', async () => { + session.resumeGoal.mockRejectedValueOnce(new KimiError(ErrorCodes.GOAL_NOT_FOUND, 'No current goal')); + await handleGoalCommand(host, 'resume'); + expect(host.showStatus).toHaveBeenCalledWith('No goal to resume.'); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('`replace` with no objective is a hint (status), not an error', async () => { + await handleGoalCommand(host, 'replace'); + expect(host.showStatus).toHaveBeenCalledWith(expect.stringContaining('Provide a goal objective')); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('status/pause/cancel work without a configured model', async () => { + const { host: noModelHost, session: s } = makeHost({ model: '' }); + await handleGoalCommand(noModelHost, 'status'); + await handleGoalCommand(noModelHost, 'pause'); + await handleGoalCommand(noModelHost, 'cancel'); + expect(s.getGoal).toHaveBeenCalled(); + expect(s.pauseGoal).toHaveBeenCalled(); + expect(s.cancelGoal).toHaveBeenCalled(); + expect(noModelHost.showError).not.toHaveBeenCalled(); + }); + + it('resume without a configured model does not activate the goal', async () => { + const { host: noModelHost, session: s } = makeHost({ model: '' }); + await handleGoalCommand(noModelHost, 'resume'); + expect(noModelHost.showError).toHaveBeenCalled(); + expect(s.resumeGoal).not.toHaveBeenCalled(); + expect(noModelHost.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('creation without a configured model shows LLM_NOT_SET_MESSAGE', async () => { + const { host: noModelHost, session: s } = makeHost({ model: '' }); + await handleGoalCommand(noModelHost, 'Ship feature X'); + expect(noModelHost.showError).toHaveBeenCalled(); + expect(s.createGoal).not.toHaveBeenCalled(); + }); + + it('creation without an active session shows LLM_NOT_SET_MESSAGE', async () => { + const { host: noSessionHost, session: s } = makeHost({ hasSession: false }); + await handleGoalCommand(noSessionHost, 'Ship feature X'); + expect(noSessionHost.showError).toHaveBeenCalled(); + expect(s.createGoal).not.toHaveBeenCalled(); + }); +}); + +describe('dispatchInput /goal integration', () => { + afterEach(() => { + setExperimentalFeatures([]); + }); + + it('routes /goal through the real resolver, creates the goal, and sends the objective', async () => { + const { host, session } = makeHost(); + + dispatchInput(host, '/goal Ship feature X'); + + await vi.waitFor(() => { + expect(session.createGoal).toHaveBeenCalledWith( + expect.objectContaining({ objective: 'Ship feature X' }), + ); + }); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + expect(host.sendNormalUserInput).not.toHaveBeenCalledWith('/goal Ship feature X'); + }); + + it('restores the input when /goal is rejected by the busy gate while streaming', async () => { + const { host, session } = makeHost({ streaming: true }); + + dispatchInput(host, '/goal Ship feature X'); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith( + 'Cannot /goal while streaming — press Esc or Ctrl-C first.', + ); + }); + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.restoreInputText).toHaveBeenCalledWith('/goal Ship feature X'); + }); + + it('restores the input when the post-creation busy re-check rejects /goal', async () => { + const { host, session } = makeHost({ hasSession: false }); + Object.assign(host, { + // A first prompt starts a turn while the lazy session creation awaits. + ensureSession: vi.fn(async () => { + host.state.appState.streamingPhase = 'thinking'; + return session; + }), + }); + + dispatchInput(host, '/goal Ship feature X'); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith( + 'Cannot /goal while streaming — press Esc or Ctrl-C first.', + ); + }); + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.restoreInputText).toHaveBeenCalledWith('/goal Ship feature X'); + }); + + it('does not restore over a draft typed while lazy session creation was pending', async () => { + const { host, session } = makeHost({ hasSession: false }); + Object.assign(host, { + ensureSession: vi.fn(async () => { + host.state.appState.streamingPhase = 'thinking'; + // The user kept typing after submitting /goal. + vi.mocked(host.state.editor.getText).mockReturnValue('a newer draft'); + return session; + }), + }); + + dispatchInput(host, '/goal Ship feature X'); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith( + 'Cannot /goal while streaming — press Esc or Ctrl-C first.', + ); + }); + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.restoreInputText).not.toHaveBeenCalled(); + }); + + it('restores the input when lazy session creation fails before /goal runs', async () => { + const { host, session } = makeHost({ hasSession: false }); + Object.assign(host, { + ensureSession: vi.fn(async () => undefined), + }); + + dispatchInput(host, '/goal Ship feature X'); + + await vi.waitFor(() => { + expect(host.restoreInputText).toHaveBeenCalledWith('/goal Ship feature X'); + }); + expect(session.createGoal).not.toHaveBeenCalled(); + }); + + it('does not restore when an editor-replacement panel opened during creation', async () => { + const { host, session } = makeHost({ hasSession: false }); + Object.assign(host, { + ensureSession: vi.fn(async () => { + // The user opened a panel (e.g. /help) while creation was pending. + Object.assign(host.state, { editorReplacementMounted: true }); + return undefined; + }), + }); + + dispatchInput(host, '/goal Ship feature X'); + + await vi.waitFor(() => { + expect(host.state.editorReplacementMounted).toBe(true); + }); + // Allow the post-creation branch to run before asserting. + await new Promise((resolve) => setImmediate(resolve)); + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.restoreInputText).not.toHaveBeenCalled(); + }); +}); + +describe('goalArgumentCompletions', () => { + function values(prefix: string): string[] | null { + const items = goalArgumentCompletions(prefix); + return items === null ? null : items.map((i) => i.value); + } + + function labels(prefix: string): string[] | null { + const items = goalArgumentCompletions(prefix); + return items === null ? null : items.map((i) => i.label); + } + + it('offers every subcommand for an empty prefix', () => { + expect(values('')).toEqual(['status', 'pause', 'resume', 'cancel', 'replace', 'next']); + }); + + it('prefix-filters subcommands case-insensitively', () => { + expect(values('pa')).toEqual(['pause']); + expect(values('RE')).toEqual(['resume', 'replace']); + }); + + it('returns items whose value/label are the token itself', () => { + const items = goalArgumentCompletions('paus'); + expect(items).toEqual([ + { value: 'pause', label: 'pause', description: 'Pause the active goal' }, + ]); + }); + + it('suppresses the menu once a token is fully typed and unambiguous', () => { + // `status` is the sole match and equals the prefix exactly, so there is + // nothing left to complete: the menu hides and Enter submits `/goal status` + // instead of confirming a no-op completion. + expect(values('status')).toBeNull(); + expect(values('pause')).toBeNull(); + // `re` still has two completions, so the menu stays open. + expect(values('re')).toEqual(['resume', 'replace']); + }); + + it('stops completing once past the first token (space typed)', () => { + expect(values('pause ')).toBeNull(); + expect(values('replace Ship feature')).toBeNull(); + expect(values('next Ship feature')).toBeNull(); + }); + + it('completes /goal next manage as the second token', () => { + expect(values('next ')).toEqual(['next manage']); + expect(values('next m')).toEqual(['next manage']); + expect(values('next MA')).toEqual(['next manage']); + expect(labels('next m')).toEqual(['manage']); + expect(values('next manage')).toBeNull(); + }); + + it('returns null when nothing matches', () => { + expect(values('zzz')).toBeNull(); + expect(values('next ship')).toBeNull(); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/plugin-commands.test.ts b/apps/kimi-code/test/tui/commands/plugin-commands.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..eae75a09971046d1592874d77dce777a18d0c120 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/plugin-commands.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'vitest'; + +import { buildPluginSlashCommands, pluginCommandName } from '#/tui/commands/plugin-commands'; + +describe('pluginCommandName', () => { + it('namespaces a command with its plugin id', () => { + expect(pluginCommandName('my-plugin', 'deploy')).toBe('my-plugin:deploy'); + }); +}); + +describe('buildPluginSlashCommands', () => { + it('namespaces commands and maps them to their bodies', () => { + const { commands, commandMap } = buildPluginSlashCommands([ + { + pluginId: 'my-plugin', + name: 'deploy', + description: 'Deploy', + body: 'Deploy $ARGUMENTS', + path: '/p/deploy.md', + }, + ]); + expect(commands).toEqual([{ name: 'my-plugin:deploy', aliases: [], description: 'Deploy' }]); + expect(commandMap.get('my-plugin:deploy')).toBe('Deploy $ARGUMENTS'); + }); + + it('returns empty commands for no defs', () => { + const { commands, commandMap } = buildPluginSlashCommands([]); + expect(commands).toEqual([]); + expect(commandMap.size).toBe(0); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/plugins-capability.test.ts b/apps/kimi-code/test/tui/commands/plugins-capability.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0f5809bf47def48f0eb75f10b371c885146e06d --- /dev/null +++ b/apps/kimi-code/test/tui/commands/plugins-capability.test.ts @@ -0,0 +1,356 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { log } from '@moonshot-ai/kimi-code-sdk'; +import { resetCapabilitiesCache, setCapabilities, type Component } from '@moonshot-ai/pi-tui'; + +import { __pluginsCommandInternals } from '#/tui/commands/plugins'; +import { NoticeMessageComponent } from '#/tui/components/messages/status-message'; + +const { + isCapabilityEntry, + installCapabilityFromPanel, + isDefaultMarketplaceCatalog, + pollCapabilityInstall, + removePlugin, +} = __pluginsCommandInternals; + +function fakeHost(overrides: { + capabilityStatus?: () => Promise<{ + state?: string; + steps?: readonly unknown[]; + install: { running: boolean; step?: string; percent?: number; error?: string }; + }>; +}) { + const statuses: string[] = []; + const notices: { title: string; detail?: string }[] = []; + const renders: number[] = []; + const transcriptEntries: Component[] = []; + const installCapability = vi.fn(() => Promise.resolve()); + const getCapability = + overrides.capabilityStatus ?? + (() => Promise.resolve({ state: 'ready', steps: [], install: { running: false } })); + const host = { + // Session-less (lazy session): plugin and capability calls fall back to + // the harness facade. + session: undefined, + harness: { + removePlugin: () => Promise.resolve(), + getCapability, + installCapability, + listCapabilities: () => Promise.resolve([]), + }, + requireSession: () => ({ + getCapability, + installCapability, + }), + showStatus: (text: string) => { + statuses.push(text); + }, + showError: (text: string) => { + statuses.push(text); + }, + showNotice: (title: string, detail?: string) => { + notices.push({ title, detail }); + transcriptEntries.push(new NoticeMessageComponent(title, detail)); + }, + restoreEditor: () => undefined, + state: { + ui: { requestRender: () => renders.push(1) }, + transcriptContainer: { + addChild: (entry: Component) => transcriptEntries.push(entry), + }, + }, + }; + return { host: host as never, statuses, notices, renders, transcriptEntries, installCapability }; +} + +function fakePanel() { + const lines: (string | undefined)[] = []; + return { + panel: { + setInstalling: (label: string) => { + lines.push(label); + }, + clearInstalling: () => { + lines.push(undefined); + }, + } as never, + lines, + }; +} + +function visibleLines(entries: readonly Component[], width = 100): string[] { + return entries + .flatMap((entry) => entry.render(width)) + .map((line) => + line + .replaceAll(/\u001B]8;;[^\u001B]*\u001B\\/g, '') + .replaceAll(/\u001B\[[0-9;]*m/g, '') + .trimEnd(), + ); +} + +function unwrappedVisibleText(entries: readonly Component[]): string { + return visibleLines(entries) + .join('\n') + .replaceAll(/\s+/g, ''); +} + +describe('plugins command capability surface', () => { + beforeEach(() => { + vi.restoreAllMocks(); + vi.spyOn(log, 'info').mockImplementation(() => undefined); + vi.spyOn(log, 'warn').mockImplementation(() => undefined); + }); + + afterEach(() => { + resetCapabilitiesCache(); + }); + + it('routes built-in entries through capabilities', () => { + expect( + isCapabilityEntry({ id: 'kimi-cu', source: 'capability:kimi-cu', builtIn: true } as never), + ).toBe(true); + expect( + isCapabilityEntry({ + id: 'kimi-webbridge', + source: 'capability:kimi-webbridge', + builtIn: true, + } as never), + ).toBe(true); + expect( + isCapabilityEntry({ id: 'kimi-cu', source: 'https://example.test/plugin.zip' } as never), + ).toBe(false); + // A forged capability: source without the parser-proof flag is a plain row. + expect(isCapabilityEntry({ id: 'kimi-cu', source: 'capability:kimi-cu' } as never)).toBe( + false, + ); + }); + + it('logs progress without replacing the generic installing label', async () => { + let calls = 0; + const { host } = fakeHost({ + capabilityStatus: () => { + calls += 1; + if (calls === 1) { + return Promise.resolve({ install: { running: true, step: 'download', percent: 40 } }); + } + return Promise.resolve({ install: { running: false } }); + }, + }); + const result = await pollCapabilityInstall(host, 'kimi-cu'); + + expect(result?.install.running).toBe(false); + expect(log.info).toHaveBeenCalledWith('capability install progress', { + capabilityId: 'kimi-cu', + step: 'download', + percent: 40, + }); + }); + + it('removePlugin notes that capability runtimes are left untouched', async () => { + const { host, statuses } = fakeHost({}); + await removePlugin(host, 'kimi-cu'); + expect(statuses.some((s) => s.includes('Removed kimi-cu'))).toBe(true); + expect(statuses.some((s) => s.includes('runtime binaries were left untouched'))).toBe(true); + expect(statuses.some((s) => s.includes('plugin wiring is disabled for new sessions'))).toBe(true); + expect(statuses.some((s) => s.includes('Restart Kimi Code before reinstalling'))).toBe(true); + expect(statuses.some((s) => s.includes('Run /new or /reload'))).toBe(false); + }); + + it('keeps the runtime note for the Windows backing plugin id', async () => { + const { host, statuses } = fakeHost({}); + await removePlugin(host, 'kimi-cu-win'); + expect(statuses.some((s) => s.includes('Removed kimi-cu-win'))).toBe(true); + expect(statuses.some((s) => s.includes('runtime binaries were left untouched'))).toBe(true); + }); + + it('treats only the default catalog (and the dev server) as injectable', () => { + expect(isDefaultMarketplaceCatalog(undefined, {})).toBe(true); + // The dev marketplace server started by scripts/dev.mjs serves this + // repo's own catalog — it counts as default, not as a user override. + expect( + isDefaultMarketplaceCatalog(undefined, { + KIMI_CODE_PLUGIN_MARKETPLACE_URL: 'http://127.0.0.1:60056/marketplace.json', + KIMI_CODE_PLUGIN_MARKETPLACE_FROM_DEV_SERVER: '1', + }), + ).toBe(true); + expect( + isDefaultMarketplaceCatalog(undefined, { + KIMI_CODE_PLUGIN_MARKETPLACE_URL: 'https://example.test/marketplace.json', + }), + ).toBe(false); + expect(isDefaultMarketplaceCatalog('https://example.test/marketplace.json', {})).toBe(false); + }); + + it('removePlugin stays quiet for non-capability plugins', async () => { + const { host, statuses } = fakeHost({}); + await removePlugin(host, 'superpowers'); + expect(statuses.some((s) => s.includes('runtime binaries'))).toBe(false); + }); + + it('starts a capability install only when none is running', async () => { + const idle = fakeHost({}); + await installCapabilityFromPanel( + idle.host, + fakePanel().panel, + { id: 'kimi-cu', displayName: 'Kimi Computer Use', source: 'capability:kimi-cu' } as never, + ); + expect(idle.installCapability).toHaveBeenCalledWith('kimi-cu'); + }); + + it('follows an in-progress capability install instead of restarting it', async () => { + let calls = 0; + const { host, installCapability, statuses } = fakeHost({ + capabilityStatus: () => { + calls += 1; + // The pre-check sees the running install; the poll then sees it settle. + return Promise.resolve( + calls === 1 + ? { state: 'partial', steps: [], install: { running: true, step: 'download', percent: 40 } } + : { state: 'ready', steps: [], install: { running: false } }, + ); + }, + }); + + await installCapabilityFromPanel( + host, + fakePanel().panel, + { id: 'kimi-cu', displayName: 'Kimi Computer Use', source: 'capability:kimi-cu' } as never, + ); + + // The service rejects duplicate starts (40922) — a healthy in-progress + // install must be followed via polling, never reported as a failure. + expect(installCapability).not.toHaveBeenCalled(); + expect(statuses.some((s) => s.includes('Failed to install'))).toBe(false); + expect(statuses.some((s) => s.includes('is installed'))).toBe(true); + }); + + it('renders visible clickable store URLs after WebBridge installs in a hyperlink-capable terminal', async () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: true }); + const { host, statuses, notices, transcriptEntries } = fakeHost({}); + + await installCapabilityFromPanel( + host, + fakePanel().panel, + { + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + source: 'capability:kimi-webbridge', + } as never, + ); + + expect(notices).toContainEqual({ title: 'Kimi Browser Extension is installed.', detail: undefined }); + expect(statuses).not.toContain('Run /new or /reload to apply plugin changes.'); + const rendered = transcriptEntries.flatMap((entry) => entry.render(100)).join('\n'); + expect(rendered).toContain( + '\u001B]8;;https://chromewebstore.google.com/detail/kimi-webbridge/fldmhceldgbpfpkbgopacenieobmligc\u001B\\', + ); + expect(rendered).toContain('Chrome Web Store'); + expect(rendered).toContain('Edge Add-ons'); + expect(rendered).toContain('Manual installation guide'); + expect(rendered).toContain('/reload'); + expect(rendered).toContain('/new'); + }); + + it('renders full store URLs after WebBridge installs in a terminal without hyperlinks', async () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: false }); + const { host, transcriptEntries } = fakeHost({}); + + await installCapabilityFromPanel( + host, + fakePanel().panel, + { + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + source: 'capability:kimi-webbridge', + } as never, + ); + + const rendered = transcriptEntries.flatMap((entry) => entry.render(100)).join('\n'); + expect(rendered).not.toContain('\u001B]8;;'); + expect(unwrappedVisibleText(transcriptEntries)).toContain( + 'https://chromewebstore.google.com/detail/kimi-webbridge/fldmhceldgbpfpkbgopacenieobmligc', + ); + }); + + it('separates the WebBridge install result from its setup steps with one blank line', async () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: true }); + const { host, transcriptEntries } = fakeHost({}); + + await installCapabilityFromPanel( + host, + fakePanel().panel, + { + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + source: 'capability:kimi-webbridge', + } as never, + ); + + const lines = visibleLines(transcriptEntries, 180); + const installed = lines.findIndex((line) => line.includes('Kimi Browser Extension is installed.')); + const intro = lines.findIndex((line) => + line.includes('Two steps left to use Kimi Browser Extension:'), + ); + const firstStep = lines.findIndex((line) => + line.includes('Install the browser extension'), + ); + const secondStep = lines.findIndex((line) => line.includes('Run /reload or /new to apply it.')); + expect(lines.slice(installed + 1, intro)).toEqual(['']); + expect(firstStep).toBe(intro + 1); + expect(lines[firstStep]).toContain('1.'); + expect(lines.find((line) => line.includes('Chrome Web Store'))).toContain('•'); + expect(lines.find((line) => line.includes('Edge Add-ons'))).toContain('•'); + expect(lines.find((line) => line.includes('Manual installation guide'))).toContain('•'); + expect(lines[secondStep]).toContain('2.'); + }); + + it('shows the engine error when a background capability install fails', async () => { + const { host, statuses } = fakeHost({ + capabilityStatus: () => + Promise.resolve({ + state: 'not_installed', + steps: [], + install: { running: false, error: 'Authenticode signature is not valid' }, + }), + }); + + await installCapabilityFromPanel( + host, + fakePanel().panel, + { id: 'kimi-cu', displayName: 'Kimi Computer Use', source: 'capability:kimi-cu' } as never, + ); + + expect(statuses).toContain( + 'Kimi Computer Use installation failed: Authenticode signature is not valid', + ); + expect(statuses).toContain('Fix the reported error, then install again from /plugins.'); + }); + + it('shows required permissions once after installation instead of exposing step details', async () => { + const { host, statuses } = fakeHost({ + capabilityStatus: () => Promise.resolve({ + id: 'kimi-cu', + state: 'partial', + steps: [{ id: 'permissions', state: 'missing', detail: 'screenRecording' }], + install: { running: false }, + }), + }); + + await installCapabilityFromPanel( + host, + fakePanel().panel, + { id: 'kimi-cu', displayName: 'Kimi Computer Use', source: 'capability:kimi-cu' } as never, + ); + + expect(statuses.some((s) => s.includes('Grant Accessibility and Screen Recording'))).toBe(true); + expect(statuses.some((s) => s.includes('screenRecording'))).toBe(false); + expect(log.warn).toHaveBeenCalledWith( + 'capability needs attention', + expect.objectContaining({ + capabilityId: 'kimi-cu', + steps: [expect.objectContaining({ detail: 'screenRecording' })], + }), + ); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/provider.test.ts b/apps/kimi-code/test/tui/commands/provider.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..300c1995ade30284cd91048c43b415e4ec608970 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/provider.test.ts @@ -0,0 +1,155 @@ +/** + * Scenario: /provider post-add default-model selection. + * Responsibilities: the picked effort is gated for persistence by the model's + * effective default, and a session-only pick is still applied to the runtime + * after the config refresh (which only reactivates from persisted values). + * Wiring: real setDefaultModel with the harness/authFlow boundaries stubbed by + * a small host rig. + * Run: pnpm -C apps/kimi-code exec vitest run test/tui/commands/provider.test.ts + */ +import type { ModelAlias } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import type { SlashCommandHost } from '#/tui/commands'; +import { setDefaultModel } from '#/tui/commands/provider'; + +function makeHost( + options: { + refreshReachedLiveSession?: boolean; + activateReachedLiveSession?: boolean; + } = {}, +) { + const appState = { + availableModels: { + // Declares no efforts; the Anthropic profile inference supplies + // [low, medium, high, xhigh, max] with the default resolved to 'high'. + opus: { + provider: 'compatible', + model: 'claude-opus-4-7', + maxContextSize: 200_000, + } as unknown as ModelAlias, + }, + availableProviders: { + compatible: { type: 'anthropic' }, + }, + }; + const host = { + state: { appState }, + waitForLazyCreation: vi.fn(async () => {}), + harness: { + setConfig: vi.fn(async () => ({})), + }, + authFlow: { + refreshConfigAfterLogin: vi.fn(async () => options.refreshReachedLiveSession === true), + activateModelAfterLogin: vi.fn(async () => options.activateReachedLiveSession === true), + }, + track: vi.fn(), + showStatus: vi.fn(), + } as unknown as SlashCommandHost & { + harness: { setConfig: ReturnType }; + authFlow: { + refreshConfigAfterLogin: ReturnType; + activateModelAfterLogin: ReturnType; + }; + waitForLazyCreation: ReturnType; + track: ReturnType; + }; + return { host }; +} + +describe('setDefaultModel', () => { + it('applies an above-default pick to the runtime when the gate keeps it session-only', async () => { + const { host } = makeHost(); + + await setDefaultModel(host, 'opus', 'xhigh'); + + expect(host.harness.setConfig).toHaveBeenCalledWith({ + defaultModel: 'opus', + thinking: { enabled: true }, + }); + expect(host.authFlow.activateModelAfterLogin).toHaveBeenCalledWith('opus', 'xhigh'); + // The application must come after the refresh, or the persisted value + // reactivated by refreshConfigAfterLogin would clobber the pick. + expect( + host.authFlow.activateModelAfterLogin.mock.invocationCallOrder[0]!, + ).toBeGreaterThan(host.authFlow.refreshConfigAfterLogin.mock.invocationCallOrder[0]!); + // Without a session the engine never sees the pick, so the TUI stays the + // sole model_switch producer. + expect(host.track).toHaveBeenCalledWith('model_switch', { model: 'opus' }); + }); + + it('does not re-apply the effort when the pick persists', async () => { + const { host } = makeHost(); + + await setDefaultModel(host, 'opus', 'high'); + + expect(host.harness.setConfig).toHaveBeenCalledWith({ + defaultModel: 'opus', + thinking: { enabled: true, effort: 'high' }, + }); + expect(host.authFlow.activateModelAfterLogin).not.toHaveBeenCalled(); + }); + + it('does not re-apply a boolean on pick', async () => { + const { host } = makeHost(); + + await setDefaultModel(host, 'opus', 'on'); + + expect(host.harness.setConfig).toHaveBeenCalledWith({ + defaultModel: 'opus', + thinking: { enabled: true }, + }); + expect(host.authFlow.activateModelAfterLogin).not.toHaveBeenCalled(); + }); + + it('leaves model_switch to the engine when activation changed the bound alias', async () => { + const { host } = makeHost({ refreshReachedLiveSession: true }); + + await setDefaultModel(host, 'opus', 'high'); + + // refreshConfigAfterLogin routed through session.setModel with a changed + // alias, which the engine already tracks — a TUI-side event would + // double-count the switch. + expect(host.track).not.toHaveBeenCalled(); + }); + + it('leaves model_switch to the engine when a lazy session came live mid-flow and rebounded', async () => { + // Session-less at entry, but the first prompt's lazy creation completes + // while setConfig / the refresh are pending, so the session-only re-apply + // lands on the now-live session and actually switches its alias (engine + // emits). + const { host } = makeHost({ activateReachedLiveSession: true }); + + await setDefaultModel(host, 'opus', 'xhigh'); + + expect(host.authFlow.activateModelAfterLogin).toHaveBeenCalledWith('opus', 'xhigh'); + expect(host.track).not.toHaveBeenCalled(); + }); + + it('emits model_switch when a v1-created session only rebinds the same alias', async () => { + // v1 session-less + session-only effort: the refresh creates the session + // with the picked model (creation emits nothing), then the re-apply + // reaches that live session but its setModel is an alias no-op (no engine + // event either) — the TUI must stay the producer for the pick. + const { host } = makeHost({ + refreshReachedLiveSession: false, + activateReachedLiveSession: false, + }); + + await setDefaultModel(host, 'opus', 'xhigh'); + + expect(host.authFlow.activateModelAfterLogin).toHaveBeenCalledWith('opus', 'xhigh'); + expect(host.track).toHaveBeenCalledWith('model_switch', { model: 'opus' }); + }); + + it('waits for an in-flight lazy creation before activating (v2)', async () => { + const { host } = makeHost(); + + await setDefaultModel(host, 'opus', 'high'); + + expect(host.waitForLazyCreation).toHaveBeenCalled(); + expect( + host.waitForLazyCreation.mock.invocationCallOrder[0]!, + ).toBeLessThan(host.harness.setConfig.mock.invocationCallOrder[0]!); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/registry.test.ts b/apps/kimi-code/test/tui/commands/registry.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ee3bc7b4d2abf553ec0df8507dd43f6dd42e92f --- /dev/null +++ b/apps/kimi-code/test/tui/commands/registry.test.ts @@ -0,0 +1,244 @@ +import { + BUILTIN_SLASH_COMMANDS, + findBuiltInSlashCommand, + parseSlashInput, + resolveSlashCommandAvailability, + addDirArgumentCompletions, + sortSlashCommands, + swarmArgumentCompletions, + towerArgumentCompletions, + type KimiSlashCommand, +} from '#/tui/commands/index'; +import { describe, expect, it } from 'vitest'; + +describe('parseSlashInput', () => { + it('parses command names and trimmed args', () => { + expect(parseSlashInput('/help')).toEqual({ name: 'help', args: '' }); + expect(parseSlashInput('/model kimi-k2 ')).toEqual({ + name: 'model', + args: 'kimi-k2', + }); + }); + + it('returns null for non-commands and path-like input', () => { + expect(parseSlashInput('hello')).toBeNull(); + expect(parseSlashInput('/')).toBeNull(); + expect(parseSlashInput('/ ')).toBeNull(); + expect(parseSlashInput('/some/path')).toBeNull(); + expect(parseSlashInput('/some/path with args')).toBeNull(); + }); +}); + +describe('built-in slash command registry', () => { + it('finds built-ins by name or alias', () => { + expect(findBuiltInSlashCommand('exit')?.name).toBe('exit'); + expect(findBuiltInSlashCommand('quit')?.name).toBe('exit'); + expect(findBuiltInSlashCommand('q')?.name).toBe('exit'); + expect(findBuiltInSlashCommand('clear')?.name).toBe('new'); + expect(findBuiltInSlashCommand('bug')?.name).toBe('feedback'); + expect(findBuiltInSlashCommand('btw')?.name).toBe('btw'); + expect(findBuiltInSlashCommand('mcp')?.name).toBe('mcp'); + expect(findBuiltInSlashCommand('status')?.name).toBe('status'); + expect(findBuiltInSlashCommand('usage')?.aliases).not.toContain('status'); + expect(findBuiltInSlashCommand('unknown')).toBeUndefined(); + }); + + it('marks plan clear as idle-only while normal plan toggles are always available', () => { + const plan = findBuiltInSlashCommand('plan'); + expect(plan).toBeDefined(); + expect(resolveSlashCommandAvailability(plan!, '')).toBe('always'); + expect(resolveSlashCommandAvailability(plan!, 'on')).toBe('always'); + expect(resolveSlashCommandAvailability(plan!, 'clear')).toBe('idle-only'); + }); + + it('keeps swarm mode changes and swarm tasks idle-only', () => { + const swarm = findBuiltInSlashCommand('swarm'); + expect(swarm).toBeDefined(); + expect((swarm as KimiSlashCommand).experimentalFlag).toBeUndefined(); + expect(resolveSlashCommandAvailability(swarm!, 'on')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(swarm!, 'off')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(swarm!, 'Ship feature X')).toBe('idle-only'); + }); + + it('offers swarm subcommand argument completions', () => { + const values = (prefix: string): string[] | null => { + const items = swarmArgumentCompletions(prefix); + return items === null ? null : items.map((item) => item.value); + }; + + expect(values('')).toEqual(['on', 'off']); + expect(values('O')).toEqual(['on', 'off']); + expect(swarmArgumentCompletions('of')).toEqual([ + { value: 'off', label: 'off', description: 'Turn swarm mode off' }, + ]); + expect(values('on')).toBeNull(); + expect(values('off')).toBeNull(); + expect(values('Ship feature X')).toBeNull(); + }); + + it('offers tower subcommand argument completions', () => { + const values = (prefix: string): string[] | null => { + const items = towerArgumentCompletions(prefix); + return items === null ? null : items.map((item) => item.value); + }; + + expect(values('')).toEqual(['status', 'teardown', 'on', 'off']); + expect(values('T')).toEqual(['teardown']); + expect(towerArgumentCompletions('tea')).toEqual([ + { value: 'teardown', label: 'teardown', description: 'Tear down the tower' }, + ]); + expect(values('status')).toBeNull(); + expect(values('on')).toBeNull(); + expect(values('Ship feature X')).toBeNull(); + }); + + it('offers add-dir list and directory argument completions', () => { + const values = (prefix: string): string[] | null => { + const items = addDirArgumentCompletions(prefix); + return items === null ? null : items.map((item) => item.value); + }; + + expect(values('')).toEqual(['list']); + expect(values('L')).toEqual(['list']); + expect(values('list')).toBeNull(); + const directoryCompletions = values('/') ?? []; + expect(directoryCompletions.length).toBeGreaterThan(0); + expect(directoryCompletions.every((value) => value.startsWith('/') && value.endsWith('/'))).toBe(true); + expect(directoryCompletions.some((value) => value.startsWith('/.'))).toBe(false); + expect(values('/.')).toBeNull(); + const homeCompletions = values('~/') ?? []; + expect(homeCompletions.length).toBeGreaterThan(0); + expect(homeCompletions.every((value) => value.startsWith('~/') && value.endsWith('/'))).toBe(true); + expect(homeCompletions.some((value) => value.startsWith('~/.'))).toBe(false); + expect(homeCompletions.some((value) => value.startsWith('~/sers/'))).toBe(false); + }); + + it('defaults commands without explicit availability to idle-only', () => { + const command: KimiSlashCommand = { + name: 'example', + aliases: [], + description: 'Example command', + }; + + expect(resolveSlashCommandAvailability(command, '')).toBe('idle-only'); + }); + + it('sorts commands by priority descending and name ascending', () => { + const commands: KimiSlashCommand[] = [ + { name: 'zebra', aliases: [], description: 'Z', priority: 100 }, + { name: 'alpha', aliases: [], description: 'A', priority: 100 }, + { name: 'middle', aliases: [], description: 'M', priority: 50 }, + { name: 'plain', aliases: [], description: 'P' }, + ]; + + expect(sortSlashCommands(commands).map((command) => command.name)).toEqual([ + 'alpha', + 'zebra', + 'middle', + 'plain', + ]); + }); + + it('registers goal with subcommand-aware availability', () => { + const goal = findBuiltInSlashCommand('goal'); + expect(goal).toBeDefined(); + expect((goal as KimiSlashCommand).experimentalFlag).toBeUndefined(); + expect(resolveSlashCommandAvailability(goal!, '')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'status')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'pause')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'cancel')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'next')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'next Ship feature Y')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'next manage')).toBe('always'); + expect(resolveSlashCommandAvailability(goal!, 'status report')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(goal!, 'pause the rollout')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(goal!, 'cancel the migration')).toBe('idle-only'); + // `clear` is no longer a subcommand; it parses as an objective -> idle-only. + expect(resolveSlashCommandAvailability(goal!, 'clear')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(goal!, 'resume')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(goal!, 'Ship feature X')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(goal!, 'replace Ship feature Y')).toBe('idle-only'); + }); + + it('contains the expected command names once', () => { + const names = BUILTIN_SLASH_COMMANDS.map((command) => command.name); + + expect(new Set(names).size).toBe(names.length); + expect(names).toEqual( + expect.arrayContaining([ + 'add-dir', + 'compact', + 'btw', + 'editor', + 'exit', + 'export-debug-zip', + 'fork', + 'help', + 'init', + 'login', + 'logout', + 'mcp', + 'model', + 'new', + 'permission', + 'plan', + 'reload', + 'reload-tui', + 'secondary-model', + 'sessions', + 'settings', + 'status', + 'theme', + 'title', + 'tower', + 'undo', + 'usage', + 'version', + 'yolo', + 'auto', + ]), + ); + }); + + it('keeps TUI reload always available and full reload idle-only', () => { + const reload = findBuiltInSlashCommand('reload'); + const reloadTui = findBuiltInSlashCommand('reload-tui'); + + expect(reload).toBeDefined(); + expect(reloadTui).toBeDefined(); + expect(resolveSlashCommandAvailability(reload!, '')).toBe('idle-only'); + expect(resolveSlashCommandAvailability(reloadTui!, '')).toBe('always'); + }); + + it('exposes secondary-model unconditionally, always available', () => { + const command = findBuiltInSlashCommand('secondary-model'); + expect(command).toBeDefined(); + expect((command as KimiSlashCommand).experimentalFlag).toBeUndefined(); + expect(resolveSlashCommandAvailability(command!, '')).toBe('always'); + }); + + it('gates tower behind the tower experiment', () => { + const command = findBuiltInSlashCommand('tower'); + expect(command).toBeDefined(); + expect((command as KimiSlashCommand).experimentalFlag).toBe('tower'); + }); + + it('keeps every tower subcommand always available, including objectives', () => { + const command = findBuiltInSlashCommand('tower'); + expect(command).toBeDefined(); + expect(resolveSlashCommandAvailability(command!, '')).toBe('always'); + expect(resolveSlashCommandAvailability(command!, 'on')).toBe('always'); + expect(resolveSlashCommandAvailability(command!, 'off')).toBe('always'); + expect(resolveSlashCommandAvailability(command!, 'status')).toBe('always'); + expect(resolveSlashCommandAvailability(command!, 'teardown')).toBe('always'); + expect(resolveSlashCommandAvailability(command!, 'Ship feature X')).toBe('always'); + }); + + it('registers remote-control as always available', () => { + const command = findBuiltInSlashCommand('remote-control'); + expect(command).toBeDefined(); + expect((command as KimiSlashCommand).experimentalFlag).toBeUndefined(); + expect(resolveSlashCommandAvailability(command!, '')).toBe('always'); + }); + +}); diff --git a/apps/kimi-code/test/tui/commands/reload.test.ts b/apps/kimi-code/test/tui/commands/reload.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1aa1311b328e56f0b9d7cd4110639b07f2299fa8 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/reload.test.ts @@ -0,0 +1,240 @@ +import { mkdir, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { + handleReloadCommand, + handleReloadTuiCommand, +} from '#/tui/commands/reload'; +import { currentTheme } from '#/tui/theme'; +import type { SlashCommandHost } from '#/tui/commands'; +import { + isExperimentalFlagEnabled, + setExperimentalFeatures, +} from '#/tui/commands/experimental-flags'; +import { + createMarkdownOptions, + setMarkdownRenderLatex, +} from '#/tui/utils/markdown-options'; + +const tempDirs: string[] = []; +const originalKimiCodeHome = process.env['KIMI_CODE_HOME']; + +afterEach(async () => { + setExperimentalFeatures([]); + for (const dir of tempDirs.splice(0)) { + await rm(dir, { recursive: true, force: true }); + } + if (originalKimiCodeHome === undefined) { + delete process.env['KIMI_CODE_HOME']; + } else { + process.env['KIMI_CODE_HOME'] = originalKimiCodeHome; + } +}); + +describe('reload slash commands', () => { + it('reloads tui.toml without touching Core session state', async () => { + await writeTuiConfig(` +theme = "light" +cache_expiry_hint = false + +[editor] +command = "vim" + +[notifications] +enabled = false +notification_condition = "always" + +[upgrade] +auto_install = false +`); + const session = { reloadSession: vi.fn() }; + const host = makeHost({ session }); + + await handleReloadTuiCommand(host); + + expect(host.harness.getConfig).not.toHaveBeenCalled(); + expect(host.harness.getExperimentalFeatures).not.toHaveBeenCalled(); + expect(session.reloadSession).not.toHaveBeenCalled(); + expect(host.state.appState).toMatchObject({ + theme: 'light', + editorCommand: 'vim', + cacheExpiryHint: false, + notifications: { enabled: false, condition: 'always' }, + upgrade: { autoInstall: false }, + }); + expect(host.showStatus).toHaveBeenCalledWith( + 'TUI config reloaded.', + 'success', + ); + }); + + it('reloads the active session, refreshes runtime config, and applies tui.toml', async () => { + await writeTuiConfig('theme = "light"\n'); + const session = { id: 'ses-1', reloadSession: vi.fn(async () => ({})) }; + const host = makeHost({ session }); + + await handleReloadCommand(host); + + expect(host.harness.reloadSession).toHaveBeenCalledWith({ + id: session.id, + forcePluginSessionStartReminder: true, + }); + expect(session.reloadSession).not.toHaveBeenCalled(); + expect(host.reloadCurrentSessionView).toHaveBeenCalledWith( + session, + 'Session reloaded.', + ); + expect(host.harness.getConfig).toHaveBeenCalledWith({ reload: true }); + expect(host.harness.getExperimentalFeatures).toHaveBeenCalledOnce(); + expect(host.refreshSlashCommandAutocomplete).toHaveBeenCalledOnce(); + expect(isExperimentalFlagEnabled('micro_compaction')).toBe(true); + expect(host.state.appState.theme).toBe('light'); + expect(host.state.appState.availableModels).toEqual({ + fresh: { provider: 'test', model: 'fresh-model', maxContextSize: 1000 }, + }); + }); + + it('awaits the async theme application before refreshing terminal tracking', async () => { + await writeTuiConfig('theme = "auto"\n'); + const host = makeHost(); + const mutable = host as unknown as { + applyTheme: (theme: string) => Promise; + refreshTerminalThemeTracking: () => void; + state: { appState: { theme: string } }; + }; + + let themeWhenTracked: string | undefined; + // Theme application resolves on a later microtask, mirroring the real + // async palette load; tracking must observe the *new* theme. + mutable.applyTheme = vi.fn(async (theme: string) => { + await Promise.resolve(); + mutable.state.appState.theme = theme; + }); + mutable.refreshTerminalThemeTracking = vi.fn(() => { + themeWhenTracked = mutable.state.appState.theme; + }); + + await handleReloadTuiCommand(host); + + expect(themeWhenTracked).toBe('auto'); + }); + + it('applies the render_latex toggle before theme application rebuilds Markdown', async () => { + await writeTuiConfig('render_latex = false\n'); + const host = makeHost(); + + // applyTheme invalidates transcript components, which rebuild their + // Markdown children by copying the shared options — the reloaded value + // must already be live at that point. + let latexWhenThemeApplied: boolean | undefined; + const mutable = host as unknown as { applyTheme: unknown }; + mutable.applyTheme = vi.fn(() => { + latexWhenThemeApplied = createMarkdownOptions().renderLatex; + }); + + try { + await handleReloadTuiCommand(host); + expect(latexWhenThemeApplied).toBe(false); + } finally { + setMarkdownRenderLatex(true); + } + }); + + it('refreshes workspace commands and lazy defaults on a session-less v2 reload', async () => { + await writeTuiConfig('theme = "dark"\n'); + const host = makeHost(); + const refreshSkillCommands = vi.fn(async () => {}); + const refreshPluginCommands = vi.fn(async () => {}); + const hydrateLazyConfigDefaults = vi.fn(async () => {}); + Object.assign(host, { + refreshSkillCommands, + refreshPluginCommands, + hydrateLazyConfigDefaults, + }); + + await handleReloadCommand(host); + + expect(refreshSkillCommands).toHaveBeenCalledOnce(); + expect(refreshPluginCommands).toHaveBeenCalledOnce(); + expect(hydrateLazyConfigDefaults).toHaveBeenCalledOnce(); + // Autocomplete must rebuild after the command maps are refreshed. + expect(refreshSkillCommands.mock.invocationCallOrder[0]).toBeLessThan( + host.refreshSlashCommandAutocomplete.mock.invocationCallOrder[0]!, + ); + expect(host.showStatus).toHaveBeenCalledWith( + 'Runtime and TUI config reloaded; no active session.', + 'success', + ); + }); +}); + +async function writeTuiConfig(text: string): Promise { + const dir = join(tmpdir(), `kimi-tui-reload-${Date.now()}-${Math.random().toString(36).slice(2)}`); + tempDirs.push(dir); + await mkdir(dir, { recursive: true }); + process.env['KIMI_CODE_HOME'] = dir; + await writeFile(join(dir, 'tui.toml'), text, 'utf-8'); +} + +function makeHost({ + session, +}: { + readonly session?: Record; +} = {}) { + const state = { + appState: { + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + availableModels: {}, + availableProviders: {}, + }, + editor: { + setDisablePasteBurst: vi.fn(), + }, + theme: { + palette: { + success: '#00ff00', + }, + }, + }; + return { + state, + session, + harness: { + reloadSession: vi.fn(async () => session), + getConfig: vi.fn(async () => ({ + models: { + fresh: { provider: 'test', model: 'fresh-model', maxContextSize: 1000 }, + }, + providers: { + test: { type: 'kimi', apiKey: 'test-key' }, + }, + })), + getExperimentalFeatures: vi.fn(async () => [{ id: 'micro_compaction', enabled: true }]), + }, + setAppState: vi.fn((patch: Record) => { + Object.assign(state.appState, patch); + }), + applyTheme: vi.fn((theme: string) => { + state.appState.theme = theme; + }), + refreshTerminalThemeTracking: vi.fn(), + refreshSlashCommandAutocomplete: vi.fn(), + reloadCurrentSessionView: vi.fn(async () => {}), + showStatus: vi.fn(), + } as unknown as SlashCommandHost & { + readonly harness: { + readonly reloadSession: ReturnType; + readonly getConfig: ReturnType; + readonly getExperimentalFeatures: ReturnType; + }; + readonly refreshSlashCommandAutocomplete: ReturnType; + readonly reloadCurrentSessionView: ReturnType; + readonly showStatus: ReturnType; + }; +} diff --git a/apps/kimi-code/test/tui/commands/resolve.test.ts b/apps/kimi-code/test/tui/commands/resolve.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9cd1067589fcab89c630a38ac8e1a52a73098508 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/resolve.test.ts @@ -0,0 +1,363 @@ +import { + resolveSkillCommand, + resolveSlashCommandInput, + setExperimentalFeatures, + slashBusyMessage, + slashCommandBusyReason, +} from '#/tui/commands/index'; +import { afterEach, describe, expect, it } from 'vitest'; + +function resolve( + input: string, + overrides: Partial[0]> = {}, +) { + return resolveSlashCommandInput({ + input, + skillCommandMap: new Map(), + pluginCommandMap: new Map(), + isStreaming: false, + isCompacting: false, + ...overrides, + }); +} + +describe('resolveSlashCommandInput', () => { + afterEach(() => { + setExperimentalFeatures([]); + }); + + it('returns not-command for normal text', () => { + expect(resolve('hello')).toEqual({ kind: 'not-command' }); + }); + + it('resolves built-in commands by name and alias', () => { + expect(resolve('/help')).toMatchObject({ kind: 'builtin', name: 'help', args: '' }); + expect(resolve('/q')).toMatchObject({ kind: 'builtin', name: 'exit', args: '' }); + expect(resolve('/clear')).toMatchObject({ kind: 'builtin', name: 'new', args: '' }); + expect(resolve('/fork')).toMatchObject({ kind: 'builtin', name: 'fork', args: '' }); + expect(resolve('/title New title')).toMatchObject({ + kind: 'builtin', + name: 'title', + args: 'New title', + }); + expect(resolve('/add-dir list')).toMatchObject({ + kind: 'builtin', + name: 'add-dir', + args: 'list', + }); + expect(resolve('/init')).toMatchObject({ kind: 'builtin', name: 'init', args: '' }); + expect(resolve('/btw')).toMatchObject({ + kind: 'builtin', + name: 'btw', + args: '', + }); + expect(resolve('/btw what are you doing?')).toMatchObject({ + kind: 'builtin', + name: 'btw', + args: 'what are you doing?', + }); + expect(resolve('/experiments')).toMatchObject({ + kind: 'builtin', + name: 'experiments', + args: '', + }); + }); + + it('resolves /remote-control and /rc as built-ins', () => { + expect(resolve('/rc')).toMatchObject({ kind: 'builtin', name: 'remote-control' }); + expect(resolve('/remote-control')).toMatchObject({ kind: 'builtin', name: 'remote-control' }); + }); + + it('blocks idle-only built-ins while streaming', () => { + expect(resolve('/new', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'new', + reason: 'streaming', + }); + expect(resolve('/init', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'init', + reason: 'streaming', + }); + expect(resolve('/sessions', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'sessions', + reason: 'streaming', + }); + expect(resolve('/resume', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'resume', + reason: 'streaming', + }); + expect(resolve('/undo', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'undo', + reason: 'streaming', + }); + expect(resolve('/reload', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'reload', + reason: 'streaming', + }); + expect(resolve('/add-dir ../shared', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'add-dir', + reason: 'streaming', + }); + expect(resolve('/experiments', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'experiments', + reason: 'streaming', + }); + expect(resolve('/swarm on', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'swarm', + reason: 'streaming', + }); + expect(resolve('/swarm off', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'swarm', + reason: 'streaming', + }); + }); + + it('blocks model and session pickers while compacting', () => { + expect(resolve('/sessions', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'sessions', + reason: 'compacting', + }); + expect(resolve('/resume', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'resume', + reason: 'compacting', + }); + expect(resolve('/reload', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'reload', + reason: 'compacting', + }); + expect(resolve('/add-dir ../shared', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'add-dir', + reason: 'compacting', + }); + expect(resolve('/experiments', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'experiments', + reason: 'compacting', + }); + expect(resolve('/swarm on', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'swarm', + reason: 'compacting', + }); + expect(resolve('/swarm off', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'swarm', + reason: 'compacting', + }); + }); + + it('allows always-available built-ins while streaming', () => { + expect(resolve('/plan on', { isStreaming: true })).toMatchObject({ + kind: 'builtin', + name: 'plan', + args: 'on', + }); + expect(resolve('/mcp', { isStreaming: true })).toMatchObject({ + kind: 'builtin', + name: 'mcp', + args: '', + }); + expect(resolve('/mcp', { isCompacting: true })).toMatchObject({ + kind: 'builtin', + name: 'mcp', + args: '', + }); + expect(resolve('/reload-tui', { isStreaming: true })).toMatchObject({ + kind: 'builtin', + name: 'reload-tui', + args: '', + }); + expect(resolve('/reload-tui', { isCompacting: true })).toMatchObject({ + kind: 'builtin', + name: 'reload-tui', + args: '', + }); + expect(resolve('/btw side question', { isStreaming: true })).toMatchObject({ + kind: 'builtin', + name: 'btw', + args: 'side question', + }); + }); + + it('blocks plan clear while compacting because it is idle-only', () => { + expect(resolve('/plan clear', { isCompacting: true })).toEqual({ + kind: 'blocked', + commandName: 'plan', + reason: 'compacting', + }); + }); + + it('resolves skill commands and keeps them resolvable while busy (queued downstream)', () => { + const skillCommandMap = new Map([['skill:review', 'review']]); + + expect(resolve('/skill:review src/app.ts', { skillCommandMap })).toEqual({ + kind: 'skill', + commandName: 'skill:review', + skillName: 'review', + args: 'src/app.ts', + }); + expect(resolve('/skill:review src/app.ts', { skillCommandMap, isStreaming: true })).toEqual({ + kind: 'skill', + commandName: 'skill:review', + skillName: 'review', + args: 'src/app.ts', + }); + }); + + it('resolves unprefixed built-in skill commands and keeps them resolvable while busy', () => { + const skillCommandMap = new Map([['mcp-config', 'mcp-config']]); + + expect(resolve('/mcp-config', { skillCommandMap })).toEqual({ + kind: 'skill', + commandName: 'mcp-config', + skillName: 'mcp-config', + args: '', + }); + expect(resolve('/mcp-config', { skillCommandMap, isCompacting: true })).toEqual({ + kind: 'skill', + commandName: 'mcp-config', + skillName: 'mcp-config', + args: '', + }); + }); + + it('resolves unprefixed sub-skill commands with dotted names', () => { + const skillCommandMap = new Map([['outer.inner', 'outer.inner']]); + + expect(resolve('/outer.inner src/app.ts', { skillCommandMap })).toEqual({ + kind: 'skill', + commandName: 'outer.inner', + skillName: 'outer.inner', + args: 'src/app.ts', + }); + }); + + it('returns message for unknown slash input', () => { + expect(resolve('/does-not-exist arg')).toEqual({ + kind: 'message', + input: '/does-not-exist arg', + }); + }); + + it('resolves /swarm without an experimental flag', () => { + expect(resolve('/swarm Ship feature X')).toMatchObject({ + kind: 'builtin', + name: 'swarm', + args: 'Ship feature X', + }); + }); + + it('resolves /tower to the builtin command when the tower flag is enabled', () => { + setExperimentalFeatures([{ id: 'tower', enabled: true }]); + + expect(resolve('/tower Ship feature X')).toMatchObject({ + kind: 'builtin', + name: 'tower', + args: 'Ship feature X', + }); + }); + + it('does not resolve /tower as a builtin when the tower flag is disabled', () => { + expect(resolve('/tower Ship feature X')).toEqual({ + kind: 'message', + input: '/tower Ship feature X', + }); + }); +}); + +describe('goal command resolution', () => { + afterEach(() => { + setExperimentalFeatures([]); + }); + + it('resolves /goal to the builtin command without an experimental flag', () => { + expect(resolve('/goal Ship feature X')).toMatchObject({ + kind: 'builtin', + name: 'goal', + args: 'Ship feature X', + }); + }); + + it('blocks goal creation while streaming', () => { + expect(resolve('/goal Ship feature X', { isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'goal', + reason: 'streaming', + }); + }); + + it('does not block status/pause/cancel/bare goal while streaming', () => { + for (const sub of ['status', 'pause', 'cancel']) { + expect(resolve(`/goal ${sub}`, { isStreaming: true })).toMatchObject({ + kind: 'builtin', + name: 'goal', + }); + } + expect(resolve('/goal', { isStreaming: true })).toMatchObject({ + kind: 'builtin', + name: 'goal', + }); + }); +}); + +describe('slash command busy helpers', () => { + it('resolves skill command aliases with and without skill prefix', () => { + const map = new Map([ + ['skill:review', 'review'], + ['mcp-config', 'mcp-config'], + ]); + + expect(resolveSkillCommand(map, 'skill:review')).toBe('review'); + expect(resolveSkillCommand(map, 'review')).toBe('review'); + expect(resolveSkillCommand(map, 'mcp-config')).toBe('mcp-config'); + }); + + it('formats busy messages', () => { + expect(slashCommandBusyReason({ isStreaming: true, isCompacting: false })).toBe('streaming'); + expect(slashCommandBusyReason({ isStreaming: false, isCompacting: true })).toBe('compacting'); + expect(slashBusyMessage('new', 'streaming')).toContain('Cannot /new while streaming'); + expect(slashBusyMessage('new', 'compacting')).toContain('Cannot /new while compacting'); + }); + + it('resolves a namespaced plugin command to a plugin-command intent', () => { + const pluginCommandMap = new Map([['my-plugin:deploy', 'Deploy $ARGUMENTS']]); + expect(resolve('/my-plugin:deploy prod', { pluginCommandMap })).toEqual({ + kind: 'plugin-command', + commandName: 'deploy', + pluginId: 'my-plugin', + args: 'prod', + }); + }); + + it('resolves a nested plugin command whose name contains a slash', () => { + const pluginCommandMap = new Map([['my-plugin:frontend/component', 'body']]); + expect(resolve('/my-plugin:frontend/component spin', { pluginCommandMap })).toEqual({ + kind: 'plugin-command', + commandName: 'frontend/component', + pluginId: 'my-plugin', + args: 'spin', + }); + }); + + it('blocks a plugin command while streaming', () => { + const pluginCommandMap = new Map([['my-plugin:deploy', 'Deploy']]); + expect(resolve('/my-plugin:deploy', { pluginCommandMap, isStreaming: true })).toEqual({ + kind: 'blocked', + commandName: 'my-plugin:deploy', + reason: 'streaming', + }); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/secondary-model.test.ts b/apps/kimi-code/test/tui/commands/secondary-model.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9bce58d4c0fa343c72ce0e2a9e828344dafe9986 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/secondary-model.test.ts @@ -0,0 +1,234 @@ +/** + * Scenario: /secondary-model command behavior in the interactive TUI. + * Responsibilities: picker filtering, persistence of `[secondary_model] default_model` + * (keeping existing pool descriptions), and error paths. + * Wiring: real command and selector with the SDK/session boundaries stubbed by a small host rig. + * Run: pnpm -C apps/kimi-code exec vitest run test/tui/commands/secondary-model.test.ts + */ +import type { ModelAlias } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import type { SlashCommandHost } from '#/tui/commands'; +import { handleSecondaryModelCommand } from '#/tui/commands/config'; +import { TabbedModelSelectorComponent } from '#/tui/components/dialogs/tabbed-model-selector'; + +interface PickerOptions { + readonly models: Record; + readonly currentValue: string; + readonly selectedValue?: string; + readonly title?: string; + readonly thinkingControl?: boolean; + readonly onSelect: (selection: { alias: string }) => void; +} + +function model(name: string): ModelAlias { + return { + provider: 'test', + model: name, + maxContextSize: 200_000, + displayName: name, + } as unknown as ModelAlias; +} + +function makeHost(options?: { + readonly secondaryModel?: { defaultModel?: string; models?: Record }; +}) { + const appState = { + availableModels: { + k2: model('k2'), + cheap: model('cheap'), + // The v1 derived entry must never be selectable. + '__secondary__': model('cheap'), + // The pool's reserved symbolic choice must never be selectable either. + 'primary': model('primary'), + } as Record, + availableProviders: {}, + transcriptEntries: [], + }; + const host = { + state: { + appState, + transcriptEntries: [], + }, + authFlow: { + refreshOAuthProviderModels: vi.fn(async () => undefined), + }, + harness: { + getConfig: vi.fn(async () => ({ + providers: {}, + secondaryModel: options?.secondaryModel, + })), + setConfig: vi.fn(async () => ({})), + }, + setAppState: vi.fn((patch) => Object.assign(appState, patch)), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + showStatus: vi.fn(), + showError: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + } as unknown as SlashCommandHost & { + harness: { + getConfig: ReturnType; + setConfig: ReturnType; + }; + mountEditorReplacement: ReturnType; + showStatus: ReturnType; + showError: ReturnType; + showNotice: ReturnType; + }; + return { host }; +} + +function mountedPicker(host: { mountEditorReplacement: ReturnType }): PickerOptions { + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + const component = host.mountEditorReplacement.mock.calls[0]![0]; + expect(component).toBeInstanceOf(TabbedModelSelectorComponent); + return (component as unknown as { opts: PickerOptions }).opts; +} + +describe('handleSecondaryModelCommand', () => { + it('opens the picker filtered to user models, with the configured default as current', async () => { + const { host } = makeHost({ secondaryModel: { defaultModel: 'cheap' } }); + + await handleSecondaryModelCommand(host, ''); + + const opts = mountedPicker(host); + expect(Object.keys(opts.models)).toEqual(['k2', 'cheap']); + expect(opts.currentValue).toBe('cheap'); + expect(opts.title).toContain('secondary model'); + // Pool bindings carry no explicit thinking level — the picker hides the + // Thinking footer instead of offering a no-op choice. + expect(opts.thinkingControl).toBe(false); + }); + + it('persists only default_model when no pool exists (implicit single-entry pool)', async () => { + const { host } = makeHost(); + + await handleSecondaryModelCommand(host, ''); + mountedPicker(host).onSelect({ alias: 'k2' }); + + await vi.waitFor(() => { + expect(host.showStatus).toHaveBeenCalled(); + }); + expect(host.harness.setConfig).toHaveBeenCalledWith({ + secondaryModel: { defaultModel: 'k2' }, + }); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('adds the picked alias to an existing pool with an empty description', async () => { + const { host } = makeHost({ + secondaryModel: { + defaultModel: 'cheap', + models: { cheap: 'fast and cheap' }, + }, + }); + + await handleSecondaryModelCommand(host, ''); + mountedPicker(host).onSelect({ alias: 'k2' }); + + await vi.waitFor(() => { + expect(host.showStatus).toHaveBeenCalled(); + }); + expect(host.harness.setConfig).toHaveBeenCalledWith({ + secondaryModel: { + defaultModel: 'k2', + models: { cheap: 'fast and cheap', k2: '' }, + }, + }); + }); + + it('keeps existing pool descriptions and other pool entries on save', async () => { + const { host } = makeHost({ + secondaryModel: { + defaultModel: 'cheap', + models: { cheap: 'fast and cheap', k2: 'hard tasks' }, + }, + }); + + await handleSecondaryModelCommand(host, ''); + mountedPicker(host).onSelect({ alias: 'k2' }); + + await vi.waitFor(() => { + expect(host.showStatus).toHaveBeenCalled(); + }); + expect(host.harness.setConfig).toHaveBeenCalledWith({ + secondaryModel: { + defaultModel: 'k2', + models: { cheap: 'fast and cheap', k2: 'hard tasks' }, + }, + }); + }); + + it('pre-selects a valid alias argument instead of erroring', async () => { + const { host } = makeHost(); + + await handleSecondaryModelCommand(host, 'cheap'); + + const opts = mountedPicker(host); + expect(opts.selectedValue).toBe('cheap'); + }); + + it('rejects an unknown alias argument without opening the picker', async () => { + const { host } = makeHost(); + + await handleSecondaryModelCommand(host, 'nope'); + + expect(host.showError).toHaveBeenCalledWith('Unknown model alias: nope'); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('rejects the synthesized derived alias as an argument', async () => { + const { host } = makeHost(); + + await handleSecondaryModelCommand(host, '__secondary__'); + + expect(host.showError).toHaveBeenCalledWith('Unknown model alias: __secondary__'); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('rejects the reserved primary alias as an argument', async () => { + const { host } = makeHost(); + + await handleSecondaryModelCommand(host, 'primary'); + + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('reserved')); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('reports the reserved error for primary even when it is the only configured model', async () => { + const { host } = makeHost(); + host.state.appState.availableModels = { primary: model('primary') }; + + await handleSecondaryModelCommand(host, 'primary'); + + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('reserved')); + expect(host.showNotice).not.toHaveBeenCalled(); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('shows a notice when no models are configured', async () => { + const { host } = makeHost(); + host.state.appState.availableModels = {}; + + await handleSecondaryModelCommand(host, ''); + + expect(host.showNotice).toHaveBeenCalled(); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('reports a persistence failure without a status message', async () => { + const { host } = makeHost(); + host.harness.setConfig.mockRejectedValueOnce(new Error('disk full')); + + await handleSecondaryModelCommand(host, ''); + mountedPicker(host).onSelect({ alias: 'k2' }); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalled(); + }); + expect(host.showError.mock.calls[0]![0]).toContain('disk full'); + expect(host.showStatus).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/skills.test.ts b/apps/kimi-code/test/tui/commands/skills.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9cf46bd609e5243d3ecc8e98fa2ef3253d64f9c --- /dev/null +++ b/apps/kimi-code/test/tui/commands/skills.test.ts @@ -0,0 +1,105 @@ +import { buildSkillSlashCommands, isUserActivatableSkill } from '#/tui/commands/index'; +import type { SkillSummary } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it } from 'vitest'; + +function skill( + name: string, + type?: SkillSummary['type'], + extra: Partial = {}, +): SkillSummary { + return { + name, + type, + description: `${name} skill`, + ...extra, + } as SkillSummary; +} + +describe('skill slash commands', () => { + it('allows user-activatable skill types', () => { + expect(isUserActivatableSkill(skill('default'))).toBe(true); + expect(isUserActivatableSkill(skill('prompt', 'prompt'))).toBe(true); + expect(isUserActivatableSkill(skill('inline', 'inline'))).toBe(true); + expect(isUserActivatableSkill(skill('flow', 'flow'))).toBe(true); + }); + + it('filters non-user-activatable skill types', () => { + expect(isUserActivatableSkill(skill('agent', 'agent'))).toBe(false); + }); + + it('builds slash commands and command map entries with skill prefixes for non-built-in skills', () => { + const built = buildSkillSlashCommands([ + skill('review', 'prompt'), + skill('nested-review', 'prompt', { + description: 'Nested review skill', + path: '/skills/parent/nested-review/SKILL.md', + }), + skill('agent-only', 'agent'), + skill('commit', 'flow'), + ]); + + expect(built.commands.map((command) => command.name)).toEqual([ + 'skill:commit', + 'skill:nested-review', + 'skill:review', + ]); + expect(built.commands[0]).toMatchObject({ + name: 'skill:commit', + aliases: [], + description: 'commit skill', + }); + expect(built.commands[1]).toMatchObject({ + name: 'skill:nested-review', + aliases: [], + description: 'Nested review skill', + }); + expect([...built.commandMap.entries()]).toEqual([ + ['skill:commit', 'commit'], + ['skill:nested-review', 'nested-review'], + ['skill:review', 'review'], + ]); + }); + + it('sorts built-in skill slash commands before external skill commands', () => { + const built = buildSkillSlashCommands([ + skill('zeta', 'prompt', { source: 'user' }), + skill('alpha', 'prompt', { source: 'project' }), + skill('update-config', 'inline', { source: 'builtin' }), + skill('mcp-config', 'inline', { source: 'builtin' }), + ]); + + expect(built.commands.map((command) => command.name)).toEqual([ + 'mcp-config', + 'update-config', + 'skill:alpha', + 'skill:zeta', + ]); + expect([...built.commandMap.entries()]).toEqual([ + ['mcp-config', 'mcp-config'], + ['update-config', 'update-config'], + ['skill:alpha', 'alpha'], + ['skill:zeta', 'zeta'], + ]); + }); + + it('keeps disableModelInvocation skills slash-invocable', () => { + const built = buildSkillSlashCommands([ + skill('mcp-config', 'inline', { disableModelInvocation: true, source: 'builtin' }), + ]); + + expect(built.commands.map((command) => command.name)).toEqual(['mcp-config']); + expect(built.commandMap.get('mcp-config')).toBe('mcp-config'); + }); + + it('keeps sub-skills slash-invocable', () => { + const built = buildSkillSlashCommands([ + skill('outer.inner', 'prompt', { + isSubSkill: true, + source: 'project', + }), + ]); + + expect(built.commands.map((command) => command.name)).toEqual(['outer.inner']); + expect(built.commandMap.get('outer.inner')).toBe('outer.inner'); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/survey-preferences.test.ts b/apps/kimi-code/test/tui/commands/survey-preferences.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8b8073025bffd96daeda5ba93be56157642b444 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/survey-preferences.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { applySurveyPreferenceChoice } from '#/tui/commands/config'; +import { darkColors } from '#/tui/theme/colors'; + +const mocks = vi.hoisted(() => ({ + saveTuiConfig: vi.fn(), +})); + +vi.mock('../../../src/tui/config', async () => { + const actual = await vi.importActual( + '../../../src/tui/config.js', + ); + return { + ...actual, + saveTuiConfig: mocks.saveTuiConfig, + }; +}); + +function makeHost(disableFeedbackSurvey: boolean) { + return { + state: { + appState: { + theme: 'auto' as const, + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' as const }, + upgrade: { autoInstall: true }, + disableFeedbackSurvey, + }, + theme: { palette: darkColors }, + }, + setAppState: vi.fn(), + showStatus: vi.fn(), + }; +} + +describe('survey preference commands', () => { + it('saves the opt-out to tui.toml and mirrors it into appState', async () => { + mocks.saveTuiConfig.mockClear(); + const host = makeHost(false); + + await applySurveyPreferenceChoice(host, false); + + expect(mocks.saveTuiConfig).toHaveBeenCalledWith( + expect.objectContaining({ disableFeedbackSurvey: true }), + ); + expect(host.setAppState).toHaveBeenCalledWith({ disableFeedbackSurvey: true }); + expect(host.showStatus).toHaveBeenCalledWith('Feedback survey disabled.'); + }); + + it('re-enables the survey from an opt-out state', async () => { + mocks.saveTuiConfig.mockClear(); + const host = makeHost(true); + + await applySurveyPreferenceChoice(host, true); + + expect(mocks.saveTuiConfig).toHaveBeenCalledWith( + expect.objectContaining({ disableFeedbackSurvey: false }), + ); + expect(host.setAppState).toHaveBeenCalledWith({ disableFeedbackSurvey: false }); + expect(host.showStatus).toHaveBeenCalledWith('Feedback survey enabled.'); + }); + + it('does not rewrite the config when the value is unchanged', async () => { + mocks.saveTuiConfig.mockClear(); + const host = makeHost(false); + + await applySurveyPreferenceChoice(host, true); + + expect(mocks.saveTuiConfig).not.toHaveBeenCalled(); + expect(host.setAppState).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith('Feedback survey already enabled.'); + }); + + it('reports a save failure without touching appState', async () => { + mocks.saveTuiConfig.mockRejectedValueOnce(new Error('disk full')); + const host = makeHost(false); + + await applySurveyPreferenceChoice(host, false); + + expect(host.setAppState).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith( + 'Failed to save session rating setting: disk full', + 'error', + ); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/swarm.test.ts b/apps/kimi-code/test/tui/commands/swarm.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..49407b14523857b27dda0d1a94efcdb378b65158 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/swarm.test.ts @@ -0,0 +1,347 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { handleSwarmCommand } from '#/tui/commands/index'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import { currentTheme } from '#/tui/theme'; +import { PERMISSION_MODE_DESCRIPTIONS } from '#/tui/utils/permission-mode'; + +const ENTER = '\r'; +const ESCAPE = '\u001B'; +const DOWN = '\u001B[B'; + +function stripAnsi(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +interface TestComponent { + render(width: number): string[]; +} + +function makeHost( + overrides: { + model?: string; + hasSession?: boolean; + permissionMode?: 'manual' | 'auto' | 'yolo'; + swarmMode?: boolean; + } = {}, +) { + const session = { + setPermission: vi.fn(async () => {}), + setSwarmMode: vi.fn(async () => {}), + }; + const hasSession = overrides.hasSession ?? true; + const host = { + state: { + appState: { + model: overrides.model ?? 'kimi-model', + permissionMode: overrides.permissionMode ?? 'auto', + swarmMode: overrides.swarmMode ?? false, + }, + theme: currentTheme, + transcriptContainer: { addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: hasSession ? session : undefined, + requireSession: () => session, + setAppState: vi.fn((patch: Record) => Object.assign(host.state.appState, patch)), + showError: vi.fn(), + showNotice: vi.fn(), + showStatus: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + sendNormalUserInput: vi.fn(), + } as unknown as SlashCommandHost; + return { host, session }; +} + +interface TestPicker { + handleInput(data: string): void; + render(width: number): string[]; +} + +function mountedPicker(host: SlashCommandHost): TestPicker { + const mock = host.mountEditorReplacement as ReturnType; + return mock.mock.calls[0]?.[0] as TestPicker; +} + +function markerAddChild(host: SlashCommandHost): ReturnType { + return host.state.transcriptContainer.addChild as ReturnType; +} + +function expectSwarmMarker(host: SlashCommandHost, text: string): void { + const components = markerAddChild(host).mock.calls.map(([component]) => component as TestComponent); + const rendered = stripAnsi(components.at(-1)?.render(80).join('\n') ?? ''); + expect(rendered).toContain(text); +} + +describe('handleSwarmCommand', () => { + it('sends the swarm prompt as a normal prompt after enabling swarm mode', async () => { + const { host, session } = makeHost({ permissionMode: 'auto' }); + + await handleSwarmCommand(host, 'Ship feature X'); + + expect(session.setPermission).not.toHaveBeenCalled(); + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'task'); + expect(host.state.swarmModeEntry).toBe('task'); + expectSwarmMarker(host, 'Swarm activated'); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + + it('sends the swarm prompt without re-entering swarm mode when already on', async () => { + const { host, session } = makeHost({ permissionMode: 'auto', swarmMode: true }); + + await handleSwarmCommand(host, 'Ship feature X'); + + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(host.state.swarmModeEntry).toBeUndefined(); + expectSwarmMarker(host, 'Swarm activated'); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + + it('turns swarm mode on without sending a prompt', async () => { + const { host, session } = makeHost({ model: '' }); + + await handleSwarmCommand(host, 'on'); + + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'manual'); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: true }); + expect(host.state.swarmModeEntry).toBe('manual'); + expectSwarmMarker(host, 'Swarm activated'); + expect(host.showStatus).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('asks before turning swarm mode on in Manual mode', async () => { + const { host, session } = makeHost({ model: '', permissionMode: 'manual' }); + + await handleSwarmCommand(host, 'on'); + + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(session.setPermission).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + const text = stripAnsi(mountedPicker(host).render(80).join('\n')); + expect(text).toContain('Always Ask mode can block swarm work'); + mountedPicker(host).handleInput(ENTER); + + await vi.waitFor(() => { + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'manual'); + }); + expect(session.setPermission).toHaveBeenCalledWith('auto'); + expect(session.setSwarmMode).toHaveBeenCalledTimes(1); + expect(host.setAppState).toHaveBeenCalledWith({ permissionMode: 'auto' }); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: true }); + expect(host.state.swarmModeEntry).toBe('manual'); + expectSwarmMarker(host, 'Swarm activated'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('turns swarm mode on when called without args while swarm mode is off', async () => { + const { host, session } = makeHost({ model: '', swarmMode: false }); + + await handleSwarmCommand(host, ''); + + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'manual'); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: true }); + expect(host.state.swarmModeEntry).toBe('manual'); + expectSwarmMarker(host, 'Swarm activated'); + expect(host.showError).not.toHaveBeenCalled(); + expect(host.showStatus).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('does not call the session when swarm mode is already on', async () => { + const { host, session } = makeHost({ model: '', swarmMode: true }); + + await handleSwarmCommand(host, 'on'); + + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(host.setAppState).not.toHaveBeenCalledWith({ swarmMode: true }); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith('Swarm mode is already on.'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('turns swarm mode off without sending a prompt', async () => { + const { host, session } = makeHost({ model: '', swarmMode: true }); + + await handleSwarmCommand(host, 'off'); + + expect(session.setSwarmMode).toHaveBeenCalledWith(false, 'manual'); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: false }); + expect(host.state.swarmModeEntry).toBeUndefined(); + expectSwarmMarker(host, 'Swarm deactivated'); + expect(host.showStatus).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('turns swarm mode off when called without args while swarm mode is on', async () => { + const { host, session } = makeHost({ model: '', swarmMode: true }); + + await handleSwarmCommand(host, ''); + + expect(session.setSwarmMode).toHaveBeenCalledWith(false, 'manual'); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: false }); + expect(host.state.swarmModeEntry).toBeUndefined(); + expectSwarmMarker(host, 'Swarm deactivated'); + expect(host.showError).not.toHaveBeenCalled(); + expect(host.showStatus).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('does not call the session when swarm mode is already off', async () => { + const { host, session } = makeHost({ model: '', swarmMode: false }); + + await handleSwarmCommand(host, 'off'); + + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(host.setAppState).not.toHaveBeenCalledWith({ swarmMode: false }); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.showStatus).toHaveBeenCalledWith('Swarm mode is already off.'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('asks before starting a swarm task in Manual mode', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + + await handleSwarmCommand(host, 'Ship feature X'); + + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(session.setPermission).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + const text = stripAnsi(mountedPicker(host).render(80).join('\n')); + expect(text).toContain('Always Ask mode can block swarm work'); + expect(text).toContain('Switch to Ask When Needed and start'); + expect(text).not.toContain('Do not start'); + }); + + it('defaults to Auto when confirming a Manual-mode swarm start', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + + await handleSwarmCommand(host, 'Ship feature X'); + mountedPicker(host).handleInput(ENTER); + + await vi.waitFor(() => { + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + expect(session.setPermission).toHaveBeenCalledWith('auto'); + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'task'); + expect(session.setSwarmMode).toHaveBeenCalledTimes(1); + expect(host.setAppState).toHaveBeenCalledWith({ permissionMode: 'auto' }); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: true }); + expect(host.showNotice).toHaveBeenCalledWith('Permission mode: Never Ask'); + expect(host.showStatus).toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.auto, 'warning'); + expect(host.state.swarmModeEntry).toBe('task'); + expectSwarmMarker(host, 'Swarm activated'); + }); + + it('can start a Manual-mode swarm task without changing permission', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + + await handleSwarmCommand(host, 'Ship feature X'); + const picker = mountedPicker(host); + picker.handleInput(DOWN); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + await vi.waitFor(() => { + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + expect(session.setPermission).not.toHaveBeenCalled(); + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'task'); + expect(session.setSwarmMode).toHaveBeenCalledTimes(1); + expect(host.showNotice).not.toHaveBeenCalled(); + expect(host.showStatus).not.toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.auto, 'warning'); + expect(host.state.swarmModeEntry).toBe('task'); + expectSwarmMarker(host, 'Swarm activated'); + }); + + it('can start a Manual-mode swarm task after switching to YOLO', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + + await handleSwarmCommand(host, 'Ship feature X'); + const picker = mountedPicker(host); + picker.handleInput(DOWN); + picker.handleInput(ENTER); + + await vi.waitFor(() => { + expect(host.sendNormalUserInput).toHaveBeenCalledWith('Ship feature X'); + }); + expect(session.setPermission).toHaveBeenCalledWith('yolo'); + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'task'); + expect(session.setSwarmMode).toHaveBeenCalledTimes(1); + expect(host.setAppState).toHaveBeenCalledWith({ permissionMode: 'yolo' }); + expect(host.setAppState).toHaveBeenCalledWith({ swarmMode: true }); + expect(host.showNotice).toHaveBeenCalledWith('Permission mode: Ask When Needed'); + expect(host.showStatus).toHaveBeenCalledWith(PERMISSION_MODE_DESCRIPTIONS.yolo, 'warning'); + expect(host.state.swarmModeEntry).toBe('task'); + expectSwarmMarker(host, 'Swarm activated'); + }); + + it('returns the command to the input box when a Manual-mode swarm start is cancelled', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + + await handleSwarmCommand(host, 'Ship feature X'); + mountedPicker(host).handleInput(ESCAPE); + + expect(host.restoreInputText).toHaveBeenCalledWith('/swarm Ship feature X'); + expect(host.showStatus).toHaveBeenCalledWith('Swarm task not started.'); + expect(session.setPermission).not.toHaveBeenCalled(); + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('does not start when permission update fails', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + session.setPermission.mockRejectedValueOnce(new Error('denied')); + + await handleSwarmCommand(host, 'Ship feature X'); + mountedPicker(host).handleInput(ENTER); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('Failed to set permission mode'), + ); + }); + expect(session.setSwarmMode).not.toHaveBeenCalled(); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('does not send from Manual mode when enabling swarm mode fails after confirmation', async () => { + const { host, session } = makeHost({ permissionMode: 'manual' }); + session.setSwarmMode.mockRejectedValueOnce(new Error('denied')); + + await handleSwarmCommand(host, 'Ship feature X'); + mountedPicker(host).handleInput(ENTER); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('Failed to enable swarm mode'), + ); + }); + expect(session.setPermission).toHaveBeenCalledWith('auto'); + expect(session.setSwarmMode).toHaveBeenCalledWith(true, 'task'); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('does not send a prompt when enabling swarm mode fails', async () => { + const { host, session } = makeHost({ permissionMode: 'auto' }); + session.setSwarmMode.mockRejectedValueOnce(new Error('denied')); + + await handleSwarmCommand(host, 'Ship feature X'); + + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('Failed to enable swarm mode'), + ); + expect(markerAddChild(host)).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/tower.test.ts b/apps/kimi-code/test/tui/commands/tower.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3033bf314492a16cf966d48a1169451208e3f38a --- /dev/null +++ b/apps/kimi-code/test/tui/commands/tower.test.ts @@ -0,0 +1,211 @@ +import { describe, expect, it, vi } from 'vitest'; + +import type { Session } from '@moonshot-ai/kimi-code-sdk'; + +import { handleTowerCommand } from '#/tui/commands/index'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import { TOWER_STATUS_PROMPT, TOWER_TEARDOWN_PROMPT } from '#/tui/constant/kimi-tui'; + +function makeHost( + overrides: { + hasSession?: boolean; + towerMode?: boolean; + refuseTowerEntry?: boolean; + model?: string; + } = {}, +) { + let engineMode = overrides.towerMode ?? false; + const session = { + setTowerMode: vi.fn(async (enabled: boolean) => { + if (!(overrides.refuseTowerEntry && enabled)) engineMode = enabled; + }), + getStatus: vi.fn(async () => ({ towerMode: engineMode })), + }; + const hasSession = overrides.hasSession ?? true; + const host = { + state: { + appState: { + towerMode: overrides.towerMode ?? false, + model: overrides.model ?? 'test-model', + }, + }, + session: hasSession ? session : undefined, + ensureSession: vi.fn(async () => { + host.session = session as unknown as Session; + return session as unknown as Session; + }), + requireSession: () => { + if (host.session === undefined) throw new Error('No active session'); + return host.session; + }, + setAppState: vi.fn((patch: Record) => Object.assign(host.state.appState, patch)), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + sendNormalUserInput: vi.fn(), + } as unknown as SlashCommandHost; + return { host, session }; +} + +describe('handleTowerCommand', () => { + it('reports tower status when called without args, without touching the mode', async () => { + const { host, session } = makeHost({ towerMode: false }); + + await handleTowerCommand(host, ''); + + expect(host.sendNormalUserInput).toHaveBeenCalledWith(TOWER_STATUS_PROMPT); + expect(session.setTowerMode).not.toHaveBeenCalled(); + expect(host.ensureSession).not.toHaveBeenCalled(); + }); + + it('reports tower status for the status subcommand, without touching the mode', async () => { + const { host, session } = makeHost({ towerMode: true }); + + await handleTowerCommand(host, 'status'); + + expect(host.sendNormalUserInput).toHaveBeenCalledWith(TOWER_STATUS_PROMPT); + expect(session.setTowerMode).not.toHaveBeenCalled(); + }); + + it('sends the teardown instruction for the teardown subcommand, without touching the mode', async () => { + const { host, session } = makeHost({ towerMode: true }); + + await handleTowerCommand(host, 'teardown'); + + expect(host.sendNormalUserInput).toHaveBeenCalledWith(TOWER_TEARDOWN_PROMPT); + expect(session.setTowerMode).not.toHaveBeenCalled(); + }); + + it('turns tower mode on with an explicit on subcommand', async () => { + const { host, session } = makeHost({ towerMode: false }); + + await handleTowerCommand(host, 'on'); + + expect(session.setTowerMode).toHaveBeenCalledWith(true, undefined); + expect(host.setAppState).toHaveBeenCalledWith({ towerMode: true }); + expect(host.showNotice).toHaveBeenCalledWith('Tower mode: ON'); + expect(host.showError).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('turns tower mode off with an explicit off subcommand', async () => { + const { host, session } = makeHost({ towerMode: true }); + + await handleTowerCommand(host, 'off'); + + expect(session.setTowerMode).toHaveBeenCalledWith(false, undefined); + expect(host.setAppState).toHaveBeenCalledWith({ towerMode: false }); + expect(host.showNotice).toHaveBeenCalledWith('Tower mode: OFF'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('reasserts the mode idempotently when tower mode is already on', async () => { + const { host, session } = makeHost({ towerMode: true }); + + await handleTowerCommand(host, 'on'); + + expect(session.setTowerMode).toHaveBeenCalledWith(true, undefined); + expect(host.showStatus).toHaveBeenCalledWith('Tower mode is already on.'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('reasserts the mode idempotently when tower mode is already off', async () => { + const { host, session } = makeHost({ towerMode: false }); + + await handleTowerCommand(host, 'off'); + + expect(session.setTowerMode).toHaveBeenCalledWith(false, undefined); + expect(host.showStatus).toHaveBeenCalledWith('Tower mode is already off.'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('turns tower mode on with a base branch', async () => { + const { host, session } = makeHost({ towerMode: false }); + + await handleTowerCommand(host, 'develop'); + + expect(session.setTowerMode).toHaveBeenCalledWith(true, 'develop'); + expect(host.setAppState).toHaveBeenCalledWith({ towerMode: true }); + expect(host.showNotice).toHaveBeenCalledWith('Tower mode: ON (base: develop)'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('updates the base when tower mode is already on', async () => { + const { host, session } = makeHost({ towerMode: true }); + + await handleTowerCommand(host, 'develop'); + + expect(session.setTowerMode).toHaveBeenCalledWith(true, 'develop'); + expect(host.showNotice).toHaveBeenCalledWith('Tower base: develop'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('does not show the base notice when enabling with a base fails', async () => { + const { host, session } = makeHost({ towerMode: false }); + session.setTowerMode.mockRejectedValueOnce(new Error('not a local branch')); + + await handleTowerCommand(host, 'develop'); + + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('Failed to enable tower mode'), + ); + expect(host.showNotice).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('reports a failure when enabling tower mode fails', async () => { + const { host, session } = makeHost({ towerMode: false }); + session.setTowerMode.mockRejectedValueOnce(new Error('denied')); + + await handleTowerCommand(host, 'on'); + + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('Failed to enable tower mode'), + ); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('reports a failure when disabling tower mode fails', async () => { + const { host, session } = makeHost({ towerMode: true }); + session.setTowerMode.mockRejectedValueOnce(new Error('denied')); + + await handleTowerCommand(host, 'off'); + + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('Failed to disable tower mode'), + ); + expect(host.setAppState).not.toHaveBeenCalledWith({ towerMode: false }); + }); + + it('does not show ON when the engine refuses entry', async () => { + const { host } = makeHost({ towerMode: false, refuseTowerEntry: true }); + + await handleTowerCommand(host, 'on'); + + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('could not be enabled')); + expect(host.setAppState).toHaveBeenCalledWith({ towerMode: false }); + expect(host.showNotice).not.toHaveBeenCalledWith('Tower mode: ON'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('lazy-creates the session on the v2 engine when none exists', async () => { + const { host, session } = makeHost({ hasSession: false }); + + await handleTowerCommand(host, 'on'); + + expect(host.ensureSession).toHaveBeenCalled(); + expect(session.setTowerMode).toHaveBeenCalledWith(true, undefined); + expect(host.showNotice).toHaveBeenCalledWith('Tower mode: ON'); + expect(host.showError).not.toHaveBeenCalled(); + }); + + it('returns quietly when lazy session creation fails', async () => { + const { host, session } = makeHost({ hasSession: false }); + host.ensureSession = vi.fn(async () => undefined); + + await handleTowerCommand(host, 'on'); + + expect(session.setTowerMode).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/undo.test.ts b/apps/kimi-code/test/tui/commands/undo.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff950e2eaf0032a5feb3581d5dfc7eff2e0112ba --- /dev/null +++ b/apps/kimi-code/test/tui/commands/undo.test.ts @@ -0,0 +1,162 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { handleUndoCommand } from '#/tui/commands/undo'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import type { TranscriptEntry } from '#/tui/types'; + +function entry(partial: Partial & Pick): TranscriptEntry { + return { + id: `t-${Math.random().toString(36).slice(2, 10)}`, + turnId: undefined, + renderMode: 'plain', + ...partial, + }; +} + +function hostWith(entries: TranscriptEntry[]): SlashCommandHost { + return { + session: { undoHistory: vi.fn(async () => {}) }, + state: { + transcriptEntries: entries, + transcriptContainer: { children: [], addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + appState: { streamingPhase: 'idle' }, + }, + showError: vi.fn(), + } as unknown as SlashCommandHost; +} + +describe('/undo with bundled prompts', () => { + it('removes the bundle cards with their prompt, keeping a standalone skill card before them', async () => { + const entries: TranscriptEntry[] = [ + entry({ kind: 'user', content: 'earlier question' }), + entry({ + kind: 'skill_activation', + content: 'Activated skill: review', + skillTrigger: 'user-slash', + }), + entry({ kind: 'user', content: 'prompt one' }), + entry({ kind: 'assistant', content: 'answer one' }), + entry({ + kind: 'skill_activation', + content: 'Activated skill: security', + skillTrigger: 'user-slash', + bundledWithPrompt: true, + }), + entry({ kind: 'user', content: 'prompt two' }), + entry({ kind: 'assistant', content: 'answer two' }), + ]; + const host = hostWith(entries); + + await handleUndoCommand(host, '1'); + + expect(host.session?.undoHistory).toHaveBeenCalledWith(1); + expect(entries.map((item) => item.content)).toEqual([ + 'earlier question', + 'Activated skill: review', + 'prompt one', + 'answer one', + ]); + }); + + it('removes bundle cards around an interleaved hook result and keeps the hook result', async () => { + const entries: TranscriptEntry[] = [ + entry({ + kind: 'skill_activation', + content: 'Activated skill: review', + skillTrigger: 'user-slash', + bundledWithPrompt: true, + }), + entry({ kind: 'assistant', content: 'hook note', hookResult: true }), + entry({ kind: 'user', content: 'bundled prompt' }), + entry({ kind: 'assistant', content: 'bundled answer' }), + ]; + const host = hostWith(entries); + + await handleUndoCommand(host, '1'); + + expect(host.session?.undoHistory).toHaveBeenCalledWith(1); + expect(entries.map((item) => item.content)).toEqual(['hook note']); + }); + + it('does not count bundle cards as undo anchors of their own', async () => { + const entries: TranscriptEntry[] = [ + entry({ kind: 'user', content: 'prompt one' }), + entry({ kind: 'assistant', content: 'answer one' }), + entry({ + kind: 'skill_activation', + content: 'Activated skill: review', + skillTrigger: 'user-slash', + bundledWithPrompt: true, + }), + entry({ kind: 'user', content: 'prompt two' }), + entry({ kind: 'assistant', content: 'answer two' }), + ]; + const host = hostWith(entries); + + await handleUndoCommand(host, '2'); + + expect(host.session?.undoHistory).toHaveBeenCalledWith(2); + expect(entries).toHaveLength(0); + }); +}); + +describe('/undo todo panel refresh', () => { + function hostWithTodos( + entries: TranscriptEntry[], + session: Record, + ): { host: SlashCommandHost; setTodoList: ReturnType } { + const host = hostWith(entries); + const setTodoList = vi.fn(); + (host as { streamingUI?: unknown }).streamingUI = { setTodoList }; + (host as { session?: unknown }).session = session; + return { host, setTodoList }; + } + + it('re-pulls the engine todo state after a successful undo', async () => { + const entries: TranscriptEntry[] = [ + entry({ kind: 'user', content: 'question' }), + entry({ kind: 'assistant', content: 'answer' }), + ]; + const { host, setTodoList } = hostWithTodos(entries, { + undoHistory: vi.fn(async () => {}), + getTodos: vi.fn(async () => [{ title: 'kept', status: 'pending' }]), + }); + + await handleUndoCommand(host, '1'); + + expect(setTodoList).toHaveBeenCalledWith([{ title: 'kept', status: 'pending' }]); + }); + + it('keeps the panel as-is when the engine has no todo read surface', async () => { + const entries: TranscriptEntry[] = [ + entry({ kind: 'user', content: 'question' }), + entry({ kind: 'assistant', content: 'answer' }), + ]; + const { host, setTodoList } = hostWithTodos(entries, { + undoHistory: vi.fn(async () => {}), + getTodos: vi.fn(async () => { + throw new Error('getTodos is only available on the agent-core-v2 engine.'); + }), + }); + + await handleUndoCommand(host, '1'); + + expect(setTodoList).not.toHaveBeenCalled(); + }); + + it('hides the panel when the restored todos are all done', async () => { + const entries: TranscriptEntry[] = [ + entry({ kind: 'user', content: 'question' }), + entry({ kind: 'assistant', content: 'answer' }), + ]; + const { host, setTodoList } = hostWithTodos(entries, { + undoHistory: vi.fn(async () => {}), + getTodos: vi.fn(async () => [{ title: 'finished', status: 'done' }]), + }); + + await handleUndoCommand(host, '1'); + + expect(setTodoList).toHaveBeenCalledWith([]); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/update-preferences.test.ts b/apps/kimi-code/test/tui/commands/update-preferences.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..23e6a24fcb53e483eeba5026e5313008a23e88a6 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/update-preferences.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { applyUpdatePreferenceChoice } from '#/tui/commands/config'; +import { darkColors } from '#/tui/theme/colors'; + +const mocks = vi.hoisted(() => ({ + saveTuiConfig: vi.fn(), +})); + +vi.mock('../../../src/tui/config', async () => { + const actual = await vi.importActual( + '../../../src/tui/config.js', + ); + return { + ...actual, + saveTuiConfig: mocks.saveTuiConfig, + }; +}); + +describe('update preference commands', () => { + it('saves automatic update preference changes to tui.toml', async () => { + const setAppState = vi.fn(); + const showStatus = vi.fn(); + const track = vi.fn(); + const host = { + state: { + appState: { + theme: 'auto' as const, + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' as const }, + upgrade: { autoInstall: true }, + }, + theme: { palette: darkColors }, + }, + setAppState, + showStatus, + track, + }; + + await applyUpdatePreferenceChoice(host, false); + + expect(mocks.saveTuiConfig).toHaveBeenCalledWith({ + theme: 'auto', + editorCommand: null, + disablePasteBurst: false, + renderLatex: true, + cacheExpiryHint: true, + disableFeedbackSurvey: false, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: false }, + statusLine: { items: null, command: null }, + }); + expect(setAppState).toHaveBeenCalledWith({ upgrade: { autoInstall: false } }); + expect(track).toHaveBeenCalledWith('upgrade_preference_changed', { auto_install: false }); + expect(showStatus).toHaveBeenCalledWith('Automatic updates disabled.'); + }); + + it('preserves a render_latex opt-out when saving an unrelated preference', async () => { + mocks.saveTuiConfig.mockClear(); + const host = { + state: { + appState: { + theme: 'auto' as const, + editorCommand: null, + renderLatex: false, + notifications: { enabled: true, condition: 'unfocused' as const }, + upgrade: { autoInstall: true }, + }, + theme: { palette: darkColors }, + }, + setAppState: vi.fn(), + showStatus: vi.fn(), + track: vi.fn(), + }; + + await applyUpdatePreferenceChoice(host, false); + + expect(mocks.saveTuiConfig).toHaveBeenCalledWith( + expect.objectContaining({ renderLatex: false }), + ); + }); +}); diff --git a/apps/kimi-code/test/tui/commands/web.test.ts b/apps/kimi-code/test/tui/commands/web.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d31e10ca416c87178e89c23190819d4fb994dee8 --- /dev/null +++ b/apps/kimi-code/test/tui/commands/web.test.ts @@ -0,0 +1,350 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { setCapabilities } from '@moonshot-ai/pi-tui'; + +import { findBuiltInSlashCommand, resolveSlashCommandAvailability } from '#/tui/commands/index'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import { + handleRemoteControlCommand, + handleWebCommand, + webSessionUrl, +} from '#/tui/commands/web'; +import { renderTerminalQr } from '#/utils/remote-control-qr'; + +const mocks = vi.hoisted(() => ({ + startServerForeground: vi.fn(), + startRemoteControl: vi.fn(), + tryResolveServerToken: vi.fn(), + getDataDir: vi.fn(() => '/tmp/kimi-home'), + openUrl: vi.fn(), +})); + +vi.mock('#/cli/sub/web/remote-control', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, startRemoteControl: mocks.startRemoteControl }; +}); + +vi.mock('#/cli/sub/web/run', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, startServerForeground: mocks.startServerForeground }; +}); + +vi.mock('#/cli/sub/web/shared', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + tryResolveServerToken: mocks.tryResolveServerToken, + }; +}); + +vi.mock('#/utils/open-url', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, openUrl: mocks.openUrl }; +}); + +vi.mock('#/utils/paths', async (importOriginal) => { + const actual = await importOriginal(); + return { ...actual, getDataDir: mocks.getDataDir }; +}); + +const indentedQr = (url: string): string => + renderTerminalQr(url).trimEnd().replaceAll(/^/gm, ' '); + +function makeHost() { + const host = { + session: { id: 'ses-1' }, + showStatus: vi.fn(), + showError: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + setExitOpenUrl: vi.fn(), + setExitForegroundTask: vi.fn(), + stop: vi.fn(async () => {}), + waitForLazyCreation: vi.fn(async () => {}), + } as unknown as SlashCommandHost & { + showStatus: ReturnType; + showError: ReturnType; + mountEditorReplacement: ReturnType; + restoreEditor: ReturnType; + setExitOpenUrl: ReturnType; + setExitForegroundTask: ReturnType; + stop: ReturnType; + waitForLazyCreation: ReturnType; + }; + return host; +} + +describe('web slash command', () => { + it('is registered as an always-available built-in', () => { + const command = findBuiltInSlashCommand('web'); + expect(command).toBeDefined(); + expect(resolveSlashCommandAvailability(command!, '')).toBe('always'); + }); + + it('registers /remote-control and /rc as the same always-available built-in', () => { + const command = findBuiltInSlashCommand('remote-control'); + expect(command).toBeDefined(); + expect(findBuiltInSlashCommand('rc')).toBe(command); + expect(resolveSlashCommandAvailability(command!, '')).toBe('always'); + }); +}); + +describe('handleWebCommand', () => { + beforeEach(() => { + vi.clearAllMocks(); + mocks.getDataDir.mockReturnValue('/tmp/kimi-home'); + }); + + it('shows an error and does nothing when there is no active session', async () => { + const host = makeHost(); + host.session = undefined; + + await handleWebCommand(host); + + expect(host.showError).toHaveBeenCalledOnce(); + expect(host.setExitForegroundTask).not.toHaveBeenCalled(); + expect(host.stop).not.toHaveBeenCalled(); + }); + + it('registers a foreground takeover and stops the TUI without opening a URL yet', async () => { + const host = makeHost(); + + await handleWebCommand(host); + + expect(host.setExitForegroundTask).toHaveBeenCalledOnce(); + expect(host.stop).toHaveBeenCalledOnce(); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + expect(mocks.openUrl).not.toHaveBeenCalled(); + }); + + it('starts the new server on takeover, printing the banner and opening the deep link', async () => { + mocks.tryResolveServerToken.mockReturnValue('tok-1'); + const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + mocks.startServerForeground.mockImplementation( + async (_options: unknown, hooks: { onReady?: (origin: string) => void }) => { + hooks.onReady?.('http://127.0.0.1:58627'); + }, + ); + const host = makeHost(); + + await handleWebCommand(host); + const task = host.setExitForegroundTask.mock.calls[0]![0] as ( + exitCode: number, + ) => Promise; + await task(0); + + expect(mocks.startServerForeground).toHaveBeenCalledOnce(); + expect(mocks.openUrl).toHaveBeenCalledWith( + 'http://127.0.0.1:58627/sessions/ses-1#token=tok-1', + ); + const written = writeSpy.mock.calls.map((call) => String(call[0])).join(''); + expect(written).toContain('Kimi server ready'); + expect(written).toContain('Ctrl+C'); + expect(written).toContain('/sessions/ses-1'); + writeSpy.mockRestore(); + }); +}); + +describe('handleRemoteControlCommand', () => { + it('stays in the TUI with a readable error when another instance holds Remote Control', async () => { + vi.clearAllMocks(); + const { mkdtempSync, mkdirSync, rmSync, writeFileSync } = await import('node:fs'); + const { tmpdir } = await import('node:os'); + const { join } = await import('node:path'); + const tempRoot = mkdtempSync(join(tmpdir(), 'kimi-rc-lock-')); + const dataDir = join(tempRoot, 'home'); + mkdirSync(join(dataDir, 'server'), { recursive: true }); + writeFileSync( + join(dataDir, 'server', 'rc.json'), + JSON.stringify({ + pid: process.pid, + nonce: 'holder', + local_origin: 'http://127.0.0.1:58627', + device_id: 'device-1', + url: 'https://code-rc.kimi.com/devices/device-1/?rc=1&from=kimi_code_cli', + started_at: Date.now(), + }), + ); + mocks.getDataDir.mockReturnValue(dataDir); + const host = makeHost(); + + try { + await handleRemoteControlCommand(host); + + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('already running')); + expect(host.showError).toHaveBeenCalledWith( + expect.stringContaining('/devices/device-1/'), + ); + expect(host.setExitForegroundTask).not.toHaveBeenCalled(); + expect(host.stop).not.toHaveBeenCalled(); + expect(mocks.startServerForeground).not.toHaveBeenCalled(); + } finally { + rmSync(tempRoot, { recursive: true, force: true }); + } + }); + + it('starts the tunnel and saves a token-free session QR code', async () => { + vi.clearAllMocks(); + setCapabilities({ images: null, trueColor: true, hyperlinks: false }); + const { mkdtempSync, readFileSync, rmSync } = await import('node:fs'); + const { tmpdir } = await import('node:os'); + const { isAbsolute, join } = await import('node:path'); + const QRCode = await import('qrcode'); + const tempRoot = mkdtempSync(join(tmpdir(), 'kimi-rc-qrcode-')); + const dataDir = join(tempRoot, 'custom-home'); + const entryUrl = + 'https://code-rc.kimi.com/devices/device-1/?rc=1&from=kimi_code_cli'; + const sessionUrl = + 'https://code-rc.kimi.com/devices/device-1/sessions/ses-1?rc=1&from=kimi_code_cli'; + const pngPath = join(dataDir, 'rc-qrcode.png'); + mocks.getDataDir.mockReturnValue(dataDir); + mocks.tryResolveServerToken.mockReturnValue('local-server-token'); + const close = vi.fn(async () => {}); + mocks.startRemoteControl.mockResolvedValue({ + deviceId: 'device-1', + deviceName: 'example-device', + url: entryUrl, + close, + }); + mocks.startServerForeground.mockImplementation( + async ( + _options: unknown, + hooks: { + onReady?: (origin: string) => void | Promise; + onShutdown?: (reason: string) => void | Promise; + }, + ) => { + await hooks.onReady?.('http://127.0.0.1:58627'); + await hooks.onShutdown?.('SIGINT'); + }, + ); + const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + const host = makeHost(); + + try { + await handleRemoteControlCommand(host); + const task = host.setExitForegroundTask.mock.calls[0]![0] as () => Promise; + await task(); + + expect(mocks.startRemoteControl).toHaveBeenCalledWith( + expect.objectContaining({ + homeDir: dataDir, + localOrigin: 'http://127.0.0.1:58627', + localServerToken: 'local-server-token', + }), + ); + expect(mocks.openUrl).toHaveBeenCalledWith(sessionUrl); + const written = writeSpy.mock.calls.map((call) => String(call[0])).join(''); + expect(written).toContain('Kimi Remote Control ready'); + expect(written).toContain(indentedQr(sessionUrl)); + expect(written).not.toContain(indentedQr(entryUrl)); + expect(isAbsolute(pngPath)).toBe(true); + expect(written).toContain(`QR code PNG: ${pngPath}`); + const png = readFileSync(pngPath); + expect(png.subarray(0, 8)).toEqual(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])); + expect(png).toEqual(await QRCode.toBuffer(sessionUrl)); + expect(written).toContain( + 'Local UI: http://127.0.0.1:58627/#token=local-server-token', + ); + expect(written).not.toContain(`${entryUrl}#token=`); + expect(written).not.toContain(`${sessionUrl}#token=`); + expect(close).toHaveBeenCalledOnce(); + } finally { + writeSpy.mockRestore(); + rmSync(tempRoot, { recursive: true, force: true }); + } + }); + + it('opens the device entry URL without a session instead of creating one', async () => { + vi.clearAllMocks(); + setCapabilities({ images: null, trueColor: true, hyperlinks: false }); + const { mkdtempSync, readFileSync, rmSync } = await import('node:fs'); + const { tmpdir } = await import('node:os'); + const { join } = await import('node:path'); + const QRCode = await import('qrcode'); + const tempRoot = mkdtempSync(join(tmpdir(), 'kimi-rc-entry-')); + const dataDir = join(tempRoot, 'custom-home'); + const entryUrl = + 'https://code-rc.kimi.com/devices/device-1/?rc=1&from=kimi_code_cli'; + mocks.getDataDir.mockReturnValue(dataDir); + mocks.tryResolveServerToken.mockReturnValue('local-server-token'); + const close = vi.fn(async () => {}); + mocks.startRemoteControl.mockResolvedValue({ + deviceId: 'device-1', + deviceName: 'example-device', + url: entryUrl, + close, + }); + mocks.startServerForeground.mockImplementation( + async ( + _options: unknown, + hooks: { + onReady?: (origin: string) => void | Promise; + onShutdown?: (reason: string) => void | Promise; + }, + ) => { + await hooks.onReady?.('http://127.0.0.1:58627'); + await hooks.onShutdown?.('SIGINT'); + }, + ); + const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true); + const host = makeHost(); + host.session = undefined; + + try { + await handleRemoteControlCommand(host); + + expect(host.waitForLazyCreation).toHaveBeenCalledOnce(); + expect(host.showError).not.toHaveBeenCalled(); + expect(host.setExitForegroundTask).toHaveBeenCalledOnce(); + expect(host.stop).toHaveBeenCalledOnce(); + + const task = host.setExitForegroundTask.mock.calls[0]![0] as () => Promise; + await task(); + + expect(mocks.openUrl).toHaveBeenCalledWith(entryUrl); + const written = writeSpy.mock.calls.map((call) => String(call[0])).join(''); + expect(written).toContain(indentedQr(entryUrl)); + expect(written).not.toContain('/sessions/'); + expect(readFileSync(join(dataDir, 'rc-qrcode.png'))).toEqual( + await QRCode.toBuffer(entryUrl), + ); + expect(close).toHaveBeenCalledOnce(); + } finally { + writeSpy.mockRestore(); + rmSync(tempRoot, { recursive: true, force: true }); + } + }); +}); + +describe('webSessionUrl', () => { + it('deep-links to the session under the origin', () => { + expect(webSessionUrl('http://127.0.0.1:58627', 'abc123')).toBe( + 'http://127.0.0.1:58627/sessions/abc123', + ); + }); + + it('strips a trailing slash from the origin', () => { + expect(webSessionUrl('http://127.0.0.1:58627/', 'abc123')).toBe( + 'http://127.0.0.1:58627/sessions/abc123', + ); + }); + + it('encodes session ids so the web UI can decode them', () => { + expect(webSessionUrl('http://127.0.0.1:58627', 'a/b c')).toBe( + 'http://127.0.0.1:58627/sessions/a%2Fb%20c', + ); + }); + + it('carries the bearer token in the fragment so the browser authenticates on load', () => { + expect(webSessionUrl('http://127.0.0.1:58627', 'abc123', 'tok-1')).toBe( + 'http://127.0.0.1:58627/sessions/abc123#token=tok-1', + ); + }); + + it('omits the fragment when no token is available', () => { + expect(webSessionUrl('http://127.0.0.1:58627', 'abc123', undefined)).toBe( + 'http://127.0.0.1:58627/sessions/abc123', + ); + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/banner.test.ts b/apps/kimi-code/test/tui/components/chrome/banner.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d2d5034a2a2561a4159ed65a7c76e8104134559 --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/banner.test.ts @@ -0,0 +1,242 @@ +import chalk from 'chalk'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { visibleWidth } from '@moonshot-ai/pi-tui'; + +import { BannerComponent } from '#/tui/components/chrome/banner'; +import { currentTheme } from '#/tui/theme'; +import type { BannerState } from '#/tui/types'; + +function makeBannerState(overrides: Partial = {}): BannerState { + return { + key: 'component-banner', + tag: null, + mainText: '', + subText: null, + display: 'always', + ...overrides, + }; +} + +const banner: BannerState = makeBannerState({ + tag: "What's new:", + mainText: 'This is the main banner message for testing purposes.', + subText: 'This is a short subtext line.', +}); + +describe('BannerComponent', () => { + const previousChalkLevel = chalk.level; + + beforeEach(() => { + chalk.level = 3; + }); + + afterEach(() => { + chalk.level = previousChalkLevel; + }); + + it('renders star tag, main text, and subtext', () => { + const lines = new BannerComponent(banner).render(80); + expect(lines.length).toBe(3); + expect(lines[0]).toContain('✦'); + expect(lines[0]).toContain("What's new:"); + expect(lines[0]).toContain('This is the main banner message'); + expect(lines[1]).toContain('This is a short subtext'); + expect(lines[2]).toBe(''); + }); + + it('does not add an extra colon to the tag', () => { + const lines = new BannerComponent(banner).render(80); + expect(lines[0]).not.toContain("What's new::"); + }); + + it('renders without a tag when tag is empty', () => { + const lines = new BannerComponent(makeBannerState({ mainText: 'Hello' })).render(80); + expect(lines.length).toBe(2); + expect(lines[0]).not.toContain('✦'); + expect(lines[0]).toContain('Hello'); + expect(lines[1]).toBe(''); + }); + + it('wraps long main text to fit available width', () => { + const width = 30; + const lines = new BannerComponent(banner).render(width); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + expect(lines.some((line) => line.includes('…'))).toBe(false); + const mainContentLines = lines.filter((line) => + /main|banner|message|testing|purposes/.test(line), + ); + expect(mainContentLines.length).toBeGreaterThan(1); + }); + + it('wraps long subtext to fit available width', () => { + const width = 30; + const state = makeBannerState({ + mainText: 'Short', + subText: 'Short subtext line one plus subtext line two for wrapping tests.', + }); + const lines = new BannerComponent(state).render(width); + expect(lines[0]).toContain('Short'); + const subContentLines = lines.filter((line) => + /Short subtext|line one|plus|subtext|line two|for|wrapping|tests/.test(line), + ); + expect(subContentLines.length).toBeGreaterThan(1); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + }); + + it('keeps every line within terminal width on very narrow terminals', () => { + for (const width of [0, 1, 2, 3, 5, 10]) { + const lines = new BannerComponent(banner).render(width); + expect(lines.length).toBeGreaterThan(0); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(Math.max(0, width)); + } + } + }); + + it('shows tag only on the first wrapped line', () => { + const width = 40; + const state = makeBannerState({ + tag: 'New:', + mainText: 'This is a very long main text line that should wrap automatically.', + }); + const lines = new BannerComponent(state).render(width); + const mainRows = lines.slice(0, -1); + let tagCount = 0; + for (const line of mainRows) { + if (line.includes('✦ New:')) tagCount += 1; + } + expect(tagCount).toBe(1); + expect(mainRows.length).toBeGreaterThan(1); + const firstIndex = lines.findIndex((line) => line.includes('✦ New:')); + expect(firstIndex).toBe(0); + }); + + it('continues main text under the tag column and keeps subtext aligned with the tag text', () => { + const width = 80; + const lines = new BannerComponent(banner).render(width); + const firstLine = lines[0]!; + const mainStartIndex = firstLine.indexOf('This is the main banner message'); + const tagPrefixVisibleWidth = visibleWidth(firstLine.slice(0, mainStartIndex)); + const subLine = lines[1]!; + const subStartIndex = subLine.indexOf('This is a short subtext'); + const subIndentVisibleWidth = visibleWidth(subLine.slice(0, subStartIndex)); + // The subtext starts two columns after the left edge ("✦ "), which aligns + // with the tag text itself rather than the main-text column. + expect(subIndentVisibleWidth).toBe(visibleWidth('✦ ')); + expect(tagPrefixVisibleWidth).toBeGreaterThan(visibleWidth('✦ ')); + }); + + it('drops the tag when it does not fit', () => { + const width = 5; + const lines = new BannerComponent(banner).render(width); + expect(lines[0]).not.toContain('✦'); + expect(lines[0]).not.toContain("What's new"); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + }); + + it('still renders the tag when it fits', () => { + const width = 40; + const lines = new BannerComponent(banner).render(width); + expect(lines[0]).toContain('✦'); + expect(lines[0]).toContain("What's new"); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + }); + + it('does not render subtext when empty', () => { + const lines = new BannerComponent(makeBannerState({ tag: 'Tip', mainText: 'Use /help' })).render(80); + expect(lines.length).toBe(2); + expect(lines[0]).toContain('Use /help'); + expect(lines[1]).toBe(''); + }); + + it('supports explicit newlines in main text', () => { + const lines = new BannerComponent(makeBannerState({ mainText: 'Line 1\nLine 2' })).render(80); + expect(lines.length).toBe(3); + expect(lines[0]).toContain('Line 1'); + expect(lines[1]).toContain('Line 2'); + expect(lines[2]).toBe(''); + }); + + it('styles tag, main text, and subtext with theme colors', () => { + const lines = new BannerComponent(banner).render(80); + expect(lines[0]).toContain(currentTheme.boldFg('primary', "✦ What's new:")); + expect(lines[0]).toContain( + currentTheme.boldFg('textStrong', 'This is the main banner message for testing purposes.'), + ); + expect(lines[1]).toContain(currentTheme.fg('textDim', 'This is a short subtext line.')); + }); + + it('does not stack the dim modifier on top of the textDim color', () => { + const lines = new BannerComponent(banner).render(80); + expect(lines[1]).toContain('This is a short subtext'); + expect(lines[1]).not.toContain(''); + expect(lines[2]).toBe(''); + }); + + it('keeps subsequent main lines indented to the main-text column and subtext aligned with the tag text', () => { + const width = 24; + const lines = new BannerComponent( + makeBannerState({ + tag: 'New:', + mainText: 'Line 1 with a lot of content', + subText: 'Sub text', + }), + ).render(width); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + expect(lines[0]).toContain('✦ New:'); + const firstLine = lines[0]!; + const mainTextStart = visibleWidth(firstLine.slice(0, firstLine.indexOf('Line 1'))); + const continuationLine = lines.find((line) => line.includes('of content'))!; + expect(visibleWidth(continuationLine.slice(0, continuationLine.indexOf('of content')))).toBe(mainTextStart); + const subLine = lines.find((line) => line.includes('Sub text'))!; + expect(visibleWidth(subLine.slice(0, subLine.indexOf('Sub text')))).toBe(visibleWidth('✦ ')); + }); + + it('moves a long tag onto its own line so the main text keeps a usable width', () => { + // Regression: remote banner configs can set a full-sentence tag. Inline it + // would leave the main text only a few columns, which hard-breaks words. + const width = 50; + const lines = new BannerComponent( + makeBannerState({ + tag: 'Use Kimi K3 with High thinking effort', + mainText: '- for the best balance between token spend and capability', + subText: 'Run /model to switch to K3 and set thinking effort to High', + }), + ).render(width); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + // The tag occupies the first line alone; no main text is squeezed next to it. + expect(lines[0]).toContain('✦ Use Kimi K3 with High thinking effort'); + expect(lines[0]).not.toContain('- for'); + // Words stay intact (no mid-word hard breaks like "balan"/"ce"). + const joined = lines.join('\n'); + for (const word of ['balance', 'between', 'capability', 'thinking', 'effort']) { + expect(joined).toContain(word); + } + // Main text and subtext align with the tag text (right after "✦ "). + const mainLine = lines.find((line) => line.includes('- for'))!; + expect(visibleWidth(mainLine.slice(0, mainLine.indexOf('- for')))).toBe(visibleWidth('✦ ')); + const subLine = lines.find((line) => line.includes('Run /model'))!; + expect(visibleWidth(subLine.slice(0, subLine.indexOf('Run /model')))).toBe(visibleWidth('✦ ')); + }); + + it('keeps a short tag inline when the remaining width is enough', () => { + const width = 40; + const lines = new BannerComponent( + makeBannerState({ tag: 'Tip:', mainText: 'Use /help to list commands.' }), + ).render(width); + expect(lines[0]).toContain('✦ Tip:'); + expect(lines[0]).toContain('Use /help'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/device-code-box.test.ts b/apps/kimi-code/test/tui/components/chrome/device-code-box.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0d4e929f84723fe8fcd057494820eccd275f6d5 --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/device-code-box.test.ts @@ -0,0 +1,79 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { DeviceCodeBoxComponent } from '#/tui/components/chrome/device-code-box'; +import { darkColors } from '#/tui/theme/colors'; + +function strip(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +const url = 'https://www.kimi.com/code/authorize_device?user_code=N32D-W3YD'; +const code = 'N32D-W3YD'; +const title = 'Sign in to Kimi Code'; +const hint = 'Press Ctrl-C to cancel'; + +describe('DeviceCodeBoxComponent', () => { + it('renders a rounded border that frames the title, url and code', () => { + const component = new DeviceCodeBoxComponent({ + title, + url, + code, + hint, + }); + + const lines = component.render(80).map(strip); + const joined = lines.join('\n'); + + expect(lines[1]?.startsWith('╭')).toBe(true); + expect(lines[1]?.endsWith('╮')).toBe(true); + expect(lines.at(-2)?.startsWith('╰')).toBe(true); + expect(lines.at(-2)?.endsWith('╯')).toBe(true); + + expect(joined).toContain(title); + expect(joined).toContain(url); + expect(joined).toContain(code); + expect(joined).toContain(hint); + expect(joined).toContain('Verification code'); + }); + + it('truncates long urls when the terminal is narrow', () => { + const component = new DeviceCodeBoxComponent({ + title, + url, + code, + }); + + const lines = component.render(40).map(strip); + const urlLine = lines.find((line) => line.includes('https://')); + expect(urlLine).toBeDefined(); + expect(urlLine).toContain('…'); + expect(urlLine?.length).toBeLessThanOrEqual(40); + }); + + it('omits the hint row when no hint is provided', () => { + const component = new DeviceCodeBoxComponent({ + title, + url, + code, + }); + + const joined = component.render(80).map(strip).join('\n'); + expect(joined).not.toContain('Press Ctrl-C'); + }); + + it('keeps every line within narrow widths', () => { + const component = new DeviceCodeBoxComponent({ + title, + url, + code, + hint, + }); + + for (const width of [39, 20, 10, 4]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts b/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..08883ebd3f55f13f6207ee8d7701aa7cd615e387 --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/footer-status-line.test.ts @@ -0,0 +1,264 @@ +import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { describe, expect, it } from 'vitest'; + +import { FooterComponent } from '#/tui/components/chrome/footer'; +import { + runStatusLineCommand, + STATUS_LINE_MAX_CAPTURE_BYTES, + StatusLineCommandRunner, + type StatusLinePayload, +} from '#/tui/utils/status-line-command'; +import type { AppState } from '#/tui/types'; + +const baseState: AppState = { + version: '1.2.3', + workDir: '/tmp/project', + additionalDirs: [], + sessionId: 'ses-1', + sessionTitle: null, + model: 'kimi-k2', + permissionMode: 'manual', + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + stepRetry: null, + planMode: false, + inputMode: 'prompt', + swarmMode: false, + towerMode: false, + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + availableModels: {}, + availableProviders: {}, + mcpServersSummary: null, +}; + +const payload: StatusLinePayload = { + model: 'kimi-k2', + cwd: '/tmp/project', + gitBranch: 'main', + permissionMode: 'manual', + planMode: false, + contextUsage: 12, + contextTokens: 1024, + maxContextTokens: 8192, + sessionId: 'ses-1', + version: '1.2.3', +}; + +function plain(text: string): string { + // eslint-disable-next-line no-control-regex + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('FooterComponent status_line items', () => { + it('renders only the chosen slots in the given order', () => { + const state: AppState = { + ...baseState, + statusLine: { items: ['cwd', 'model'], command: null }, + }; + const footer = new FooterComponent(state); + + const line1 = plain(footer.render(120)[0]!); + const cwdAt = line1.indexOf('/tmp/project'); + const modelAt = line1.indexOf('kimi-k2'); + expect(cwdAt).toBeGreaterThanOrEqual(0); + expect(modelAt).toBeGreaterThan(cwdAt); + expect(line1).not.toContain('goal'); + }); + + it('keeps the default layout when statusLine is unset', () => { + const footer = new FooterComponent({ ...baseState }); + + const line1 = plain(footer.render(120)[0]!); + expect(line1).toContain('kimi-k2'); + expect(line1).toContain('/tmp/project'); + }); + + it('drops the rotating tips when tips is not in items', () => { + const withTips = plain(new FooterComponent(baseState).render(200)[0]!); + const state: AppState = { + ...baseState, + statusLine: { items: ['model', 'cwd'], command: null }, + }; + const withoutTips = plain(new FooterComponent(state).render(200)[0]!); + + expect(withoutTips.length).toBeLessThan(withTips.length); + expect(withoutTips.trimEnd()).toMatch(/kimi-k2 {2}\/tmp\/project$/); + }); + + it('honors the configured position of the tips slot', () => { + // The tip content itself rotates; locate it via a tips-only render. + const tipsOnly = plain( + new FooterComponent({ + ...baseState, + statusLine: { items: ['tips'], command: null }, + }).render(200)[0]!, + ).trim(); + + const tipsFirst = plain( + new FooterComponent({ + ...baseState, + statusLine: { items: ['tips', 'model'], command: null }, + }).render(200)[0]!, + ); + const tipsLast = plain( + new FooterComponent({ + ...baseState, + statusLine: { items: ['model', 'tips'], command: null }, + }).render(200)[0]!, + ); + + expect(tipsOnly.length).toBeGreaterThan(0); + expect(tipsFirst.indexOf(tipsOnly)).toBeLessThan(tipsFirst.indexOf('kimi-k2')); + expect(tipsLast.indexOf('kimi-k2')).toBeLessThan(tipsLast.indexOf(tipsOnly)); + }); + + it('renders nothing on line 1 for an empty items list', () => { + const state: AppState = { + ...baseState, + statusLine: { items: [], command: null }, + }; + const footer = new FooterComponent(state); + + expect(plain(footer.render(120)[0]!).trim()).toBe(''); + }); +}); + +describe('runStatusLineCommand', () => { + it('passes the payload as JSON on stdin and returns the first stdout line', async () => { + const line = await runStatusLineCommand('cat', payload); + + expect(line).not.toBeNull(); + const parsed = JSON.parse(line!); + expect(parsed.model).toBe('kimi-k2'); + expect(parsed.gitBranch).toBe('main'); + expect(parsed.cwd).toBe('/tmp/project'); + }); + + it('returns null on a nonzero exit', async () => { + expect(await runStatusLineCommand('exit 3', payload)).toBeNull(); + }); + + it('returns null on empty output', async () => { + expect(await runStatusLineCommand('true', payload)).toBeNull(); + }); + + it('returns null when the command overruns the timeout', async () => { + expect(await runStatusLineCommand('sleep 2', payload, 100)).toBeNull(); + }); + + it('trims the line and ignores later lines', async () => { + const line = await runStatusLineCommand('printf "first\\nsecond\\n"', payload); + + expect(line).toBe('first'); + }); + + it('caps the captured output instead of accumulating an unending stream', async () => { + // 200 KB on a single line, then exit: only the capped prefix is kept. + const line = await runStatusLineCommand( + 'head -c 200000 /dev/zero | tr "\\0" "a"', + payload, + ); + + expect(line).not.toBeNull(); + expect(line!.length).toBeLessThanOrEqual(STATUS_LINE_MAX_CAPTURE_BYTES); + }); +}); + +describe('FooterComponent status_line command', () => { + it('swaps line 1 to the command output once it lands', async () => { + const state: AppState = { + ...baseState, + statusLine: { items: null, command: 'printf "my-custom-status"' }, + }; + const footer = new FooterComponent(state); + + // Before the first run completes the built-in layout is still shown. + expect(plain(footer.render(120)[0]!)).toContain('kimi-k2'); + + await new Promise((resolve) => setTimeout(resolve, 200)); + + expect(plain(footer.render(120)[0]!)).toContain('my-custom-status'); + }); + + it('keeps the built-in layout when the command fails', async () => { + const state: AppState = { + ...baseState, + statusLine: { items: null, command: 'exit 1' }, + }; + const footer = new FooterComponent(state); + + await new Promise((resolve) => setTimeout(resolve, 200)); + + expect(plain(footer.render(120)[0]!)).toContain('kimi-k2'); + }); +}); + +describe('StatusLineCommandRunner', () => { + it('caches the last good line and coalesces refreshes in the same interval', async () => { + const runner = new StatusLineCommandRunner('printf "x"', () => {}); + + runner.maybeRefresh(payload); + runner.maybeRefresh(payload); + await new Promise((resolve) => setTimeout(resolve, 200)); + + expect(runner.current()).toBe('x'); + }); + + it('runs a deferred refresh after the throttle interval instead of dropping it', async () => { + const dir = join(tmpdir(), `sl-trailing-${process.pid}-${Math.random().toString(36).slice(2)}`); + mkdirSync(dir, { recursive: true }); + try { + const counterFile = join(dir, 'count'); + const scriptFile = join(dir, 'count.sh'); + writeFileSync(counterFile, '0'); + writeFileSync( + scriptFile, + '#!/bin/sh\nn=$(cat "$1")\necho $((n+1)) > "$1"\nprintf "run-%s" "$n"\n', + ); + const runner = new StatusLineCommandRunner(`sh ${scriptFile} ${counterFile}`, () => {}); + + runner.maybeRefresh(payload); + await new Promise((resolve) => setTimeout(resolve, 250)); + runner.maybeRefresh(payload); // throttled: must defer, not drop + await new Promise((resolve) => setTimeout(resolve, 250)); + expect(readFileSync(counterFile, 'utf-8').trim()).toBe('1'); + + await new Promise((resolve) => setTimeout(resolve, 800)); + expect(readFileSync(counterFile, 'utf-8').trim()).toBe('2'); + runner.dispose(); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('recreates the runner when the command changes', async () => { + const state: AppState = { + ...baseState, + statusLine: { items: null, command: 'printf "aaa"' }, + }; + const footer = new FooterComponent(state); + footer.render(120); // kicks the first run + await new Promise((resolve) => setTimeout(resolve, 450)); + expect(plain(footer.render(120)[0]!)).toContain('aaa'); + + footer.setState({ ...state, statusLine: { items: null, command: 'printf "bbb"' } }); + footer.render(120); // kicks the replacement run + await new Promise((resolve) => setTimeout(resolve, 450)); + + const line1 = plain(footer.render(120)[0]!); + expect(line1).toContain('bbb'); + expect(line1).not.toContain('aaa'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/footer.test.ts b/apps/kimi-code/test/tui/components/chrome/footer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ce0701fb1307206c9141f7bc89ed15baadab83a --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/footer.test.ts @@ -0,0 +1,322 @@ +import chalk from 'chalk'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { FooterComponent } from '#/tui/components/chrome/footer'; +import { setRainbowDance, type RainbowDanceController } from '#/tui/easter-eggs/dance'; +import { currentTheme, darkColors, lightColors } from '#/tui/theme'; +import type { ModelAlias } from '@moonshot-ai/kimi-code-sdk'; +import type { AppState } from '#/tui/types'; + +const TRUECOLOR_PATTERN = /\[38;2;(\d+);(\d+);(\d+)m/g; + +function truecolorCodes(text: string): Set { + const codes = new Set(); + for (const match of text.matchAll(TRUECOLOR_PATTERN)) { + codes.add(`${match[1]},${match[2]},${match[3]}`); + } + return codes; +} + +// Dark dance colors the footer never uses outside of /dance. +const RAINBOW_CYAN = '91,192,190'; +const RAINBOW_GREEN = '78,200,126'; + +function setDanceView(colored: boolean, phase: number): void { + const dance: RainbowDanceController = { + colored, + phase, + start: () => {}, + stop: () => {}, + dispose: () => {}, + }; + setRainbowDance(dance); +} + +const appState: AppState = { + version: '1.2.3', + workDir: '/tmp/project', + additionalDirs: [], + sessionId: 'ses-1', + sessionTitle: null, + model: 'kimi-k2', + permissionMode: 'manual', + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + stepRetry: null, + planMode: false, + inputMode: 'prompt', + swarmMode: false, + towerMode: false, + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + availableModels: {}, + availableProviders: {}, + mcpServersSummary: null, +}; + +describe('FooterComponent', () => { + const previousChalkLevel = chalk.level; + + beforeEach(() => { + chalk.level = 3; + }); + + afterEach(() => { + chalk.level = previousChalkLevel; + setRainbowDance(undefined); + }); + + it('paints the model name in rainbow while colored', () => { + setDanceView(true, 0); + const footer = new FooterComponent(appState); + + const codes = truecolorCodes(footer.render(120).join('\n')); + + // "kimi-k2" spreads across the palette, pulling in colors the footer + // never renders on its own. + expect(codes.has(RAINBOW_CYAN)).toBe(true); + expect(codes.has(RAINBOW_GREEN)).toBe(true); + }); + + it('renders the model name in its normal color when not dancing', () => { + const footer = new FooterComponent(appState); + + const codes = truecolorCodes(footer.render(120).join('\n')); + + expect(codes.has(RAINBOW_CYAN)).toBe(false); + expect(codes.has(RAINBOW_GREEN)).toBe(false); + }); + + it('repaints from the active palette on the next render (no setColors needed)', () => { + const footer = new FooterComponent(appState); + const before = footer.render(120).join('\n'); + + currentTheme.setPalette(lightColors); + try { + const after = footer.render(120).join('\n'); + // Reads currentTheme live, so a palette swap changes the emitted colours. + expect(after).not.toBe(before); + } finally { + currentTheme.setPalette(darkColors); + } + }); + + it('shows the effort for an effort-capable model', () => { + const effortModel: ModelAlias = { + provider: 'managed:kimi-code', + model: 'kimi-k2', + maxContextSize: 262144, + supportEfforts: ['low', 'high', 'max'], + defaultEffort: 'high', + }; + const state: AppState = { + ...appState, + thinkingEffort: 'max', + availableModels: { 'kimi-k2': effortModel }, + }; + const footer = new FooterComponent(state); + + expect(footer.render(120).join('\n')).toContain('thinking: max'); + }); + + it('does not show the effort for a legacy boolean model', () => { + const plainModel: ModelAlias = { + provider: 'managed:kimi-code', + model: 'kimi-k2', + maxContextSize: 262144, + capabilities: ['thinking'], + }; + const state: AppState = { + ...appState, + thinkingEffort: 'high', + availableModels: { 'kimi-k2': plainModel }, + }; + const footer = new FooterComponent(state); + const rendered = footer.render(120).join('\n'); + + expect(rendered).toContain('thinking'); + expect(rendered).not.toContain('thinking:high'); + }); + + it('shows the tower mode chip only when tower mode is on', () => { + const on = new FooterComponent({ ...appState, towerMode: true }); + expect(on.render(120).join('\n')).toContain('tower'); + + const off = new FooterComponent(appState); + expect(off.render(120).join('\n')).not.toContain('tower'); + }); +}); + +describe('FooterComponent overrides', () => { + it('shows the overridden effort list', () => { + const effortModelWithOverride: ModelAlias = { + provider: 'managed:kimi-code', + model: 'kimi-k2', + maxContextSize: 262144, + supportEfforts: ['low', 'high', 'max'], + defaultEffort: 'max', + overrides: { supportEfforts: ['low', 'high'], defaultEffort: 'high' }, + }; + const state: AppState = { + ...appState, + thinkingEffort: 'high', + availableModels: { 'kimi-k2': effortModelWithOverride }, + }; + const footer = new FooterComponent(state); + + expect(footer.render(120).join('\n')).toContain('thinking: high'); + }); +}); + +describe('FooterComponent displayName override', () => { + it('renders the overridden display name', () => { + const state: AppState = { + ...appState, + model: 'kimi-k2', + availableModels: { + 'kimi-k2': { + provider: 'managed:kimi-code', + model: 'kimi-k2', + maxContextSize: 262144, + displayName: 'Remote Name', + overrides: { displayName: 'Custom Name' }, + }, + }, + }; + const footer = new FooterComponent(state); + + expect(footer.render(120).join('\n')).toContain('Custom Name'); + expect(footer.render(120).join('\n')).not.toContain('Remote Name'); + }); +}); + +describe('FooterComponent line-2 hints', () => { + function stripAnsi(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); + } + + it('shows the warning hint on line 2', () => { + const footer = new FooterComponent(appState); + footer.setWarningHint('Goal objective is too long'); + + const line2 = stripAnsi(footer.render(120)[1] ?? ''); + + expect(line2).toContain('Goal objective is too long'); + }); + + it('gives the transient hint precedence, then restores the warning hint', () => { + const footer = new FooterComponent(appState); + footer.setWarningHint('Goal objective is too long'); + + footer.setTransientHint('Press Ctrl+C again to exit'); + expect(stripAnsi(footer.render(120)[1] ?? '')).toContain('Press Ctrl+C again to exit'); + expect(stripAnsi(footer.render(120)[1] ?? '')).not.toContain('Goal objective is too long'); + + footer.setTransientHint(null); + expect(stripAnsi(footer.render(120)[1] ?? '')).toContain('Goal objective is too long'); + }); + + it('clears the warning hint with null', () => { + const footer = new FooterComponent(appState); + footer.setWarningHint('Goal objective is too long'); + footer.setWarningHint(null); + + expect(stripAnsi(footer.render(120)[1] ?? '')).not.toContain('Goal objective is too long'); + }); +}); + +describe('FooterComponent ctrl+o hint', () => { + function plain(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); + } + function line1(footer: FooterComponent, width = 160): string { + return plain(footer.render(width)[0] ?? ''); + } + + it('shows no hint while there is no tool output to toggle', () => { + const footer = new FooterComponent(appState); + footer.setExpandHintProvider(() => null); + expect(line1(footer)).not.toContain('ctrl+o'); + footer.dispose(); + }); + + it('offers expand while collapsed output exists and collapse once it is shown', () => { + const footer = new FooterComponent(appState); + let hint: 'expand' | 'collapse' | null = 'expand'; + footer.setExpandHintProvider(() => hint); + expect(line1(footer)).toContain('ctrl+o expand'); + hint = 'collapse'; + expect(line1(footer)).toContain('ctrl+o collapse'); + footer.dispose(); + }); + + it('keeps the hint and drops the rotating tip when only one of them fits', () => { + // Same left-hand slots without the tips: measures the space the hint competes for. + const noTips = new FooterComponent({ + ...appState, + statusLine: { items: ['mode', 'model', 'cwd'], command: null }, + }); + const leftWidth = plain(noTips.render(200)[0] ?? '').trimEnd().length; + noTips.dispose(); + + const footer = new FooterComponent(appState); + footer.setExpandHintProvider(() => 'expand'); + const narrow = line1(footer, leftWidth + 2 + 'ctrl+o expand'.length); + expect(narrow.endsWith('ctrl+o expand')).toBe(true); + expect(narrow).not.toContain(' | '); + footer.dispose(); + }); +}); + +describe('FooterComponent ctrl+o hint with a status_line command', () => { + it('moves the hint to line 2 when a command owns line 1', async () => { + const footer = new FooterComponent({ + ...appState, + statusLine: { items: null, command: 'printf "my-custom-status"' }, + }); + footer.setExpandHintProvider(() => 'expand'); + footer.render(120); + await new Promise((resolve) => setTimeout(resolve, 200)); + + const [line1, line2] = footer.render(120).map((line) => line.replaceAll(/\[[0-9;]*m/g, '')); + expect(line1).toContain('my-custom-status'); + expect(line1).not.toContain('ctrl+o'); + expect(line2).toContain('ctrl+o expand'); + expect(line2).toContain('context:'); + footer.dispose(); + }); +}); + +describe('FooterComponent ctrl+o hint beside an inline tips slot', () => { + function plain(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); + } + + it('drops the inline tip when the hint would not fit beside it', () => { + const noTips = new FooterComponent({ + ...appState, + statusLine: { items: ['mode', 'model', 'cwd'], command: null }, + }); + const leftWidth = plain(noTips.render(200)[0] ?? '').trimEnd().length; + noTips.dispose(); + + const footer = new FooterComponent({ + ...appState, + statusLine: { items: ['mode', 'tips', 'model', 'cwd'], command: null }, + }); + footer.setExpandHintProvider(() => 'expand'); + const width = leftWidth + 2 + 'ctrl+o expand'.length; + const line1 = plain(footer.render(width)[0] ?? ''); + expect(line1.endsWith('ctrl+o expand')).toBe(true); + expect(line1.length).toBeLessThanOrEqual(width); + footer.dispose(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/gutter-container.test.ts b/apps/kimi-code/test/tui/components/chrome/gutter-container.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..37dea81286e0ef874c176c308c985f750bc9616b --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/gutter-container.test.ts @@ -0,0 +1,117 @@ +import type { Component, TuiMouseEvent } from '@moonshot-ai/pi-tui'; +import { describe, expect, it, vi } from 'vitest'; + +import { GutterContainer } from '#/tui/components/chrome/gutter-container'; + +class FakeChild implements Component { + constructor( + private readonly lines: (innerWidth: number) => string[], + ) {} + invalidate(): void {} + render(width: number): string[] { + return this.lines(width); + } +} + +class MouseChild extends FakeChild { + readonly events: TuiMouseEvent[] = []; + handleMouse(event: TuiMouseEvent) { + this.events.push(event); + return { handled: true as const }; + } +} + +function clickAt(x: number, y: number, width: number, height: number): TuiMouseEvent { + return { + type: 'click', + button: 'left', + x, + y, + screenX: x, + screenY: y, + width, + height, + shift: false, + alt: false, + ctrl: false, + clickCount: 1, + }; +} + +describe('GutterContainer', () => { + it('prefixes every child line with `left` spaces', () => { + const c = new GutterContainer(2, 2); + c.addChild(new FakeChild(() => ['hello', 'world'])); + expect(c.render(20)).toEqual([' hello', ' world']); + }); + + it('shrinks the width passed to children by left + right', () => { + const seenWidth = vi.fn<(w: number) => string[]>(() => ['x']); + const c = new GutterContainer(2, 3); + c.addChild(new FakeChild(seenWidth)); + c.render(20); + expect(seenWidth).toHaveBeenCalledWith(15); + }); + + it('clamps inner width to at least 1 when gutters would otherwise consume it', () => { + const seenWidth = vi.fn<(w: number) => string[]>(() => ['x']); + const c = new GutterContainer(5, 5); + c.addChild(new FakeChild(seenWidth)); + c.render(2); + expect(seenWidth).toHaveBeenCalledWith(1); + }); + + it('stacks lines from multiple children in order', () => { + const c = new GutterContainer(1, 0); + c.addChild(new FakeChild(() => ['a1', 'a2'])); + c.addChild(new FakeChild(() => ['b1'])); + expect(c.render(10)).toEqual([' a1', ' a2', ' b1']); + }); + + it('returns an empty array when there are no children', () => { + const c = new GutterContainer(2, 2); + expect(c.render(20)).toEqual([]); + }); + + it('preserves ANSI sequences within child lines (only the leading pad is plain)', () => { + const colored = 'red'; + const c = new GutterContainer(2, 2); + c.addChild(new FakeChild(() => [colored])); + expect(c.render(20)).toEqual([` ${colored}`]); + }); + + it('keeps a leading OSC 133 zone marker at byte 0, before the gutter', () => { + const c = new GutterContainer(2, 2); + const marked = `\u001B]133;A\u0007content`; + const doubleMarked = `\u001B]133;B\u0007\u001B]133;C\u0007last`; + c.addChild(new FakeChild(() => [marked, doubleMarked])); + expect(c.render(20)).toEqual([ + `\u001B]133;A\u0007 content`, + `\u001B]133;B\u0007\u001B]133;C\u0007 last`, + ]); + }); + + it('translates mouse events into the inner coordinate frame', () => { + const child = new MouseChild(() => ['x']); + const c = new GutterContainer(2, 3); + c.addChild(child); + + c.handleMouse(clickAt(5, 0, 20, 1)); + expect(child.events).toHaveLength(1); + expect(child.events[0]).toMatchObject({ x: 3, width: 15 }); + }); + + it('measures child heights at the inner width when hit-testing', () => { + const first = new MouseChild((w) => (w >= 19 ? ['a'] : ['a', 'a'])); + const second = new MouseChild(() => ['b']); + const c = new GutterContainer(1, 1); + c.addChild(first); + c.addChild(second); + + // Inner width is 17, where the first child wraps to two rows. + c.handleMouse(clickAt(3, 1, 19, 3)); + expect(first.events).toHaveLength(1); + expect(first.events[0]).toMatchObject({ y: 1 }); + expect(second.events).toHaveLength(0); + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/moon-loader.test.ts b/apps/kimi-code/test/tui/components/chrome/moon-loader.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffdc5bcbeb159a5e34fd07b15ba74055d6259799 --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/moon-loader.test.ts @@ -0,0 +1,42 @@ +import type { TUI } from '@moonshot-ai/pi-tui'; +import { afterEach, describe, expect, it } from 'vitest'; + +import { MoonLoader } from '#/tui/components/chrome/moon-loader'; + +// MoonLoader starts a real setInterval in its constructor, so every loader +// created in these tests must be stopped to avoid leaving live timers behind. +const loaders: MoonLoader[] = []; + +function createLoader(): MoonLoader { + const ui = { requestRender() {} } as unknown as TUI; + const loader = new MoonLoader(ui, 'moon'); + loaders.push(loader); + return loader; +} + +afterEach(() => { + for (const loader of loaders) loader.stop(); + loaders.length = 0; +}); + +describe('MoonLoader', () => { + it('keeps the tip out of renderInline so it does not squeeze against the swarm progress bar', () => { + const loader = createLoader(); + loader.setTip(' · Tip: ctrl+s: steer mid-turn'); + loader.setAvailableWidth(80); + + const inline = loader.renderInline(); + expect(inline).not.toContain('Tip'); + expect(inline).not.toContain('steer'); + expect(inline.trim().length).toBeGreaterThan(0); + }); + + it('still shows the tip on its own row when width allows', () => { + const loader = createLoader(); + loader.setTip(' · Tip: ctrl+s: steer mid-turn'); + loader.setAvailableWidth(80); + + const row = loader.render(80).join('\n'); + expect(row).toContain('Tip: ctrl+s: steer mid-turn'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/chrome/welcome.test.ts b/apps/kimi-code/test/tui/components/chrome/welcome.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..47e6b7a0f049eba82aff0e80a8f0b79b097ca0fe --- /dev/null +++ b/apps/kimi-code/test/tui/components/chrome/welcome.test.ts @@ -0,0 +1,107 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { WelcomeComponent } from '#/tui/components/chrome/welcome'; +import { setRainbowDance, type RainbowDanceController } from '#/tui/easter-eggs/dance'; +import { darkColors } from '#/tui/theme/colors'; +import type { AppState } from '#/tui/types'; + +const TRUECOLOR_PATTERN = /\u001B\[38;2;(\d+);(\d+);(\d+)m/g; + +const appState: AppState = { + version: '1.2.3', + workDir: '/tmp/project', + additionalDirs: [], + sessionId: 'ses-1', + sessionTitle: null, + model: 'kimi-k2', + permissionMode: 'manual', + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + stepRetry: null, + planMode: false, + inputMode: 'prompt', + swarmMode: false, + towerMode: false, + theme: 'dark', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + availableModels: {}, + availableProviders: {}, + mcpServersSummary: null, +}; + +function truecolorCodes(text: string): Set { + const codes = new Set(); + for (const match of text.matchAll(TRUECOLOR_PATTERN)) { + codes.add(`${match[1]},${match[2]},${match[3]}`); + } + return codes; +} + +/** The two header rows (logo + title) of the rendered welcome box. */ +function headerOf(lines: string[]): string { + return [lines[3], lines[4]].join('\n'); +} + +function setDanceView(colored: boolean, phase: number): void { + const dance: RainbowDanceController = { + colored, + phase, + start: () => {}, + stop: () => {}, + dispose: () => {}, + }; + setRainbowDance(dance); +} + +describe('WelcomeComponent', () => { + const previousChalkLevel = chalk.level; + + beforeEach(() => { + chalk.level = 3; + }); + + afterEach(() => { + chalk.level = previousChalkLevel; + setRainbowDance(undefined); + }); + + it('renders the banner in a single brand color by default', () => { + const codes = truecolorCodes(headerOf(new WelcomeComponent(appState).render(80))); + + // No rainbow by default — just the brand primary (plus the dim tagline). + expect(codes.size).toBeLessThanOrEqual(2); + }); + + it('paints the banner in rainbow while colored', () => { + setDanceView(true, 0); + const codes = truecolorCodes(headerOf(new WelcomeComponent(appState).render(80))); + + expect(codes.size).toBeGreaterThanOrEqual(5); + }); + + it('renders exactly the default banner when not colored', () => { + const base = headerOf(new WelcomeComponent(appState).render(80)); + setDanceView(false, 5); + const off = headerOf(new WelcomeComponent(appState).render(80)); + + expect(off).toBe(base); + }); + + it('keeps every line within the requested width on narrow terminals', () => { + for (const width of [0, 1, 2, 4, 10, 39, 80]) { + for (const line of new WelcomeComponent(appState).render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/agent-activity-viewer.test.ts b/apps/kimi-code/test/tui/components/dialogs/agent-activity-viewer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..12158c387ad99f9d58ca63dff15c632950bac52e --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/agent-activity-viewer.test.ts @@ -0,0 +1,320 @@ +import type { Terminal } from '@moonshot-ai/pi-tui'; +import type { BackgroundTaskInfo } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import { AgentActivityViewer, formatSubagentActivityPreview } from '#/tui/components/dialogs/agent-activity-viewer'; +import type { SubagentActivityRecord } from '#/tui/controllers/subagent-activity-store'; + +const ANSI_SGR = /\[[0-9;]*m/g; +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +/** Kitty CSI-u form of Ctrl+O (codepoint 111, modifier 1+4). */ +const CTRL_O = '\u001B[111;5u'; + +/** Minimal Terminal stub — only `rows` is read by the component. */ +function fakeTerminal(rows: number, columns = 120): Terminal { + return { + start: () => {}, + stop: () => {}, + drainInput: () => Promise.resolve(), + write: () => {}, + get columns() { + return columns; + }, + get rows() { + return rows; + }, + get kittyProtocolActive() { + return false; + }, + moveBy: () => {}, + hideCursor: () => {}, + showCursor: () => {}, + clearLine: () => {}, + clearFromCursor: () => {}, + clearScreen: () => {}, + setTitle: () => {}, + setProgress: () => {}, + }; +} + +function agentTask(overrides: Record = {}): BackgroundTaskInfo { + return { + taskId: 'agent-task-1', + kind: 'agent', + agentId: 'agent-1', + description: 'find things', + status: 'running', + startedAt: Date.now() - 60_000, + endedAt: null, + ...overrides, + } as BackgroundTaskInfo; +} + +function record(overrides: Partial = {}): SubagentActivityRecord { + return { + agentId: 'agent-1', + agentName: 'explore', + description: 'find things', + parentToolCallId: 'tc-1', + steps: [], + totalSteps: 0, + status: 'running', + version: 1, + ...overrides, + }; +} + +function makeViewer( + props: Partial[0]> & { + record?: SubagentActivityRecord; + } = {}, + rows = 20, + columns = 80, +): AgentActivityViewer { + return new AgentActivityViewer( + { + taskId: 'agent-task-1', + info: agentTask(), + record: props.record, + onClose: vi.fn(), + ...props, + }, + fakeTerminal(rows, columns), + ); +} + +function renderPlain(viewer: AgentActivityViewer, width = 80): string { + return strip(viewer.render(width).join('\n')); +} + +describe('AgentActivityViewer', () => { + it('fills exactly terminal.rows lines', () => { + const viewer = makeViewer({}, 20); + expect(viewer.render(80).length).toBe(20); + }); + + it('shows agent label, status and step range in the header', () => { + const viewer = makeViewer({ + record: record({ + steps: [ + { step: 8, textTail: '', toolCalls: [] }, + { step: 9, textTail: '', toolCalls: [] }, + ], + totalSteps: 12, + }), + }); + const text = renderPlain(viewer, 120); + expect(text).toContain('Agent activity'); + expect(text).toContain('explore › find things'); + expect(text).toContain('running'); + expect(text).toContain('step 8–9 / 12'); + expect(text).toContain('earlier steps discarded'); + }); + + it('renders steps with tool call headers and result renderer output', () => { + const viewer = makeViewer({ + record: record({ + steps: [ + { + step: 0, + textTail: 'Looking for the event bus definition.', + toolCalls: [ + { + id: 't1', + name: 'Grep', + args: { pattern: 'IEventBus', output_mode: 'content' }, + status: 'done', + startedAt: 0, + result: { + tool_call_id: 't1', + output: 'src/a.ts:1:IEventBus\nsrc/b.ts:2:IEventBus', + is_error: false, + }, + }, + ], + }, + ], + totalSteps: 1, + }), + }); + const text = renderPlain(viewer); + expect(text).toContain('── step 0 ──'); + expect(text).toContain('Looking for the event bus definition.'); + expect(text).toContain('Used Grep (IEventBus) · 2 matches across 2 files'); + // The grep glance (path samples in `path:line` form) is the collapsed + // card's outcome row. + expect(text).toContain('src/a.ts:1, src/b.ts:2'); + viewer.handleInput(CTRL_O); + expect(renderPlain(viewer)).toContain('src/a.ts:1, src/b.ts:2'); + }); + + it('hides successful output by default and reveals it with ctrl+o', () => { + const longOutput = Array.from({ length: 10 }, (_, i) => `line ${String(i + 1)}`).join('\n'); + const makeRecord = (): SubagentActivityRecord => + record({ + steps: [ + { + step: 0, + textTail: '', + toolCalls: [ + { + id: 't1', + name: 'Bash', + args: { command: 'ls' }, + status: 'done', + startedAt: 0, + result: { tool_call_id: 't1', output: longOutput, is_error: false }, + }, + ], + }, + ], + totalSteps: 1, + }); + + const collapsed = makeViewer({ record: makeRecord() }); + const collapsedText = renderPlain(collapsed); + // Collapsed: the last output line is the outcome row, nothing else. + expect(collapsedText).toContain('Bash'); + expect(collapsedText).toContain('line 10'); + expect(collapsedText).not.toContain('line 9'); + + collapsed.handleInput(CTRL_O); + const expandedText = renderPlain(collapsed); + expect(expandedText).toContain('line 10'); + }); + + it('opens pinned to the latest activity and keeps scroll position when the user scrolled up', () => { + const steps = Array.from({ length: 8 }, (_, i) => ({ + step: i, + textTail: `step ${String(i)} text`, + toolCalls: [], + })); + const rec = record({ steps, totalSteps: 8 }); + const viewer = makeViewer({ record: rec }, 12); + + // Initial render follows the tail: the last step is visible. + expect(renderPlain(viewer)).toContain('step 7 text'); + + // User scrolls to the top, then new activity arrives (version bump): + // the view must stay where the user parked it. + viewer.handleInput('g'); + expect(renderPlain(viewer)).toContain('step 0 text'); + rec.steps.push({ step: 8, textTail: 'step 8 text', toolCalls: [] }); + rec.version += 1; + viewer.setProps({ taskId: 'agent-task-1', info: agentTask(), record: rec, onClose: vi.fn() }); + const after = renderPlain(viewer); + expect(after).toContain('step 0 text'); + expect(after).not.toContain('step 8 text'); + }); + + it('shows an explicit empty state when no record exists', () => { + const viewer = makeViewer({ record: undefined }); + expect(renderPlain(viewer)).toContain('[no activity recorded]'); + }); + + it('renders the terminal result summary section', () => { + const viewer = makeViewer({ + info: agentTask({ status: 'completed' }), + record: record({ status: 'completed', resultSummary: 'Found 3 call sites.' }), + }); + const text = renderPlain(viewer); + expect(text).toContain('completed'); + expect(text).toContain('Result'); + expect(text).toContain('Found 3 call sites.'); + }); + + it('closes on q and escape', () => { + const onClose = vi.fn(); + const viewer = makeViewer({ record: record(), onClose }); + viewer.handleInput('q'); + expect(onClose).toHaveBeenCalledTimes(1); + viewer.handleInput('\u001B'); + expect(onClose).toHaveBeenCalledTimes(2); + }); +}); + +describe('formatSubagentActivityPreview', () => { + it('renders steps, tool calls and the terminal result as plain text', () => { + const text = formatSubagentActivityPreview( + record({ + status: 'completed', + resultSummary: 'Found 3 call sites.', + totalSteps: 1, + steps: [ + { + step: 0, + textTail: 'Looking around.', + toolCalls: [ + { + id: 't1', + name: 'Grep', + args: { pattern: 'IEventBus', output_mode: 'content' }, + status: 'done', + startedAt: 0, + result: { + tool_call_id: 't1', + output: 'src/a.ts:1:IEventBus\nsrc/b.ts:2:IEventBus', + is_error: false, + }, + }, + { + id: 't2', + name: 'Read', + args: { path: '/repo/src/a.ts' }, + status: 'running', + startedAt: 0, + liveOutputTail: 'reading…', + }, + ], + }, + ], + }), + ); + expect(text).toContain('── step 0 ──'); + expect(text).toContain('Looking around.'); + expect(text).toContain('✓ Used Grep (IEventBus) · 2 matches across 2 files'); + expect(text).toContain('● Using Read (/repo/src/a.ts)'); + expect(text).toContain('│ reading…'); // live tail for the in-flight call + expect(text).toContain('Result:'); + expect(text).toContain('Found 3 call sites.'); + // The preview frame styles whole lines itself — the preview stays ANSI-free. + expect(text).not.toMatch(/\[[0-9;]*m/); + }); + + it('shows the live output tail for a running call', () => { + const text = formatSubagentActivityPreview( + record({ + totalSteps: 1, + steps: [ + { + step: 0, + textTail: '', + toolCalls: [ + { + id: 't1', + name: 'Bash', + args: { command: 'pnpm test' }, + status: 'running', + startedAt: 0, + liveOutputTail: '42 passing', + }, + ], + }, + ], + }), + ); + expect(text).toContain('● Using Bash (pnpm test)'); + expect(text).toContain('│ 42 passing'); + }); + + it('returns a waiting placeholder for a fresh running record', () => { + expect(formatSubagentActivityPreview(record())).toBe('Waiting for activity…'); + }); + + it('returns an empty string for a terminal record without any activity', () => { + expect(formatSubagentActivityPreview(record({ status: 'failed' }))).toBe(''); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/api-key-input-dialog.test.ts b/apps/kimi-code/test/tui/components/dialogs/api-key-input-dialog.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..610ea23e2689eb43adf5430d8965236da14fa8bf --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/api-key-input-dialog.test.ts @@ -0,0 +1,21 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { ApiKeyInputDialogComponent } from '#/tui/components/dialogs/api-key-input-dialog'; + +describe('ApiKeyInputDialogComponent', () => { + it('keeps every line within narrow widths', () => { + const dialog = new ApiKeyInputDialogComponent( + 'Kimi Code', + ['Paste your API key below.', 'It will be stored locally.'], + () => {}, + ); + dialog.focused = true; + + for (const width of [39, 20, 10]) { + for (const line of dialog.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/approval-panel.test.ts b/apps/kimi-code/test/tui/components/dialogs/approval-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..16d031131bfc4c1a96f574bcc13ba7b4358cebe1 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/approval-panel.test.ts @@ -0,0 +1,483 @@ +import { CURSOR_MARKER } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { ApprovalPanelComponent } from '#/tui/components/dialogs/approval-panel'; +import type { + DiffDisplayBlock, + FileContentDisplayBlock, + PendingApproval, +} from '#/tui/reverse-rpc/types'; + +import { captureProcessWrite } from '../../../helpers/process'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function makePending(): PendingApproval { + return { + data: { + id: 'approval_1', + tool_call_id: 'tool_1', + tool_name: 'WriteFile', + action: 'write a file', + description: 'Update README.md', + display: [], + choices: [ + { label: 'Approve once', response: 'approved' }, + { label: 'Approve for this session', response: 'approved_for_session' }, + { label: 'Reject', response: 'rejected' }, + { label: 'Reject with feedback', response: 'rejected', requires_feedback: true }, + ], + }, + }; +} + +function makeDialog(): { + dialog: ApprovalPanelComponent; + responses: Array<{ + response: string; + feedback?: string | undefined; + selected_label?: string | undefined; + }>; +} { + const responses: Array<{ + response: string; + feedback?: string | undefined; + selected_label?: string | undefined; + }> = []; + const dialog = new ApprovalPanelComponent( + makePending(), + (response) => responses.push(response), + ); + return { dialog, responses }; +} + +describe('ApprovalPanelComponent', () => { + it('renders only numeric approval shortcuts in the hint', () => { + const { dialog } = makeDialog(); + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain('1/2/3/4 choose'); + expect(out).not.toContain('y/a/n/f'); + }); + + it('renders choice descriptions beneath the label when present', () => { + const pending: PendingApproval = { + data: { + id: 'approval_goal', + tool_call_id: 'tool_goal', + tool_name: 'CreateGoal', + action: 'Creating a goal', + description: '', + display: [], + choices: [ + { + label: 'Switch to Never Ask and start', + response: 'approved', + selected_label: 'auto', + description: 'Tools are approved automatically, and questions are skipped.', + }, + { label: 'Do not start', response: 'cancelled', selected_label: 'cancel' }, + ], + }, + }; + const out = strip(new ApprovalPanelComponent(pending, () => {}).render(80).join('\n')); + expect(out).toContain('1. Switch to Never Ask and start'); + expect(out).toContain('Tools are approved automatically, and questions are skipped.'); + // A choice without a description stays label-only — no stray blank helper line. + expect(out).toContain('2. Do not start'); + }); + + it('renders dangerous shell warnings with simple copy and no icon', () => { + const pending: PendingApproval = { + data: { + id: 'approval_danger', + tool_call_id: 'tool_danger', + tool_name: 'Bash', + action: 'run', + description: '', + display: [ + { + type: 'shell', + language: 'bash', + command: 'rm -rf /tmp/cache', + danger: 'recursive delete', + }, + ], + choices: [{ label: 'Approve once', response: 'approved' }], + }, + }; + const dialog = new ApprovalPanelComponent(pending, () => {}); + + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain('Dangerous: recursive delete'); + expect(out).not.toContain('potentially destructive'); + expect(out).not.toContain('⚠'); + }); + + it('wraps a long single-line shell command instead of truncating it', () => { + const head = 'approve-long-command-head'; + const tail = 'approve-long-command-tail'; + const command = `printf ${head}_${'x'.repeat(220)}_${tail}`; + const pending: PendingApproval = { + data: { + id: 'approval_long_command', + tool_call_id: 'tool_long_command', + tool_name: 'Bash', + action: 'run', + description: '', + display: [ + { + type: 'shell', + language: 'bash', + command, + }, + ], + choices: [{ label: 'Approve once', response: 'approved' }], + }, + }; + const dialog = new ApprovalPanelComponent(pending, () => {}); + + const rendered = dialog.render(60); + const out = strip(rendered.join('\n')); + expect(rendered.length).toBeGreaterThan(8); + expect(out).toContain(head); + expect(out).toContain(tail); + expect(out).not.toContain('...'); + expect(out).not.toContain('…'); + }); + + it('numeric shortcuts still drive approval actions', () => { + const { dialog, responses } = makeDialog(); + dialog.handleInput('2'); + expect(responses).toEqual([{ response: 'approved_for_session', feedback: undefined }]); + }); + + it('shortcut 4 enters feedback mode and submits the typed feedback', () => { + const { dialog, responses } = makeDialog(); + dialog.handleInput('4'); + dialog.handleInput('n'); + dialog.handleInput('o'); + dialog.handleInput('\r'); + expect(responses).toEqual([{ response: 'rejected', feedback: 'no' }]); + }); + + it('renders feedback input inline with the selected choice', () => { + const { dialog } = makeDialog(); + dialog.handleInput('4'); + + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain('▶ 4. Reject with feedback'); + expect(out).not.toContain('\n > '); + }); + + it('legacy y/a/n/f shortcuts no longer trigger approval actions', () => { + for (const key of ['y', 'a', 'n', 'f']) { + const { dialog, responses } = makeDialog(); + dialog.handleInput(key); + expect(responses).toEqual([]); + } + }); + + it('feedback input supports left/right cursor editing', () => { + const { dialog, responses } = makeDialog(); + dialog.handleInput('4'); + dialog.handleInput('n'); + dialog.handleInput('o'); + dialog.handleInput('\u001B[D'); + dialog.handleInput('!'); + dialog.handleInput('\r'); + expect(responses).toEqual([{ response: 'rejected', feedback: 'n!o' }]); + }); + + it('feedback input keeps editor shortcuts like ctrl+b / ctrl+f', () => { + const { dialog, responses } = makeDialog(); + dialog.handleInput('4'); + dialog.handleInput('a'); + dialog.handleInput('b'); + dialog.handleInput('c'); + dialog.handleInput('\u0002'); + dialog.handleInput('\u0002'); + dialog.handleInput('X'); + dialog.handleInput('\u0006'); + dialog.handleInput('Y'); + dialog.handleInput('\r'); + expect(responses).toEqual([{ response: 'rejected', feedback: 'aXbYc' }]); + }); + + it('renders an IME cursor marker while editing feedback', () => { + const { dialog } = makeDialog(); + dialog.focused = true; + dialog.handleInput('4'); + + const out = dialog.render(80).join('\n'); + expect(out).toContain(CURSOR_MARKER); + }); + + it.each(['\u0003', '\u0004', '\u001B'])( + 'shortcut %j rejects approval immediately', + (key) => { + const { dialog, responses } = makeDialog(); + dialog.handleInput(key); + expect(responses).toEqual([{ response: 'rejected' }]); + }, + ); + + it('renders ExitPlanMode with plan-specific header and plan-review choices', () => { + const pending: PendingApproval = { + data: { + id: 'approval_plan', + tool_call_id: 'tool_plan', + tool_name: 'ExitPlanMode', + action: 'review plan', + description: '', + display: [], + choices: [ + { label: 'Approve', response: 'approved' }, + { label: 'Reject', response: 'rejected' }, + { label: 'Revise', response: 'rejected', requires_feedback: true }, + ], + }, + }; + const dialog = new ApprovalPanelComponent(pending, () => {}); + + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain('Ready to build with this plan?'); + expect(out).not.toContain('Approve ExitPlanMode?'); + expect(out).toContain('Approve'); + expect(out).toContain('Reject'); + expect(out).toContain('Revise'); + expect(out).not.toContain('Approve for this session'); + expect(out).not.toContain('Investigate'); + }); + + // Inline expand-in-place used to inflate the panel past the viewport on + // any non-trivial Edit, which then collided with pi-tui's inline scroll + // and made the terminal flicker / refuse to scroll. The panel now always + // renders the diff in its compact cluster form; ctrl+e instead asks the + // host to open a dedicated full-screen preview that can manage its own + // scrolling. + it('renders an Edit diff in compact form and asks the host to open a preview on ctrl+e', () => { + const responses: Array<{ response: string }> = []; + const oldLines: string[] = []; + const newLines: string[] = []; + for (let i = 1; i <= 30; i++) { + oldLines.push(`old${String(i)}`); + newLines.push(`new${String(i)}`); + } + const diffBlock: DiffDisplayBlock = { + type: 'diff', + path: 'src/foo.ts', + old_text: oldLines.join('\n'), + new_text: newLines.join('\n'), + }; + const pending: PendingApproval = { + data: { + id: 'approval_diff', + tool_call_id: 'tool_diff', + tool_name: 'Edit', + action: 'edit', + description: '', + display: [diffBlock], + choices: [{ label: 'Approve once', response: 'approved' }], + }, + }; + let toolOutputToggles = 0; + const previewCalls: Array = []; + const dialog = new ApprovalPanelComponent( + pending, + (r) => responses.push(r), + () => toolOutputToggles++, + (block) => previewCalls.push(block), + ); + + const before = strip(dialog.render(120).join('\n')); + expect(before).toContain('+30'); + expect(before).toContain('-30'); + expect(before).toContain('ctrl+e preview'); + expect(before).not.toContain('new30'); // compact view stays compact + + dialog.handleInput('\u0005'); // Ctrl+E + + // The panel itself does not expand; it delegates to the host. + const after = strip(dialog.render(120).join('\n')); + expect(after).not.toContain('new30'); + expect(after).toContain('ctrl+e preview'); + expect(previewCalls).toEqual([diffBlock]); + // The unrelated forward-only callback must not fire for ctrl+e. + expect(toolOutputToggles).toBe(0); + expect(responses).toEqual([]); + }); + + it('forwards ctrl+o to the global tool-output toggle without affecting the panel', () => { + const pending: PendingApproval = { + data: { + id: 'approval_forward', + tool_call_id: 'tool_forward', + tool_name: 'Edit', + action: 'edit', + description: '', + display: [ + { + type: 'diff', + path: 'src/foo.ts', + old_text: Array.from({ length: 30 }, (_, i) => `old${String(i + 1)}`).join('\n'), + new_text: Array.from({ length: 30 }, (_, i) => `new${String(i + 1)}`).join('\n'), + }, + ], + choices: [{ label: 'Approve once', response: 'approved' }], + }, + }; + let globalToggleCalls = 0; + const dialog = new ApprovalPanelComponent(pending, () => {}, () => globalToggleCalls++); + + dialog.handleInput('\u000F'); // Ctrl+O + + const after = strip(dialog.render(120).join('\n')); + expect(globalToggleCalls).toBe(1); + expect(after).toContain('ctrl+e preview'); + expect(after).not.toContain('new30'); + }); + + it('does nothing on ctrl+e when there is nothing to preview', () => { + const pending: PendingApproval = { + data: { + id: 'approval_plan_only', + tool_call_id: 'tool_plan_only', + tool_name: 'ExitPlanMode', + action: 'review plan', + description: '', + display: [], + choices: [{ label: 'Approve', response: 'approved' }], + }, + }; + const previewCalls: Array = []; + const dialog = new ApprovalPanelComponent( + pending, + () => {}, + undefined, + (block) => previewCalls.push(block), + ); + + dialog.handleInput('\u0005'); // Ctrl+E + expect(previewCalls).toEqual([]); + }); + + it('renders Write as a syntax-highlighted code block (file_content), not a diff', () => { + const responses: Array<{ response: string }> = []; + const lines: string[] = []; + for (let i = 1; i <= 30; i++) lines.push(`const x${String(i)} = ${String(i)};`); + const contentBlock: FileContentDisplayBlock = { + type: 'file_content', + path: 'src/new.ts', + content: lines.join('\n'), + }; + const pending: PendingApproval = { + data: { + id: 'approval_write', + tool_call_id: 'tool_write', + tool_name: 'Write', + action: 'write', + description: '', + display: [contentBlock], + choices: [{ label: 'Approve once', response: 'approved' }], + }, + }; + const previewCalls: Array = []; + const dialog = new ApprovalPanelComponent( + pending, + (r) => responses.push(r), + undefined, + (block) => previewCalls.push(block), + ); + + const collapsed = strip(dialog.render(120).join('\n')); + // No diff markers, no +N -M header. + expect(collapsed).not.toMatch(/^\s*\+\d+/m); + expect(collapsed).not.toMatch(/^\s*-\d+/m); + expect(collapsed).toContain('src/new.ts'); + expect(collapsed).toContain('const x1 = 1;'); + expect(collapsed).toContain('const x10 = 10;'); + expect(collapsed).not.toContain('const x25 = 25;'); + expect(collapsed).toContain('20 more lines hidden (ctrl+e to preview)'); + expect(collapsed).toContain('ctrl+e preview'); + + dialog.handleInput('\u0005'); // Ctrl+E hands off to the host preview. + const after = strip(dialog.render(120).join('\n')); + // The panel itself stays compact; the full content is opened elsewhere. + expect(after).not.toContain('const x30 = 30;'); + expect(previewCalls).toEqual([contentBlock]); + expect(responses).toEqual([]); + }); + + it('renders unknown file_content extensions as plain text without stderr noise', () => { + const pending: PendingApproval = { + data: { + id: 'approval_unknown_write', + tool_call_id: 'tool_unknown_write', + tool_name: 'Write', + action: 'write', + description: '', + display: [{ type: 'file_content', path: 'demo.abcxyz', content: 'hello\nworld' }], + choices: [{ label: 'Approve once', response: 'approved' }], + }, + }; + const stderr = captureProcessWrite('stderr'); + try { + const previewCalls: Array = []; + const dialog = new ApprovalPanelComponent( + pending, + () => {}, + undefined, + (block) => previewCalls.push(block), + ); + const collapsed = strip(dialog.render(120).join('\n')); + expect(collapsed).toContain('hello'); + + dialog.handleInput('\u0005'); // Ctrl+E + expect(previewCalls).toHaveLength(1); + expect(stderr.text()).not.toContain('Could not find the language'); + } finally { + stderr.restore(); + } + }); + + it('returns feedback for plan-review revise choice', () => { + const responses: Array<{ + response: string; + feedback?: string | undefined; + selected_label?: string | undefined; + }> = []; + const pending: PendingApproval = { + data: { + id: 'approval_plan', + tool_call_id: 'tool_plan', + tool_name: 'ExitPlanMode', + action: 'review plan', + description: '', + display: [], + choices: [ + { label: 'Approve', response: 'approved' }, + { + label: 'Revise', + response: 'rejected', + selected_label: 'Revise', + requires_feedback: true, + }, + ], + }, + }; + const dialog = new ApprovalPanelComponent( + pending, + (response) => responses.push(response), + ); + + dialog.handleInput('2'); + dialog.handleInput('n'); + dialog.handleInput('o'); + dialog.handleInput('\r'); + expect(responses).toEqual([ + { response: 'rejected', feedback: 'no', selected_label: 'Revise' }, + ]); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/approval-preview.test.ts b/apps/kimi-code/test/tui/components/dialogs/approval-preview.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..316b5f89d842ab22b01b6830e9a859486df113ba --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/approval-preview.test.ts @@ -0,0 +1,171 @@ +import type { Terminal } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { + ApprovalPreviewViewer, + type ApprovalPreviewBlock, +} from '#/tui/components/dialogs/approval-preview'; +const ANSI_SGR = /\[[0-9;]*m/g; +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function fakeTerminal(rows: number, columns = 120): Terminal { + return { + start: () => {}, + stop: () => {}, + drainInput: () => Promise.resolve(), + write: () => {}, + get columns() { + return columns; + }, + get rows() { + return rows; + }, + get kittyProtocolActive() { + return false; + }, + moveBy: () => {}, + hideCursor: () => {}, + showCursor: () => {}, + clearLine: () => {}, + clearFromCursor: () => {}, + clearScreen: () => {}, + setTitle: () => {}, + setProgress: () => {}, + }; +} + +function makeViewer(opts: { + block: ApprovalPreviewBlock; + rows?: number; + columns?: number; + onClose?: () => void; +}): ApprovalPreviewViewer { + return new ApprovalPreviewViewer( + { + block: opts.block, + onClose: opts.onClose ?? (() => {}), + }, + fakeTerminal(opts.rows ?? 24, opts.columns ?? 100), + ); +} + +describe('ApprovalPreviewViewer', () => { + it('fills exactly terminal.rows lines', () => { + const lines: string[] = []; + for (let i = 1; i <= 50; i++) lines.push(`line ${String(i)}`); + const viewer = makeViewer({ + block: { type: 'file_content', path: 'src/big.ts', content: lines.join('\n') }, + rows: 24, + }); + expect(viewer.render(100).length).toBe(24); + }); + + // The whole point of the viewer: a long Write file content stays accessible + // by paging, not by inflating the approval panel inline. + it('reveals later lines of a long file_content after PageDown', () => { + const lines: string[] = []; + for (let i = 1; i <= 200; i++) lines.push(`row-${String(i)}`); + const viewer = makeViewer({ + block: { type: 'file_content', path: 'src/big.ts', content: lines.join('\n') }, + rows: 24, + }); + + const initial = strip(viewer.render(100).join('\n')); + expect(initial).toContain('row-1'); + expect(initial).not.toContain('row-150'); + + viewer.handleInput('[6~'); // PageDown + viewer.handleInput('[6~'); + viewer.handleInput('[6~'); + + const scrolled = strip(viewer.render(100).join('\n')); + expect(scrolled).not.toContain('row-1\n'); // start of file is gone + expect(scrolled).toMatch(/row-\d{2,}/); + }); + + it('scrolls to the end with G and back to the top with g', () => { + const lines: string[] = []; + for (let i = 1; i <= 100; i++) lines.push(`L${String(i)}`); + const viewer = makeViewer({ + block: { type: 'file_content', path: 'src/x.ts', content: lines.join('\n') }, + rows: 20, + }); + + viewer.handleInput('G'); + const atEnd = strip(viewer.render(100).join('\n')); + expect(atEnd).toContain('L100'); + + viewer.handleInput('g'); + const atTop = strip(viewer.render(100).join('\n')); + expect(atTop).toContain('L1'); + expect(atTop).not.toContain('L100'); + }); + + // Both esc and ctrl+e close — ctrl+e is the same key that opened the + // viewer, so making it a toggle keeps the muscle memory simple. + it.each([ + ['escape', ''], + ['ctrl+e', ''], + ['q', 'q'], + ])('%s closes the viewer', (_label, key) => { + let closed = 0; + const viewer = makeViewer({ + block: { type: 'file_content', path: 'a.ts', content: 'x' }, + onClose: () => closed++, + }); + viewer.handleInput(key); + expect(closed).toBe(1); + }); + + it('renders a diff block with +N -M header and both sides of the hunk', () => { + const viewer = makeViewer({ + block: { + type: 'diff', + path: 'src/foo.ts', + old_text: 'alpha\nbeta\ngamma', + new_text: 'alpha\nBETA\ngamma', + }, + rows: 24, + }); + + const text = strip(viewer.render(100).join('\n')); + expect(text).toContain('src/foo.ts'); + expect(text).toContain('+1'); + expect(text).toContain('-1'); + expect(text).toContain('beta'); + expect(text).toContain('BETA'); + }); + + it('shows surrounding context lines for a diff block', () => { + const viewer = makeViewer({ + block: { + type: 'diff', + path: 'src/foo.ts', + old_text: ['before1', 'before2', 'old', 'after1', 'after2'].join('\n'), + new_text: ['before1', 'before2', 'new', 'after1', 'after2'].join('\n'), + }, + rows: 24, + }); + + const text = strip(viewer.render(100).join('\n')); + expect(text).toContain('before1'); + expect(text).toContain('before2'); + expect(text).toContain('old'); + expect(text).toContain('new'); + expect(text).toContain('after1'); + expect(text).toContain('after2'); + }); + + // Sanity: rendering is a pure slice — repeated render() calls without + // input changes produce the same output, no incremental state drift. + it('renders deterministically across repeated calls', () => { + const viewer = makeViewer({ + block: { type: 'file_content', path: 'a.ts', content: 'one\ntwo\nthree' }, + }); + const first = viewer.render(80).join('\n'); + const second = viewer.render(80).join('\n'); + expect(first).toBe(second); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/cache-hint-dialog.test.ts b/apps/kimi-code/test/tui/components/dialogs/cache-hint-dialog.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f33c9d17ddb846f6a6ab9ee50a665c0b263ee3d --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/cache-hint-dialog.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { CacheHintDialogComponent } from '#/tui/components/dialogs/cache-hint-dialog'; + +const ANSI_SGR = /\[[0-9;]*m/g; + +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function renderDialog(idleSeconds = (26 * 24 + 22) * 3600, totalTokens = 293000) { + const onSelect = vi.fn(); + const onCancel = vi.fn(); + const dialog = new CacheHintDialogComponent({ idleSeconds, totalTokens, onSelect, onCancel }); + return { dialog, onSelect, onCancel, lines: dialog.render(120).map(strip) }; +} + +describe('CacheHintDialogComponent', () => { + it('renders the title with idle duration and token count', () => { + const { lines } = renderDialog(); + expect( + lines.some((l) => l.includes('This session has been idle for 26d 22h and is ~286k tokens.')), + ).toBe(true); + }); + + it('renders the body line and the standard hint vocabulary', () => { + const { lines } = renderDialog(); + expect( + lines.some((l) => + l.includes('Cache expired — the next message re-sends the entire history at full price.'), + ), + ).toBe(true); + const titleIdx = lines.findIndex((l) => l.includes('This session has been idle')); + expect(lines[titleIdx + 1]).toContain('↑↓ navigate'); + expect(lines[titleIdx + 1]).toContain('Enter select'); + expect(lines[titleIdx + 1]).toContain('Esc cancel'); + }); + + it('renders all four options in order with right-column descriptions', () => { + const { lines } = renderDialog(); + const compact = lines.findIndex((l) => l.includes('Compact and continue')); + const fresh = lines.findIndex((l) => l.includes('Start a new session')); + const asIs = lines.findIndex((l) => l.includes('Continue as-is')); + const never = lines.findIndex((l) => l.includes("Don't ask me again")); + + expect(compact).toBeGreaterThanOrEqual(0); + expect(compact).toBeLessThan(fresh); + expect(fresh).toBeLessThan(asIs); + expect(asIs).toBeLessThan(never); + expect(lines[compact]).toContain('one-time compact cost · cheapest way to keep this topic'); + expect(lines[fresh]).toContain('zero context cost · best for a new task'); + expect(lines[asIs]).toContain('full history kept · highest cost per turn'); + }); + + it('aligns description columns across options', () => { + const { lines } = renderDialog(); + const colOf = (labelNeedle: string, descNeedle: string) => { + const line = lines.find((l) => l.includes(labelNeedle)); + expect(line).toBeDefined(); + return line!.indexOf(descNeedle); + }; + const reference = colOf('Compact and continue', 'one-time compact cost'); + expect(colOf('Start a new session', 'zero context cost')).toBe(reference); + expect(colOf('Continue as-is', 'full history kept')).toBe(reference); + }); + + it('selects the highlighted option on Enter, compact by default', () => { + const { dialog, onSelect } = renderDialog(); + dialog.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith('compact'); + }); + + it('navigates with arrows before selecting', () => { + const { dialog, onSelect } = renderDialog(); + dialog.handleInput('\u001B[B'); // down + dialog.handleInput('\u001B[B'); // down + dialog.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith('continue'); + }); + + it('cancels on Esc without selecting', () => { + const { dialog, onSelect, onCancel } = renderDialog(); + dialog.handleInput('\u001B'); + expect(onCancel).toHaveBeenCalled(); + expect(onSelect).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/choice-picker.test.ts b/apps/kimi-code/test/tui/components/dialogs/choice-picker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0fac1c1ec1bdf994c0ef6ff3d40b4e7b5a1a9a8 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/choice-picker.test.ts @@ -0,0 +1,182 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { ChoicePickerComponent, type ChoiceOption } from '#/tui/components/dialogs/choice-picker'; +import { EditorSelectorComponent } from '#/tui/components/dialogs/editor-selector'; +import { PermissionSelectorComponent } from '#/tui/components/dialogs/permission-selector'; +import { SettingsSelectorComponent } from '#/tui/components/dialogs/settings-selector'; +import { ThemeSelectorComponent } from '#/tui/components/dialogs/theme-selector'; +import { UpdatePreferenceSelectorComponent } from '#/tui/components/dialogs/update-preference-selector'; +import { currentTheme } from '#/tui/theme'; +import { darkColors } from '#/tui/theme/colors'; + +const ANSI_SGR = /\[[0-9;]*m/g; + +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +describe('ChoicePickerComponent', () => { + it('uses the model-dialog header vocabulary (capitalized keys, "type to search")', () => { + const picker = new ChoicePickerComponent({ + title: 'Add provider', + options: [ + { value: 'a', label: 'Alpha' }, + { value: 'b', label: 'Beta' }, + ], + searchable: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const lines = picker.render(120).map(strip); + + const titleIdx = lines.findIndex((l) => l.includes('Add provider')); + expect(titleIdx).toBeGreaterThanOrEqual(0); + // Title carries the same "(type to search)" suffix as /model and /provider. + expect(lines[titleIdx]).toContain('(type to search)'); + expect(lines[titleIdx]).not.toContain('type to filter'); + // Hint sits directly under the title and uses lowercase key vocabulary. + const hint = lines[titleIdx + 1]; + expect(hint).toContain('↑↓ navigate'); + expect(hint).toContain('Enter select'); + expect(hint).toContain('Esc cancel'); + expect(hint).not.toContain('enter select'); + expect(hint).not.toContain('esc cancel'); + // Blank line separates the hint from the body, like the model dialog. + expect(lines[titleIdx + 2]).toBe(''); + }); + + it('renders optional descriptions below choice labels', () => { + const picker = new ChoicePickerComponent({ + title: 'Select permission mode', + options: [ + { + value: 'manual', + label: 'Manual', + description: 'Ask before commands, edits, and other risky actions.', + }, + { + value: 'auto', + label: 'Auto', + description: 'Automatically approve tool actions and plan transitions.', + }, + ], + currentValue: 'manual', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const out = picker.render(120).map(strip); + + expect(out).toContain(' ❯ Manual ← current'); + expect(out).toContain(' Ask before commands, edits, and other risky actions.'); + expect(out).toContain(' Automatically approve tool actions and plan transitions.'); + }); + + it('renders domain selector wrappers with their configured options', () => { + const onSelect = vi.fn(); + const onCancel = vi.fn(); + + const editor = new EditorSelectorComponent({ + currentValue: 'vim', + onSelect, + onCancel, + }); + expect(editor.render(120).map(strip)).toContain(' ❯ Vim ← current'); + + const theme = new ThemeSelectorComponent({ + currentValue: 'light', + onSelect, + onCancel, + }); + expect(theme.render(120).map(strip)).toContain(' ❯ Light ← current'); + + const permission = new PermissionSelectorComponent({ + currentValue: 'manual', + initialValue: 'yolo', + onSelect, + onCancel, + }); + const permissionOutput = permission.render(120).map(strip); + expect(permissionOutput).toContain(' ❯ Ask When Needed'); + expect(permissionOutput).toContain(' Always Ask ← current'); + + const settings = new SettingsSelectorComponent({ + onSelect, + onCancel, + }); + const settingsOutput = settings.render(120).map(strip); + expect(settingsOutput).toContain(' ❯ Model'); + expect(settingsOutput).toContain(' Switch the active model and thinking mode.'); + expect(settingsOutput).toContain(' Turn automatic CLI updates on or off.'); + + const upgradePreference = new UpdatePreferenceSelectorComponent({ + currentValue: true, + onSelect, + onCancel, + }); + const upgradePreferenceOutput = upgradePreference.render(120).map(strip); + expect(upgradePreferenceOutput).toContain(' ❯ On ← current'); + expect(upgradePreferenceOutput).toContain(' Install new versions in the background.'); + }); + + it('routes Space into the query for searchable lists instead of selecting', () => { + const onSelect = vi.fn(); + const picker = new ChoicePickerComponent({ + title: 'Select a provider', + options: [ + { value: 'openai', label: 'OpenAI' }, + { value: 'azure', label: 'Azure OpenAI' }, + ], + searchable: true, + onSelect, + onCancel: vi.fn(), + }); + + picker.handleInput(' '); + expect(onSelect).not.toHaveBeenCalled(); + }); + + it('selects on Space when the list is not searchable', () => { + const onSelect = vi.fn(); + const picker = new ChoicePickerComponent({ + title: 'Pick one', + options: [{ value: 'a', label: 'Alpha' }], + onSelect, + onCancel: vi.fn(), + }); + + picker.handleInput(' '); + expect(onSelect).toHaveBeenCalledWith('a'); + }); + + it('renders the selected option description in descriptionTone, others in textMuted', () => { + const options: ChoiceOption[] = [ + { value: 'none', label: 'No attachment', description: 'Text feedback only' }, + { + value: 'logs+codebase', + label: 'Logs + codebase', + description: 'Include your codebase for deeper diagnosis.', + descriptionTone: 'warning', + }, + ]; + + const renderDescLine = (currentValue: string): string | undefined => { + const picker = new ChoicePickerComponent({ + title: 'Share diagnostic info?', + options, + currentValue, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + return picker.render(120).find((line) => strip(line).includes('Include your codebase')); + }; + + const warningLine = currentTheme.fg('warning', ' Include your codebase for deeper diagnosis.'); + const mutedLine = currentTheme.fg('textMuted', ' Include your codebase for deeper diagnosis.'); + + // Selected option: description uses the configured tone. + expect(renderDescLine('logs+codebase')).toBe(warningLine); + // Unselected option: description falls back to textMuted. + expect(renderDescLine('none')).toBe(mutedLine); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/compaction.test.ts b/apps/kimi-code/test/tui/components/dialogs/compaction.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb213cfa2a0423ef3695426f94814e16bb553ea4 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/compaction.test.ts @@ -0,0 +1,178 @@ +import chalk from 'chalk'; +import { afterEach, describe, expect, it } from 'vitest'; + +import { CompactionComponent } from '#/tui/components/dialogs/compaction'; +import { currentTheme, darkColors, lightColors } from '#/tui/theme'; + +afterEach(() => { + currentTheme.setPalette(darkColors); +}); + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('CompactionComponent', () => { + it('renders the custom instruction below the compacting label', () => { + const component = new CompactionComponent(undefined, 'keep the recent files only'); + + try { + const lines = component.render(120).map(strip); + const text = lines.join('\n'); + + expect(text).toContain('Compacting context…'); + expect(text).toContain(' keep the recent files only'); + } finally { + component.dispose(); + } + }); + + it('renders a tip suffix while compacting', () => { + const component = new CompactionComponent(undefined, undefined, 'ctrl+s: steer mid-turn'); + + try { + const lines = component.render(120).map(strip); + const text = lines.join('\n'); + + expect(text).toContain('Compacting context… · Tip: ctrl+s: steer mid-turn'); + } finally { + component.dispose(); + } + }); + + it('does not render a tip after compaction completes', () => { + const component = new CompactionComponent(undefined, undefined, 'ctrl+s: steer mid-turn'); + + try { + component.markDone(1000, 500); + const lines = component.render(120).map(strip); + const text = lines.join('\n'); + + expect(text).toContain('Compaction complete'); + expect(text).not.toContain('Tip:'); + expect(text).not.toContain('Ctrl-O'); + } finally { + component.dispose(); + } + }); + + it('renders a cancelled terminal state', () => { + const component = new CompactionComponent(); + + try { + component.markCanceled(); + const lines = component.render(120).map(strip); + const text = lines.join('\n'); + + expect(text).toContain('Compaction cancelled'); + expect(text).not.toContain('Compacting context…'); + } finally { + component.dispose(); + } + }); + + it('keeps the completed compaction summary hidden until expanded', () => { + const component = new CompactionComponent(); + + try { + component.markDone(120, 24, 'Keep the src/tui compaction notes.'); + const collapsed = component.render(120).map(strip).join('\n'); + + expect(collapsed).toContain('Compaction complete'); + expect(collapsed).toContain('120 → 24 tokens'); + expect(collapsed).toContain('Ctrl-O to show compaction summary'); + expect(collapsed).not.toContain('Keep the src/tui compaction notes.'); + + component.setExpanded(true); + const expanded = component.render(120).map(strip).join('\n'); + + expect(expanded).toContain('Compaction complete'); + expect(expanded).toContain('Ctrl-O to hide compaction summary'); + expect(expanded).toContain('Keep the src/tui compaction notes.'); + } finally { + component.dispose(); + } + }); + + it('hides the compaction summary again when collapsed', () => { + const component = new CompactionComponent(); + + try { + component.markDone(120, 24, 'Keep the src/tui compaction notes.'); + component.setExpanded(true); + component.setExpanded(false); + const text = component.render(120).map(strip).join('\n'); + + expect(text).toContain('Compaction complete'); + expect(text).toContain('Ctrl-O to show compaction summary'); + expect(text).not.toContain('Ctrl-O to hide compaction summary'); + expect(text).not.toContain('Keep the src/tui compaction notes.'); + } finally { + component.dispose(); + } + }); + + it('preserves the expanded summary when invalidating with an instruction', () => { + const component = new CompactionComponent(undefined, 'keep the recent files only'); + + try { + component.markDone(120, 24, 'Keep the src/tui compaction notes.'); + component.setExpanded(true); + component.invalidate(); + const text = component.render(120).map(strip).join('\n'); + + expect(text).toContain('keep the recent files only'); + expect(text).toContain('Keep the src/tui compaction notes.'); + expect(text.match(/keep the recent files only/g)).toHaveLength(1); + } finally { + component.dispose(); + } + }); + + it('keeps expanded summary child order on invalidate', () => { + const component = new CompactionComponent(undefined, 'keep the recent files only'); + + try { + component.markDone(120, 24, 'Keep the src/tui compaction notes.'); + component.setExpanded(true); + currentTheme.setPalette(lightColors); + component.invalidate(); + const text = component.render(120).map(strip).join('\n'); + + expect(text).toContain('Keep the src/tui compaction notes.'); + expect(text.indexOf('keep the recent files only')).toBeLessThan( + text.indexOf('Keep the src/tui compaction notes.'), + ); + } finally { + component.dispose(); + } + }); + + it('repaints the header with the active palette on invalidate', () => { + // Force truecolor so palette differences surface as ANSI codes even when + // the test runner has no TTY. + const previousLevel = chalk.level; + chalk.level = 3; + const component = new CompactionComponent(); + + try { + const headerOf = (): string => { + const line = component.render(120).find((l) => strip(l).includes('Compacting context…')); + if (line === undefined) throw new Error('header line not found'); + return line; + }; + const before = headerOf(); + + currentTheme.setPalette(lightColors); + component.invalidate(); + const after = headerOf(); + + // Same visible text, different ANSI colour codes. + expect(strip(after)).toBe(strip(before)); + expect(after).not.toBe(before); + } finally { + chalk.level = previousLevel; + component.dispose(); + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/custom-registry-import.test.ts b/apps/kimi-code/test/tui/components/dialogs/custom-registry-import.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..68c79974d9fc6004d59a37df412b586fdb204b92 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/custom-registry-import.test.ts @@ -0,0 +1,81 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it, vi } from 'vitest'; + +import { + CustomRegistryImportDialogComponent, + type CustomRegistryImportResult, +} from '#/tui/components/dialogs/custom-registry-import'; +import { darkColors } from '#/tui/theme/colors'; + +const ANSI = /\[[0-9;]*m/g; +const strip = (s: string): string => s.replaceAll(ANSI, ''); +const ESC = String.fromCodePoint(27); +const DOWN = `${ESC}[B`; +const UP = `${ESC}[A`; + +function plain(component: CustomRegistryImportDialogComponent, width = 80): string { + return component.render(width).map(strip).join('\n'); +} + +function makeDialog(defaultUrl = 'https://example.com/api.json'): { + dialog: CustomRegistryImportDialogComponent; + onDone: ReturnType; +} { + const onDone = vi.fn(); + const dialog = new CustomRegistryImportDialogComponent( + onDone as unknown as (r: CustomRegistryImportResult) => void, + defaultUrl, + ); + dialog.focused = true; + return { dialog, onDone }; +} + +describe('CustomRegistryImportDialogComponent', () => { + it('advances from the URL field to the token field on Enter instead of submitting', () => { + const { dialog, onDone } = makeDialog(); + expect(plain(dialog)).toContain('next field'); + + dialog.handleInput('\r'); + + expect(onDone).not.toHaveBeenCalled(); + expect(plain(dialog)).toContain('Enter to submit'); + }); + + it('switches fields with Up / Down arrows', () => { + const { dialog } = makeDialog(); + dialog.handleInput(DOWN); + expect(plain(dialog)).toContain('Enter to submit'); + dialog.handleInput(UP); + expect(plain(dialog)).toContain('next field'); + }); + + it('requires a non-empty Bearer token before submitting', () => { + const { dialog, onDone } = makeDialog(); + dialog.handleInput('\r'); // url -> token + dialog.handleInput('\r'); // attempt submit with an empty token + expect(onDone).not.toHaveBeenCalled(); + expect(plain(dialog)).toContain('Bearer token cannot be empty'); + }); + + it('submits the url and token once both are provided', () => { + const { dialog, onDone } = makeDialog(); + dialog.handleInput('\r'); // url -> token + for (const ch of 'sk-tok') dialog.handleInput(ch); + dialog.handleInput('\r'); // submit from the token field + + expect(onDone).toHaveBeenCalledWith({ + kind: 'ok', + value: { url: 'https://example.com/api.json', apiKey: 'sk-tok' }, + }); + }); + + it('keeps every line within narrow widths', () => { + const { dialog } = makeDialog('https://example.com/very/long/registry/path.json'); + + for (const width of [39, 35, 20, 10]) { + for (const line of dialog.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/effort-selector.test.ts b/apps/kimi-code/test/tui/components/dialogs/effort-selector.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..53ff5b17028beccc77107f048595439716e126d7 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/effort-selector.test.ts @@ -0,0 +1,151 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { EffortSelectorComponent } from '#/tui/components/dialogs/effort-selector'; + +const ANSI = /\[[0-9;]*m/g; +const strip = (s: string): string => s.replaceAll(ANSI, ''); +const ESC = String.fromCodePoint(27); +const LEFT = `${ESC}[D`; +const RIGHT = `${ESC}[C`; + +function text(component: EffortSelectorComponent, width = 120): string { + return component.render(width).map(strip).join('\n'); +} + +describe('EffortSelectorComponent', () => { + it('renders efforts as horizontal segments with the active one bracketed', () => { + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const out = text(picker); + // All efforts are rendered on a single row. + expect(out).toContain('Off'); + expect(out).toContain('Low'); + expect(out).toContain('High'); + expect(out).toContain('Max'); + // The active level is wrapped in brackets; the rest are not. + expect(out).toContain('[ High ]'); + expect(out).not.toContain('[ Off ]'); + expect(out).not.toContain('[ Max ]'); + }); + + it('invokes onSelect with the chosen effort on Enter', () => { + const onSelect = vi.fn(); + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + onSelect, + onCancel: vi.fn(), + }); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith('high'); + }); + + it('moves the active segment with Left/Right and stops at the edges', () => { + const onSelect = vi.fn(); + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + onSelect, + onCancel: vi.fn(), + }); + + // index 2 (high) -> 3 (max). + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith('max'); + + // Already at the right edge — another Right stays put. + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith('max'); + + // Walk back to the left edge (max -> high -> low -> off). + picker.handleInput(LEFT); + picker.handleInput(LEFT); + picker.handleInput(LEFT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith('off'); + + // Already at the left edge — another Left stays put. + picker.handleInput(LEFT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith('off'); + }); + + it('invokes onSessionOnlySelect on Alt+S instead of onSelect', () => { + const onSelect = vi.fn(); + const onSessionOnlySelect = vi.fn(); + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + onSelect, + onSessionOnlySelect, + onCancel: vi.fn(), + }); + picker.handleInput(`${ESC}s`); + expect(onSessionOnlySelect).toHaveBeenCalledWith('high'); + expect(onSelect).not.toHaveBeenCalled(); + }); + + it('cancels on Escape', () => { + const onCancel = vi.fn(); + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + onSelect: vi.fn(), + onCancel, + }); + picker.handleInput(ESC); + expect(onCancel).toHaveBeenCalledTimes(1); + }); + + it('renders the warning line directly below the key-hint line when provided', () => { + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + warning: 'Switching may increase token usage.', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const lines = picker.render(120).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('←→ switch')); + expect(hintIdx).toBeGreaterThanOrEqual(0); + expect(lines[hintIdx + 1]).toContain('Switching may increase token usage.'); + }); + + it('renders no warning line without the warning option', () => { + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const lines = picker.render(120).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('←→ switch')); + expect(hintIdx).toBeGreaterThanOrEqual(0); + expect(lines[hintIdx + 1]).toBe(''); + }); + + it('wraps a warning longer than the width instead of truncating it', () => { + const warning = + 'Note: Switching effort invalidates the existing prompt cache. Use /new to avoid extra token costs.'; + const picker = new EffortSelectorComponent({ + efforts: ['off', 'low', 'high', 'max'], + currentValue: 'high', + warning, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const lines = picker.render(40).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('←→ switch')); + expect(lines[hintIdx + 1]).not.toBe(''); + expect(lines[hintIdx + 2]).not.toBe(''); + // Word-wrapped: nothing dropped — the full warning survives across lines. + const squashed = lines.join('').replaceAll(/\s+/g, ''); + expect(squashed).toContain(warning.replaceAll(/\s+/g, '')); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/experiments-selector.test.ts b/apps/kimi-code/test/tui/components/dialogs/experiments-selector.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f80c3a3da0152d6c124856b3ea4cbf7190ef19aa --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/experiments-selector.test.ts @@ -0,0 +1,123 @@ +import type { ExperimentalFeatureState } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import { + ExperimentsSelectorComponent, + type ExperimentalFeatureDraftChange, +} from '#/tui/components/dialogs/experiments-selector'; + + +const ANSI = /\u001B\[[0-9;]*m/g; +const ESC = String.fromCodePoint(27); +const ENTER = '\r'; + +function strip(text: string): string { + return text.replaceAll(ANSI, ''); +} + +function feature( + overrides: Partial = {}, +): ExperimentalFeatureState { + return { + id: 'micro_compaction', + title: 'Micro compaction', + description: 'Trim older tool results.', + surface: 'core', + env: 'KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION', + defaultEnabled: true, + enabled: true, + source: 'default', + ...overrides, + }; +} + +function text(component: ExperimentsSelectorComponent, width = 120): string { + return component.render(width).map(strip).join('\n'); +} + +describe('ExperimentsSelectorComponent', () => { + it('renders searchable feature toggles with source details', () => { + const selector = new ExperimentsSelectorComponent({ + features: [ + feature({ enabled: true, source: 'config', configValue: true }), + ], + onApply: vi.fn(), + onCancel: vi.fn(), + }); + + const out = text(selector); + + expect(out).toContain(' Experimental features (type to search)'); + expect(out).toContain(' ↑↓ navigate · Space toggle · Enter apply · Esc cancel'); + expect(out).toContain(' ❯ Micro compaction enabled'); + expect(out).toContain(' id micro_compaction · config · KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION'); + expect(out).toContain(' Trim older tool results.'); + expect(out).toContain(' [ Apply changes and reload ] no changes'); + }); + + it('drafts changes with Space and applies them with Enter', () => { + const onApply = vi.fn<(changes: readonly ExperimentalFeatureDraftChange[]) => void>(); + const first = feature(); + const selector = new ExperimentsSelectorComponent({ + features: [first], + onApply, + onCancel: vi.fn(), + }); + + selector.handleInput(' '); + + expect(onApply).not.toHaveBeenCalled(); + expect(text(selector)).toContain(' ❯ Micro compaction disabled'); + expect(text(selector)).toContain( + ' id micro_compaction · default · KIMI_CODE_EXPERIMENTAL_MICRO_COMPACTION · modified', + ); + expect(text(selector)).toContain(' [ Apply changes and reload ] 1 change'); + + selector.handleInput(ENTER); + + expect(onApply).toHaveBeenCalledWith([ + { id: 'micro_compaction', enabled: false }, + ]); + }); + + it('does not draft changes for env-locked features', () => { + const onApply = vi.fn<(changes: readonly ExperimentalFeatureDraftChange[]) => void>(); + const selector = new ExperimentsSelectorComponent({ + features: [ + feature({ + enabled: true, + source: 'env', + }), + ], + onApply, + onCancel: vi.fn(), + }); + + selector.handleInput(' '); + selector.handleInput(ENTER); + + expect(text(selector)).toContain(' ❯ Micro compaction enabled'); + expect(text(selector)).toContain(' [ Apply changes and reload ] no changes'); + expect(onApply).not.toHaveBeenCalled(); + }); + + it('filters by typing and clears the query before cancelling', () => { + const onCancel = vi.fn(); + const selector = new ExperimentsSelectorComponent({ + features: [feature()], + onApply: vi.fn(), + onCancel, + }); + + selector.handleInput('m'); + selector.handleInput('i'); + selector.handleInput('c'); + expect(text(selector)).toContain('Search: mic'); + expect(text(selector)).toContain('Micro compaction'); + + selector.handleInput(ESC); + expect(onCancel).not.toHaveBeenCalled(); + selector.handleInput(ESC); + expect(onCancel).toHaveBeenCalledOnce(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/feedback-input-dialog.test.ts b/apps/kimi-code/test/tui/components/dialogs/feedback-input-dialog.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ab1b3312155a3a7aabac6e6d1ce3f806fec169c --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/feedback-input-dialog.test.ts @@ -0,0 +1,119 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; +import { beforeAll, describe, expect, it } from 'vitest'; + +import { + FeedbackInputDialogComponent, + type FeedbackInputDialogResult, +} from '#/tui/components/dialogs/feedback-input-dialog'; +import { darkColors } from '#/tui/theme/colors'; + +const ESC = String.fromCodePoint(27); +const CTRL_C = String.fromCodePoint(3); +const ANSI_RE = new RegExp(`${ESC}\\[[0-9;]*m`, 'g'); + +function strip(text: string): string { + return text.replaceAll(ANSI_RE, ''); +} + +beforeAll(() => { + chalk.level = 3; +}); + +function makeDialog(): { + dialog: FeedbackInputDialogComponent; + collected: FeedbackInputDialogResult[]; +} { + const collected: FeedbackInputDialogResult[] = []; + const dialog = new FeedbackInputDialogComponent((result) => { + collected.push(result); + }); + dialog.focused = true; + return { dialog, collected }; +} + +describe('FeedbackInputDialogComponent', () => { + it('renders a blue rounded box with title, subtitle, and footer', () => { + const { dialog } = makeDialog(); + const text = strip(dialog.render(60).join('\n')); + + expect(text).toContain('╭'); + expect(text).toContain('╮'); + expect(text).toContain('╰'); + expect(text).toContain('╯'); + expect(text).toContain('Send feedback to Kimi Code'); + expect(text).toContain("Tell us what's working or what's not."); + expect(text).toContain('Enter to submit'); + expect(text).toContain('Esc to cancel'); + }); + + it('uses the primary color for the border', () => { + const { dialog } = makeDialog(); + const rendered = dialog.render(60).join('\n'); + const sample = chalk.hex(darkColors.primary)('x'); + const ansiOpen = sample.split('x')[0]!; + expect(rendered).toContain(`${ansiOpen}╭`); + expect(rendered).toContain(`${ansiOpen}╰`); + }); + + it('keeps every line within narrow widths', () => { + const { dialog } = makeDialog(); + + for (const width of [39, 20, 10, 4]) { + for (const line of dialog.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('typing then pressing Enter submits the trimmed value', () => { + const { dialog, collected } = makeDialog(); + for (const ch of 'hello world ') { + dialog.handleInput(ch); + } + dialog.handleInput('\r'); + expect(collected).toEqual([{ kind: 'ok', value: 'hello world' }]); + }); + + it('Enter on an empty input does not submit and shows an inline empty hint', () => { + const { dialog, collected } = makeDialog(); + dialog.handleInput('\r'); + expect(collected).toEqual([]); + const text = strip(dialog.render(60).join('\n')); + expect(text).toContain('Feedback cannot be empty.'); + expect(text).not.toContain("Tell us what's working or what's not."); + }); + + it('typing again after the empty hint clears the hint', () => { + const { dialog, collected } = makeDialog(); + dialog.handleInput('\r'); + expect(strip(dialog.render(60).join('\n'))).toContain('Feedback cannot be empty.'); + dialog.handleInput('a'); + const text = strip(dialog.render(60).join('\n')); + expect(text).toContain("Tell us what's working or what's not."); + expect(text).not.toContain('Feedback cannot be empty.'); + expect(collected).toEqual([]); + }); + + it('Esc cancels the dialog', () => { + const { dialog, collected } = makeDialog(); + dialog.handleInput(ESC); + expect(collected).toEqual([{ kind: 'cancel' }]); + }); + + it('Ctrl-C cancels the dialog', () => { + const { dialog, collected } = makeDialog(); + dialog.handleInput(CTRL_C); + expect(collected).toEqual([{ kind: 'cancel' }]); + }); + + it('does not fire onDone twice', () => { + const { dialog, collected } = makeDialog(); + dialog.handleInput('h'); + dialog.handleInput('i'); + dialog.handleInput('\r'); + dialog.handleInput('\r'); + dialog.handleInput(ESC); + expect(collected).toEqual([{ kind: 'ok', value: 'hi' }]); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/goal-queue-manager.test.ts b/apps/kimi-code/test/tui/components/dialogs/goal-queue-manager.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec0f9d03b358e5be1f4b5b6ba2e55c08cf66372c --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/goal-queue-manager.test.ts @@ -0,0 +1,286 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it, vi } from 'vitest'; + +import { + GoalQueueEditDialogComponent, + GoalQueueManagerComponent, + type GoalQueueManagerAction, +} from '#/tui/components/dialogs/goal-queue-manager'; +import type { GoalQueueSnapshot, UpcomingGoal } from '#/tui/goal-queue-store'; + +const ANSI = /\u001B\[[0-9;]*m/g; +const strip = (s: string): string => s.replaceAll(ANSI, ''); +const ESC = String.fromCodePoint(27); +const CTRL_J = '\u001B[106;5u'; +const BRACKET_PASTE_START = '\u001B[200~'; +const BRACKET_PASTE_END = '\u001B[201~'; +const UP = `${ESC}[A`; +const DOWN = `${ESC}[B`; + +function goal(id: string, objective: string): UpcomingGoal { + return { + id, + objective, + createdAt: '2026-06-03T00:00:00.000Z', + updatedAt: '2026-06-03T00:00:00.000Z', + }; +} + +function snapshot(goals: readonly UpcomingGoal[]): GoalQueueSnapshot { + return { goals }; +} + +function text(component: GoalQueueManagerComponent | GoalQueueEditDialogComponent, width = 100) { + return component.render(width).map(strip).join('\n'); +} + +describe('GoalQueueManagerComponent', () => { + it('renders the upcoming goals and the management hint', () => { + const manager = new GoalQueueManagerComponent({ + goals: [goal('g1', 'Ship queued goal')], + onAction: vi.fn(), + onCancel: vi.fn(), + }); + + const out = text(manager); + expect(out).toContain('Upcoming goals'); + expect(out).toContain('↑↓ navigate · Space select · E edit · D delete · Esc cancel'); + expect(out).toContain('❯ 1. Ship queued goal'); + }); + + it('uses Space to enter move mode and reorders with Up/Down', async () => { + const first = goal('g1', 'First queued goal'); + const second = goal('g2', 'Second queued goal'); + const onAction = vi.fn(async (action: GoalQueueManagerAction) => { + expect(action).toEqual({ kind: 'move', goalId: 'g2', direction: 'up' }); + return snapshot([second, first]); + }); + const manager = new GoalQueueManagerComponent({ + goals: [first, second], + onAction, + onCancel: vi.fn(), + }); + + manager.handleInput(DOWN); + manager.handleInput(' '); + expect(text(manager)).toContain('↑↓ reorder · Space done · E edit · D delete · Esc cancel'); + manager.handleInput(UP); + + await vi.waitFor(() => { + expect(onAction).toHaveBeenCalledOnce(); + }); + const out = text(manager); + expect(out.indexOf('Second queued goal')).toBeLessThan(out.indexOf('First queued goal')); + }); + + it('deletes the selected goal and keeps the list open', async () => { + const first = goal('g1', 'First queued goal'); + const second = goal('g2', 'Second queued goal'); + const onAction = vi.fn(async (action: GoalQueueManagerAction) => { + expect(action).toEqual({ kind: 'delete', goalId: 'g1' }); + return snapshot([second]); + }); + const manager = new GoalQueueManagerComponent({ + goals: [first, second], + onAction, + onCancel: vi.fn(), + }); + + manager.handleInput('d'); + + await vi.waitFor(() => { + expect(onAction).toHaveBeenCalledOnce(); + }); + const out = text(manager); + expect(out).not.toContain('First queued goal'); + expect(out).toContain('1. Second queued goal'); + }); + + it('invalidates after an async queue action updates the list', async () => { + const first = goal('g1', 'First queued goal'); + const second = goal('g2', 'Second queued goal'); + let resolveAction: (value: GoalQueueSnapshot) => void; + const onAction = vi.fn( + () => + new Promise((resolve) => { + resolveAction = resolve; + }), + ); + const manager = new GoalQueueManagerComponent({ + goals: [first, second], + onAction, + onCancel: vi.fn(), + }); + const invalidate = vi.spyOn(manager, 'invalidate'); + + manager.handleInput('d'); + resolveAction!(snapshot([second])); + + await vi.waitFor(() => { + expect(invalidate).toHaveBeenCalled(); + }); + }); + + it('emits an edit action for the selected goal', () => { + const onAction = vi.fn(); + const manager = new GoalQueueManagerComponent({ + goals: [goal('g1', 'First queued goal')], + onAction, + onCancel: vi.fn(), + }); + + manager.handleInput('e'); + + expect(onAction).toHaveBeenCalledWith({ kind: 'edit', goalId: 'g1' }); + }); + + it('cancels with Esc', () => { + const onCancel = vi.fn(); + const manager = new GoalQueueManagerComponent({ + goals: [], + onAction: vi.fn(), + onCancel, + }); + + manager.handleInput(ESC); + + expect(onCancel).toHaveBeenCalledOnce(); + }); + + it('never renders a line wider than the terminal', () => { + const manager = new GoalQueueManagerComponent({ + goals: [goal('g1', 'A very long queued goal objective that should be truncated cleanly')], + onAction: vi.fn(), + onCancel: vi.fn(), + }); + + for (const width of [24, 40, 80]) { + for (const line of manager.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('renders multiline objectives as a single selectable row', () => { + const manager = new GoalQueueManagerComponent({ + goals: [goal('g1', 'First line\nSecond line')], + onAction: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = manager.render(100).map(strip); + + expect(lines.some((line) => line.includes('❯ 1. First line Second line'))).toBe(true); + expect(lines.some((line) => line.trim() === 'Second line')).toBe(false); + }); +}); + +describe('GoalQueueEditDialogComponent', () => { + it('submits the edited objective', () => { + const onDone = vi.fn(); + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', 'Ship queued goal'), + onDone, + }); + + dialog.handleInput(' safely'); + dialog.handleInput('\r'); + + expect(onDone).toHaveBeenCalledWith({ + kind: 'save', + goalId: 'g1', + objective: 'Ship queued goal safely', + }); + }); + + it('supports multiline objective edits', () => { + const onDone = vi.fn(); + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', 'Ship queued goal'), + onDone, + }); + + dialog.handleInput(CTRL_J); + dialog.handleInput('with a second line'); + dialog.handleInput('\r'); + + expect(onDone).toHaveBeenCalledWith({ + kind: 'save', + goalId: 'g1', + objective: 'Ship queued goal\nwith a second line', + }); + }); + + it('sanitizes bracketed paste while preserving newlines', () => { + const onDone = vi.fn(); + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', 'Ship queued goal'), + onDone, + }); + + dialog.handleInput( + `${BRACKET_PASTE_START} \u001B[31mred\u001B[0m\nnext\u0007 line${BRACKET_PASTE_END}`, + ); + dialog.handleInput('\r'); + + expect(onDone).toHaveBeenCalledWith({ + kind: 'save', + goalId: 'g1', + objective: 'Ship queued goal red\nnext line', + }); + }); + + it('renders multiline edits inside the dialog width', () => { + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', 'First line\nSecond line'), + onDone: vi.fn(), + }); + + const out = text(dialog, 36); + + expect(out).toContain('> First line'); + expect(out).toContain(' Second line'); + for (const line of dialog.render(36)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(36); + } + }); + + it('keeps the edit dialog within narrow widths', () => { + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', 'A very long queued objective for width testing'), + onDone: vi.fn(), + }); + + for (const width of [24, 20, 10]) { + for (const line of dialog.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('keeps accepting input after save returns control to the mounted dialog', () => { + const onDone = vi.fn(); + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', 'Ship queued goal'), + onDone, + }); + + dialog.handleInput('\r'); + dialog.handleInput(ESC); + + expect(onDone).toHaveBeenLastCalledWith({ kind: 'cancel', goalId: 'g1' }); + }); + + it('shows an empty objective hint instead of submitting', () => { + const onDone = vi.fn(); + const dialog = new GoalQueueEditDialogComponent({ + goal: goal('g1', ''), + onDone, + }); + + dialog.handleInput('\r'); + + expect(onDone).not.toHaveBeenCalled(); + expect(text(dialog)).toContain('Goal objective cannot be empty.'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/model-selector.test.ts b/apps/kimi-code/test/tui/components/dialogs/model-selector.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5159ec0d927074cfa7bb14b24f9eeeb7017a05f --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/model-selector.test.ts @@ -0,0 +1,567 @@ +import type { ModelAlias } from '@moonshot-ai/kimi-code-sdk'; +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it, vi } from 'vitest'; + +import { ModelSelectorComponent } from '#/tui/components/dialogs/model-selector'; +import { currentTheme } from '#/tui/theme'; +import { darkColors } from '#/tui/theme/colors'; + +const ANSI = /\[[0-9;]*m/g; +const strip = (s: string): string => s.replaceAll(ANSI, ''); +const ESC = String.fromCodePoint(27); +const UP = `${ESC}[A`; +const DOWN = `${ESC}[B`; +const LEFT = `${ESC}[D`; +const RIGHT = `${ESC}[C`; + +function model(displayName: string, capabilities: string[] = ['thinking']): ModelAlias { + return { + provider: 'managed:kimi-code', + model: displayName.toLowerCase().replaceAll(' ', '-'), + maxContextSize: 200_000, + displayName, + capabilities, + } as unknown as ModelAlias; +} + +function effortModel( + displayName: string, + supportEfforts: string[], + defaultEffort?: string, + capabilities: string[] = ['thinking'], +): ModelAlias { + return { + provider: 'managed:kimi-code', + model: displayName.toLowerCase().replaceAll(' ', '-'), + maxContextSize: 200_000, + displayName, + capabilities, + supportEfforts, + defaultEffort, + } as unknown as ModelAlias; +} + +function text(component: ModelSelectorComponent, width = 120): string { + return component.render(width).map(strip).join('\n'); +} + +describe('ModelSelectorComponent', () => { + it('lays out the provider as a right column and marks the current model', () => { + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2') }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const out = text(picker); + // Model name on the left, provider on the right, with the current marker. + expect(out).toMatch(/❯ Kimi K2\s+Kimi Code ← current/); + // Provider is no longer inlined in parentheses next to the name. + expect(out).not.toContain('Kimi K2 (Kimi Code)'); + }); + + it('toggles thinking with Left/Right (not with "/")', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2', ['thinking']) }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + onSelect, + onCancel: vi.fn(), + }); + + // "/" no longer toggles thinking (it used to); here it is simply ignored. + picker.handleInput('/'); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'on' }); + + // Right arrow flips the draft (true -> false). + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'off' }); + + // Left arrow flips it back. + picker.handleInput(LEFT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'on' }); + }); + + it('shows the Left/Right thinking hint only for toggleable models', () => { + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2', ['thinking']) }, + currentValue: 'kimi', + currentThinkingEffort: 'off', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + expect(text(picker)).toContain('Thinking (←→ to switch)'); + }); + + it('hides the Thinking footer when thinkingControl is false', () => { + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2', ['thinking']) }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + thinkingControl: false, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + expect(text(picker)).not.toContain('Thinking'); + }); + + it('ignores Left/Right when thinkingControl is false', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2', ['thinking']) }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + thinkingControl: false, + onSelect, + onCancel: vi.fn(), + }); + + // Same setup as the toggle test above: either arrow would flip 'on' to 'off'. + picker.handleInput(LEFT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'on' }); + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'on' }); + }); + + it('forces always-thinking models on and unsupported models off', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + always: model('Kimi Thinking', ['always_thinking']), + plain: model('Kimi Plain', ['tool_use']), + }, + currentValue: 'always', + currentThinkingEffort: 'off', + onSelect, + onCancel: vi.fn(), + }); + + // Always-on: On selected, Off greyed out with an explanation. + const alwaysOut = text(picker); + expect(alwaysOut).toContain('[ On ]'); + expect(alwaysOut).toContain('Off (Unsupported)'); + expect(alwaysOut).not.toContain('Always on'); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'always', thinking: 'on' }); + + // Unsupported: Off selected, On greyed out — same style, mirrored. + picker.handleInput(DOWN); + const plainOut = text(picker); + expect(plainOut).toContain('On (Unsupported)'); + expect(plainOut).toContain('[ Off ]'); + expect(plainOut).not.toContain('] unsupported'); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'plain', thinking: 'off' }); + }); + + it('ignores Left/Right on always-on and unsupported models', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + always: model('Kimi Thinking', ['always_thinking']), + plain: model('Kimi Plain', ['tool_use']), + }, + currentValue: 'always', + currentThinkingEffort: 'on', + onSelect, + onCancel: vi.fn(), + }); + + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'always', thinking: 'on' }); + + picker.handleInput(DOWN); + picker.handleInput(LEFT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'plain', thinking: 'off' }); + }); + + it('renders the unavailable thinking segment muted', () => { + const picker = new ModelSelectorComponent({ + models: { always: model('Kimi Thinking', ['always_thinking']) }, + currentValue: 'always', + currentThinkingEffort: 'on', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const raw = picker.render(120).join('\n'); + expect(raw).toContain(currentTheme.fg('textMuted', ' Off (Unsupported) ')); + }); + + it('keeps the thinking draft when moving across models', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + plain: model('Kimi Plain', ['tool_use']), + thinking: model('Kimi Thinking', ['thinking']), + }, + currentValue: 'plain', + currentThinkingEffort: 'off', + onSelect, + onCancel: vi.fn(), + }); + + picker.handleInput(DOWN); // -> thinking model (defaults On) + picker.handleInput(RIGHT); // toggle -> Off + picker.handleInput(UP); // -> plain + picker.handleInput(DOWN); // -> thinking (the Off override persists) + picker.handleInput('\r'); + + expect(onSelect).toHaveBeenCalledWith({ alias: 'thinking', thinking: 'off' }); + }); + + it('defaults a thinking-capable model to On but keeps the current model state', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + current: model('Kimi Current', ['thinking']), + other: model('Kimi Other', ['thinking']), + }, + currentValue: 'current', + currentThinkingEffort: 'off', // thinking deliberately off on the active model + onSelect, + onCancel: vi.fn(), + }); + + // The active model reflects its live (off) state. + expect(text(picker)).toContain('[ Off ]'); + picker.handleInput(DOWN); // -> the other thinking-capable model + // A capable, non-active model defaults to On without any toggle. + expect(text(picker)).toContain('[ On ]'); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ alias: 'other', thinking: 'on' }); + }); + + it('fuzzy-filters by typing and reports a match count', () => { + const onCancel = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { k2: model('Kimi K2'), turbo: model('Kimi Turbo') }, + currentValue: 'k2', + currentThinkingEffort: 'off', + searchable: true, + onSelect: vi.fn(), + onCancel, + }); + + picker.handleInput('t'); + picker.handleInput('u'); + const out = text(picker); + expect(out).toContain('Search: tu'); + expect(out).toContain('Kimi Turbo'); + expect(out).not.toContain('Kimi K2'); + expect(out).toContain('1 / 2'); + + // First Esc clears the query, second Esc cancels. + picker.handleInput(ESC); + expect(onCancel).not.toHaveBeenCalled(); + picker.handleInput(ESC); + expect(onCancel).toHaveBeenCalledTimes(1); + }); + + it('shows a "more" indicator when the list overflows a page', () => { + const models: Record = {}; + for (let i = 0; i < 12; i++) models[`m${String(i)}`] = model(`Model ${String(i)}`); + const picker = new ModelSelectorComponent({ + models, + currentValue: 'm0', + currentThinkingEffort: 'off', + searchable: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + // Default page size is 8, so 4 of the 12 models sit below the fold. + expect(text(picker)).toContain('▼ 4 more'); + }); + + it('never renders a line wider than the terminal', () => { + const picker = new ModelSelectorComponent({ + models: { + long: model('A Very Long Model Display Name That Should Be Truncated Hard'), + cjk: model('超长的中文模型名称需要被正确截断处理'), + }, + currentValue: 'long', + currentThinkingEffort: 'off', + searchable: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + for (const width of [20, 40, 80, 120]) { + for (const line of picker.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('invokes onSessionOnlySelect on Alt+S with the effective thinking state', () => { + const onSelect = vi.fn(); + const onSessionOnlySelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2', ['thinking']) }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + onSelect, + onSessionOnlySelect, + onCancel: vi.fn(), + }); + + // Toggle thinking Off, then Alt+S applies the choice to the session only. + picker.handleInput(RIGHT); + picker.handleInput(`${ESC}s`); + expect(onSessionOnlySelect).toHaveBeenCalledWith({ alias: 'kimi', thinking: 'off' }); + expect(onSelect).not.toHaveBeenCalled(); + }); + + it('ignores Alt+S and hides its hint when onSessionOnlySelect is not provided', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2') }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + onSelect, + onCancel: vi.fn(), + }); + + picker.handleInput(`${ESC}s`); + expect(onSelect).not.toHaveBeenCalled(); + expect(text(picker)).not.toContain('Alt+S session-only'); + }); + + it('shows the Alt+S session-only hint when onSessionOnlySelect is provided', () => { + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2') }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + onSelect: vi.fn(), + onSessionOnlySelect: vi.fn(), + onCancel: vi.fn(), + }); + expect(text(picker)).toContain('Alt+S session-only'); + }); + + it('renders effort segments with the default effort highlighted', () => { + const picker = new ModelSelectorComponent({ + models: { kimi: effortModel('Kimi K2', ['low', 'high', 'max'], 'high') }, + currentValue: 'kimi', + currentThinkingEffort: 'high', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const out = text(picker); + // The default effort (high) is the active segment. + expect(out).toContain('[ High ]'); + // All declared efforts plus the Off entry are present. + expect(out).toContain('Low'); + expect(out).toContain('Max'); + expect(out).toContain('Off'); + // Multi-segment control advertises the switch hint. + expect(out).toContain('Thinking (←→ to switch)'); + }); + + it('derives official Anthropic effort segments from the model name', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + opus: { + provider: 'anthropic', + model: 'claude-opus-4-6', + maxContextSize: 200000, + }, + }, + currentValue: 'opus', + currentThinkingEffort: 'high', + onSelect, + onCancel: vi.fn(), + }); + + const out = text(picker); + expect(out).toContain('Low'); + expect(out).toContain('[ High ]'); + expect(out).toContain('Max'); + expect(out).toContain('Off'); + expect(out).not.toContain('Xhigh'); + + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ alias: 'opus', thinking: 'max' }); + }); + + it('derives official always-on Anthropic models without an Off segment', () => { + const picker = new ModelSelectorComponent({ + models: { + fable: { + provider: 'anthropic', + model: 'claude-fable-5', + maxContextSize: 200000, + }, + }, + currentValue: 'fable', + currentThinkingEffort: 'high', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const out = text(picker); + expect(out).toContain('Xhigh'); + expect(out).toContain('Max'); + expect(out).not.toContain('Off'); + }); + + it('cycles efforts with Left/Right and clamps at the ends', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { kimi: effortModel('Kimi K2', ['low', 'high', 'max'], 'high') }, + currentValue: 'kimi', + currentThinkingEffort: 'high', + onSelect, + onCancel: vi.fn(), + }); + + // high -> max (Right), then clamp on a second Right. + picker.handleInput(RIGHT); + picker.handleInput(RIGHT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'max' }); + + // max -> high -> low -> off (Left x3), then clamp on another Left. + picker.handleInput(LEFT); + picker.handleInput(LEFT); + picker.handleInput(LEFT); + picker.handleInput(LEFT); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'off' }); + }); + + it('always-on effort models hide Off and clamp selection at the last effort', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + kimi: effortModel('Kimi K2', ['low', 'high', 'max'], 'high', ['always_thinking']), + }, + currentValue: 'kimi', + currentThinkingEffort: 'high', + onSelect, + onCancel: vi.fn(), + }); + + const raw = picker.render(120).join('\n'); + // Off is not surfaced at all — the selectable segments are effort-only. + expect(raw).not.toContain('Off (Unsupported)'); + // The active effort is still highlighted. + expect(strip(raw)).toContain('[ High ]'); + + // Cycling clamps at the last effort and never reaches Off. + picker.handleInput(RIGHT); // high -> max + picker.handleInput(RIGHT); // clamp at max + picker.handleInput('\r'); + expect(onSelect).toHaveBeenLastCalledWith({ alias: 'kimi', thinking: 'max' }); + }); + + it('defaults an effort model without a current level to its defaultEffort', () => { + const onSelect = vi.fn(); + const picker = new ModelSelectorComponent({ + models: { + other: effortModel('Kimi Other', ['low', 'high', 'max'], 'max'), + }, + currentValue: 'current', + currentThinkingEffort: 'off', + onSelect, + onCancel: vi.fn(), + }); + + // Non-current effort model falls back to its declared defaultEffort. + expect(text(picker)).toContain('[ Max ]'); + picker.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ alias: 'other', thinking: 'max' }); + }); + + it('falls back to the middle effort when an effort model has no defaultEffort', () => { + const picker = new ModelSelectorComponent({ + models: { + other: effortModel('Kimi Other', ['low', 'medium', 'high']), + }, + currentValue: 'current', + currentThinkingEffort: 'off', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + // support_efforts present but default_effort absent -> default to the + // middle entry (medium), not a hardcoded level. + expect(text(picker)).toContain('[ Medium ]'); + }); + + it('renders the warning line directly below the key-hint line when provided', () => { + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2') }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + warning: 'Switching may increase token usage.', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = picker.render(120).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('↑↓ navigate')); + expect(hintIdx).toBeGreaterThanOrEqual(0); + expect(lines[hintIdx + 1]).toContain('Switching may increase token usage.'); + // Model list is pushed below the inserted warning line, not overlapped. + expect(lines.findIndex((l) => l.includes('Kimi K2'))).toBeGreaterThan(hintIdx + 1); + }); + + it('wraps a warning longer than the width instead of truncating it', () => { + const warning = + 'Note: Switching models invalidates the existing prompt cache. Use /new to avoid extra token costs.'; + const picker = new ModelSelectorComponent({ + models: { kimi: model('Kimi K2') }, + currentValue: 'kimi', + currentThinkingEffort: 'on', + warning, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = picker.render(50).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('↑↓ navigate')); + expect(lines[hintIdx + 1]).not.toBe(''); + expect(lines[hintIdx + 2]).not.toBe(''); + // Word-wrapped: nothing dropped — the full warning survives across lines. + const squashed = lines.join('').replaceAll(/\s+/g, ''); + expect(squashed).toContain(warning.replaceAll(/\s+/g, '')); + }); +}); + +describe('ModelSelectorComponent overrides', () => { + it('uses overridden support_efforts for selectable efforts', () => { + const picker = new ModelSelectorComponent({ + models: { + kimi: { + ...effortModel('Kimi K2', ['low', 'high', 'max'], 'max'), + overrides: { supportEfforts: ['low', 'high'] }, + }, + }, + currentValue: 'kimi', + currentThinkingEffort: 'max', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const out = text(picker); + expect(out).toContain('Low'); + expect(out).toContain('High'); + expect(out).not.toContain('Max'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/plugins-selector.test.ts b/apps/kimi-code/test/tui/components/dialogs/plugins-selector.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac1b87e8cb7376089c474db43ad56c3df2b00298 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/plugins-selector.test.ts @@ -0,0 +1,1059 @@ +import { describe, expect, it, vi } from 'vitest'; +import chalk from 'chalk'; +import type { CapabilityStatus, PluginSummary } from '@moonshot-ai/kimi-code-sdk'; + +import { + PluginInstallTrustConfirmComponent, + PluginMcpSelectorComponent, + PluginRemoveConfirmComponent, + PluginsPanelComponent, + type PluginInstallTrustConfirmResult, + type PluginMcpSelection, + type PluginRemoveConfirmResult, + type PluginsPanelSelection, +} from '#/tui/components/dialogs/plugins-selector'; +import { currentTheme } from '#/tui/theme'; +import { darkColors, lightColors } from '#/tui/theme/colors'; +import { isOfficialPluginInstall, isOfficialPluginSource, pluginTrustLabel } from '#/tui/utils/plugin-source-label'; + +const ANSI_SGR = /\u001B\[[0-9;]*m/g; + +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, '').replaceAll('\u276F', '?'); +} + +function withAnsiColors(fn: () => T): T { + const previousChalkLevel = chalk.level; + chalk.level = 3; + try { + return fn(); + } finally { + chalk.level = previousChalkLevel; + } +} + +function renderRaw(component: { render(width: number): string[] }, width = 120): string { + return withAnsiColors(() => component.render(width).join('\n')); +} + +function dangerShortcut(text: string): string { + return withAnsiColors(() => chalk.hex(darkColors.error).bold(text)); +} + +function warningMark(): string { + // Opening ANSI escape for the warning color; the install-trust notice is the + // only element in that dialog using it, so its presence confirms the tone. + return withAnsiColors(() => chalk.hex(darkColors.warning)('\u0001').split('\u0001')[0]!); +} + +const superpowers = { + id: 'superpowers', + displayName: 'Superpowers', + version: '5.1.0', + enabled: true, + state: 'ok' as const, + skillCount: 14, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'local-path' as const, +}; + +const officialEntries = [ + { + id: 'kimi-datasource', + tier: 'official' as const, + displayName: 'Kimi Datasource', + description: 'Query supported data sources', + version: '3.1.1', + source: 'https://x/d.zip', + keywords: ['data'], + }, +]; +const thirdPartyEntries = [ + { id: 'superpowers', tier: 'curated' as const, displayName: 'Superpowers', source: 'https://x/s.zip' }, +]; +const marketplaceEntries = [...officialEntries, ...thirdPartyEntries]; + +function makePanel(opts: { + installed?: readonly PluginSummary[]; + capabilities?: readonly CapabilityStatus[]; + catalogIsDefault?: boolean; + initialTab?: 'installed' | 'official' | 'third-party' | 'custom'; + selectedId?: string; + pluginHint?: { id: string; text: string }; +}) { + const installed = opts.installed ?? []; + const onSelect = vi.fn<(s: PluginsPanelSelection) => void>(); + const onRequestMarketplace = vi.fn(); + const panel = new PluginsPanelComponent({ + installed, + installedIds: new Set(installed.map((p) => p.id)), + capabilities: opts.capabilities, + catalogIsDefault: opts.catalogIsDefault, + initialTab: opts.initialTab, + selectedId: opts.selectedId, + pluginHint: opts.pluginHint, + onSelect, + onCancel: vi.fn(), + onRequestMarketplace, + }); + return { panel, onSelect, onRequestMarketplace }; +} + +function makeCapability(overrides: Partial = {}): CapabilityStatus { + return { + id: 'kimi-cu', + displayName: 'Kimi Computer Use', + description: 'Background GUI automation', + supported: true, + state: 'partial', + steps: [ + { id: 'plugin', state: 'ok' }, + { id: 'app', state: 'ok' }, + { id: 'service', state: 'ok' }, + { id: 'permissions', state: 'missing', detail: 'screenRecording' }, + ], + install: { running: false }, + ...overrides, + }; +} + +describe('plugins selector dialogs', () => { + it('trusts only built-in Kimi CDN plugin paths', () => { + expect(pluginTrustLabel({ + id: 'kimi-datasource', + displayName: 'Kimi Datasource', + enabled: true, + state: 'ok', + skillCount: 0, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'zip-url', + originalSource: 'https://code.kimi.com/kimi-code/plugins/official/kimi-datasource.zip', + })).toBe('official'); + expect(pluginTrustLabel({ + id: 'superpowers', + displayName: 'Superpowers', + enabled: true, + state: 'ok', + skillCount: 0, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'zip-url', + originalSource: 'https://code.kimi.com/kimi-code/plugins/curated/superpowers.zip', + })).toBe('curated'); + expect(pluginTrustLabel({ + id: 'kimi-cu', + displayName: 'Kimi Computer Use', + enabled: true, + state: 'ok', + skillCount: 1, + mcpServerCount: 1, + enabledMcpServerCount: 1, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'zip-url', + originalSource: 'https://cdn.kimi.com/kimi-computer-use/latest/kimi-cu-plugin.zip', + })).toBe('official'); + expect(pluginTrustLabel({ + id: 'demo', + displayName: 'Demo', + enabled: true, + state: 'ok', + skillCount: 0, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'zip-url', + originalSource: 'https://code.kimi.com/demo.zip', + })).toBe('third-party'); + expect(pluginTrustLabel({ + id: 'local', + displayName: 'Local', + enabled: true, + state: 'ok', + skillCount: 0, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'local-path', + originalSource: 'https://code.kimi.com/kimi-code/plugins/official/local', + })).toBe('third-party'); + }); + + it('trusts the .ai Kimi plugin hosts with the same path rules', () => { + const labelFor = (originalSource: string) => + pluginTrustLabel({ + id: 'demo', + displayName: 'Demo', + enabled: true, + state: 'ok', + skillCount: 0, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'zip-url', + originalSource, + }); + // code.kimi.ai mirrors the cdnBase rules; cdn.kimi.ai the content-CDN ones. + expect(labelFor('https://code.kimi.ai/kimi-code/plugins/official/kimi-datasource.zip')).toBe('official'); + expect(labelFor('https://code.kimi.ai/kimi-code/plugins/curated/superpowers.zip')).toBe('curated'); + expect(labelFor('https://cdn.kimi.ai/kimi-computer-use/latest/kimi-cu-plugin.zip')).toBe('official'); + expect(labelFor('https://cdn.kimi.ai/kimi-computer-use-windows/latest/kimi-cu-win-plugin.zip')).toBe('official'); + // Non-plugin paths on the .ai hosts, and lookalike hosts, stay third-party. + expect(labelFor('https://code.kimi.ai/demo.zip')).toBe('third-party'); + expect(labelFor('https://cdn.kimi.ai/unrelated/plugin.zip')).toBe('third-party'); + expect(labelFor('https://code.kimi.ai.example.test/kimi-code/plugins/official/x.zip')).toBe('third-party'); + }); + + it('recognizes installed plugins by official provenance', () => { + const base = { + id: 'kimi-datasource', + displayName: 'Kimi Datasource', + enabled: true, + state: 'ok' as const, + skillCount: 0, + mcpServerCount: 0, + enabledMcpServerCount: 0, + hookCount: 0, + commandCount: 0, + hasErrors: false, + }; + // Zip installs from the official CDN path. + expect(isOfficialPluginInstall({ + ...base, + source: 'zip-url', + originalSource: 'https://code.kimi.com/kimi-code/plugins/official/kimi-datasource.zip', + })).toBe(true); + expect(isOfficialPluginInstall({ + ...base, + source: 'zip-url', + originalSource: 'https://code.kimi.ai/kimi-code/plugins/official/kimi-datasource.zip', + })).toBe(true); + expect(isOfficialPluginInstall({ + ...base, + id: 'kimi-cu', + displayName: 'Kimi Computer Use', + source: 'zip-url', + originalSource: 'https://cdn.kimi.com/kimi-computer-use/latest/kimi-cu-plugin.zip', + })).toBe(true); + // Same manifest id from a local path, GitHub, a loopback URL, or a + // third-party URL is not the official build. + expect(isOfficialPluginInstall({ ...base, source: 'local-path' })).toBe(false); + expect(isOfficialPluginInstall({ ...base, source: 'github' })).toBe(false); + expect(isOfficialPluginInstall({ + ...base, + source: 'zip-url', + originalSource: 'http://127.0.0.1:58627/kimi-code/plugins/official/kimi-datasource.zip', + })).toBe(false); + expect(isOfficialPluginInstall({ + ...base, + source: 'zip-url', + originalSource: 'https://example.test/kimi-code/plugins/official/kimi-datasource.zip', + })).toBe(false); + }); + + it('shows installed Kimi Computer Use and WebBridge plugins as official', () => { + const installed: PluginSummary[] = [ + { + ...superpowers, + id: 'kimi-cu', + displayName: 'Kimi Computer Use', + source: 'zip-url', + originalSource: 'https://cdn.kimi.com/kimi-computer-use/latest/kimi-cu-plugin.zip', + }, + { + ...superpowers, + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + source: 'zip-url', + originalSource: 'https://code.kimi.com/kimi-code/plugins/official/kimi-webbridge.zip', + }, + ]; + + const { panel } = makePanel({ installed }); + const out = strip(renderRaw(panel)); + + expect(out).toContain('id kimi-cu'); + expect(out).toContain('via cdn.kimi.com · official'); + expect(out).toContain('id kimi-webbridge'); + expect(out).toContain('via code.kimi.com · official'); + }); + + it('treats only the official Kimi CDN path as a trusted install source', () => { + expect(isOfficialPluginSource('https://code.kimi.com/kimi-code/plugins/official/kimi-datasource.zip')).toBe(true); + expect(isOfficialPluginSource('https://cdn.kimi.com/kimi-computer-use/latest/kimi-cu-plugin.zip')).toBe(true); + expect( + isOfficialPluginSource( + 'https://cdn.kimi.com/kimi-computer-use-windows/latest/kimi-cu-win-plugin.zip', + ), + ).toBe(true); + // The .ai region family follows the same path rules. + expect(isOfficialPluginSource('https://code.kimi.ai/kimi-code/plugins/official/kimi-datasource.zip')).toBe(true); + expect(isOfficialPluginSource('https://cdn.kimi.ai/kimi-computer-use/latest/kimi-cu-plugin.zip')).toBe(true); + expect( + isOfficialPluginSource( + 'https://cdn.kimi.ai/kimi-computer-use-windows/latest/kimi-cu-win-plugin.zip', + ), + ).toBe(true); + expect(isOfficialPluginSource('https://code.kimi.ai/kimi-code/plugins/curated/superpowers.zip')).toBe(false); + expect(isOfficialPluginSource('https://cdn.kimi.ai/unrelated/plugin.zip')).toBe(false); + // Curated and other Kimi CDN paths are not "official" for the install gate. + expect(isOfficialPluginSource('https://code.kimi.com/kimi-code/plugins/curated/superpowers.zip')).toBe(false); + expect(isOfficialPluginSource('https://code.kimi.com/kimi-code/plugins/foo.zip')).toBe(false); + expect(isOfficialPluginSource('https://cdn.kimi.com/unrelated/plugin.zip')).toBe(false); + // Non-Kimi hosts (loopback included), non-https schemes, local paths, and + // GitHub sources are unofficial. + expect(isOfficialPluginSource('https://example.test/kimi-code/plugins/official/x.zip')).toBe(false); + expect(isOfficialPluginSource('http://code.kimi.com/kimi-code/plugins/official/x.zip')).toBe(false); + expect(isOfficialPluginSource('http://127.0.0.1:58627/kimi-code/plugins/official/x.zip')).toBe(false); + expect(isOfficialPluginSource('./plugins/kimi-datasource')).toBe(false); + expect(isOfficialPluginSource('/abs/path/to/plugin')).toBe(false); + expect(isOfficialPluginSource('github.com/owner/repo')).toBe(false); + expect(isOfficialPluginSource('not a url')).toBe(false); + }); + + it('opens on the Installed tab with the four panel tabs', () => { + const { panel } = makePanel({ installed: [superpowers] }); + const out = strip(renderRaw(panel)); + expect(out).toContain('Plugins'); + expect(out).toContain('Installed'); + expect(out).toContain('Official'); + expect(out).toContain('Curated'); + expect(out).toContain('Custom'); + expect(out).toContain('? Superpowers enabled'); + expect(out).toContain('Space toggle'); + expect(out).toContain('1 installed'); + }); + + it('repaints from the current theme palette without remounting', () => { + const { panel } = makePanel({ installed: [superpowers] }); + const previous = currentTheme.palette; + try { + currentTheme.setPalette(darkColors); + const darkOut = renderRaw(panel); + currentTheme.setPalette(lightColors); + const lightOut = renderRaw(panel); + // A palette snapshot cached at construction would render identically + // after the switch; reading currentTheme.palette at render time must + // produce different ANSI output for the same panel instance. + expect(darkOut).not.toBe(lightOut); + } finally { + currentTheme.setPalette(previous); + } + }); + + it('toggles an installed plugin with Space', () => { + const { panel, onSelect } = makePanel({ installed: [superpowers] }); + panel.handleInput(' '); + expect(onSelect).toHaveBeenCalledWith({ kind: 'toggle', id: 'superpowers', enabled: false }); + }); + + it('routes D / M / R / Enter to remove / mcp / reload / details on the Installed tab', () => { + const { panel, onSelect } = makePanel({ installed: [superpowers] }); + panel.handleInput('d'); + panel.handleInput('m'); + panel.handleInput('r'); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ kind: 'remove', id: 'superpowers' }); + expect(onSelect).toHaveBeenCalledWith({ kind: 'mcp', id: 'superpowers' }); + expect(onSelect).toHaveBeenCalledWith({ kind: 'reload' }); + expect(onSelect).toHaveBeenCalledWith({ kind: 'details', id: 'superpowers' }); + }); + + it('Enter on an installed plugin with an available update installs it', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '4.0.0' }]; + const entries = [ + { + id: 'superpowers', + tier: 'curated' as const, + displayName: 'Superpowers', + version: '5.0.0', + source: 'https://x/s.zip', + }, + ]; + const { panel, onSelect } = makePanel({ installed }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'superpowers' }), + }); + }); + + it('Enter on an up-to-date installed plugin opens details', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '5.0.0' }]; + const entries = [ + { + id: 'superpowers', + tier: 'curated' as const, + displayName: 'Superpowers', + version: '5.0.0', + source: 'https://x/s.zip', + }, + ]; + const { panel, onSelect } = makePanel({ installed }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ kind: 'details', id: 'superpowers' }); + }); + + it('I on an installed plugin opens details even when an update is available', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '4.0.0' }]; + const entries = [ + { + id: 'superpowers', + tier: 'curated' as const, + displayName: 'Superpowers', + version: '5.0.0', + source: 'https://x/s.zip', + }, + ]; + const { panel, onSelect } = makePanel({ installed }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + panel.handleInput('i'); + expect(onSelect).toHaveBeenCalledWith({ kind: 'details', id: 'superpowers' }); + }); + + it('renders the inline plugin hint on the installed row', () => { + const datasource = { ...superpowers, id: 'kimi-datasource', displayName: 'Kimi Datasource', skillCount: 1 }; + const { panel } = makePanel({ + installed: [datasource], + selectedId: 'kimi-datasource', + pluginHint: { id: 'kimi-datasource', text: 'pending /new' }, + }); + const out = strip(renderRaw(panel)); + expect(out).toContain('? Kimi Datasource enabled pending /new'); + }); + + it('lazily loads the Official catalog, then lists installed entries first', () => { + const { panel, onRequestMarketplace } = makePanel({ installed: [superpowers] }); + panel.handleInput('\t'); // → Official + expect(onRequestMarketplace).toHaveBeenCalledTimes(1); + expect(strip(renderRaw(panel))).toContain('Loading marketplace'); + + panel.setMarketplace(marketplaceEntries, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Datasource install'); + expect(out).toContain('Query supported data sources'); + expect(out).not.toContain('Query supported data sources · v3.1.1'); + expect(out).not.toContain('id kimi-datasource'); + expect(out).not.toContain('Official plugin'); + expect(out).not.toContain('· data'); + expect(out).toContain('0 installed · 1 available'); + }); + + it('renders the hardcoded Web Bridge entry on the Official tab while loading', () => { + const { panel } = makePanel({ initialTab: 'official' }); + // The catalog is still loading, but the built-in Web Bridge entry is shown + // immediately because it is baked into the TUI, not fetched. + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Browser Extension open in browser'); + expect(out).toContain('Loading marketplace'); + }); + + it('keeps the Web Bridge entry visible when the Official catalog errors', () => { + const { panel } = makePanel({ initialTab: 'official' }); + panel.setMarketplaceError('fetch failed'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Browser Extension open in browser'); + expect(out).toContain('Marketplace unavailable: fetch failed'); + }); + + it('renders a same-id custom catalog row as a normal plugin, without capability state', () => { + // A custom marketplace may legitimately list an entry reusing the + // kimi-webbridge id: without the capability: marker it must render and + // install as a plain plugin, not borrow capability status. + const capabilities = [makeCapability({ id: 'kimi-webbridge', displayName: 'Kimi Browser Extension' })]; + const entries = [ + { + id: 'kimi-webbridge', + tier: 'official' as const, + displayName: 'Kimi Browser Extension (fork)', + source: 'https://x/fork.zip', + }, + ]; + const { panel, onSelect } = makePanel({ initialTab: 'official', capabilities }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Browser Extension (fork) install'); + + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'kimi-webbridge', source: 'https://x/fork.zip' }), + }); + }); + + it('renders capability rows from the engine while the catalog is still loading', () => { + const capabilities = [ + makeCapability(), + makeCapability({ + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + state: 'not_installed', + steps: [], + }), + ]; + const { panel, onSelect } = makePanel({ initialTab: 'official', capabilities }); + + // No setMarketplace yet — built-in runtime setup must not wait on the + // remote catalog: the engine-known rows render (and the promo is + // suppressed by the real webbridge row). + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Computer Use install'); + expect(out).toContain('Kimi Browser Extension install'); + expect(out).toContain('Background GUI automation'); + expect(out).not.toContain('id kimi-cu'); + expect(out).not.toContain('Official plugin'); + expect(out).not.toContain('open in browser'); + expect(out).toContain('Loading marketplace'); + + panel.handleInput('\r'); // index 0 → kimi-cu routes to capability install + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'kimi-cu', source: 'capability:kimi-cu' }), + }); + panel.handleInput(''); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'kimi-webbridge', source: 'capability:kimi-webbridge' }), + }); + }); + + it('keeps built-in rows out while the overridden marketplace is loading', () => { + // /plugins marketplace or the env override must be able to fully + // replace the Official tab — fallback capability rows stay out too. + const capabilities = [makeCapability()]; + const { panel } = makePanel({ initialTab: 'official', capabilities, catalogIsDefault: false }); + + const out = strip(renderRaw(panel)); + expect(out).not.toContain('Kimi Computer Use'); + expect(out).toContain('Kimi Browser Extension open in browser'); + expect(out).toContain('Loading marketplace'); + }); + + it('opens the Web Bridge webpage on Enter instead of installing', () => { + const { panel, onSelect } = makePanel({ initialTab: 'official' }); + panel.setMarketplace(marketplaceEntries, '/tmp/marketplace.json'); + // Web Bridge is pinned at index 0, so Enter selects it directly. + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'open-url', + url: 'https://www.kimi.com/features/webbridge#local-agent', + label: 'Kimi Browser Extension', + }); + }); + + it('installs a catalog official entry after navigating past Web Bridge', () => { + const { panel, onSelect } = makePanel({ initialTab: 'official' }); + panel.setMarketplace(marketplaceEntries, '/tmp/marketplace.json'); + panel.handleInput('\u001B[B'); // ↓ → kimi-datasource + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'kimi-datasource' }), + }); + }); + + it('lets the real catalog entry win over the pinned Web Bridge promo', () => { + const entries = [ + { + id: 'kimi-webbridge', + tier: 'official' as const, + displayName: 'Kimi Browser Extension', + source: 'capability:kimi-webbridge', + }, + ...officialEntries, + ]; + const { panel, onSelect } = makePanel({ initialTab: 'official' }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + // Exactly one row, and it is the installable catalog copy — the hardcoded + // open-in-browser promo is suppressed. + expect(out.split('Kimi Browser Extension').length - 1).toBe(1); + expect(out).not.toContain('open in browser'); + panel.handleInput('\r'); // index 0 → the real entry installs + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'kimi-webbridge', source: 'capability:kimi-webbridge' }), + }); + }); + + it('installs a Curated entry whose id matches the pinned WebBridge', () => { + // A curated/custom marketplace entry can legitimately reuse the + // kimi-webbridge id; on the Curated tab it must install normally, not + // open the WebBridge page (that shortcut is reserved for the pinned row). + const entries = [ + { + id: 'kimi-webbridge', + tier: 'curated' as const, + displayName: 'Kimi Browser Extension', + source: 'capability:kimi-webbridge', + }, + ]; + const { panel, onSelect } = makePanel({ initialTab: 'third-party' }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Curated'); + expect(out).toContain('Third-party plugins from our partners.'); + expect(out).toContain('Kimi Browser Extension install'); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'kimi-webbridge', source: 'capability:kimi-webbridge' }), + }); + }); + + it('installs the selected Curated entry on Enter', () => { + const { panel, onSelect } = makePanel({ installed: [superpowers], initialTab: 'third-party' }); + panel.setMarketplace(marketplaceEntries, '/tmp/marketplace.json'); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'superpowers' }), + }); + }); + + it('renders an installing state while an install is in progress', () => { + const { panel } = makePanel({ installed: [superpowers] }); + panel.setInstalling('Superpowers'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Installing Superpowers…'); + }); + + it('keeps a valid selection if ↓ is pressed while the catalog is loading', () => { + const { panel, onSelect } = makePanel({ initialTab: 'third-party' }); + // Catalog still loading (entries empty); pressing ↓ must not drive the + // selection negative, or the later Enter would read entries[-1]. + panel.handleInput('\u001B[B'); // ↓ + panel.setMarketplace(marketplaceEntries, '/tmp/marketplace.json'); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install', + entry: expect.objectContaining({ id: 'superpowers' }), + }); + }); + + it('shows untiered custom marketplace entries without the partner description', () => { + const untiered = [ + { id: 'custom-plugin', displayName: 'Custom Plugin', source: 'https://x/c.zip' }, + ]; + const { panel } = makePanel({ initialTab: 'third-party', catalogIsDefault: false }); + panel.setMarketplace(untiered, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Custom Plugin install'); + expect(out).not.toContain('Third-party plugins from our partners.'); + }); + + it('shows an update badge when the marketplace version is newer than installed', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '4.0.0' }]; + const entries = [ + { + id: 'superpowers', + tier: 'curated' as const, + displayName: 'Superpowers', + version: '5.0.0', + source: 'https://x/s.zip', + }, + ]; + const { panel } = makePanel({ installed, initialTab: 'third-party' }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Superpowers update 4.0.0 → 5.0.0'); + }); + + it('shows an update badge on the Installed tab when the marketplace version is newer', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '4.0.0' }]; + const entries = [ + { + id: 'superpowers', + tier: 'curated' as const, + displayName: 'Superpowers', + version: '5.0.0', + source: 'https://x/s.zip', + }, + ]; + const { panel } = makePanel({ installed }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Superpowers enabled update 4.0.0 → 5.0.0'); + }); + + it('updates the Windows backing plugin through its capability entry', () => { + const installed = [ + { + ...superpowers, + id: 'kimi-cu-win', + displayName: 'Kimi Computer Use for Windows', + version: '0.2.13', + }, + ]; + const capability = makeCapability({ pluginId: 'kimi-cu-win' }); + const entry = { + id: 'kimi-cu', + tier: 'official' as const, + displayName: 'Kimi Computer Use', + version: '0.2.14', + source: 'capability:kimi-cu', + builtIn: true, + }; + const { panel, onSelect } = makePanel({ installed, capabilities: [capability] }); + panel.setMarketplace([entry], '/tmp/marketplace.json'); + + expect(strip(renderRaw(panel))).toContain( + 'Kimi Computer Use for Windows enabled update 0.2.13 → 0.2.14', + ); + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ kind: 'install', entry }); + }); + + it('keeps installation state separate from capability readiness', () => { + const installed = [ + { ...superpowers, id: 'kimi-cu', displayName: 'Kimi Computer Use', version: '0.5.4' }, + ]; + const capabilities = [makeCapability()]; + const entries = [ + { + id: 'kimi-cu', + tier: 'official' as const, + displayName: 'Kimi Computer Use', + version: '0.5.4', + source: 'capability:kimi-cu', + builtIn: true, + }, + ]; + const { panel } = makePanel({ installed, capabilities }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + + const installedOut = strip(renderRaw(panel)); + expect(installedOut).toContain('Kimi Computer Use enabled'); + expect(installedOut).not.toContain('setup incomplete'); + expect(installedOut).not.toContain('needs permissions'); + + panel.handleInput('\t'); + const officialOut = strip(renderRaw(panel)); + expect(officialOut).toContain('Kimi Computer Use installed · v0.5.4'); + expect(officialOut).toContain('1 installed · 0 available'); + expect(officialOut).not.toContain('needs permissions'); + }); + + it('uses the Windows backing plugin id for Official installation state', () => { + const installed = [ + { + ...superpowers, + id: 'kimi-cu-win', + displayName: 'Kimi Computer Use for Windows', + version: '0.2.14', + }, + ]; + const capabilities = [makeCapability({ pluginId: 'kimi-cu-win' })]; + const entries = [ + { + id: 'kimi-cu', + tier: 'official' as const, + displayName: 'Kimi Computer Use', + version: '0.2.14', + source: 'capability:kimi-cu', + builtIn: true, + }, + ]; + const { panel } = makePanel({ installed, capabilities, initialTab: 'official' }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Computer Use installed · v0.2.14'); + expect(out).toContain('1 installed · 0 available'); + }); + + it('keeps Enter on the Installed tab consistent with other plugins', () => { + const installed = [ + { ...superpowers, id: 'kimi-cu', displayName: 'Kimi Computer Use', version: '0.5.4' }, + ]; + const { panel, onSelect } = makePanel({ installed, capabilities: [makeCapability()] }); + + panel.handleInput('\r'); + + expect(onSelect).toHaveBeenCalledWith({ kind: 'details', id: 'kimi-cu' }); + }); + + it('keeps unsupported capability diagnostics out of the Installed list', () => { + const installed = [ + { ...superpowers, id: 'kimi-cu', displayName: 'Kimi Computer Use', version: '0.5.4' }, + ]; + const capabilities = [ + makeCapability({ supported: false, state: 'unsupported', steps: [] }), + ]; + const { panel, onSelect } = makePanel({ installed, capabilities }); + + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Computer Use enabled'); + expect(out).not.toContain('unsupported'); + + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ kind: 'details', id: 'kimi-cu' }); + }); + + it('does not expose capability readiness, version, or optional issues in the marketplace', () => { + const capabilities = [ + makeCapability({ + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + state: 'ready', + version: 'v1.11.5', + steps: [ + { id: 'daemon-binary', state: 'ok' }, + { id: 'daemon', state: 'ok' }, + { id: 'skill', state: 'ok' }, + { id: 'extension', state: 'missing', optional: true }, + ], + }), + ]; + const installed = [ + { ...superpowers, id: 'kimi-webbridge', displayName: 'Kimi Browser Extension', version: '1.11.3' }, + ]; + const { panel } = makePanel({ installed, capabilities, initialTab: 'official' }); + panel.setMarketplace( + [{ id: 'kimi-webbridge', displayName: 'Kimi Browser Extension', source: 'capability:kimi-webbridge', tier: 'official', builtIn: true }], + '/tmp/marketplace.json', + ); + + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Browser Extension installed'); + expect(out).not.toContain('ready'); + expect(out).not.toContain('v1.11.5'); + expect(out).not.toContain('browser extension'); + }); + + it('keeps capability repair details out of marketplace rows', () => { + const capabilities = [ + makeCapability({ + id: 'kimi-webbridge', + displayName: 'Kimi Browser Extension', + state: 'partial', + steps: [ + { id: 'daemon-binary', state: 'ok' }, + { id: 'daemon', state: 'ok' }, + { id: 'skill', state: 'missing' }, + { id: 'skill-shadow', state: 'failed', optional: true }, + ], + }), + ]; + const { panel } = makePanel({ capabilities, initialTab: 'official' }); + panel.setMarketplace( + [{ id: 'kimi-webbridge', displayName: 'Kimi Browser Extension', source: 'capability:kimi-webbridge', tier: 'official', builtIn: true }], + '/tmp/marketplace.json', + ); + + const out = strip(renderRaw(panel)); + expect(out).toContain('Kimi Browser Extension install'); + expect(out).not.toContain('agent skill'); + expect(out).not.toContain('skill shadows'); + }); + + it('does not show an update badge on the Installed tab before the marketplace loads', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '4.0.0' }]; + const { panel } = makePanel({ installed }); + // The marketplace has not been loaded yet, so the badge stays hidden rather + // than guessing. + const out = strip(renderRaw(panel)); + expect(out).not.toContain('update'); + }); + + it('shows installed · v when the installed plugin is up to date', () => { + const installed = [{ ...superpowers, id: 'superpowers', version: '5.0.0' }]; + const entries = [ + { + id: 'superpowers', + tier: 'curated' as const, + displayName: 'Superpowers', + version: '5.0.0', + source: 'https://x/s.zip', + }, + ]; + const { panel } = makePanel({ installed, initialTab: 'third-party' }); + panel.setMarketplace(entries, '/tmp/marketplace.json'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Superpowers installed · v5.0.0'); + }); + + it('shows an inline error when the Official catalog fails', () => { + const { panel } = makePanel({ installed: [superpowers] }); + panel.handleInput('\t'); // → Official + panel.setMarketplaceError('fetch failed'); + const out = strip(renderRaw(panel)); + expect(out).toContain('Marketplace unavailable: fetch failed'); + expect(out).toContain('Use the Custom tab'); + }); + + it('installs from a URL typed on the Custom tab', () => { + const { panel, onSelect } = makePanel({ initialTab: 'custom' }); + const out = strip(renderRaw(panel)); + expect(out).toContain('Install from a GitHub URL'); + expect(out).toContain('╭'); + + for (const ch of 'https://github.com/owner/repo') { + panel.handleInput(ch); + } + panel.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ + kind: 'install-source', + source: 'https://github.com/owner/repo', + }); + }); + + it('toggles MCP servers from the MCP selector', () => { + const selections: PluginMcpSelection[] = []; + const picker = new PluginMcpSelectorComponent({ + info: { + id: 'kimi-datasource', + displayName: 'Kimi Datasource', + version: '1.0.0', + enabled: true, + state: 'ok', + skillCount: 1, + mcpServerCount: 1, + enabledMcpServerCount: 1, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'local-path', + installedAt: '2026-05-29T00:00:00.000Z', + root: '/plugins/kimi-datasource', + manifest: undefined, + mcpServers: [ + { + name: 'data', + runtimeName: 'plugin-kimi-datasource-data', + enabled: true, + transport: 'stdio', + command: 'node', + args: ['./bin/kimi-datasource.mjs'], + cwd: '/plugins/kimi-datasource', + }, + ], + diagnostics: [], + }, + onSelect: (selection) => { + selections.push(selection); + }, + onCancel: vi.fn(), + }); + + const raw = renderRaw(picker); + const out = strip(raw); + expect(out).toContain('MCP servers (1/1 enabled)'); + expect(out).toContain('? data enabled'); + expect(out).toContain('Enter/Space enable/disable'); + + picker.handleInput(' '); + + expect(selections).toEqual([ + { kind: 'toggle', pluginId: 'kimi-datasource', server: 'data', enabled: false }, + ]); + }); + + it('defaults plugin removal confirmation to cancel', () => { + const results: PluginRemoveConfirmResult[] = []; + const picker = new PluginRemoveConfirmComponent({ + id: 'kimi-datasource', + displayName: 'Kimi Datasource', + onDone: (result) => { + results.push(result); + }, + }); + + const out = picker.render(120).map(strip); + expect(out).toContain(' Remove Kimi Datasource (kimi-datasource)?'); + expect(out).toContain(' ? Cancel'); + expect(out).toContain(' Keep this plugin installed.'); + expect(out).toContain(' Remove only the install record; plugin files are left in place.'); + + picker.handleInput('\r'); + expect(results).toEqual([{ kind: 'cancel' }]); + }); + + it('confirms plugin removal only after choosing remove', () => { + const results: PluginRemoveConfirmResult[] = []; + const picker = new PluginRemoveConfirmComponent({ + id: 'kimi-datasource', + displayName: 'Kimi Datasource', + onDone: (result) => { + results.push(result); + }, + }); + + picker.handleInput('\u001B[B'); + const raw = renderRaw(picker); + expect(strip(raw)).toContain('Enter/Space select'); + // The destructive option label keeps its danger styling (error + bold). + expect(raw).toContain(dangerShortcut('Remove plugin')); + + picker.handleInput('\r'); + + expect(results).toEqual([{ kind: 'confirm' }]); + }); + + it('defaults the third-party install trust prompt to exit', () => { + const results: PluginInstallTrustConfirmResult[] = []; + const picker = new PluginInstallTrustConfirmComponent({ + label: 'Superpowers', + onDone: (result) => { + results.push(result); + }, + }); + + const raw = renderRaw(picker); + const out = raw.split('\n').map(strip); + expect(out).toContain(' Install third-party plugin Superpowers?'); + expect(out).toContain(' ? Exit'); + expect(out).toContain(' Cancel the installation.'); + expect(out).toContain(' Install this third-party plugin anyway.'); + // The warning explains why confirmation is required and uses the + // design-system warning color rather than muted/default text. + expect(out.some((line) => line.includes('Kimi has not reviewed'))).toBe(true); + expect(out.some((line) => line.includes('trust the source'))).toBe(true); + expect(raw).toContain(warningMark()); + + picker.handleInput('\r'); + expect(results).toEqual([{ kind: 'cancel' }]); + }); + + it('installs a third-party plugin only after switching to trust', () => { + const results: PluginInstallTrustConfirmResult[] = []; + const picker = new PluginInstallTrustConfirmComponent({ + label: 'Superpowers', + onDone: (result) => { + results.push(result); + }, + }); + + picker.handleInput('\u001B[B'); + const raw = renderRaw(picker); + expect(strip(raw)).toContain('Enter/Space select'); + // The opt-in option keeps its danger styling (error + bold). + expect(raw).toContain(dangerShortcut('Trust and install')); + + picker.handleInput('\r'); + + expect(results).toEqual([{ kind: 'confirm' }]); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/provider-manager.test.ts b/apps/kimi-code/test/tui/components/dialogs/provider-manager.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6596cf705b51815734dc0f7879a766dd3c5c47a4 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/provider-manager.test.ts @@ -0,0 +1,137 @@ +import type { ProviderConfig } from '@moonshot-ai/kimi-code-sdk'; +import chalk from 'chalk'; +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; + +import { + ProviderManagerComponent, + type ProviderManagerOptions, +} from '#/tui/components/dialogs/provider-manager'; +import { darkColors } from '#/tui/theme/colors'; + +// Truecolor SGR fragments for the darkColors tokens we assert on +// (see theme/colors.ts). Forcing chalk.level below guarantees they appear. +const PRIMARY = '38;2;79;168;255'; // colors.primary #4FA8FF +const MUTED = '38;2;107;107;107'; // colors.textMuted #6B6B6B +const BOLD = '[1m'; +const ESC = String.fromCodePoint(27); + +const SGR = new RegExp(`${ESC}\\[[0-9;]*m`, 'g'); + +function rendered(component: ProviderManagerComponent, width = 120): string { + return component.render(width).join('\n').replaceAll(SGR, ''); +} + +function makeComponent(overrides: Partial = {}): ProviderManagerComponent { + return new ProviderManagerComponent({ + providers: {} as Record, + onAdd: vi.fn(), + onDeleteSource: vi.fn(), + onClose: vi.fn(), + ...overrides, + }); +} + +function addRowLine(component: ProviderManagerComponent, width = 120): string | undefined { + return component.render(width).find((line) => line.includes('Add New Platform')); +} + +describe('ProviderManagerComponent', () => { + let previousLevel: typeof chalk.level; + beforeAll(() => { + previousLevel = chalk.level; + chalk.level = 3; + }); + afterAll(() => { + chalk.level = previousLevel; + }); + + it('renders [ Add New Platform ] in the brand color, never muted, when not selected', () => { + // A configured provider occupies row 0 (selected); the add row sits below + // it and is therefore not the highlighted row. + const component = makeComponent({ + providers: { + acme: { baseUrl: 'https://acme.test' }, + } as unknown as Record, + activeProviderId: 'acme', + }); + const line = addRowLine(component); + expect(line).toBeDefined(); + expect(line).toContain(PRIMARY); + expect(line).not.toContain(MUTED); + }); + + it('bolds [ Add New Platform ] when it is the selected row', () => { + // With no configured providers the synthetic add row is the only row, so it + // starts as the highlighted selection. + const component = makeComponent(); + const line = addRowLine(component); + expect(line).toBeDefined(); + expect(line).toContain(BOLD); + expect(line).toContain(PRIMARY); + }); + + it('marks the active provider with the shared "← current" marker, not a bullet', () => { + const component = makeComponent({ + providers: { + acme: { baseUrl: 'https://acme.test' }, + } as unknown as Record, + activeProviderId: 'acme', + }); + const plain = component + .render(120) + .join('\n') + .replaceAll(/\[[0-9;]*m/g, ''); + expect(plain).toContain('← current'); + expect(plain).not.toContain('●'); + }); + + it('uses the same header shape as the model dialog (one top border, title, hint, no inner border)', () => { + const component = makeComponent({ + providers: { + acme: { baseUrl: 'https://acme.test' }, + } as unknown as Record, + activeProviderId: 'acme', + }); + const lines = component.render(120).map((l) => l.replaceAll(SGR, '')); + const isBorder = (l: string | undefined): boolean => /^─+$/.test((l ?? '').trim()); + + const titleIdx = lines.findIndex((l) => l.includes('Providers')); + expect(titleIdx).toBeGreaterThanOrEqual(0); + // The line directly under the title is the hint, never an inner border (the + // old `border · title · border` sandwich is gone). + expect(isBorder(lines[titleIdx + 1])).toBe(false); + expect(lines[titleIdx + 1]).toContain('navigate'); + expect(lines[titleIdx + 1]).toContain('Esc cancel'); + // Blank line separates the hint from the body, exactly like the model dialog. + expect(lines[titleIdx + 2]).toBe(''); + // Only the top and bottom full-width borders remain — two, not three. + expect(lines.filter(isBorder).length).toBe(2); + }); + + it('deletes the highlighted provider via the D key with a y/N confirm', () => { + const onDeleteSource = vi.fn(); + const component = makeComponent({ + providers: { + acme: { baseUrl: 'https://acme.test' }, + } as unknown as Record, + activeProviderId: 'acme', + onDeleteSource, + }); + component.handleInput('D'); + expect(rendered(component)).toContain('[y/N]'); + component.handleInput('y'); + expect(onDeleteSource).toHaveBeenCalledWith(['acme']); + }); + + it('closes on Esc', () => { + const onClose = vi.fn(); + const component = makeComponent({ + providers: { + acme: { baseUrl: 'https://acme.test' }, + } as unknown as Record, + onClose, + }); + component.handleInput(ESC); + expect(onClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts b/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..322d10e9135ce997738526322548a7628f26ae1e --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/question-dialog.test.ts @@ -0,0 +1,560 @@ +import { CURSOR_MARKER } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; +import { beforeAll, describe, expect, it } from 'vitest'; + +import { QuestionDialogComponent } from '#/tui/components/dialogs/question-dialog'; +import type { PendingQuestion } from '#/tui/reverse-rpc/types'; +import { currentTheme } from '#/tui/theme'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +// Collapse all whitespace runs so wrapped content can be matched against its +// original (single-line) form without caring where the line break landed. +function flatten(text: string): string { + return strip(text).replaceAll(/\s+/g, ' ').trim(); +} + +beforeAll(() => { + chalk.level = 3; +}); + +function makePending( + questions: PendingQuestion['data']['questions'], + requestId = 'q_1', +): PendingQuestion { + return { + data: { + id: requestId, + tool_call_id: 'tc_1', + questions, + }, + }; +} + +function makeDialog( + pending: PendingQuestion, + onToggleToolOutput?: () => void, +): { + dialog: QuestionDialogComponent; + collected: string[][]; + methods: Array; +} { + const collected: string[][] = []; + const methods: Array = []; + const dialog = new QuestionDialogComponent( + pending, + (response) => { + collected.push(response.answers); + methods.push(response.method); + }, + 6, + onToggleToolOutput, + ); + return { dialog, collected, methods }; +} + +describe('QuestionDialogComponent', () => { + it('single-select answers auto-advance and only submit from the review tab', () => { + const pending = makePending([ + { + question: 'Q1?', + multi_select: false, + options: [{ label: 'A1' }, { label: 'B1' }], + }, + { + question: 'Q2?', + multi_select: false, + options: [{ label: 'A2' }, { label: 'B2' }], + }, + ]); + const { dialog, collected, methods } = makeDialog(pending); + + dialog.handleInput('2'); + expect(collected).toEqual([]); + expect(strip(dialog.render(80).join('\n'))).toMatch(/Q2\?/); + + dialog.handleInput('\r'); + expect(collected).toEqual([]); + + const reviewRaw = dialog.render(80).join('\n'); + const review = strip(reviewRaw); + expect(review).toContain('Review your answer before submit'); + expect(review).toContain('Ready to submit your answers?'); + expect(review).not.toContain('? Ready to submit your answers?'); + expect(review).not.toContain('Please answer all questions before submitting.'); + expect(reviewRaw).toContain( + currentTheme.boldFg('text', ' Review your answer before submit'), + ); + expect(reviewRaw).toContain(currentTheme.fg('text', ' Ready to submit your answers?')); + expect(review).toContain('B1'); + expect(review).toContain('A2'); + + dialog.handleInput('1'); + expect(collected).toEqual([['B1', 'A2']]); + expect(methods).toEqual(['enter']); + }); + + it('last single-select question goes straight to review instead of wrapping back', () => { + const pending = makePending([ + { + question: 'Q1?', + multi_select: false, + options: [{ label: 'A1' }, { label: 'B1' }], + }, + { + question: 'Q2?', + multi_select: false, + options: [{ label: 'A2' }, { label: 'B2' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + + dialog.handleInput('\t'); + dialog.handleInput('2'); + + const review = strip(dialog.render(80).join('\n')); + expect(review).toContain('Review your answer before submit'); + expect(review).toContain('Some questions are still unanswered.'); + expect(review).toContain('B2'); + expect(review).toContain('Not answered'); + expect(collected).toEqual([]); + }); + + it('renders optional body text above options', () => { + const pending = makePending([ + { + question: 'Approve this plan?', + body: '# Plan\n\n1. Make the focused change.', + multi_select: false, + options: [{ label: 'Approve' }, { label: 'Reject' }], + }, + ]); + const { dialog } = makeDialog(pending); + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain('# Plan'); + expect(out).toContain('1. Make the focused change.'); + expect(out).toContain('Approve'); + expect(out).toContain('Other'); + }); + + it('multi-select uses space and number keys to toggle choices', () => { + const pending = makePending([ + { + question: 'Pick many?', + multi_select: true, + options: [{ label: 'A' }, { label: 'B' }, { label: 'C' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + + dialog.handleInput(' '); + dialog.handleInput('\u001B[B'); + dialog.handleInput('\u001B[B'); + dialog.handleInput('3'); + dialog.handleInput('\t'); + + const review = strip(dialog.render(80).join('\n')); + expect(review).toContain('A, C'); + expect(review).not.toContain('Not answered'); + expect(collected).toEqual([]); + }); + + it('review shows an unanswered warning and still allows submit', () => { + const pending = makePending([ + { + question: 'Q1?', + multi_select: false, + options: [{ label: 'A1' }, { label: 'B1' }], + }, + { + question: 'Q2?', + multi_select: false, + options: [{ label: 'A2' }, { label: 'B2' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + + dialog.handleInput('\t'); + dialog.handleInput('2'); + + const before = strip(dialog.render(80).join('\n')); + expect(before).toContain('Not answered'); + expect(before).toContain('Some questions are still unanswered.'); + + dialog.handleInput('\r'); + expect(collected).toHaveLength(1); + expect(collected[0]?.[0]).toBeUndefined(); + expect(collected[0]?.[1]).toBe('B2'); + }); + + it('review cancel dismisses the whole request', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + + dialog.handleInput('\t'); + dialog.handleInput('2'); + + expect(collected).toEqual([[]]); + }); + + it('single-select Other input is inline and auto-advances after commit', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + other_label: 'Custom', + other_description: 'Type your own answer', + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog, collected, methods } = makeDialog(pending); + + dialog.handleInput('3'); + let out = strip(dialog.render(80).join('\n')); + expect(out).toContain('→ [3] Custom:'); + expect(out).not.toContain('Type your own answer'); + + dialog.handleInput('H'); + dialog.handleInput('i'); + dialog.handleInput('\r'); + + out = strip(dialog.render(80).join('\n')); + expect(out).toContain('Review your answer before submit'); + expect(out).toContain('Ready to submit your answers?'); + expect(out).not.toContain('? Ready to submit your answers?'); + expect(out).toContain('Hi'); + + dialog.handleInput('1'); + expect(collected).toEqual([['Hi']]); + expect(methods).toEqual(['enter']); + }); + + it('Other input supports left/right cursor editing before commit', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + other_label: 'Custom', + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog } = makeDialog(pending); + + dialog.handleInput('3'); + dialog.handleInput('H'); + dialog.handleInput('i'); + dialog.handleInput('\u001B[D'); + dialog.handleInput('!'); + dialog.handleInput('\r'); + + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain('H!i'); + expect(out).toContain('Review your answer before submit'); + }); + + it('renders an IME cursor marker while editing Other when focused', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + other_label: 'Custom', + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog } = makeDialog(pending); + + dialog.focused = true; + dialog.handleInput('3'); + + const out = dialog.render(80).join('\n'); + expect(out).toContain(CURSOR_MARKER); + }); + + it('keeps selected options green even when the cursor returns to them', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog } = makeDialog(pending); + + dialog.handleInput('\r'); + dialog.handleInput('\u001B[D'); + + const out = dialog.render(80).join('\n'); + expect(out).toContain(currentTheme.boldFg('success', ' → [1] A')); + expect(out).not.toContain(currentTheme.fg('primary', ' → [1] A')); + }); + + it('stretches the border to the full available width', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog } = makeDialog(pending); + + const lines = dialog.render(80); + expect(strip(lines[0] ?? '')).toHaveLength(80); + expect(strip(lines.at(-1) ?? '')).toHaveLength(80); + }); + + it('does not show the submit tab as completed when all questions are answered', () => { + const pending = makePending([ + { + question: 'Q1?', + multi_select: false, + options: [{ label: 'A1' }, { label: 'B1' }], + }, + { + question: 'Q2?', + multi_select: false, + options: [{ label: 'A2' }, { label: 'B2' }], + }, + ]); + const { dialog } = makeDialog(pending); + + dialog.handleInput('\r'); + dialog.handleInput('\r'); + + const out = strip(dialog.render(80).join('\n')); + expect(out).toContain(' Submit '); + expect(out).not.toContain('(✓) Submit'); + expect(out).not.toContain('(○) Submit'); + }); + + it('renders the active tab with a highlighted background instead of the circle marker', () => { + const pending = makePending([ + { + question: 'Q1?', + header: 'First', + multi_select: false, + options: [{ label: 'A1' }, { label: 'B1' }], + }, + { + question: 'Q2?', + header: 'Second', + multi_select: false, + options: [{ label: 'A2' }, { label: 'B2' }], + }, + ]); + const { dialog } = makeDialog(pending); + + const out = dialog.render(80).join('\n'); + expect(out).toContain( + chalk.bgHex(currentTheme.color('primary')).hex(currentTheme.color('text')).bold(' First '), + ); + expect(out).not.toContain('(●) First'); + }); + + it('preserves Other drafts across tabs and question navigation', () => { + const pending = makePending([ + { + question: 'Pick toppings?', + multi_select: true, + options: [{ label: 'Cheese' }, { label: 'Pepperoni' }], + }, + ]); + const { dialog } = makeDialog(pending); + + dialog.handleInput('3'); + dialog.handleInput('M'); + dialog.handleInput('u'); + dialog.handleInput('s'); + dialog.handleInput('h'); + dialog.handleInput('r'); + dialog.handleInput('o'); + dialog.handleInput('o'); + dialog.handleInput('m'); + dialog.handleInput('\t'); + + let out = strip(dialog.render(80).join('\n')); + expect(out).toContain('Not answered'); + + dialog.handleInput('\u001B[D'); + out = strip(dialog.render(80).join('\n')); + expect(out).toContain('Other: Mushroom'); + + dialog.handleInput('\r'); + dialog.handleInput('\r'); + dialog.handleInput('\t'); + out = strip(dialog.render(80).join('\n')); + expect(out).toContain('Mushroom'); + }); + + it('multi-select Other can be toggled off after it is committed', () => { + const pending = makePending([ + { + question: 'Pick toppings?', + multi_select: true, + options: [{ label: 'Cheese' }, { label: 'Pepperoni' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + + // Select Other and commit a custom value. + dialog.handleInput('3'); + dialog.handleInput('M'); + dialog.handleInput('u'); + dialog.handleInput('s'); + dialog.handleInput('h'); + dialog.handleInput('r'); + dialog.handleInput('o'); + dialog.handleInput('o'); + dialog.handleInput('m'); + dialog.handleInput('\r'); + + // Toggle it off using the same key. + dialog.handleInput('3'); + // Select a preset option to confirm the answer still builds correctly. + dialog.handleInput('1'); + dialog.handleInput('\t'); + + const review = strip(dialog.render(80).join('\n')); + expect(review).toContain('Cheese'); + expect(review).not.toContain('Mushroom'); + + dialog.handleInput('1'); + expect(collected).toEqual([['Cheese']]); + }); + + it('escape dismisses with empty answers array', () => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + dialog.handleInput('\u001B'); + expect(collected).toEqual([[]]); + }); + + it.each(['\u0003', '\u0004'])('ctrl shortcut %j dismisses question dialog', (key) => { + const pending = makePending([ + { + question: 'Pick one?', + multi_select: false, + options: [{ label: 'A' }, { label: 'B' }], + }, + ]); + const { dialog, collected } = makeDialog(pending); + dialog.handleInput(key); + expect(collected).toEqual([[]]); + }); + it('forwards ctrl+o to the global tool-output toggle without answering', () => { + let toggles = 0; + const pending = makePending([ + { question: 'Q?', multi_select: false, options: [{ label: 'A' }] }, + ]); + const { dialog, collected } = makeDialog(pending, () => toggles++); + dialog.handleInput('\u000F'); // Ctrl+O + expect(toggles).toBe(1); + expect(collected).toEqual([]); + }); + + describe('long-content wrapping', () => { + const longQuestion = + 'Please confirm whether this dangerous shell command should really be executed in the current workspace, including all of its side effects on the filesystem and the network.'; + const longBody = + 'This single-line body description is intentionally written without any embedded newlines so the renderer is forced to wrap it across multiple rows instead of truncating with an ellipsis.'; + const longLabel = + 'Apply changes to every file under the current workspace including nested submodules and lockfiles'; + const longDescription = + 'This option will rewrite history on the remote branch and force-push, so collaborators will need to re-sync their local checkouts before continuing any work.'; + + it('wraps the question text across multiple lines instead of truncating', () => { + const pending = makePending([ + { + question: longQuestion, + multi_select: false, + options: [{ label: 'Yes' }, { label: 'No' }], + }, + ]); + const { dialog } = makeDialog(pending); + const rendered = dialog.render(40); + const joined = rendered.map((line) => strip(line).trimEnd()).join('\n'); + const flat = flatten(rendered.join('\n')); + + expect(joined).not.toContain('…'); + // Question text should span multiple physical lines. + expect(joined.split('\n').filter((l) => l.includes('?') || /Please|workspace|side/.test(l)).length).toBeGreaterThan(1); + // And the full content should still be reconstructable. + expect(flat).toContain(longQuestion); + }); + + it('wraps body lines that exceed the terminal width', () => { + const pending = makePending([ + { + question: 'Q?', + body: longBody, + multi_select: false, + options: [{ label: 'A' }], + }, + ]); + const { dialog } = makeDialog(pending); + const rendered = dialog.render(40); + const joined = rendered.map((line) => strip(line).trimEnd()).join('\n'); + const flat = flatten(rendered.join('\n')); + + expect(joined).not.toContain('…'); + expect(flat).toContain(longBody); + }); + + it('wraps long option labels and descriptions', () => { + const pending = makePending([ + { + question: 'Q?', + multi_select: false, + options: [ + { + label: longLabel, + description: longDescription, + }, + ], + }, + ]); + const { dialog } = makeDialog(pending); + const rendered = dialog.render(40); + const joined = rendered.map((line) => strip(line).trimEnd()).join('\n'); + const flat = flatten(rendered.join('\n')); + + expect(joined).not.toContain('…'); + expect(flat).toContain(longLabel); + expect(flat).toContain(longDescription); + }); + + it('wraps long questions in the submit-tab review', () => { + const pending = makePending([ + { + question: longQuestion, + multi_select: false, + options: [{ label: 'Yes' }, { label: 'No' }], + }, + ]); + const { dialog } = makeDialog(pending); + dialog.handleInput('1'); + const rendered = dialog.render(40); + const joined = rendered.map((line) => strip(line).trimEnd()).join('\n'); + const flat = flatten(rendered.join('\n')); + + expect(joined).toContain('Review your answer before submit'); + expect(joined).not.toContain('…'); + expect(flat).toContain(longQuestion); + }); + }); + +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/session-picker.test.ts b/apps/kimi-code/test/tui/components/dialogs/session-picker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4af77adaaf2074e27b726a9c0432db520d8aeca --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/session-picker.test.ts @@ -0,0 +1,1167 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { SessionPickerComponent } from '#/tui/components/dialogs/session-picker'; + +function stripAnsi(text: string): string { + return text.replaceAll(/\[[0-?]*[ -/]*[@-~]/g, ''); +} + +function renderPlain(component: SessionPickerComponent, width = 120): string { + return stripAnsi(component.render(width).join('\n')); +} + +const BACKSPACE = String.fromCodePoint(127); +const ESC = String.fromCodePoint(27); + +describe('SessionPickerComponent', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('forwards Ctrl-C and Ctrl-D to optional host shortcuts', () => { + const onCtrlC = vi.fn(); + const onCtrlD = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onCtrlC, + onCtrlD, + }); + + component.handleInput('\u0003'); + component.handleInput('\u0004'); + + expect(onCtrlC).toHaveBeenCalledOnce(); + expect(onCtrlD).toHaveBeenCalledOnce(); + }); + + it('renders millisecond updated_at timestamps as relative times', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_minutes', + title: 'minutes old', + work_dir: '/tmp/project', + updated_at: now - 2 * 60 * 1000, + }, + { + id: 'ses_hours', + title: 'hours old', + work_dir: '/tmp/project', + updated_at: now - 3 * 60 * 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_other', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).toContain('2m ago'); + expect(output).toContain('3h ago'); + expect(output).not.toContain('just now'); + }); + + it('renders title, full session id, work_dir, and last_prompt for each session', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_01HXYABCDEFGHIJK', + title: 'Refactor sessions list', + last_prompt: 'please redesign the picker UI', + work_dir: '/tmp/project', + updated_at: now - 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_other', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).toContain('Refactor sessions list'); + // Session id is rendered in full, never abbreviated with an ellipsis. + expect(output).toContain('ses_01HXYABCDEFGHIJK'); + expect(output).not.toMatch(/ses_01\S*…/); + expect(output).toContain('/tmp/project'); + expect(output).toContain('please redesign the picker UI'); + }); + + it('omits the last-prompt row when last_prompt is missing', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_no_prompt', + title: 'no prompt yet', + work_dir: '/tmp/project', + updated_at: now - 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_other', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).not.toMatch(/^\s*›/m); + }); + + it('truncates overly long last_prompt content', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const longPrompt = 'a'.repeat(500); + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_long', + title: 'long prompt', + last_prompt: longPrompt, + work_dir: '/tmp/project', + updated_at: now - 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_other', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = component.render(60).map((line) => stripAnsi(line)); + const promptLine = lines.find((line) => line.trimStart().startsWith('›')); + expect(promptLine).toBeDefined(); + expect(promptLine!.length).toBeLessThanOrEqual(60); + expect(promptLine!.endsWith('…')).toBe(true); + expect(promptLine).not.toContain(longPrompt); + }); + + it('marks the current session with a "← current" badge', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_current', + title: 'this is current', + work_dir: '/tmp/project', + updated_at: now, + }, + { + id: 'ses_other', + title: 'not current', + work_dir: '/tmp/project', + updated_at: now - 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_current', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = component.render(120).map((line) => stripAnsi(line)); + const currentLine = lines.find((line) => line.includes('this is current')); + const otherLine = lines.find((line) => line.includes('not current')); + expect(currentLine).toContain('← current'); + expect(otherLine).not.toContain('← current'); + }); + + it('places the relative time on the same line as the title, not right-aligned', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_inline_time', + title: 'Short title', + work_dir: '/tmp/project', + updated_at: now - 5 * 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_other', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = component.render(120).map((line) => stripAnsi(line)); + const headerLine = lines.find((line) => line.includes('Short title')); + expect(headerLine).toBeDefined(); + // Title and time sit side-by-side with only the small inline separator. + expect(headerLine).toMatch(/Short title\s{1,4}5m ago/); + // No long run of trailing spaces, i.e. not right-aligned. + expect(headerLine).not.toMatch(/Short title\s{8,}/); + }); + + it('prepends [imported] badge before the title for sessions migrated from kimi-cli', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_imported', + title: 'Migrated session', + work_dir: '/tmp/project', + updated_at: now - 60 * 1000, + metadata: { imported_from_kimi_cli: true }, + }, + { + id: 'ses_native', + title: 'Fresh session', + work_dir: '/tmp/project', + updated_at: now - 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_other', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const lines = component.render(120).map((line) => stripAnsi(line)); + const importedLine = lines.find((line) => line.includes('Migrated session')); + const nativeLine = lines.find((line) => line.includes('Fresh session')); + expect(importedLine).toContain('[imported] Migrated session'); + expect(nativeLine).not.toContain('[imported]'); + }); + + it('keeps every rendered line within the terminal width even for CJK content', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_cjk_long_session_id_value', + title: '现在要重构一下 TUI 的 sessions 列表,要渲染几个字段,让 UI 更好看', + last_prompt: + '我们要渲染几个:sessionid title lastPrompt。工作目录,修改时间。需要重新设计下 UI。', + work_dir: '/Users/someone/Desktop/中文目录/very-long-project-folder-name', + updated_at: now - 5 * 60 * 1000, + }, + ], + loading: false, + currentSessionId: 'ses_cjk_long_session_id_value', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + for (const width of [40, 80, 120, 238]) { + const lines = component.render(width); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + // Regression for #240: a long session id, the inline time + "(current)" + // badge, and a long prompt all used to be appended past the terminal edge, + // which crashed the renderer with "Rendered line exceeds terminal width" on + // very narrow terminals. + it('never renders a line wider than the terminal, even on tiny widths (#240)', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + + const id = 'ses_fbe574f3-572d-487f-9fa0-d09694f599d4'; + const component = new SessionPickerComponent({ + sessions: [ + { + id, + title: 'refactor the sessions list so the UI looks much nicer than before', + last_prompt: 'please redesign the picker UI to be much nicer than before', + work_dir: '/Users/getlong/Development/cesiumdb', + updated_at: now - 5 * 60 * 1000, + metadata: { imported_from_kimi_cli: true }, + }, + ], + loading: false, + currentSessionId: id, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + for (let width = 10; width <= 60; width++) { + const lines = component.render(width); + for (const [idx, line] of lines.entries()) { + expect(visibleWidth(line), `width=${String(width)} line#${String(idx)}`).toBeLessThanOrEqual( + width, + ); + } + } + }); + + it('calls onToggleScope with the selected session id when Ctrl+A is pressed', () => { + const onToggleScope = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_a', + title: 'Session A', + work_dir: '/tmp/project-a', + updated_at: 1, + }, + { + id: 'ses_b', + title: 'Session B', + work_dir: '/tmp/project-b', + updated_at: 2, + }, + ], + loading: false, + currentSessionId: '', + scope: 'cwd', + onSelect: vi.fn(), + onCancel: vi.fn(), + onToggleScope, + }); + + component.handleInput('\u001B[B'); + component.handleInput('\u0001'); + + expect(onToggleScope).toHaveBeenCalledOnce(); + expect(onToggleScope).toHaveBeenCalledWith('ses_b'); + }); + + it('calls onToggleScope with the current session id when Ctrl+A is pressed with no sessions', () => { + const onToggleScope = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [], + loading: false, + currentSessionId: 'ses_current', + scope: 'cwd', + onSelect: vi.fn(), + onCancel: vi.fn(), + onToggleScope, + }); + + component.handleInput('\u0001'); + + expect(onToggleScope).toHaveBeenCalledOnce(); + expect(onToggleScope).toHaveBeenCalledWith('ses_current'); + }); + + it('renders the Ctrl+A all-sessions hint when the current cwd has no sessions', () => { + const component = new SessionPickerComponent({ + sessions: [], + loading: false, + currentSessionId: 'ses_current', + scope: 'cwd', + onSelect: vi.fn(), + onCancel: vi.fn(), + onToggleScope: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).toContain('No sessions found.'); + expect(output).toContain('Ctrl+A all'); + }); + + it('renders all-sessions scope header and Ctrl+A current-cwd hint', () => { + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_all', + title: 'All scope session', + work_dir: '/tmp/project', + updated_at: 1, + }, + ], + loading: false, + currentSessionId: '', + scope: 'all', + onSelect: vi.fn(), + onCancel: vi.fn(), + onToggleScope: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).toContain('All sessions'); + expect(output).toContain('↑↓ navigate · Ctrl+A current cwd · Enter select · Esc cancel'); + }); + + it('selects the full session row on Enter', () => { + const onSelect = vi.fn(); + const session = { + id: 'ses_row', + title: 'Row session', + work_dir: '/tmp/project-row', + updated_at: 1, + }; + const component = new SessionPickerComponent({ + sessions: [session], + loading: false, + currentSessionId: '', + scope: 'cwd', + onSelect, + onCancel: vi.fn(), + }); + + component.handleInput('\r'); + + expect(onSelect).toHaveBeenCalledOnce(); + expect(onSelect).toHaveBeenCalledWith(session); + }); + + it('loads the next 50 sessions after moving past the loaded page', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + const component = new SessionPickerComponent({ + sessions: Array.from({ length: 120 }, (_, index) => ({ + id: `ses_${String(index).padStart(4, '0')}`, + title: `Session ${String(index).padStart(4, '0')}`, + work_dir: '/tmp/project', + updated_at: now - index * 1000, + })), + loading: false, + currentSessionId: '', + scope: 'all', + pageSize: 50, + maxVisibleSessions: 4, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + for (let i = 0; i < 50; i++) { + component.handleInput('\u001B[B'); + } + + const output = renderPlain(component); + + expect(output).toContain('Session 0050'); + expect(output).toContain('Showing 49-52 of 100 loaded / 120 sessions'); + }); + + it('keeps initial selected session id and loads enough pages for it', () => { + const component = new SessionPickerComponent({ + sessions: Array.from({ length: 80 }, (_, index) => ({ + id: `ses_${String(index).padStart(4, '0')}`, + title: `Session ${String(index).padStart(4, '0')}`, + work_dir: '/tmp/project', + updated_at: index, + })), + loading: false, + currentSessionId: '', + scope: 'all', + initialSelectedSessionId: 'ses_0070', + pageSize: 50, + maxVisibleSessions: 4, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).toContain('Session 0070'); + expect(output).toContain('Showing 69-72 of 80 sessions'); + }); + + it('shows type-to-search copy only when the query is empty', () => { + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_search_copy', + title: 'Search copy session', + work_dir: '/tmp/project', + updated_at: 1, + }, + ], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + const output = renderPlain(component); + + expect(output).toContain('Sessions (type to search)'); + expect(output).not.toContain('Search:'); + + component.handleInput('x'); + const searchOutput = renderPlain(component); + + expect(searchOutput).toContain('Search: x'); + expect(searchOutput).not.toContain('Sessions (type to search)'); + }); + + it('fuzzy-filters by session name only when typing', () => { + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_alpha', + title: 'Alpha session', + last_prompt: 'needleprompt do not match', + work_dir: '/tmp/needleprompt', + updated_at: 1, + }, + { + id: 'ses_beta', + title: 'Beta session', + last_prompt: 'other prompt', + work_dir: '/tmp/other', + updated_at: 2, + }, + { + id: 'ses_fuzzy', + title: 'N1e2e3d4l5e session', + last_prompt: 'prompt only', + work_dir: '/tmp/project', + updated_at: 3, + }, + ], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + component.handleInput('n'); + component.handleInput('e'); + component.handleInput('e'); + component.handleInput('d'); + component.handleInput('l'); + component.handleInput('e'); + + const output = renderPlain(component); + + expect(output).toContain('Search: needle'); + expect(output).toContain('N1e2e3d4l5e session'); + expect(output).not.toContain('Alpha session'); + expect(output).not.toContain('Beta session'); + }); + + it('clears the query on Backspace and cancels on Esc only after the query is empty', () => { + const onCancel = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_alpha', + title: 'Alpha session', + work_dir: '/tmp/project', + updated_at: 1, + }, + { + id: 'ses_beta', + title: 'Beta session', + work_dir: '/tmp/project', + updated_at: 2, + }, + ], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel, + }); + + component.handleInput('z'); + expect(renderPlain(component)).toContain('Search: z'); + + component.handleInput(BACKSPACE); + expect(renderPlain(component)).not.toContain('Search:'); + expect(onCancel).not.toHaveBeenCalled(); + + component.handleInput('z'); + expect(renderPlain(component)).toContain('Search: z'); + + component.handleInput(ESC); + expect(renderPlain(component)).not.toContain('Search:'); + expect(onCancel).not.toHaveBeenCalled(); + + component.handleInput(ESC); + expect(onCancel).toHaveBeenCalledOnce(); + }); + + it('selects the filtered session row on Enter', () => { + const onSelect = vi.fn(); + const target = { + id: 'ses_gamma', + title: 'Gamma session', + work_dir: '/tmp/project-gamma', + updated_at: 3, + }; + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_alpha', + title: 'Alpha session', + work_dir: '/tmp/project-alpha', + updated_at: 1, + }, + { + id: 'ses_beta', + title: 'Beta session', + work_dir: '/tmp/project-beta', + updated_at: 2, + }, + target, + ], + loading: false, + currentSessionId: '', + onSelect, + onCancel: vi.fn(), + }); + + component.handleInput('g'); + component.handleInput('a'); + component.handleInput('m'); + component.handleInput('\r'); + + expect(onSelect).toHaveBeenCalledOnce(); + expect(onSelect).toHaveBeenCalledWith(target); + }); + + it('loads the next 50 matching sessions after moving past the filtered page', () => { + const now = new Date('2026-05-11T12:00:00.000Z').getTime(); + vi.spyOn(Date, 'now').mockReturnValue(now); + const component = new SessionPickerComponent({ + sessions: [ + ...Array.from({ length: 80 }, (_, index) => ({ + id: `ses_needle_${String(index).padStart(4, '0')}`, + title: `Needle ${String(index).padStart(4, '0')}`, + work_dir: '/tmp/project', + updated_at: now - index * 1000, + })), + ...Array.from({ length: 40 }, (_, index) => ({ + id: `ses_other_${String(index).padStart(4, '0')}`, + title: `Other ${String(index).padStart(4, '0')}`, + work_dir: '/tmp/project', + updated_at: now - (80 + index) * 1000, + })), + ], + loading: false, + currentSessionId: '', + pageSize: 50, + maxVisibleSessions: 4, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + component.handleInput('n'); + component.handleInput('e'); + component.handleInput('e'); + component.handleInput('d'); + component.handleInput('l'); + component.handleInput('e'); + for (let i = 0; i < 50; i++) { + component.handleInput('\u001B[B'); + } + + const output = renderPlain(component); + + expect(output).toContain('Needle 0050'); + expect(output).toContain('Showing 49-52 of 80 loaded / 80 matches'); + }); + + it('calls onToggleScope with the selected filtered session id when Ctrl+A is pressed', () => { + const onToggleScope = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [ + { + id: 'ses_alpha', + title: 'Alpha session', + work_dir: '/tmp/project-a', + updated_at: 1, + }, + { + id: 'ses_beta', + title: 'Beta session', + work_dir: '/tmp/project-b', + updated_at: 2, + }, + ], + loading: false, + currentSessionId: '', + scope: 'cwd', + onSelect: vi.fn(), + onCancel: vi.fn(), + onToggleScope, + }); + + component.handleInput('b'); + component.handleInput('e'); + component.handleInput('t'); + component.handleInput('a'); + component.handleInput('\u0001'); + + expect(onToggleScope).toHaveBeenCalledOnce(); + expect(onToggleScope).toHaveBeenCalledWith('ses_beta'); + }); + + it('fires onLoadMore when the cursor reaches the last fetched row', () => { + const onLoadMore = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [ + { id: 'ses_a', title: 'Alpha', work_dir: '/tmp/project', updated_at: 1 }, + { id: 'ses_b', title: 'Beta', work_dir: '/tmp/project', updated_at: 2 }, + ], + loading: false, + currentSessionId: '', + hasMore: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + onLoadMore, + }); + + component.handleInput('\u001B[B'); + + expect(onLoadMore).toHaveBeenCalledOnce(); + }); + + it('does not fire onLoadMore while a page fetch is in flight', () => { + const onLoadMore = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [ + { id: 'ses_a', title: 'Alpha', work_dir: '/tmp/project', updated_at: 1 }, + { id: 'ses_b', title: 'Beta', work_dir: '/tmp/project', updated_at: 2 }, + ], + loading: false, + currentSessionId: '', + hasMore: true, + loadingMore: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + onLoadMore, + }); + + component.handleInput('\u001B[B'); + + expect(onLoadMore).not.toHaveBeenCalled(); + }); + + it('appendSessions extends the list and keeps the active query', () => { + const component = new SessionPickerComponent({ + sessions: [{ id: 'ses_alpha', title: 'Alpha session', work_dir: '/tmp/p', updated_at: 1 }], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + component.handleInput('g'); + expect(renderPlain(component)).toContain('No matches'); + + component.appendSessions([ + { id: 'ses_gamma', title: 'Gamma session', work_dir: '/tmp/p', updated_at: 2 }, + ]); + + const output = renderPlain(component); + expect(output).toContain('Search: g'); + expect(output).toContain('Gamma session'); + expect(output).not.toContain('Alpha session'); + }); + + it('appendSessions keeps the selected row', () => { + const onSelect = vi.fn(); + const beta = { id: 'ses_beta', title: 'Beta session', work_dir: '/tmp/p', updated_at: 2 }; + const component = new SessionPickerComponent({ + sessions: [ + { id: 'ses_alpha', title: 'Alpha session', work_dir: '/tmp/p', updated_at: 1 }, + beta, + ], + loading: false, + currentSessionId: '', + onSelect, + onCancel: vi.fn(), + }); + + component.handleInput('\u001B[B'); + component.appendSessions([ + { id: 'ses_gamma', title: 'Gamma session', work_dir: '/tmp/p', updated_at: 3 }, + ]); + component.handleInput('\r'); + + expect(onSelect).toHaveBeenCalledOnce(); + expect(onSelect).toHaveBeenCalledWith(beta); + }); + + it('fires onSearchDrain only when the query becomes active with unfetched pages', () => { + const onSearchDrain = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [{ id: 'ses_alpha', title: 'Alpha session', work_dir: '/tmp/p', updated_at: 1 }], + loading: false, + currentSessionId: '', + hasMore: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + onSearchDrain, + }); + + component.handleInput('a'); + component.handleInput('l'); + + expect(onSearchDrain).toHaveBeenCalledOnce(); + }); + + it('does not fire onSearchDrain when every page is already fetched', () => { + const onSearchDrain = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [{ id: 'ses_alpha', title: 'Alpha session', work_dir: '/tmp/p', updated_at: 1 }], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onSearchDrain, + }); + + component.handleInput('a'); + + expect(onSearchDrain).not.toHaveBeenCalled(); + }); + + it('announces unfetched pages and in-flight fetches in the footer', () => { + const component = new SessionPickerComponent({ + sessions: [ + { id: 'ses_a', title: 'Alpha', work_dir: '/tmp/project', updated_at: 1 }, + { id: 'ses_b', title: 'Beta', work_dir: '/tmp/project', updated_at: 2 }, + ], + loading: false, + currentSessionId: '', + hasMore: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + expect(renderPlain(component)).toContain('· scroll for more'); + + component.setPaging(true, true); + expect(renderPlain(component)).toContain('· loading more…'); + + component.setPaging(false, false); + const settled = renderPlain(component); + expect(settled).not.toContain('· scroll for more'); + expect(settled).not.toContain('· loading more…'); + }); + + it('notes the background drain in the footer while searching with unfetched pages', () => { + const component = new SessionPickerComponent({ + sessions: [{ id: 'ses_alpha', title: 'Alpha session', work_dir: '/tmp/p', updated_at: 1 }], + loading: false, + currentSessionId: '', + hasMore: true, + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + + component.handleInput('a'); + + expect(renderPlain(component)).toContain('· searching all…'); + }); + + describe('session deletion', () => { + const CTRL_X = '\u0018'; + + function deferred(): { + promise: Promise; + resolve: () => void; + reject: (error: unknown) => void; + } { + let resolve!: () => void; + let reject!: (error: unknown) => void; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve, reject }; + } + + async function flushMicrotasks(): Promise { + await new Promise((r) => { + setTimeout(r, 0); + }); + } + + const alpha = { id: 'ses_alpha', title: 'Alpha session', work_dir: '/tmp/p', updated_at: 2 }; + const beta = { id: 'ses_beta', title: 'Beta session', work_dir: '/tmp/p', updated_at: 1 }; + + it('arms an inline delete confirmation on Ctrl+X for the selected row', () => { + const onDeleteRequest = vi.fn(async () => {}); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest, + }); + + component.handleInput(CTRL_X); + + expect(renderPlain(component)).toContain('Delete session "Alpha session"? [y/N]'); + expect(onDeleteRequest).not.toHaveBeenCalled(); + }); + + it('does nothing on Ctrl+X without a delete handler or a selected row', () => { + const noHandler = new SessionPickerComponent({ + sessions: [alpha], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + noHandler.handleInput(CTRL_X); + expect(renderPlain(noHandler)).not.toContain('Delete session'); + + const noRows = new SessionPickerComponent({ + sessions: [], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest: vi.fn(async () => {}), + }); + noRows.handleInput(CTRL_X); + expect(renderPlain(noRows)).not.toContain('Delete session'); + }); + + it('confirms on y, shows a deleting state, and clears it after success', async () => { + const { promise, resolve } = deferred(); + const onDeleteRequest = vi.fn(() => promise); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest, + }); + + component.handleInput(CTRL_X); + component.handleInput('y'); + + expect(onDeleteRequest).toHaveBeenCalledOnce(); + expect(onDeleteRequest).toHaveBeenCalledWith(alpha); + expect(renderPlain(component)).toContain('Deleting session "Alpha session"…'); + + resolve(); + await flushMicrotasks(); + + const output = renderPlain(component); + expect(output).not.toContain('Deleting session'); + expect(output).not.toContain('Delete session'); + }); + + it('cancels on n and on Esc without calling onDeleteRequest or onCancel', () => { + const onDeleteRequest = vi.fn(async () => {}); + const onCancel = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel, + onDeleteRequest, + }); + + component.handleInput(CTRL_X); + component.handleInput('n'); + expect(renderPlain(component)).not.toContain('Delete session'); + + component.handleInput(CTRL_X); + component.handleInput(ESC); + expect(renderPlain(component)).not.toContain('Delete session'); + + expect(onDeleteRequest).not.toHaveBeenCalled(); + expect(onCancel).not.toHaveBeenCalled(); + }); + + it('ignores all other keys while the confirmation is armed', () => { + const onDeleteRequest = vi.fn(async () => {}); + const onSelect = vi.fn(); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect, + onCancel: vi.fn(), + onDeleteRequest, + }); + + component.handleInput(CTRL_X); + component.handleInput('\r'); + component.handleInput('\u001B[B'); + component.handleInput('x'); + component.handleInput(CTRL_X); + + expect(renderPlain(component)).toContain('Delete session "Alpha session"? [y/N]'); + expect(onDeleteRequest).not.toHaveBeenCalled(); + expect(onSelect).not.toHaveBeenCalled(); + }); + + it('ignores keys while a delete is in flight', async () => { + const { promise, resolve } = deferred(); + const onDeleteRequest = vi.fn(() => promise); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest, + }); + + component.handleInput(CTRL_X); + component.handleInput('y'); + component.handleInput('y'); + component.handleInput(CTRL_X); + component.handleInput('\r'); + component.handleInput(ESC); + + expect(onDeleteRequest).toHaveBeenCalledOnce(); + + resolve(); + await flushMicrotasks(); + }); + + it('returns to the list when the delete fails', async () => { + const { promise, reject } = deferred(); + const onDeleteRequest = vi.fn(() => promise); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest, + }); + + component.handleInput(CTRL_X); + component.handleInput('y'); + reject(new Error('boom')); + await flushMicrotasks(); + + const output = renderPlain(component); + expect(output).not.toContain('Deleting session'); + expect(output).not.toContain('Delete session'); + expect(onDeleteRequest).toHaveBeenCalledOnce(); + }); + + it('adds Ctrl+X delete to the hint when deletion is available', () => { + const component = new SessionPickerComponent({ + sessions: [alpha], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest: vi.fn(async () => {}), + }); + + expect(renderPlain(component)).toContain('Ctrl+X delete'); + }); + + it('ignores input while a selection is in flight', async () => { + const { promise, resolve } = deferred(); + const onSelect = vi.fn(() => promise); + const onDeleteRequest = vi.fn(async () => {}); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect, + onCancel: vi.fn(), + onDeleteRequest, + }); + + component.handleInput('\r'); + expect(onSelect).toHaveBeenCalledOnce(); + + component.handleInput(CTRL_X); + expect(renderPlain(component)).not.toContain('Delete session'); + component.handleInput('y'); + component.handleInput('\r'); + expect(onSelect).toHaveBeenCalledOnce(); + expect(onDeleteRequest).not.toHaveBeenCalled(); + + resolve(); + await flushMicrotasks(); + + component.handleInput(CTRL_X); + expect(renderPlain(component)).toContain('Delete session "Alpha session"? [y/N]'); + }); + + it('unlocks input when the selection fails', async () => { + const { promise, reject } = deferred(); + const onSelect = vi.fn(() => promise); + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect, + onCancel: vi.fn(), + onDeleteRequest: vi.fn(async () => {}), + }); + + component.handleInput('\r'); + expect(onSelect).toHaveBeenCalledOnce(); + + reject(new Error('boom')); + await flushMicrotasks(); + + component.handleInput(CTRL_X); + expect(renderPlain(component)).toContain('Delete session "Alpha session"? [y/N]'); + }); + + it('keeps every line within the terminal width with a delete confirmation armed', () => { + const component = new SessionPickerComponent({ + sessions: [alpha, beta], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest: vi.fn(async () => {}), + }); + component.handleInput(CTRL_X); + + for (const width of [10, 20, 24, 40]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('keeps the [y/N] confirmation keys visible when the title is truncated', () => { + const longTitled = { + id: 'ses_long', + title: 'A very long session title that cannot fit a narrow terminal', + work_dir: '/tmp/p', + updated_at: 2, + }; + const component = new SessionPickerComponent({ + sessions: [longTitled], + loading: false, + currentSessionId: '', + onSelect: vi.fn(), + onCancel: vi.fn(), + onDeleteRequest: vi.fn(async () => {}), + }); + + component.handleInput(CTRL_X); + + for (const width of [40, 24, 20, 12, 8]) { + expect(renderPlain(component, width)).toContain('? [y/N]'); + } + }); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/survey-preference-selector.test.ts b/apps/kimi-code/test/tui/components/dialogs/survey-preference-selector.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6538d939092d4618d67bc5073871b3047afbb958 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/survey-preference-selector.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from 'vitest'; + +import { SurveyPreferenceSelectorComponent } from '#/tui/components/dialogs/survey-preference-selector'; + +const ANSI = /\[[0-9;]*m/g; +const strip = (s: string): string => s.replaceAll(ANSI, ''); + +describe('SurveyPreferenceSelectorComponent', () => { + it('maps the current preference onto the picker options', () => { + const selected: boolean[] = []; + const enabledPicker = new SurveyPreferenceSelectorComponent({ + currentValue: true, + onSelect: (value) => selected.push(value), + onCancel: () => {}, + }); + const disabledPicker = new SurveyPreferenceSelectorComponent({ + currentValue: false, + onSelect: (value) => selected.push(value), + onCancel: () => {}, + }); + + expect(strip(enabledPicker.render(60).join('\n'))).toContain('Feedback survey'); + expect(strip(disabledPicker.render(60).join('\n'))).toContain('Off'); + + enabledPicker.handleInput('\r'); + expect(selected).toEqual([true]); + disabledPicker.handleInput('\r'); + expect(selected).toEqual([true, false]); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/tabbed-model-selector.test.ts b/apps/kimi-code/test/tui/components/dialogs/tabbed-model-selector.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c202e0bf857ea021101f161b09148312355049b4 --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/tabbed-model-selector.test.ts @@ -0,0 +1,172 @@ +import type { ModelAlias } from '@moonshot-ai/kimi-code-sdk'; +import chalk from 'chalk'; +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; + +import { TabbedModelSelectorComponent } from '#/tui/components/dialogs/tabbed-model-selector'; +import { currentTheme } from '#/tui/theme'; +import { darkColors, lightColors } from '#/tui/theme/colors'; + +const ESC = String.fromCodePoint(27); +const SGR = new RegExp(`${ESC}\\[[0-9;]*m`, 'g'); +const strip = (s: string): string => s.replaceAll(SGR, ''); +const TAB = '\t'; +const RIGHT = `${ESC}[C`; +// chalk.bgHex(colors.primary) → background truecolor for #4FA8FF. +const PRIMARY_BG = '48;2;79;168;255'; + +function model(displayName: string, provider: string): ModelAlias { + return { + provider, + model: displayName.toLowerCase().replaceAll(' ', '-'), + maxContextSize: 200_000, + displayName, + capabilities: ['thinking'], + } as unknown as ModelAlias; +} + +function make(): { + component: TabbedModelSelectorComponent; + onSelect: ReturnType; +} { + const onSelect = vi.fn(); + const component = new TabbedModelSelectorComponent({ + models: { + k2: model('Kimi K2', 'managed:kimi-code'), + gpt: model('GPT-5', 'openai'), + }, + currentValue: 'k2', + currentThinkingEffort: 'off', + onSelect, + onCancel: vi.fn(), + }); + component.focused = true; + return { component, onSelect }; +} + +describe('TabbedModelSelectorComponent', () => { + let previousLevel: typeof chalk.level; + const previousPalette = currentTheme.palette; + beforeAll(() => { + previousLevel = chalk.level; + chalk.level = 3; + currentTheme.setPalette(darkColors); + }); + afterAll(() => { + chalk.level = previousLevel; + currentTheme.setPalette(previousPalette); + }); + + it('renders an "All" + per-provider tab strip', () => { + const out = strip(make().component.render(120).join('\n')); + expect(out).toContain('All'); + expect(out).toContain('Kimi Code'); + expect(out).toContain('openai'); + }); + + it('highlights the active tab with a filled background (AskUserQuestion style)', () => { + // currentValue k2 → the active tab is "Kimi Code"; its cell carries the + // primary background SGR. + const raw = make().component.render(120).join('\n'); + expect(raw).toContain(PRIMARY_BG); + }); + + it('repaints the tab strip from the current theme palette without remounting', () => { + const { component } = make(); + const stripLine = (lines: string[]): string => + lines.find((l) => l.includes('All') && l.includes('openai')) ?? ''; + const previous = currentTheme.palette; + try { + currentTheme.setPalette(darkColors); + const darkStrip = stripLine(component.render(120)); + currentTheme.setPalette(lightColors); + const lightStrip = stripLine(component.render(120)); + // The strip is drawn from currentTheme.palette at render time; a + // construction-time palette snapshot would render the same strip after + // the switch. + expect(darkStrip).not.toBe(lightStrip); + } finally { + currentTheme.setPalette(previous); + } + }); + + it('opens on the All tab by default (showing every provider\'s models)', () => { + const out = strip(make().component.render(120).join('\n')); + expect(out).toContain('Kimi K2'); + expect(out).toContain('GPT-5'); + }); + + it('cycles provider tabs with Tab', () => { + const { component } = make(); + // tabs = [All, Kimi Code, openai]; active starts on All. + // Two Tabs → openai, whose list shows GPT-5 and not Kimi K2. + component.handleInput(TAB); + component.handleInput(TAB); + const out = strip(component.render(120).join('\n')); + expect(out).toContain('GPT-5'); + expect(out).not.toContain('Kimi K2'); + }); + + it('forwards thinking toggle (←/→) and selection (Enter) to the active tab', () => { + const { component, onSelect } = make(); + component.handleInput(RIGHT); // toggle thinking on for k2 + component.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith({ alias: 'k2', thinking: 'on' }); + }); + + it('frames the tab strip with a blank line above and below it', () => { + const lines = make().component.render(120).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('navigate') && l.includes('Esc cancel')); + const stripIdx = lines.findIndex((l) => l.includes('All') && l.includes('openai')); + expect(hintIdx).toBeGreaterThanOrEqual(0); + expect(lines[hintIdx + 1]).toBe(''); // blank between hint and tabs + expect(stripIdx).toBe(hintIdx + 2); + expect(lines[stripIdx + 1]).toBe(''); // blank between tabs and list + }); + + it('mentions the Tab provider switch first in the hint line', () => { + const lines = make().component.render(120).map(strip); + const hint = lines.find((l) => l.includes('navigate') && l.includes('Esc cancel')); + expect(hint).toBeDefined(); + expect(hint).toContain('Tab toggle provider'); + // It comes first, before the navigation hint. + expect(hint!.indexOf('Tab toggle provider')).toBeLessThan(hint!.indexOf('↑↓ navigate')); + }); + + it('renders the default title, and a custom title when provided', () => { + expect(strip(make().component.render(120).join('\n'))).toContain('Select a model'); + + const titled = new TabbedModelSelectorComponent({ + models: { k2: model('Kimi K2', 'managed:kimi-code') }, + currentValue: 'k2', + currentThinkingEffort: 'off', + title: ' Choose a model for this task', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const out = strip(titled.render(120).join('\n')); + expect(out).toContain('Choose a model for this task'); + expect(out).not.toContain('Select a model '); + }); + + it('keeps the tab strip between hint and list when a warning line is present', () => { + const component = new TabbedModelSelectorComponent({ + models: { + k2: model('Kimi K2', 'managed:kimi-code'), + gpt: model('GPT-5', 'openai'), + }, + currentValue: 'k2', + currentThinkingEffort: 'off', + warning: 'Switching may increase token usage.', + onSelect: vi.fn(), + onCancel: vi.fn(), + }); + const lines = component.render(120).map(strip); + const hintIdx = lines.findIndex((l) => l.includes('navigate') && l.includes('Esc cancel')); + expect(lines[hintIdx + 1]).toContain('Switching may increase token usage.'); + expect(lines[hintIdx + 2]).toBe(''); // blank between warning and tabs + const stripIdx = lines.findIndex((l) => l.includes('All') && l.includes('openai')); + expect(stripIdx).toBe(hintIdx + 3); + expect(lines[stripIdx + 1]).toBe(''); // blank between tabs and list + expect(lines.findIndex((l) => l.includes('Kimi K2'))).toBeGreaterThan(stripIdx); + }); +}); diff --git a/apps/kimi-code/test/tui/components/dialogs/trust-prompt.test.ts b/apps/kimi-code/test/tui/components/dialogs/trust-prompt.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1627893d5bef40587f2b91c45b5702a96e093bc --- /dev/null +++ b/apps/kimi-code/test/tui/components/dialogs/trust-prompt.test.ts @@ -0,0 +1,103 @@ +import { describe, expect, it, vi } from 'vitest'; + +import type { WorkspaceTrustMcpServerInfo } from '@moonshot-ai/kimi-code-sdk'; + +import { TrustPromptComponent } from '#/tui/components/dialogs/trust-prompt'; + +const ANSI_SGR = /\[[0-9;]*m/g; + +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function renderLines(gatedMcpServers: readonly WorkspaceTrustMcpServerInfo[] = []): string[] { + const prompt = new TrustPromptComponent({ + workDir: '/tmp/demo-workspace', + gatedMcpServers, + onSelect: vi.fn(), + }); + return prompt.render(100).map(strip); +} + +describe('TrustPromptComponent', () => { + it('renders the header vocabulary and the workspace path', () => { + const lines = renderLines(); + const titleIdx = lines.findIndex((l) => l.includes('Trust this folder?')); + expect(titleIdx).toBeGreaterThanOrEqual(0); + const hint = lines[titleIdx + 1]; + expect(hint).toContain('↑↓ navigate'); + expect(hint).toContain('Enter select'); + expect(hint).toContain('Esc exit'); + expect(lines.some((l) => l.includes('/tmp/demo-workspace'))).toBe(true); + }); + + it('lists the gated project MCP servers when present', () => { + const lines = renderLines([ + { name: 'nested-server', transport: 'stdio', command: 'nested-cmd', args: ['--safe'], cwd: '/tmp' }, + { name: 'root-server', transport: 'http', url: 'https://example.test/mcp' }, + ]); + expect(lines.some((l) => l.includes('Project MCP targets'))).toBe(true); + expect(lines.some((l) => l.includes('nested-server (stdio): command=nested-cmd'))).toBe(true); + expect(lines.some((l) => l.includes('args=["--safe"] cwd=/tmp'))).toBe(true); + expect(lines.some((l) => l.includes('root-server (http): url=https://example.test/mcp'))).toBe(true); + expect(renderLines().some((l) => l.includes('This folder defines'))).toBe(false); + }); + + it('strips terminal control characters from workspace-supplied MCP targets', () => { + const lines = renderLines([ + { name: 'evil', transport: 'stdio', command: 'cmd\u001B[2J\u0007evil' }, + { name: 'multi\nline', transport: 'http', url: 'https://example.test/\u001B]8;;https://evil.test\u0007' }, + ]); + const text = lines.join('\n'); + // ESC and BEL are dropped, defusing the sequences into harmless literal text. + expect(text).toContain('evil (stdio): command=cmd[2Jevil'); + expect(text).toContain('multiline (http): url=https://example.test/]8;;https://evil.test'); + expect(text).not.toContain('\u001B]8;;https://evil.test'); + }); + + it('defaults to Trust this folder', () => { + const onSelect = vi.fn(); + const prompt = new TrustPromptComponent({ + workDir: '/tmp/demo-workspace', + gatedMcpServers: [], + onSelect, + }); + prompt.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith('trust'); + }); + + it('stays on trust when moving up past the top', () => { + const onSelect = vi.fn(); + const prompt = new TrustPromptComponent({ + workDir: '/tmp/demo-workspace', + gatedMcpServers: [], + onSelect, + }); + prompt.handleInput('\u001B[A'); + prompt.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith('trust'); + }); + + it('selects distrust after moving the cursor down', () => { + const onSelect = vi.fn(); + const prompt = new TrustPromptComponent({ + workDir: '/tmp/demo-workspace', + gatedMcpServers: [], + onSelect, + }); + prompt.handleInput('\u001B[B'); + prompt.handleInput('\r'); + expect(onSelect).toHaveBeenCalledWith('distrust'); + }); + + it('treats Esc as distrust', () => { + const onSelect = vi.fn(); + const prompt = new TrustPromptComponent({ + workDir: '/tmp/demo-workspace', + gatedMcpServers: [], + onSelect, + }); + prompt.handleInput('\u001B'); + expect(onSelect).toHaveBeenCalledWith('distrust'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/custom-editor.test.ts b/apps/kimi-code/test/tui/components/editor/custom-editor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..914c62e98838b07ea2ddbbc27b5eb002327e0052 --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/custom-editor.test.ts @@ -0,0 +1,879 @@ +import type { + AutocompleteItem, + AutocompleteProvider, + AutocompleteSuggestions, + TUI, +} from '@moonshot-ai/pi-tui'; +import { describe, expect, it, vi } from 'vitest'; + +import { CustomEditor } from '#/tui/components/editor/custom-editor'; +import { FileMentionProvider } from '#/tui/components/editor/file-mention-provider'; + +function makeEditor(): CustomEditor { + const tui = { + requestRender: vi.fn(), + render: vi.fn(() => []), + terminal: { rows: 40, cols: 120 }, + } as unknown as TUI; + return new CustomEditor(tui); +} + +async function flushAutocomplete(): Promise { + await Promise.resolve(); + await Promise.resolve(); +} + +function providerReturning(items: AutocompleteItem[]): AutocompleteProvider { + return { + getSuggestions: vi.fn(async () => ({ items, prefix: '/' })), + applyCompletion: vi.fn((lines, cursorLine, cursorCol) => ({ lines, cursorLine, cursorCol })), + }; +} + +function providerRecordingForce(items: AutocompleteItem[]): { + provider: AutocompleteProvider; + calls: Array<{ force: boolean | undefined; text: string }>; +} { + const calls: Array<{ force: boolean | undefined; text: string }> = []; + const provider: AutocompleteProvider = { + getSuggestions: vi.fn(async (lines, cursorLine, cursorCol, options) => { + const text = (lines[cursorLine] ?? '').slice(0, cursorCol); + calls.push({ force: options?.force, text }); + return { items, prefix: text }; + }), + applyCompletion: vi.fn((lines, cursorLine, cursorCol) => ({ lines, cursorLine, cursorCol })), + }; + return { provider, calls }; +} + +describe('CustomEditor autocomplete Escape handling', () => { + it('escape closes a visible slash command menu without firing app-level escape', async () => { + const editor = makeEditor(); + const onEscape = vi.fn(); + editor.onEscape = onEscape; + editor.setAutocompleteProvider(providerReturning([{ value: 'help', label: 'help' }])); + + editor.handleInput('/'); + await flushAutocomplete(); + + expect(editor.isShowingAutocomplete()).toBe(true); + + editor.handleInput('\u001B'); + + expect(editor.isShowingAutocomplete()).toBe(false); + expect(onEscape).not.toHaveBeenCalled(); + }); + + it('escape cancels an in-flight slash command menu request', async () => { + const editor = makeEditor(); + const onEscape = vi.fn(); + let resolveSuggestions: (items: AutocompleteItem[]) => void = () => {}; + const provider: AutocompleteProvider = { + getSuggestions: vi.fn( + () => + new Promise((resolve) => { + resolveSuggestions = (items) => { + resolve({ items, prefix: '/' }); + }; + }), + ), + applyCompletion: vi.fn((lines, cursorLine, cursorCol) => ({ lines, cursorLine, cursorCol })), + }; + editor.onEscape = onEscape; + editor.setAutocompleteProvider(provider); + + editor.handleInput('/'); + await flushAutocomplete(); + editor.handleInput('\u001B'); + resolveSuggestions([{ value: 'help', label: 'help' }]); + await flushAutocomplete(); + + expect(editor.isShowingAutocomplete()).toBe(false); + expect(onEscape).not.toHaveBeenCalled(); + }); +}); + +describe('CustomEditor onNonEscapeInput', () => { + it('fires for a printable key and not for a lone Escape', () => { + const editor = makeEditor(); + const onNonEscapeInput = vi.fn(); + editor.onNonEscapeInput = onNonEscapeInput; + + editor.handleInput('a'); + expect(onNonEscapeInput).toHaveBeenCalledOnce(); + + editor.handleInput('\u001B'); + expect(onNonEscapeInput).toHaveBeenCalledOnce(); + }); + + it('fires for control keys so they break a pending double-Esc', () => { + const editor = makeEditor(); + const onNonEscapeInput = vi.fn(); + editor.onNonEscapeInput = onNonEscapeInput; + + editor.handleInput('\u0003'); + expect(onNonEscapeInput).toHaveBeenCalledOnce(); + }); +}); + +describe('CustomEditor slash argument completion refresh', () => { + it('reopens /add-dir directory completions after tab completion and entering slash', async () => { + const editor = makeEditor(); + const provider = new FileMentionProvider( + [ + { + name: 'add-dir', + description: 'Add directory', + getArgumentCompletions: (prefix) => + prefix === '/' ? [{ value: '/tmp/shared/', label: 'shared/' }] : null, + }, + ], + process.cwd(), + null, + ); + editor.setAutocompleteProvider(provider); + + for (const char of '/add-dir ') { + editor.handleInput(char); + } + await flushAutocomplete(); + + editor.handleInput('/'); + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + + expect(editor.getText()).toBe('/add-dir /'); + expect(editor.isShowingAutocomplete()).toBe(true); + }); + + it('reopens the next directory level after tab-accepting a directory', async () => { + const editor = makeEditor(); + const provider = new FileMentionProvider( + [ + { + name: 'add-dir', + description: 'Add directory', + getArgumentCompletions: (prefix) => { + if (prefix === '/') return [{ value: '/tmp/shared/', label: 'shared/' }]; + if (prefix === '/tmp/shared/') + return [{ value: '/tmp/shared/child/', label: 'child/' }]; + return null; + }, + }, + ], + process.cwd(), + null, + ); + editor.setAutocompleteProvider(provider); + + for (const char of '/add-dir ') { + editor.handleInput(char); + } + await flushAutocomplete(); + + editor.handleInput('/'); + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + expect(editor.isShowingAutocomplete()).toBe(true); + + editor.handleInput('\t'); + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + + expect(editor.getText()).toBe('/add-dir /tmp/shared/'); + expect(editor.isShowingAutocomplete()).toBe(true); + }); +}); + +describe('CustomEditor slash command name Tab-accept', () => { + it('reopens subcommand completions after Tab-accepting a slash command name', async () => { + const editor = makeEditor(); + const provider = new FileMentionProvider( + [ + { + name: 'goal', + description: 'Manage goals', + getArgumentCompletions: (prefix) => + prefix === '' + ? [ + { value: 'status', label: 'status' }, + { value: 'pause', label: 'pause' }, + ] + : null, + }, + ], + process.cwd(), + null, + ); + editor.setAutocompleteProvider(provider); + + for (const char of '/go') { + editor.handleInput(char); + } + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + expect(editor.isShowingAutocomplete()).toBe(true); + + editor.handleInput('\t'); + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + + expect(editor.getText()).toBe('/goal '); + expect(editor.isShowingAutocomplete()).toBe(true); + }); + + it('does not fall back to file completions for a command without subcommands', async () => { + const editor = makeEditor(); + const provider = new FileMentionProvider( + [ + { + name: 'compact', + description: 'Compact context', + }, + ], + process.cwd(), + null, + ); + editor.setAutocompleteProvider(provider); + + for (const char of '/comp') { + editor.handleInput(char); + } + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + expect(editor.isShowingAutocomplete()).toBe(true); + + editor.handleInput('\t'); + await new Promise((resolve) => setTimeout(resolve, 20)); + await flushAutocomplete(); + + expect(editor.getText()).toBe('/compact '); + expect(editor.isShowingAutocomplete()).toBe(false); + }); +}); + +describe('CustomEditor @ mention completion refresh', () => { + it('reopens the next directory level after tab-accepting an @ directory', async () => { + const editor = makeEditor(); + const provider: AutocompleteProvider = { + getSuggestions: vi.fn( + async ( + lines: string[], + cursorLine: number, + cursorCol: number, + ): Promise => { + const text = (lines[cursorLine] ?? '').slice(0, cursorCol); + if (text === '@') { + return { items: [{ value: '@shared/', label: 'shared/' }], prefix: '@' }; + } + if (text === '@shared/') { + return { items: [{ value: '@shared/child/', label: 'child/' }], prefix: '@shared/' }; + } + return { items: [], prefix: '' }; + }, + ), + applyCompletion: vi.fn( + ( + lines: string[], + cursorLine: number, + cursorCol: number, + item: AutocompleteItem, + prefix: string, + ) => { + const line = lines[cursorLine] ?? ''; + const beforePrefix = line.slice(0, cursorCol - prefix.length); + const afterCursor = line.slice(cursorCol); + const newLine = beforePrefix + item.value + afterCursor; + const newLines = [...lines]; + newLines[cursorLine] = newLine; + return { + lines: newLines, + cursorLine, + cursorCol: beforePrefix.length + item.value.length, + }; + }, + ), + }; + editor.setAutocompleteProvider(provider); + + editor.handleInput('@'); + await new Promise((resolve) => setTimeout(resolve, 30)); + await flushAutocomplete(); + expect(editor.isShowingAutocomplete()).toBe(true); + + editor.handleInput('\t'); + await new Promise((resolve) => setTimeout(resolve, 30)); + await flushAutocomplete(); + + expect(editor.getText()).toBe('@shared/'); + expect(editor.isShowingAutocomplete()).toBe(true); + }); +}); + +describe('CustomEditor Tab key handling', () => { + it('does not open autocomplete when Tab is pressed with the dropdown closed', async () => { + const editor = makeEditor(); + const provider = providerReturning([{ value: '@src/file.ts', label: 'file.ts' }]); + editor.setAutocompleteProvider(provider); + + editor.handleInput('\t'); + await new Promise((resolve) => setTimeout(resolve, 30)); + await flushAutocomplete(); + + expect(provider.getSuggestions).not.toHaveBeenCalled(); + expect(editor.isShowingAutocomplete()).toBe(false); + }); +}); + +describe('CustomEditor slash argument hint', () => { + // oxlint-disable-next-line no-control-regex -- ESC (\u001B) is required to match ANSI SGR escape sequences + const stripAnsi = (s: string): string => s.replaceAll(/\u001B\[[0-9;]*m/g, ''); + + it('renders the argument hint after a command with a trailing space', () => { + const editor = makeEditor(); + editor.setArgumentHints(new Map([['add-dir', '[list] | ']])); + + for (const char of '/add-dir ') { + editor.handleInput(char); + } + + const plain = editor.render(90).map(stripAnsi).join('\n'); + expect(plain).toContain('[list] | '); + }); + + it('renders the argument hint after a command without a trailing space', () => { + const editor = makeEditor(); + editor.setArgumentHints(new Map([['add-dir', '[list] | ']])); + + for (const char of '/add-dir') { + editor.handleInput(char); + } + + const plain = editor.render(90).map(stripAnsi).join('\n'); + expect(plain).toContain('[list] | '); + }); + + it('hides the hint once an argument is typed', () => { + const editor = makeEditor(); + editor.setArgumentHints(new Map([['add-dir', '[list] | ']])); + + for (const char of '/add-dir foo') { + editor.handleInput(char); + } + + const plain = editor.render(90).map(stripAnsi).join('\n'); + expect(plain).not.toContain('[list] | '); + }); + + it('does not render a hint for an unknown command', () => { + const editor = makeEditor(); + editor.setArgumentHints(new Map([['add-dir', '[list] | ']])); + + for (const char of '/unknown ') { + editor.handleInput(char); + } + + const plain = editor.render(90).map(stripAnsi).join('\n'); + expect(plain).not.toContain('[list] | '); + }); + + it('does not render the argument hint in bash mode', () => { + const editor = makeEditor(); + editor.setArgumentHints(new Map([['add-dir', '[list] | ']])); + editor.inputMode = 'bash'; + + for (const char of '/add-dir') { + editor.handleInput(char); + } + + const plain = editor.render(90).map(stripAnsi).join('\n'); + expect(plain).not.toContain('[list] | '); + }); + + it('does not highlight the slash token in bash mode', () => { + const editor = makeEditor(); + editor.inputMode = 'bash'; + + for (const char of '/add-dir') { + editor.handleInput(char); + } + + const contentLine = editor.render(90)[1] ?? ''; + const tokenIdx = contentLine.indexOf('/add-dir'); + expect(tokenIdx).toBeGreaterThan(-1); + // Prompt mode wraps `/add-dir` in a primary-colour ANSI sequence; in bash + // mode the token is plain text, so the byte right before it is a space. + expect(contentLine[tokenIdx - 1]).toBe(' '); + }); +}); + +describe('CustomEditor slash menu description wrapping', () => { + // oxlint-disable-next-line no-control-regex -- ESC (\u001B) is required to match ANSI SGR escape sequences + const stripAnsi = (s: string): string => s.replaceAll(/\u001B\[[0-9;]*m/g, ''); + + it('wraps long slash command descriptions to at most two lines with an ellipsis', async () => { + const editor = makeEditor(); + const description = 'word '.repeat(60).trim(); + editor.setAutocompleteProvider( + providerReturning([{ value: 'deep', label: 'deep', description }]), + ); + + editor.handleInput('/'); + await flushAutocomplete(); + + const plain = editor.render(90).map(stripAnsi); + const descriptionLines = plain.filter((line) => line.includes('word')); + expect(descriptionLines).toHaveLength(2); + expect(descriptionLines[1]).toContain('…'); + }); + + it('keeps non-slash autocomplete descriptions on a single line', async () => { + const editor = makeEditor(); + const description = 'path '.repeat(60).trim(); + const provider: AutocompleteProvider = { + getSuggestions: vi.fn(async () => ({ + items: [{ value: '@src/file.ts', label: 'file.ts', description }], + prefix: '@f', + })), + applyCompletion: vi.fn((lines, cursorLine, cursorCol) => ({ + lines, + cursorLine, + cursorCol, + })), + }; + editor.setAutocompleteProvider(provider); + + editor.handleInput('@'); + // @-mention requests are debounced (20ms), unlike slash menus. + await new Promise((resolve) => setTimeout(resolve, 30)); + await flushAutocomplete(); + + const plain = editor.render(90).map(stripAnsi); + const descriptionLines = plain.filter((line) => line.includes('path')); + expect(descriptionLines).toHaveLength(1); + expect(plain.join('\n')).not.toContain('…'); + }); +}); + +describe('CustomEditor Kitty key release handling', () => { + it('ignores Kitty key release events instead of inserting their CSI-u payload', () => { + const editor = makeEditor(); + + editor.handleInput('\u001B[47;1:3u'); + editor.handleInput('\u001B[110;1:3u'); + + expect(editor.getText()).toBe(''); + }); +}); + +describe('CustomEditor paste marker expansion', () => { + const PASTE_START = '\u001B[200~'; + const PASTE_END = '\u001B[201~'; + + function simulateLargePaste(editor: CustomEditor, content: string): void { + editor.handleInput(`${PASTE_START}${content}${PASTE_END}`); + } + + it('expands paste marker when bracketed paste arrives while cursor is on marker', () => { + const editor = makeEditor(); + const longText = 'line\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, longText); + + expect(editor.getText()).toMatch(/\[paste #1 \+15 lines\]/); + + simulateLargePaste(editor, 'anything'); + + expect(editor.getText()).not.toContain('[paste #'); + expect(editor.getText()).toContain(longText); + }); + + it('does not expand when cursor is not on a paste marker', () => { + const editor = makeEditor(); + const longText = 'line\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, longText); + + editor.handleInput('hello'); + + const textBefore = editor.getText(); + expect(textBefore).toContain('[paste #1'); + expect(textBefore).toContain('hello'); + + const anotherLong = 'other\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, anotherLong); + + expect(editor.getText()).toContain('[paste #1'); + expect(editor.getText()).toContain('[paste #2'); + }); + + it('expands only the marker under cursor when multiple markers exist', () => { + const editor = makeEditor(); + const text1 = 'first\n'.repeat(15).trimEnd(); + const text2 = 'second\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, text1); + editor.handleInput(' '); + simulateLargePaste(editor, text2); + + expect(editor.getText()).toContain('[paste #1'); + expect(editor.getText()).toContain('[paste #2'); + + simulateLargePaste(editor, 'anything'); + + expect(editor.getText()).toContain('[paste #1'); + expect(editor.getText()).not.toContain('[paste #2'); + expect(editor.getText()).toContain(text2); + }); + + it('handles Ctrl+V expansion when cursor is on marker', () => { + const editor = makeEditor(); + editor.onPasteImage = vi.fn(async () => false); + const longText = 'line\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, longText); + + expect(editor.getText()).toMatch(/\[paste #1/); + + editor.handleInput(process.platform === 'win32' ? '\u001Bv' : '\u0016'); + + expect(editor.getText()).not.toContain('[paste #'); + expect(editor.getText()).toContain(longText); + }); + + it('can re-expand after undo restores the marker', () => { + const editor = makeEditor(); + const longText = 'line\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, longText); + + const markerText = editor.getText(); + expect(markerText).toMatch(/\[paste #1/); + + simulateLargePaste(editor, 'anything'); + expect(editor.getText()).toContain(longText); + + // Undo (Ctrl+-) restores both the marker text and its paste-registry entry. + editor.handleInput('\u001B[45;5u'); + expect(editor.getText()).toContain('[paste #1'); + + simulateLargePaste(editor, 'anything'); + expect(editor.getText()).not.toContain('[paste #'); + expect(editor.getText()).toContain(longText); + }); + + it('suppresses multi-chunk bracketed paste data after marker expansion', () => { + const editor = makeEditor(); + const longText = 'line\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, longText); + + editor.handleInput(`${PASTE_START}chunk1`); + editor.handleInput(`chunk2${PASTE_END}`); + + expect(editor.getText()).not.toContain('chunk1'); + expect(editor.getText()).not.toContain('chunk2'); + expect(editor.getText()).toContain(longText); + }); + + it('handles paste-end sequence split across chunks', () => { + const editor = makeEditor(); + const longText = 'line\n'.repeat(15).trimEnd(); + simulateLargePaste(editor, longText); + + // Split: PASTE_START in chunk 1, paste-end split across chunk 2 and 3 + editor.handleInput(`${PASTE_START}data`); + editor.handleInput('\u001B[20'); + editor.handleInput('1~'); + + expect(editor.getText()).toContain(longText); + expect(editor.getText()).not.toContain('data'); + + // Verify editor is not stuck — next keystrokes should work normally + editor.handleInput('x'); + expect(editor.getText()).toContain('x'); + }); + + it('falls back to the text paste path when the image paste handler rejects', async () => { + const editor = makeEditor(); + const onTextPaste = vi.fn(); + editor.onTextPaste = onTextPaste; + editor.onPasteImage = vi.fn(async () => { + throw new Error('clipboard backend broken'); + }); + + // Regression: a rejecting onPasteImage must not leak an unhandled + // rejection — the CLI's crash path turns those into a silent exit. + const rejections: unknown[] = []; + const onRejection = (reason: unknown): void => { + rejections.push(reason); + }; + process.on('unhandledRejection', onRejection); + try { + editor.handleInput(process.platform === 'win32' ? '\u001Bv' : '\u0016'); + await new Promise((resolve) => { + setImmediate(resolve); + }); + + expect(onTextPaste).toHaveBeenCalledOnce(); + expect(rejections).toHaveLength(0); + } finally { + process.off('unhandledRejection', onRejection); + } + }); + + it('queues Enter and typing until an asynchronous image paste inserts its placeholder', async () => { + const editor = makeEditor(); + const submit = vi.fn(); + editor.onSubmit = submit; + let resolvePaste!: (handled: boolean) => void; + editor.onPasteImage = () => + new Promise((resolve) => { + resolvePaste = (handled) => { + editor.insertTextAtCursor?.('[image #1 (1×1)] '); + resolve(handled); + }; + }); + + const pasteKey = process.platform === 'win32' ? '\u001Bv' : '\u0016'; + editor.handleInput(pasteKey); + editor.handleInput('hello'); + editor.handleInput('\r'); + + expect(editor.getText()).toBe(''); + expect(submit).not.toHaveBeenCalled(); + + resolvePaste(true); + await new Promise((resolve) => setImmediate(resolve)); + + expect(submit).toHaveBeenCalledWith('[image #1 (1×1)] hello'); + }); +}); + +describe('CustomEditor shortcut telemetry hooks', () => { + it('reports undo shortcuts before delegating to the base editor', () => { + const editor = makeEditor(); + const onUndo = vi.fn(); + editor.onUndo = onUndo; + + editor.handleInput('a'); + editor.handleInput('\u001F'); + + expect(onUndo).toHaveBeenCalledOnce(); + }); + + it('invokes onToggleTodoExpand on Ctrl+T', () => { + const editor = makeEditor(); + const onToggleTodoExpand = vi.fn().mockReturnValue(true); + editor.onToggleTodoExpand = onToggleTodoExpand; + + editor.handleInput('\u0014'); + + expect(onToggleTodoExpand).toHaveBeenCalledOnce(); + }); + + it.each(['\u000E', '\u001B[110;5u'] as const)( + 'toggles Updates focus on %j without changing the draft', + (key) => { + const editor = makeEditor(); + const onPageNotify = vi.fn().mockReturnValue(true); + editor.onPageNotify = onPageNotify; + editor.setText('draft\nsecond line'); + const cursor = editor.getCursor(); + editor.handleInput(key); + expect(onPageNotify).toHaveBeenCalledWith(); + expect(editor.getText()).toBe('draft\nsecond line'); + expect(editor.getCursor()).toEqual(cursor); + }, + ); + + it.each([ + ['\u001B[D', 'left'], + ['\u001B[C', 'right'], + ['\u001B[A', 'up'], + ['\u001B[B', 'down'], + ['\u001B', 'escape'], + ] as const)('routes %j to the focused Updates panel as %s', (key, panelKey) => { + const editor = makeEditor(); + const onNotifyPanelKey = vi.fn().mockReturnValue(true); + editor.onNotifyPanelKey = onNotifyPanelKey; + editor.setText('draft'); + editor.handleInput(key); + expect(onNotifyPanelKey).toHaveBeenCalledWith(panelKey); + expect(editor.getText()).toBe('draft'); + }); + + it.each(['\u001B[D', '\u001B[A', '\u001B'] as const)( + 'leaves %j to autocomplete even when the Updates panel is focused', + (key) => { + const editor = makeEditor(); + const onNotifyPanelKey = vi.fn(); + editor.onNotifyPanelKey = onNotifyPanelKey; + const internals = editor as unknown as { cancelAutocompleteActivity: () => void }; + const cancelAutocomplete = vi.spyOn(internals, 'cancelAutocompleteActivity'); + cancelAutocomplete.mockImplementation(() => {}); + vi.spyOn(editor, 'hasAutocompleteActivity').mockReturnValue(true); + editor.setText('/rev'); + editor.handleInput(key); + expect(onNotifyPanelKey).not.toHaveBeenCalled(); + if (key === '\u001B') expect(cancelAutocomplete).toHaveBeenCalledOnce(); + }, + ); + + it('keeps the original editor bindings when Updates paging is unavailable', () => { + const editor = makeEditor(); + const baseline = makeEditor(); + editor.onPageNotify = () => false; + for (const instance of [editor, baseline]) instance.setText('first\nsecond'); + for (const key of ['\u0010', '\u000E']) { + editor.handleInput(key); + baseline.handleInput(key); + expect(editor.getCursor()).toEqual(baseline.getCursor()); + expect(editor.getText()).toBe(baseline.getText()); + } + }); + +}); + +describe('CustomEditor bash mode border label', () => { + // oxlint-disable-next-line no-control-regex -- ESC (\u001B) is required to match ANSI SGR escape sequences + const stripAnsi = (s: string): string => s.replaceAll(/\u001B\[[0-9;]*m/g, ''); + + it('shows "! shell mode" on the top border in bash mode', () => { + const editor = makeEditor(); + editor.inputMode = 'bash'; + const top = stripAnsi(editor.render(90)[0] ?? ''); + expect(top.startsWith('╭')).toBe(true); + expect(top).toContain('! shell mode'); + expect(top.endsWith('╮')).toBe(true); + }); + + it('does not show the shell mode label in prompt mode', () => { + const editor = makeEditor(); + const top = stripAnsi(editor.render(90)[0] ?? ''); + expect(top).not.toContain('! shell mode'); + }); + + it('keeps the top border at full width when the label is present', () => { + const editor = makeEditor(); + editor.inputMode = 'bash'; + const width = 90; + const top = stripAnsi(editor.render(width)[0] ?? ''); + expect(top).toHaveLength(width); + }); +}); + +describe('CustomEditor bash mode via paste', () => { + const PASTE_START = '\u001B[200~'; + const PASTE_END = '\u001B[201~'; + + it('enters bash mode and strips the leading ! when !cmd is pasted into an empty prompt', () => { + const editor = makeEditor(); + const modes: Array<'prompt' | 'bash'> = []; + editor.onInputModeChange = (mode) => modes.push(mode); + + editor.handleInput(`${PASTE_START}!ls${PASTE_END}`); + + expect(editor.inputMode).toBe('bash'); + expect(editor.getText()).toBe('ls'); + expect(modes).toEqual(['bash']); + }); + + it('enters bash mode on a bare pasted ! with an empty buffer', () => { + const editor = makeEditor(); + editor.handleInput(`${PASTE_START}!${PASTE_END}`); + + expect(editor.inputMode).toBe('bash'); + expect(editor.getText()).toBe(''); + }); + + it('does not enter bash mode when pasting !cmd into a non-empty prompt', () => { + const editor = makeEditor(); + editor.handleInput('hello'); + editor.handleInput(`${PASTE_START}!ls${PASTE_END}`); + + expect(editor.inputMode).toBe('prompt'); + expect(editor.getText()).toContain('hello'); + expect(editor.getText()).toContain('!ls'); + }); + + it('does not enter bash mode for a pasted command without a leading !', () => { + const editor = makeEditor(); + editor.handleInput(`${PASTE_START}ls${PASTE_END}`); + + expect(editor.inputMode).toBe('prompt'); + expect(editor.getText()).toBe('ls'); + }); + + it('keeps the typed ! behaviour (bash mode, empty buffer)', () => { + const editor = makeEditor(); + editor.handleInput('!'); + + expect(editor.inputMode).toBe('bash'); + expect(editor.getText()).toBe(''); + }); + + it('enters bash mode on a CSI-u encoded ! keystroke (Kitty/VSCode terminals)', () => { + const editor = makeEditor(); + editor.handleInput('\u001B[33u'); + + expect(editor.inputMode).toBe('bash'); + expect(editor.getText()).toBe(''); + }); +}); + +describe('CustomEditor bash mode file completion', () => { + it('triggers file completion (force:true) for a leading / in bash mode, not the slash menu', async () => { + const editor = makeEditor(); + const { provider, calls } = providerRecordingForce([{ value: 'auto', label: 'auto' }]); + editor.setAutocompleteProvider(provider); + editor.inputMode = 'bash'; + + editor.handleInput('/'); + await flushAutocomplete(); + + expect(calls).toContainEqual(expect.objectContaining({ force: true, text: '/' })); + expect(editor.isShowingAutocomplete()).toBe(true); + }); + + it('triggers file completion (force:true) for an inline / in bash mode', async () => { + const editor = makeEditor(); + const { provider, calls } = providerRecordingForce([{ value: 'etc', label: 'etc' }]); + editor.setAutocompleteProvider(provider); + editor.inputMode = 'bash'; + + for (const char of 'ls /') { + editor.handleInput(char); + } + await flushAutocomplete(); + + expect(calls).toContainEqual(expect.objectContaining({ force: true, text: 'ls /' })); + expect(editor.isShowingAutocomplete()).toBe(true); + }); + + it('keeps force:false (slash menu) for a leading / in prompt mode', async () => { + const editor = makeEditor(); + const { provider, calls } = providerRecordingForce([{ value: 'help', label: 'help' }]); + editor.setAutocompleteProvider(provider); + // inputMode defaults to 'prompt' + + editor.handleInput('/'); + await flushAutocomplete(); + + expect(calls).toContainEqual(expect.objectContaining({ force: false, text: '/' })); + expect(editor.isShowingAutocomplete()).toBe(true); + }); + + it('never falls back to force:false for a slash-shaped command in bash mode', async () => { + const editor = makeEditor(); + const { provider, calls } = providerRecordingForce([{ value: 'list', label: 'list' }]); + editor.setAutocompleteProvider(provider); + editor.inputMode = 'bash'; + + for (const char of '/add-dir ') { + editor.handleInput(char); + } + await new Promise((resolve) => setTimeout(resolve, 30)); + await flushAutocomplete(); + + // A force:false request would let pi-tui's own slash-command handling pop + // up subcommand completions for `/add-dir `. Bash mode must only ever + // request force:true path completion. + expect(calls.length).toBeGreaterThan(0); + expect(calls.every((call) => call.force === true)).toBe(true); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts b/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..de34a88c0b29db35f13b557285c1672b22ad61fa --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/file-mention-provider.test.ts @@ -0,0 +1,782 @@ +import { spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { FileMentionProvider } from '#/tui/components/editor/file-mention-provider'; + +function ctrl(): AbortSignal { + return new AbortController().signal; +} + +const NO_FD = null; + +function resolveFdPath(): string | null { + const command = process.platform === 'win32' ? 'where' : 'which'; + const result = spawnSync(command, ['fd'], { encoding: 'utf-8' }); + if (result.status !== 0 || !result.stdout) return null; + const firstLine = result.stdout.split(/\r?\n/).find(Boolean); + return firstLine ? firstLine.trim() : null; +} + +const FD_PATH = resolveFdPath(); +const IS_FD_INSTALLED = Boolean(FD_PATH); +const GOAL_COMMAND = { + name: 'goal', + description: 'Start or manage a goal', + getArgumentCompletions: (prefix: string) => + prefix.length === 0 + ? [ + { + value: 'status', + label: 'status', + }, + ] + : null, +}; + +const NEW_COMMAND = { + name: 'new', + aliases: ['clear'], + description: 'Start a fresh session in the current workspace', +}; + +const LARK_CALENDAR_COMMAND = { + name: 'skill:lark-calendar', + aliases: [], + description: 'Manage Lark calendars', +}; + +const HELP_COMMAND = { + name: 'help', + aliases: ['h'], + description: 'Show help', +}; + +const HELP_FULL_COMMAND = { + name: 'help', + aliases: ['h', '?'], + description: 'Show help', +}; + +const ADD_DIR_COMMAND = { + name: 'add-dir', + description: 'Add or list an additional workspace directory', + getArgumentCompletions: (prefix: string) => + prefix === '/' + ? [ + { + value: '/tmp/shared/', + label: 'shared/', + description: '/tmp/shared', + }, + ] + : null, +}; + +describe('FileMentionProvider', () => { + let workDir: string; + let extraDirs: string[]; + + beforeEach(() => { + workDir = mkdtempSync(join(tmpdir(), 'kimi-file-mention-')); + extraDirs = []; + }); + + afterEach(() => { + rmSync(workDir, { recursive: true, force: true }); + for (const extraDir of extraDirs) { + rmSync(extraDir, { recursive: true, force: true }); + } + }); + + function createExtraDir(): string { + const extraDir = mkdtempSync(join(tmpdir(), 'kimi-file-mention-extra-')); + extraDirs.push(extraDir); + return extraDir; + } + + it('returns null when there is no completable prefix', async () => { + const provider = new FileMentionProvider([], workDir, NO_FD); + const result = await provider.getSuggestions(['hello world'], 0, 11, { signal: ctrl() }); + expect(result).toBeNull(); + }); + + it('does not complete slash arguments before existing free text', async () => { + const provider = new FileMentionProvider([GOAL_COMMAND], workDir, NO_FD); + const line = '/goal Fix the checkout docs'; + const result = await provider.getSuggestions([line], 0, '/goal '.length, { signal: ctrl() }); + expect(result).toBeNull(); + }); + + it('opens @ file mention when typed in the middle of a slash command argument', async () => { + writeFileSync(join(workDir, 'README.md'), 'readme'); + const provider = new FileMentionProvider([GOAL_COMMAND], workDir, NO_FD); + // Cursor sits in the middle of the /goal argument text, right after a + // freshly typed `@`. The slash-argument guard must not suppress the @ + // file list here. + const line = '/goal Fix the @checkout docs'; + const result = await provider.getSuggestions([line], 0, '/goal Fix the @'.length, { + signal: ctrl(), + }); + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('@'); + expect(result!.items.map((item) => item.value)).toContain('@README.md'); + }); + + it('still completes slash arguments at the end of an empty argument', async () => { + const provider = new FileMentionProvider([GOAL_COMMAND], workDir, NO_FD); + const line = '/goal '; + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + expect(result).not.toBeNull(); + expect(result!.prefix).toBe(''); + expect(result!.items.map((item) => item.value)).toEqual(['status']); + }); + + it('opens add-dir directory completions after slash command completion and entering slash', async () => { + const provider = new FileMentionProvider([ADD_DIR_COMMAND], workDir, NO_FD); + const command = ADD_DIR_COMMAND; + const completed = provider.applyCompletion(['/add'], 0, 4, { value: command.name, label: command.name }, '/add'); + const completedLine = completed.lines[0]!; + const line = `${completedLine}/`; + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(completedLine).toBe('/add-dir '); + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/'); + expect(result!.items.map((item) => item.value)).toEqual(['/tmp/shared/']); + }); + + it('searches slash command aliases and displays aliases in the command label', async () => { + const provider = new FileMentionProvider([NEW_COMMAND], workDir, NO_FD); + const line = '/clear'; + + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/clear'); + expect(result!.items[0]).toMatchObject({ + value: 'new', + label: 'new (clear)', + }); + }); + + it('prefers exact alias matches over fuzzy skill matches', async () => { + const provider = new FileMentionProvider( + [NEW_COMMAND, LARK_CALENDAR_COMMAND], + workDir, + NO_FD, + ); + const line = '/clear'; + + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items[0]).toMatchObject({ + value: 'new', + label: 'new (clear)', + }); + expect(result!.items[0]?.value).not.toBe('skill:lark-calendar'); + }); + + it('does not show aliases when the primary name already matches', async () => { + const provider = new FileMentionProvider([HELP_COMMAND], workDir, NO_FD); + const line = '/h'; + + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items[0]).toMatchObject({ + value: 'help', + label: 'help', + }); + }); + + it('does not show aliases in labels when query is empty', async () => { + const provider = new FileMentionProvider([NEW_COMMAND], workDir, NO_FD); + const line = '/'; + + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items[0]).toMatchObject({ + value: 'new', + label: 'new', + }); + }); + + it('includes the argument hint in the description like the inner provider does', async () => { + const provider = new FileMentionProvider( + [{ name: 'goal', description: 'Start or manage a goal', argumentHint: '' }], + workDir, + NO_FD, + ); + + const result = await provider.getSuggestions(['/go'], 0, 3, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items[0]).toMatchObject({ + value: 'goal', + description: ' — Start or manage a goal', + }); + }); + + it('joins multiple aliases with an ASCII comma in the label', async () => { + const provider = new FileMentionProvider([HELP_FULL_COMMAND], workDir, NO_FD); + // '?' only matches the alias, not the primary name, so the label must + // list the aliases. + const result = await provider.getSuggestions(['/?'], 0, 2, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items[0]).toMatchObject({ + value: 'help', + label: 'help (h, ?)', + }); + }); + + it('returns null for a bare slash when no commands are registered', async () => { + const provider = new FileMentionProvider([], workDir, NO_FD); + + const result = await provider.getSuggestions(['/'], 0, 1, { signal: ctrl() }); + + expect(result).toBeNull(); + }); + + it('ranks primary-name matches above alias matches with equal scores', async () => { + const provider = new FileMentionProvider( + [ + { name: 'bar', aliases: ['foo'], description: 'Bar command' }, + { name: 'foo', aliases: [], description: 'Foo command' }, + ], + workDir, + NO_FD, + ); + + const result = await provider.getSuggestions(['/foo'], 0, 4, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items[0]?.value).toBe('foo'); + expect(result!.items[1]).toMatchObject({ + value: 'bar', + label: 'bar (foo)', + }); + }); + + it('does not turn leading-whitespace slash into root path completion', async () => { + const provider = new FileMentionProvider([], workDir, NO_FD); + const result = await provider.getSuggestions([' /'], 0, 2, { signal: ctrl() }); + expect(result).toBeNull(); + }); + + it('still allows forced root path completion after leading whitespace', async () => { + const provider = new FileMentionProvider([], workDir, NO_FD); + const result = await provider.getSuggestions([' /'], 0, 2, { signal: ctrl(), force: true }); + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/'); + }); + + it('does not trigger the @ branch when @ is preceded by a non-delimiter', async () => { + const provider = new FileMentionProvider([], workDir, NO_FD); + const result = await provider.getSuggestions(['email@example'], 0, 13, { signal: ctrl() }); + expect(result).toBeNull(); + }); + + it('uses a filesystem fallback for @ mentions when fd is not available', async () => { + mkdirSync(join(workDir, 'src', 'components'), { recursive: true }); + writeFileSync(join(workDir, 'src', 'components', 'Button.tsx'), 'export {};'); + writeFileSync(join(workDir, 'README.md'), 'readme'); + const provider = new FileMentionProvider([], workDir, NO_FD); + + const result = await provider.getSuggestions(['@but'], 0, 4, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('@but'); + expect(result!.items.map((item) => item.value)).toContain('@src/components/Button.tsx'); + }); + + it('uses the filesystem fallback for additionalDirs when fd is unavailable', async () => { + const extraDir = createExtraDir(); + mkdirSync(join(extraDir, 'src'), { recursive: true }); + writeFileSync(join(extraDir, 'src', 'Additional.ts'), 'export {};'); + const provider = new FileMentionProvider([], workDir, join(workDir, 'missing-fd'), [extraDir]); + + const result = await provider.getSuggestions(['@add'], 0, 4, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value)).toContain( + `@${join(extraDir, 'src', 'Additional.ts').replaceAll('\\', '/')}`, + ); + }); + + it.runIf(IS_FD_INSTALLED)( + 'uses fd for additionalDirs even when cwd is large enough to exhaust the fallback scanner', + async () => { + // Fill cwd with enough entries to push the filesystem fallback past its + // 2000-entry scan cap, so it would never reach the additional root. fd + // searches each root independently and still finds the deep target. + for (let i = 0; i < 2000; i++) { + writeFileSync(join(workDir, `filler-${i}.ts`), 'export {};'); + } + const extraDir = createExtraDir(); + mkdirSync(join(extraDir, 'deep'), { recursive: true }); + writeFileSync(join(extraDir, 'deep', 'target-needle.ts'), 'export {};'); + const provider = new FileMentionProvider([], workDir, FD_PATH!, [extraDir]); + + const result = await provider.getSuggestions(['@target-needle'], 0, '@target-needle'.length, { + signal: ctrl(), + }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value)).toContain( + `@${join(extraDir, 'deep', 'target-needle.ts').replaceAll('\\', '/')}`, + ); + }, + ); + + it.runIf(IS_FD_INSTALLED)( + 'treats a bare fd command name as executable and resolves it via PATH', + async () => { + // A bare "fd" (system PATH lookup) must not be mistaken for unavailable; + // otherwise the large cwd would push the fallback scanner past its cap + // and hide the deep target in the additional root. + for (let i = 0; i < 2000; i++) { + writeFileSync(join(workDir, `filler-${i}.ts`), 'export {};'); + } + const extraDir = createExtraDir(); + mkdirSync(join(extraDir, 'deep'), { recursive: true }); + writeFileSync(join(extraDir, 'deep', 'target-needle.ts'), 'export {};'); + const provider = new FileMentionProvider([], workDir, 'fd', [extraDir]); + + const result = await provider.getSuggestions(['@target-needle'], 0, '@target-needle'.length, { + signal: ctrl(), + }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value)).toContain( + `@${join(extraDir, 'deep', 'target-needle.ts').replaceAll('\\', '/')}`, + ); + }, + ); + + it('keeps cwd @ mention values relative and additionalDir values absolute', async () => { + mkdirSync(join(workDir, 'src'), { recursive: true }); + writeFileSync(join(workDir, 'src', 'Cwd.ts'), 'export {};'); + const extraDir = createExtraDir(); + mkdirSync(join(extraDir, 'src'), { recursive: true }); + writeFileSync(join(extraDir, 'src', 'Additional.ts'), 'export {};'); + const provider = new FileMentionProvider([], workDir, NO_FD, [extraDir]); + + const cwdResult = await provider.getSuggestions(['@cwd'], 0, 4, { signal: ctrl() }); + expect(cwdResult).not.toBeNull(); + expect(cwdResult!.items.map((item) => item.value)).toContain('@src/Cwd.ts'); + + const additionalResult = await provider.getSuggestions(['@add'], 0, 4, { signal: ctrl() }); + expect(additionalResult).not.toBeNull(); + expect(additionalResult!.items.map((item) => item.value)).toContain( + `@${join(extraDir, 'src', 'Additional.ts').replaceAll('\\', '/')}`, + ); + }); + + it('deduplicates cwd and additionalDir candidates by absolute path', async () => { + const extraDir = join(workDir, 'extra'); + mkdirSync(join(extraDir, 'src'), { recursive: true }); + writeFileSync(join(extraDir, 'src', 'Overlap.ts'), 'export {};'); + const provider = new FileMentionProvider([], workDir, NO_FD, [extraDir]); + + const result = await provider.getSuggestions(['@overlap'], 0, 8, { signal: ctrl() }); + + expect(result).not.toBeNull(); + const overlapItems = result!.items.filter( + (item) => item.description === join(extraDir, 'src', 'Overlap.ts').replaceAll('\\', '/'), + ); + expect(overlapItems).toHaveLength(1); + }); + + it.runIf(IS_FD_INSTALLED)( + 'does not bypass fd filtering with filesystem suggestions when fd returns no matches', + async () => { + writeFileSync(join(workDir, 'README.md'), 'readme'); + const provider = new FileMentionProvider([], workDir, FD_PATH!); + + const result = await provider.getSuggestions(['@zzz-no-match-xyz'], 0, '@zzz-no-match-xyz'.length, { + signal: ctrl(), + }); + + expect(result).toBeNull(); + }, + ); + + it('filesystem fallback returns folders and excludes .git', async () => { + mkdirSync(join(workDir, 'src')); + mkdirSync(join(workDir, '.git')); + writeFileSync(join(workDir, '.git', 'config'), 'secret'); + const provider = new FileMentionProvider([], workDir, NO_FD); + + const result = await provider.getSuggestions(['@'], 0, 1, { signal: ctrl() }); + + expect(result).not.toBeNull(); + const values = result!.items.map((item) => item.value); + expect(values).toContain('@src/'); + expect(values.some((value) => value.startsWith('@.git'))).toBe(false); + }); + + it('filesystem fallback quotes paths with spaces', async () => { + mkdirSync(join(workDir, 'my folder')); + const provider = new FileMentionProvider([], workDir, NO_FD); + + const result = await provider.getSuggestions(['@my'], 0, 3, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value)).toContain('@"my folder/"'); + }); + + it('filesystem fallback does not recurse into symlinked directories', async () => { + writeFileSync(join(workDir, 'target.txt'), 'target'); + symlinkSync('.', join(workDir, 'current'), 'dir'); + const provider = new FileMentionProvider([], workDir, NO_FD); + + const result = await provider.getSuggestions(['@target'], 0, 7, { signal: ctrl() }); + + expect(result).not.toBeNull(); + const values = result!.items.map((item) => item.value); + expect(values).toContain('@target.txt'); + expect(values.some((value) => value.startsWith('@current/'))).toBe(false); + }); + + it('delegates path suggestions to pi-tui for regular path completion', async () => { + mkdirSync(join(workDir, 'src')); + writeFileSync(join(workDir, 'README.md'), 'readme'); + const provider = new FileMentionProvider([], workDir, NO_FD); + + const result = await provider.getSuggestions([''], 0, 0, { signal: ctrl(), force: true }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value)).toEqual(['src/', 'README.md']); + }); + + it('applyCompletion delegates file and directory insertion to pi-tui', () => { + const provider = new FileMentionProvider([], workDir, NO_FD); + + const file = provider.applyCompletion( + ['hey @read'], + 0, + 9, + { value: '@README.md', label: 'README.md' }, + '@read', + ); + expect(file.lines[0]).toBe('hey @README.md '); + + const dir = provider.applyCompletion( + ['hey @sr'], + 0, + 7, + { value: '@src/', label: 'src/' }, + '@sr', + ); + expect(dir.lines[0]).toBe('hey @src/'); + }); + + describe('bash-mode path completion dotfile filtering', () => { + it('hides dot-prefixed entries (matching /add-dir) in bash mode', async () => { + mkdirSync(join(workDir, '.hidden')); + mkdirSync(join(workDir, 'visible')); + writeFileSync(join(workDir, '.dotfile'), ''); + writeFileSync(join(workDir, 'normal.txt'), ''); + + const provider = new FileMentionProvider([], workDir, NO_FD, [], () => 'bash'); + const text = `cd ${workDir}/`; + const result = await provider.getSuggestions([text], 0, text.length, { + signal: ctrl(), + force: true, + }); + + expect(result).not.toBeNull(); + const labels = result!.items.map((item) => item.label); + expect(labels).toContain('visible/'); + expect(labels).toContain('normal.txt'); + expect(labels).not.toContain('.hidden/'); + expect(labels).not.toContain('.dotfile'); + }); + + it('keeps dot-prefixed entries in prompt mode', async () => { + mkdirSync(join(workDir, '.hidden')); + writeFileSync(join(workDir, '.dotfile'), ''); + + const provider = new FileMentionProvider([], workDir, NO_FD, [], () => 'prompt'); + const text = `cd ${workDir}/`; + const result = await provider.getSuggestions([text], 0, text.length, { + signal: ctrl(), + force: true, + }); + + expect(result).not.toBeNull(); + const labels = result!.items.map((item) => item.label); + expect(labels).toContain('.hidden/'); + expect(labels).toContain('.dotfile'); + }); + }); + + describe('bash-mode path applyCompletion', () => { + it('does not double the leading slash for a bare / path', () => { + const provider = new FileMentionProvider([], workDir, NO_FD, [], () => 'bash'); + const result = provider.applyCompletion( + ['/'], + 0, + 1, + { value: '/Applications/', label: 'Applications/' }, + '/', + ); + expect(result.lines[0]).toBe('/Applications/'); + expect(result.cursorCol).toBe('/Applications/'.length); + }); + + it('replaces the path prefix after a command without a trailing space', () => { + const provider = new FileMentionProvider([], workDir, NO_FD, [], () => 'bash'); + const result = provider.applyCompletion( + ['cd /App'], + 0, + 7, + { value: '/Applications/', label: 'Applications/' }, + '/App', + ); + expect(result.lines[0]).toBe('cd /Applications/'); + expect(result.cursorCol).toBe('cd /Applications/'.length); + }); + + it('keeps the cursor inside the closing quote for a spaced directory', () => { + const provider = new FileMentionProvider([], workDir, NO_FD, [], () => 'bash'); + const result = provider.applyCompletion( + ['cd /tmp/My'], + 0, + 10, + { value: '"/tmp/My Dir/"', label: 'My Dir/' }, + '/tmp/My', + ); + expect(result.lines[0]).toBe('cd "/tmp/My Dir/"'); + // Cursor sits before the closing quote so the next `/` continues inside it. + expect(result.cursorCol).toBe('cd "/tmp/My Dir/'.length); + }); + + it('keeps pi-tui slash-command behaviour in prompt mode', () => { + const provider = new FileMentionProvider([], workDir, NO_FD, [], () => 'prompt'); + const result = provider.applyCompletion( + ['/'], + 0, + 1, + { value: 'help', label: 'help' }, + '/', + ); + // pi-tui's slash-command branch: beforePrefix + '/' + value + ' ' + expect(result.lines[0]).toBe('/help '); + }); + }); + + describe('bash-mode slash argument completion suppression', () => { + it('does not invoke slash argument completions for an absolute path in bash mode', async () => { + const getArgumentCompletions = vi.fn(() => [ + { value: '/should-not-appear/', label: 'should-not-appear/' }, + ]); + const provider = new FileMentionProvider( + [{ name: 'add-dir', description: 'Add directory', getArgumentCompletions }], + workDir, + NO_FD, + [], + () => 'bash', + ); + + const text = '/add-dir/tmp/'; + const result = await provider.getSuggestions([text], 0, text.length, { + signal: ctrl(), + force: true, + }); + + expect(getArgumentCompletions).not.toHaveBeenCalled(); + expect(result?.items.map((item) => item.label) ?? []).not.toContain('should-not-appear/'); + }); + + it('does not invoke slash argument completions for a trailing-space command in bash mode', async () => { + const getArgumentCompletions = vi.fn(() => [{ value: 'list', label: 'list' }]); + const provider = new FileMentionProvider( + [{ name: 'add-dir', description: 'Add directory', getArgumentCompletions }], + workDir, + NO_FD, + [], + () => 'bash', + ); + + // `/add-dir ` (trailing space) used to be re-triggered with force:false, + // which let pi-tui's own slash-command handling return subcommand + // completions. Bash mode now only ever triggers force:true path + // completion, so the argument completer must not run. + const text = '/add-dir '; + const result = await provider.getSuggestions([text], 0, text.length, { + signal: ctrl(), + force: true, + }); + + expect(getArgumentCompletions).not.toHaveBeenCalled(); + expect(result?.items.map((item) => item.label) ?? []).not.toContain('list'); + }); + + it('keeps slash argument completion in prompt mode', async () => { + const getArgumentCompletions = vi.fn(() => [{ value: '/shared/', label: 'shared/' }]); + const provider = new FileMentionProvider( + [{ name: 'add-dir', description: 'Add directory', getArgumentCompletions }], + workDir, + NO_FD, + [], + () => 'prompt', + ); + + const text = '/add-dir /'; + const result = await provider.getSuggestions([text], 0, text.length, { + signal: ctrl(), + force: false, + }); + + expect(getArgumentCompletions).toHaveBeenCalled(); + expect(result?.items.map((item) => item.label)).toContain('shared/'); + }); + }); + + describe('inline skill completion', () => { + const REVIEW_COMMAND = { + name: 'skill:review', + aliases: [], + description: 'Review changes', + }; + const SECURITY_COMMAND = { + name: 'skill:security', + aliases: [], + description: 'Check security', + }; + const SKILL_NAMES = new Set(['skill:review', 'skill:security']); + + function skillProvider( + commands: ConstructorParameters[0] = [ + REVIEW_COMMAND, + SECURITY_COMMAND, + HELP_COMMAND, + ], + ) { + return new FileMentionProvider( + commands, + workDir, + NO_FD, + [], + () => 'prompt', + SKILL_NAMES, + ); + } + + it('offers skill-only suggestions for a `/` after whitespace mid-input', async () => { + const provider = skillProvider(); + const line = 'hello /'; + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/'); + expect(result!.items.map((item) => item.value).sort()).toEqual([ + 'skill:review', + 'skill:security', + ]); + }); + + it('filters inline suggestions by the typed prefix', async () => { + const provider = skillProvider(); + const line = 'hello /rev'; + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/rev'); + expect(result!.items.map((item) => item.value)).toEqual(['skill:review']); + }); + + it('offers the skill picker for a `/` at the start of a later line', async () => { + const provider = skillProvider(); + const result = await provider.getSuggestions(['first line', '/'], 1, 1, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value).sort()).toEqual([ + 'skill:review', + 'skill:security', + ]); + }); + + it('stays in skill-only mode while typing a token on a later line', async () => { + const provider = skillProvider(); + const result = await provider.getSuggestions(['first line', '/rev'], 1, 4, { + signal: ctrl(), + }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/rev'); + expect(result!.items.map((item) => item.value)).toEqual(['skill:review']); + }); + + it('offers inline skills on an indented later line', async () => { + const provider = skillProvider(); + const result = await provider.getSuggestions(['first line', ' /skill:rev'], 1, 12, { + signal: ctrl(), + }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/skill:rev'); + expect(result!.items.map((item) => item.value)).toEqual(['skill:review']); + }); + + it('offers inline skills for an indented token on the first line', async () => { + const provider = skillProvider(); + const result = await provider.getSuggestions([' /skill:rev'], 0, 12, { signal: ctrl() }); + + expect(result).not.toBeNull(); + expect(result!.prefix).toBe('/skill:rev'); + expect(result!.items.map((item) => item.value)).toEqual(['skill:review']); + }); + + it('does not leak built-in commands onto later lines', async () => { + const provider = skillProvider(); + const result = await provider.getSuggestions(['first line', '/hel'], 1, 4, { + signal: ctrl(), + }); + + expect(result?.items.map((item) => item.value) ?? []).not.toContain('help'); + }); + + it('returns null for a prose slash when no skills are registered', async () => { + const provider = new FileMentionProvider([HELP_COMMAND], workDir, NO_FD, [], () => 'prompt'); + const line = 'hello /'; + const result = await provider.getSuggestions([line], 0, line.length, { signal: ctrl() }); + expect(result).toBeNull(); + }); + + it('keeps slash-command argument completions ahead of inline skills', async () => { + const provider = skillProvider([ADD_DIR_COMMAND, REVIEW_COMMAND]); + const line = '/add-dir /'; + const result = await provider.getSuggestions([line], 0, line.length, { + signal: ctrl(), + force: false, + }); + + expect(result).not.toBeNull(); + expect(result!.items.map((item) => item.value)).toEqual(['/tmp/shared/']); + }); + + it('applyCompletion preserves the slash and appends a trailing space', () => { + const provider = skillProvider(); + const line = 'hello /rev'; + const result = provider.applyCompletion( + [line], + 0, + line.length, + { value: 'skill:review', label: 'skill:review', data: { inlineSkill: true } }, + '/rev', + ); + + expect(result.lines[0]).toBe('hello /skill:review '); + expect(result.cursorCol).toBe('hello /skill:review '.length); + }); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/normalize-caps-locked-ctrl.test.ts b/apps/kimi-code/test/tui/components/editor/normalize-caps-locked-ctrl.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d2151f721289f99fa01f8c3486075a82a189955 --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/normalize-caps-locked-ctrl.test.ts @@ -0,0 +1,76 @@ +import { describe, it, expect } from 'vitest'; + +import { normalizeCapsLockedCtrl } from '#/tui/components/editor/custom-editor'; + +// Kitty keyboard protocol emits `ESC[;[:eventType]u`. +// Modifier mask bits: shift=1, alt=2, ctrl=4, super=8, hyper=16, meta=32, +// caps_lock=64, num_lock=128. The pi-tui bug this helper works around is +// that when caps_lock is on, terminals report the codepoint of ctrl+letter +// as the *uppercase* ASCII letter (e.g. 68 = 'D' instead of 100 = 'd'), +// which pi-tui's matcher compares literally and fails. We rewrite the +// sequence back to the unlocked form before dispatching. + +describe('normalizeCapsLockedCtrl', () => { + it('rewrites ctrl+D reported with caps_lock back to ctrl+d', () => { + // ctrl(4) + caps_lock(64) = 68, reported = 69 + expect(normalizeCapsLockedCtrl('\u001B[68;69u')).toBe('\u001B[100;5u'); + }); + + it('rewrites ctrl+C / ctrl+O / ctrl+S under caps_lock', () => { + expect(normalizeCapsLockedCtrl('\u001B[67;69u')).toBe('\u001B[99;5u'); + expect(normalizeCapsLockedCtrl('\u001B[79;69u')).toBe('\u001B[111;5u'); + expect(normalizeCapsLockedCtrl('\u001B[83;69u')).toBe('\u001B[115;5u'); + }); + + it('preserves the trailing event-type sub-parameter', () => { + // `:3u` = key release event + expect(normalizeCapsLockedCtrl('\u001B[68;69:3u')).toBe('\u001B[100;5:3u'); + // multiple sub-parameters still survive + expect(normalizeCapsLockedCtrl('\u001B[68;69:3:1u')).toBe('\u001B[100;5:3:1u'); + }); + + it('leaves plain uppercase typed with only caps_lock alone', () => { + // User intentionally typing an uppercase letter — do not downgrade. + // caps_lock(64) alone = 64, reported = 65 + expect(normalizeCapsLockedCtrl('\u001B[68;65u')).toBe('\u001B[68;65u'); + }); + + it('leaves ctrl+letter without caps_lock alone', () => { + // ctrl(4) alone = 4, reported = 5 + expect(normalizeCapsLockedCtrl('\u001B[68;5u')).toBe('\u001B[68;5u'); + expect(normalizeCapsLockedCtrl('\u001B[100;5u')).toBe('\u001B[100;5u'); + }); + + it('leaves ctrl+shift+letter with caps_lock alone', () => { + // shift(1) + ctrl(4) + caps_lock(64) = 69, reported = 70. + // User explicitly wants the shifted form — don't rewrite. + expect(normalizeCapsLockedCtrl('\u001B[68;70u')).toBe('\u001B[68;70u'); + }); + + it('rewrites ctrl+alt+letter under caps_lock (shift not involved)', () => { + // alt(2) + ctrl(4) + caps_lock(64) = 70, reported = 71 + expect(normalizeCapsLockedCtrl('\u001B[68;71u')).toBe('\u001B[100;7u'); + }); + + it('ignores codepoints outside A-Z even with ctrl+caps_lock', () => { + // Digit '1' (49) — uppercase mapping would be nonsense. + expect(normalizeCapsLockedCtrl('\u001B[49;69u')).toBe('\u001B[49;69u'); + // Symbol '[' (91) — just past 'Z'. + expect(normalizeCapsLockedCtrl('\u001B[91;69u')).toBe('\u001B[91;69u'); + // '@' (64) — just before 'A'. + expect(normalizeCapsLockedCtrl('\u001B[64;69u')).toBe('\u001B[64;69u'); + }); + + it('passes through non-CSI-u input unchanged', () => { + // Plain printable character + expect(normalizeCapsLockedCtrl('H')).toBe('H'); + // Legacy ctrl+d control byte + expect(normalizeCapsLockedCtrl('\u0004')).toBe('\u0004'); + // Legacy ctrl+c control byte + expect(normalizeCapsLockedCtrl('\u0003')).toBe('\u0003'); + // Arrow key CSI (not CSI-u) + expect(normalizeCapsLockedCtrl('\u001B[A')).toBe('\u001B[A'); + // Empty string + expect(normalizeCapsLockedCtrl('')).toBe(''); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/prompt-symbol.test.ts b/apps/kimi-code/test/tui/components/editor/prompt-symbol.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7537551de3268f9e6714cbc487721410a1a8319 --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/prompt-symbol.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect } from 'vitest'; + +import { injectPromptSymbol } from '#/tui/components/editor/custom-editor'; + +describe('injectPromptSymbol', () => { + it('places a "> " prompt at columns 2-3 (col 0 = border, col 1 = single-space gap)', () => { + expect(injectPromptSymbol(' hello world')).toBe(' > hello world'); + }); + + it('preserves overall visible width (prompt occupies padding slots)', () => { + const original = ' hello '; + expect(injectPromptSymbol(original)).toHaveLength(original.length); + }); + + it('preserves trailing ANSI escapes (e.g. cursor inverse marker)', () => { + const line = ' [7m [0m '; + const out = injectPromptSymbol(line); + expect(out).toBe(' > [7m [0m '); + }); + + it('emits no SGR (terminal default foreground renders the symbol)', () => { + const out = injectPromptSymbol(' hello'); + expect(out).not.toMatch(/\[/); + }); + + it('returns undefined when the line is too short', () => { + expect(injectPromptSymbol(' ')).toBeUndefined(); + expect(injectPromptSymbol('')).toBeUndefined(); + }); + + it('returns undefined when the leading four characters are not all spaces', () => { + expect(injectPromptSymbol('x hello')).toBeUndefined(); + expect(injectPromptSymbol(' x hello')).toBeUndefined(); + expect(injectPromptSymbol(' x hello')).toBeUndefined(); + expect(injectPromptSymbol(' xhello')).toBeUndefined(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/side-borders.test.ts b/apps/kimi-code/test/tui/components/editor/side-borders.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d3145b1419e2329cc5674d5f1f9db8552ed9d46 --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/side-borders.test.ts @@ -0,0 +1,106 @@ +import { describe, it, expect } from 'vitest'; + +import { wrapWithSideBorders } from '#/tui/components/editor/custom-editor'; + +const id = (s: string): string => s; + +describe('wrapWithSideBorders', () => { + it('turns the top horizontal border into a ╭…╮ run', () => { + const out = wrapWithSideBorders(['──────────', ' hi ', '──────────'], id); + expect(out[0]).toBe('╭────────╮'); + }); + + it('turns the top horizontal border into connectors when connected above', () => { + const out = wrapWithSideBorders(['──────────', ' hi ', '──────────'], id, { + connectedAbove: true, + }); + expect(out[0]).toBe('├────────┤'); + expect(out[2]).toBe('╰────────╯'); + }); + + it('turns the bottom horizontal border into a ╰…╯ run', () => { + const out = wrapWithSideBorders(['──────────', ' hi ', '──────────'], id); + expect(out[2]).toBe('╰────────╯'); + }); + + it('wraps content lines with │ … │, replacing the outer padding columns', () => { + // ' hi ' is 10 chars; first/last spaces become │, middle keeps its length + const out = wrapWithSideBorders(['──────────', ' hi ', '──────────'], id); + expect(out[1]).toBe('│ hi │'); + expect(out[1]).toHaveLength(' hi '.length); + }); + + it('treats scroll-indicator lines (── ↑ N more ──) as horizontal borders', () => { + const top = '─── ↑ 5 more ────'; + const bot = '─── ↓ 3 more ────'; + const out = wrapWithSideBorders([top, ' x ', bot], id); + expect(out[0]?.startsWith('╭')).toBe(true); + expect(out[0]?.endsWith('╮')).toBe(true); + expect(out[2]?.startsWith('╰')).toBe(true); + expect(out[2]?.endsWith('╯')).toBe(true); + // body of the indicator is preserved + expect(out[0]).toContain('↑ 5 more'); + expect(out[2]).toContain('↓ 3 more'); + }); + + it('handles autocomplete rows that come after the bottom border (still wrap with │)', () => { + const lines = [ + '──────────', + ' q ', + '──────────', + ' item1 ', + ' item2 ', + ]; + const out = wrapWithSideBorders(lines, id); + expect(out[0]?.startsWith('╭')).toBe(true); + expect(out[2]?.startsWith('╰')).toBe(true); + // ' item1 ' → first/last spaces become │ + expect(out[3]).toBe('│ item1 │'); + expect(out[4]).toBe('│ item2 │'); + }); + + it('paints corners and side borders through the provided borderColor', () => { + const paint = (s: string): string => `<${s}>`; + const out = wrapWithSideBorders(['─────', ' x ', '─────'], paint); + // corners and horizontals routed through paint + expect(out[0]).toBe('<╭───╮>'); + expect(out[2]).toBe('<╰───╯>'); + // side bars on content lines also painted + expect(out[1]).toBe('<│> x <│>'); + }); + + it('does not clobber non-space content sitting in the outer column (e.g. cursor overflow)', () => { + // last column holds a non-space character — leave it as-is rather than overwrite with │ + const out = wrapWithSideBorders(['─────', ' abc', '─────'], id); + // first column was a space → replaced with │; last column was 'c' → kept + expect(out[1]).toBe('│ abc'); + }); + + it('overlays a label on the top border, replacing leading dashes', () => { + const top = '─'.repeat(30); + const out = wrapWithSideBorders([top, ' x ', top], id, { label: ' ! shell mode ' }); + expect(out[0]).toBe(`╭ ! shell mode ${'─'.repeat(14)}╮`); + // width is preserved: corner + label + dashes + corner == input width + expect(out[0]).toHaveLength(top.length); + // bottom border is untouched + expect(out[2]).toBe(`╰${'─'.repeat(28)}╯`); + }); + + it('does not inject the label when it is wider than the top border', () => { + const out = wrapWithSideBorders(['──────', ' x ', '──────'], id, { + label: ' ! shell mode ', + }); + // falls back to a plain border — label must not leak or overflow + expect(out[0]).toBe('╭────╮'); + expect(out[0]).not.toContain('shell mode'); + }); + + it('does not inject the label onto a scroll-indicator top border', () => { + const top = '─── ↑ 5 more ────'; + const out = wrapWithSideBorders([top, ' x ', '─── ↓ 3 more ────'], id, { + label: ' ! shell mode ', + }); + expect(out[0]).toContain('↑ 5 more'); + expect(out[0]).not.toContain('shell mode'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/slash-highlight.test.ts b/apps/kimi-code/test/tui/components/editor/slash-highlight.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..02e885b3d08271dc1623ca8a2635873a37535ce5 --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/slash-highlight.test.ts @@ -0,0 +1,132 @@ +import chalk from 'chalk'; +import { describe, it, expect, beforeAll } from 'vitest'; + +import { highlightFirstSlashToken, highlightInlineSkillTokens } from '#/tui/components/editor/custom-editor'; + +beforeAll(() => { + // Vitest runs without a TTY so chalk auto-detects colour support as + // 0 (no colours). Force full colour so the highlighter actually + // emits the SGR escapes we're asserting on. + chalk.level = 3; +}); + +function strip(s: string): string { + return s.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function expectHighlighted(out: string, token: string): void { + expect(out).toMatch(new RegExp(`\\u001B\\[[0-9;]*m${token}\\u001B\\[`)); +} + +describe('highlightFirstSlashToken', () => { + it('colours /cmd when line starts with a slash', () => { + const out = highlightFirstSlashToken(' /help rest of input', 'primary'); + expect(out).toBeDefined(); + // Visible text unchanged + expect(strip(out!)).toBe(' /help rest of input'); + // SGR escapes surround /help + expectHighlighted(out!, '/help'); + }); + + it('colours next in /goal next', () => { + const out = highlightFirstSlashToken('/goal next Ship feature X', 'primary'); + expect(out).toBeDefined(); + expect(strip(out!)).toBe('/goal next Ship feature X'); + expectHighlighted(out!, '/goal'); + expectHighlighted(out!, 'next'); + expect(out!).toContain(' Ship feature X'); + }); + + it('colours manage in /goal next manage', () => { + const out = highlightFirstSlashToken('/goal next manage', 'primary'); + expect(out).toBeDefined(); + expect(strip(out!)).toBe('/goal next manage'); + expectHighlighted(out!, '/goal'); + expectHighlighted(out!, 'next'); + expectHighlighted(out!, 'manage'); + }); + + it('returns undefined when the line has no slash', () => { + expect(highlightFirstSlashToken('hello world', 'primary')).toBeUndefined(); + }); + + it('returns undefined when slash is not at the leading position', () => { + expect(highlightFirstSlashToken(' hello /not-cmd', 'primary')).toBeUndefined(); + }); + + it('returns undefined for path-like slash tokens', () => { + expect(highlightFirstSlashToken('/user/desktop/ foo', 'primary')).toBeUndefined(); + }); + + it('handles /token at end of line (no trailing whitespace)', () => { + const out = highlightFirstSlashToken('/exit', 'primary'); + expect(out).toBeDefined(); + expect(strip(out!)).toBe('/exit'); + }); + + it('passes through pre-existing ANSI (e.g. cursor inverse) in the tail', () => { + // Simulate pi-tui Editor inserting an inverse-video cursor marker + // somewhere after the slash token. + const line = '/help x\u001B[7m \u001B[0m'; + const out = highlightFirstSlashToken(line, 'primary'); + expect(out).toBeDefined(); + // Stripped visible content unchanged + expect(strip(out!)).toBe(strip(line)); + // Inverse cursor SGR is still present afterwards + expect(out!.includes('\u001B[7m')).toBe(true); + }); + + it('only paints the first token, not other slashes further along', () => { + const out = highlightFirstSlashToken('/a /b', 'primary'); + expect(out).toBeDefined(); + // Count the SGR opens — should be exactly one for /a. + const opens = (out!.match(/\u001B\[[0-9;]+m/g) ?? []).length; + expect(opens).toBeGreaterThanOrEqual(2); // chalk bold+fg open and reset(s) + // /b should remain plain — the substring " /b" exists verbatim. + expect(out!).toContain(' /b'); + }); +}); + +describe('highlightInlineSkillTokens', () => { + const SKILLS = new Set(['skill:review', 'skill:security', 'commit']); + + it('colours known skill tokens anywhere in the line', () => { + const out = highlightInlineSkillTokens('please /skill:review this', SKILLS, null, 'primary'); + expect(out).toBeDefined(); + expect(strip(out!)).toBe('please /skill:review this'); + expectHighlighted(out!, '/skill:review'); + }); + + it('colours multiple skill tokens in one line', () => { + const out = highlightInlineSkillTokens( + '/skill:review then /skill:security', + SKILLS, + null, + 'primary', + ); + expect(out).toBeDefined(); + expectHighlighted(out!, '/skill:review'); + expectHighlighted(out!, '/skill:security'); + }); + + it('skips the excluded leading command range', () => { + const visible = '/skill:review args'; + const out = highlightInlineSkillTokens( + visible, + SKILLS, + { start: 0, end: 13 }, + 'primary', + ); + expect(out).toBeUndefined(); + }); + + it('ignores unknown tokens and plain slashes', () => { + expect(highlightInlineSkillTokens('and /not-a-skill or /tmp', SKILLS, null, 'primary')).toBeUndefined(); + }); + + it('supports the skill: prefix fallback for bare names', () => { + const out = highlightInlineSkillTokens('please /review this', SKILLS, null, 'primary'); + expect(out).toBeDefined(); + expectHighlighted(out!, '/review'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/editor/wrapping-select-list.test.ts b/apps/kimi-code/test/tui/components/editor/wrapping-select-list.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4147ab40a4ee4e9df694a0ab1316d61f3f8bbc5 --- /dev/null +++ b/apps/kimi-code/test/tui/components/editor/wrapping-select-list.test.ts @@ -0,0 +1,141 @@ +import { visibleWidth, type SelectItem, type SelectListTheme } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { WrappingSelectList } from '#/tui/components/editor/wrapping-select-list'; + +/** Marker theme so assertions can see which style hook painted each part. */ +const MARKER_THEME: SelectListTheme = { + selectedPrefix: (s) => s, + selectedText: (s) => `[S]${s}`, + description: (s) => `[D]${s}`, + scrollInfo: (s) => `[I]${s}`, + noMatch: (s) => `[N]${s}`, +}; + +const IDENTITY_THEME: SelectListTheme = { + selectedPrefix: (s) => s, + selectedText: (s) => s, + description: (s) => s, + scrollInfo: (s) => s, + noMatch: (s) => s, +}; + +/** Mirrors pi-tui's slash command layout (editor.js). */ +const SLASH_LAYOUT = { minPrimaryColumnWidth: 12, maxPrimaryColumnWidth: 32 }; + +// With two 4-char labels and SLASH_LAYOUT at width 80, the primary column is +// 12 wide: prefix(2) + label(4) + spacing(8) puts descriptions at column 14 +// with 64 columns of room (80 - 14 - 2 safety). +const DESCRIPTION_INDENT = ' '.repeat(14); + +function makeList(items: SelectItem[], maxVisible = 5): WrappingSelectList { + return new WrappingSelectList(items, maxVisible, MARKER_THEME, SLASH_LAYOUT); +} + +describe('WrappingSelectList', () => { + it('renders short descriptions on a single line', () => { + const lines = makeList([ + { value: 'goal', label: 'goal', description: 'First command' }, + { value: 'init', label: 'init', description: 'Second command' }, + ]).render(80); + + expect(lines).toEqual([ + '[S]→ goal First command', + ' init[D] Second command', + ]); + }); + + it('wraps a long description onto a second indented line without an ellipsis', () => { + const lines = makeList([ + { value: 'goal', label: 'goal', description: 'First command' }, + { + value: 'init', + label: 'init', + description: + 'lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt', + }, + ]).render(80); + + expect(lines).toEqual([ + '[S]→ goal First command', + ' init[D] lorem ipsum dolor sit amet consectetur adipiscing elit sed do', + `[D]${DESCRIPTION_INDENT}eiusmod tempor incididunt`, + ]); + }); + + it('caps descriptions at two lines and ellipsizes the overflow', () => { + const description = 'lorem ipsum dolor sit amet consectetur adipiscing elit '.repeat(4).trim(); + const lines = makeList([ + { value: 'goal', label: 'goal', description: 'First command' }, + { value: 'init', label: 'init', description }, + ]).render(80); + + expect(lines).toHaveLength(3); + expect(lines[1]).toMatch(/^ {2}init\[D\] {8}lorem ipsum/); + expect(lines[2]).toMatch(new RegExp(`^\\[D\\]${DESCRIPTION_INDENT}`)); + expect(lines[2]!.endsWith('…')).toBe(true); + }); + + it('paints every line of the selected item with the selected style', () => { + const description = 'lorem ipsum dolor sit amet consectetur adipiscing elit '.repeat(4).trim(); + const lines = makeList([ + { value: 'goal', label: 'goal', description }, + { value: 'init', label: 'init', description: 'Second command' }, + ]).render(80); + + expect(lines[0]).toMatch(/^\[S\]→ goal {8}lorem ipsum/); + expect(lines[1]).toMatch(new RegExp(`^\\[S\\]${DESCRIPTION_INDENT}`)); + expect(lines[2]).toBe(' init[D] Second command'); + }); + + it('falls back to primary-only single lines on narrow widths', () => { + const lines = makeList([ + { value: 'goal', label: 'goal', description: 'First command' }, + { value: 'init', label: 'init', description: 'Second command' }, + ]).render(40); + + expect(lines).toEqual(['[S]→ goal', ' init']); + }); + + it('keeps the scroll indicator when items overflow maxVisible', () => { + const items = Array.from({ length: 7 }, (_, i) => ({ + value: `cmd${i}`, + label: `cmd${i}`, + description: 'Short', + })); + const lines = makeList(items, 5).render(80); + + expect(lines).toHaveLength(6); + expect(lines[5]).toBe('[I] (1/7)'); + }); + + it('does not leak ANSI resets into themed lines when the primary name is truncated', () => { + const description = 'Use when about to claim work is complete fixed or passing before committing'; + const lines = makeList([ + { value: 'verify', label: 'skill:verification-before-completion', description }, + { value: 'init', label: 'skill:another-very-long-command-name', description }, + ]).render(80); + + // truncateToWidth appends [0m when it truncates; embedded inside the + // selected/description colouring it would reset the rest of the line. + for (const line of lines) { + expect(line).not.toContain('\u001B'); + } + }); + + it('never emits a line wider than the requested width, including CJK text', () => { + const list = new WrappingSelectList( + [ + { value: 'lark', label: 'skill:lark-calendar', description: '管理飞书日历的技能描述'.repeat(8) }, + { value: 'init', label: 'init', description: 'word '.repeat(60).trim() }, + ], + 5, + IDENTITY_THEME, + SLASH_LAYOUT, + ); + + for (const line of list.render(80)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(80); + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/media/code-highlight.test.ts b/apps/kimi-code/test/tui/components/media/code-highlight.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8392f450632113e73027dc17f57198cab5f8a302 --- /dev/null +++ b/apps/kimi-code/test/tui/components/media/code-highlight.test.ts @@ -0,0 +1,71 @@ +import { createRequire } from 'node:module'; +import { dirname } from 'node:path'; + +import chalk from 'chalk'; +import { describe, expect, it } from 'vitest'; + +import { highlightLines, langFromPath } from '#/tui/components/media/code-highlight'; +import { codeHighlightTheme } from '#/tui/theme/highlight-theme'; +import { currentTheme } from '#/tui/theme/theme'; + +import { captureProcessWrite } from '../../../helpers/process'; + +const ESC = String.fromCodePoint(27); + +describe('code-highlight', () => { + it('maps known file extensions to supported highlight languages', () => { + expect(langFromPath('src/foo.ts')).toBe('typescript'); + expect(langFromPath('src/foo.TS')).toBe('typescript'); + }); + + it('treats unsupported file extensions as plain text', () => { + expect(langFromPath('src/foo.abcxyz')).toBeUndefined(); + }); + + it('does not call cli-highlight for unsupported languages', () => { + const stderr = captureProcessWrite('stderr'); + try { + expect(highlightLines('hello\nworld', 'abcxyz')).toEqual(['hello', 'world']); + expect(stderr.text()).not.toContain('Could not find the language'); + } finally { + stderr.restore(); + } + }); + + it('resets string and regexp tokens to plain styling', () => { + for (const token of ['string', 'regexp'] as const) { + expect(codeHighlightTheme[token]?.('code')).toBe('code'); + } + }); + + it('emits no red SGR for strings and regexps', () => { + // cli-highlight styles through its own chalk v4 instance; force colors on + // so the assertions below observe real SGR sequences. + const req = createRequire(import.meta.url); + const chalkV4 = req( + req.resolve('chalk', { paths: [dirname(req.resolve('cli-highlight'))] }), + ) as { level: number }; + const prevLevel = chalkV4.level; + chalkV4.level = 1; + try { + const js = highlightLines("const s = 'str';\nconst r = /re+/g;", 'javascript').join('\n'); + expect(js).not.toContain(`${ESC}[31m`); + expect(js).toContain(`${ESC}[34m`); // keywords stay highlighted + } finally { + chalkV4.level = prevLevel; + } + }); + + it('colors diff deletions and additions with the palette diff colors', () => { + const previousLevel = chalk.level; + chalk.level = 3; + try { + expect(highlightLines('- removed\n+ added', 'diff')).toEqual([ + chalk.hex(currentTheme.color('diffRemoved'))('- removed'), + chalk.hex(currentTheme.color('diffAdded'))('+ added'), + ]); + } finally { + chalk.level = previousLevel; + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/media/diff-preview.test.ts b/apps/kimi-code/test/tui/components/media/diff-preview.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d355bb7eda556f1b0ba1328754f327a407871d62 --- /dev/null +++ b/apps/kimi-code/test/tui/components/media/diff-preview.test.ts @@ -0,0 +1,192 @@ +import { describe, expect, it } from 'vitest'; + +import { + computeDiffLines, + renderDiffLines, + renderDiffLinesClustered, +} from '#/tui/components/media/diff-preview'; + +function stripAnsi(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('computeDiffLines', () => { + it('renders a complete diff when isIncomplete is false', () => { + const lines = computeDiffLines('A\nB\nC\nD', 'A\nB', 1, 1, false); + const kinds = lines.map((l) => l.kind); + expect(kinds).toEqual(['context', 'context', 'delete', 'delete']); + }); + + it('suppresses trailing deletes when isIncomplete is true', () => { + const lines = computeDiffLines('A\nB\nC\nD', 'A\nB', 1, 1, true); + const kinds = lines.map((l) => l.kind); + expect(kinds).toEqual(['context', 'context']); + }); + + it('suppresses all deletes when everything would be deleted and incomplete', () => { + const lines = computeDiffLines('A\nB\nC', '', 1, 1, true); + expect(lines).toEqual([]); + }); + + it('keeps trailing adds when isIncomplete is true', () => { + const lines = computeDiffLines('A\nB\nC', 'A\nB\nX', 1, 1, true); + const kinds = lines.map((l) => l.kind); + expect(kinds).toEqual(['context', 'context', 'delete', 'add']); + }); + + it('keeps internal delete blocks that are not trailing', () => { + const lines = computeDiffLines('A\nB\nC\nD', 'A\nC', 1, 1, true); + const kinds = lines.map((l) => l.kind); + expect(kinds).toEqual(['context', 'delete', 'context']); + }); +}); + +describe('renderDiffLines', () => { + it('does not show removed count for suppressed trailing deletes', () => { + const output = renderDiffLines('A\nB\nC\nD', 'A\nB', 'test.ts', true, 1, 1); + const text = stripAnsi(output.join('\n')); + expect(text).toContain('test.ts'); + expect(text).not.toContain('-2'); + expect(text).not.toContain('C'); + expect(text).not.toContain('D'); + // When trailing deletes are suppressed, only context lines remain; + // renderDiffLines only emits changed lines, so the body is empty. + expect(text).not.toContain('A'); + expect(text).not.toContain('B'); + }); + + it('shows removed count for complete diffs', () => { + const output = renderDiffLines('A\nB\nC\nD', 'A\nB', 'test.ts', false, 1, 1); + const text = stripAnsi(output.join('\n')); + expect(text).toContain('-2'); + expect(text).toContain('C'); + expect(text).toContain('D'); + }); +}); + +describe('renderDiffLinesClustered', () => { + it('renders header with file path and counts', () => { + const out = renderDiffLinesClustered('A\nB\nC', 'A\nX\nC', 'foo.ts'); + const text = stripAnsi(out[0]!); + expect(text).toContain('+1'); + expect(text).toContain('-1'); + expect(text).toContain('foo.ts'); + }); + + it('returns header only when there are no changes', () => { + const out = renderDiffLinesClustered('A\nB', 'A\nB', 'foo.ts'); + expect(out).toHaveLength(1); + expect(stripAnsi(out[0]!)).toContain('foo.ts'); + }); + + it('shows context lines around a single change cluster', () => { + // Five lines, change line 3 only — context is 1 each side. + const oldText = ['L1', 'L2', 'L3', 'L4', 'L5'].join('\n'); + const newText = ['L1', 'L2', 'L3X', 'L4', 'L5'].join('\n'); + const text = stripAnsi( + renderDiffLinesClustered(oldText, newText, 'f.ts', { contextLines: 1 }).join('\n'), + ); + expect(text).toContain('L2'); + expect(text).toContain('L3'); + expect(text).toContain('L3X'); + expect(text).toContain('L4'); + expect(text).not.toContain('L1'); + expect(text).not.toContain('L5'); + }); + + it('elides unchanged middle between two clusters with a separator', () => { + const oldLines: string[] = []; + for (let i = 1; i <= 30; i++) oldLines.push(`L${String(i)}`); + const newLines = oldLines.slice(); + newLines[1] = 'L2X'; // change near top + newLines[28] = 'L29X'; // change near bottom + const text = stripAnsi( + renderDiffLinesClustered(oldLines.join('\n'), newLines.join('\n'), 'f.ts', { + contextLines: 2, + }).join('\n'), + ); + expect(text).toContain('L2X'); + expect(text).toContain('L29X'); + expect(text).toMatch(/… \d+ unchanged lines? …/); + // Middle untouched lines (e.g. L15) should not appear. + expect(text).not.toContain('L15'); + }); + + it('merges nearby change clusters when the gap is within context window', () => { + const oldLines: string[] = []; + for (let i = 1; i <= 10; i++) oldLines.push(`L${String(i)}`); + const newLines = oldLines.slice(); + newLines[2] = 'L3X'; + newLines[5] = 'L6X'; // gap of 2 lines between change indices 2 and 5 → merges with contextLines=2 (mergeGap=4) + const out = renderDiffLinesClustered(oldLines.join('\n'), newLines.join('\n'), 'f.ts', { + contextLines: 2, + }).join('\n'); + const text = stripAnsi(out); + expect(text).not.toMatch(/unchanged lines? …/); + expect(text).toContain('L3X'); + expect(text).toContain('L6X'); + }); + + it('emits a partial body even when a single cluster exceeds maxLines', () => { + // Worst case from prod: 100 lines fully replaced inline → single huge + // cluster of ~200 diff entries. With maxLines=10 the renderer must + // still emit ~10 leading body rows, not just the truncation footer. + const oldLines: string[] = []; + const newLines: string[] = []; + for (let i = 1; i <= 100; i++) { + oldLines.push(`old${String(i)}`); + newLines.push(`new${String(i)}`); + } + const out = renderDiffLinesClustered( + oldLines.join('\n'), + newLines.join('\n'), + 'big.ts', + { + contextLines: 3, + maxLines: 10, + }, + ); + // header + 10 body rows + truncation footer + expect(out.length).toBe(12); + const text = stripAnsi(out.join('\n')); + expect(text).toContain('+100'); + expect(text).toContain('-100'); + expect(text).toMatch(/old\d+|new\d+/); + expect(text).toContain('ctrl+o to expand'); + }); + + it('respects oldStart and newStart for line numbers', () => { + const text = stripAnsi( + renderDiffLinesClustered('A\nB\nC', 'A\nX\nC', 'f.ts', { + contextLines: 1, + oldStart: 10, + newStart: 20, + }).join('\n'), + ); + // Context lines keep the new (post-edit) line numbers from newStart; + // deleted lines use oldStart; added lines use newStart. + expect(text).toContain(' 20 A'); + expect(text).toContain(' 11 - B'); + expect(text).toContain(' 21 + X'); + expect(text).toContain(' 22 C'); + }); + + it('truncates at cluster boundary and appends the ctrl+o footer when maxLines is set', () => { + const oldLines: string[] = []; + for (let i = 1; i <= 50; i++) oldLines.push(`L${String(i)}`); + const newLines = oldLines.slice(); + newLines[1] = 'L2X'; + newLines[20] = 'L21X'; + newLines[40] = 'L41X'; + const text = stripAnsi( + renderDiffLinesClustered(oldLines.join('\n'), newLines.join('\n'), 'f.ts', { + contextLines: 2, + maxLines: 6, + }).join('\n'), + ); + expect(text).toContain('L2X'); + expect(text).toMatch(/more change/); + expect(text).toContain('ctrl+o to expand'); + expect(text).not.toContain('L41X'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/media/image-thumbnail.test.ts b/apps/kimi-code/test/tui/components/media/image-thumbnail.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6378f3890c7b564b7ba84d29e4414b4cdff0319 --- /dev/null +++ b/apps/kimi-code/test/tui/components/media/image-thumbnail.test.ts @@ -0,0 +1,47 @@ +import { resetCapabilitiesCache, setCapabilities, visibleWidth } from '@moonshot-ai/pi-tui'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { ImageThumbnail } from '#/tui/components/media/image-thumbnail'; +import type { ImageAttachment } from '#/tui/utils/image-attachment-store'; + +const image: ImageAttachment = { + id: 1, + kind: 'image', + bytes: new Uint8Array([137, 80, 78, 71]), + mime: 'image/png', + width: 800, + height: 600, + placeholder: '[image #1 (800×600)]', +}; + +describe('ImageThumbnail', () => { + afterEach(() => { + resetCapabilitiesCache(); + vi.restoreAllMocks(); + }); + + it('keeps rendered output within narrow widths', () => { + setCapabilities({ images: null, trueColor: false, hyperlinks: false }); + + const component = new ImageThumbnail(image); + + for (const width of [39, 20, 3, 1]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('does not rebuild inline image children on repeated same-width renders', () => { + setCapabilities({ images: 'kitty', trueColor: true, hyperlinks: true }); + + const bufferFrom = vi.spyOn(Buffer, 'from'); + const component = new ImageThumbnail(image); + bufferFrom.mockClear(); + + component.render(80); + component.render(80); + + expect(bufferFrom).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/agent-group.test.ts b/apps/kimi-code/test/tui/components/messages/agent-group.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e567e96ad6815a2b916e7a99ff6183ca9385fe06 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/agent-group.test.ts @@ -0,0 +1,253 @@ +import type { TUI } from '@moonshot-ai/pi-tui'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { AgentGroupComponent } from '#/tui/components/messages/agent-group'; +import { ToolCallComponent } from '#/tui/components/messages/tool-call'; + +const ESC = String.fromCodePoint(0x1b); +const BEL = String.fromCodePoint(0x07); + +function strip(text: string): string { + return text + .replaceAll(/\u001B\[[0-9;]*m/g, '') + .replaceAll(new RegExp(`${ESC}\\]8;;[^${BEL}]*${BEL}`, 'g'), ''); +} + +function stubTui(): TUI { + return { + terminal: { rows: 40 }, + requestRender: vi.fn(), + } as unknown as TUI; +} + +function renderText(component: AgentGroupComponent, width = 120): string { + return strip(component.render(width).join('\n')); +} + +function createAgent( + id: string, + description: string, + agentName: string, + ui: TUI, +): ToolCallComponent { + const component = new ToolCallComponent( + { + id, + name: 'Agent', + args: { description }, + }, + undefined, + ui, + ); + component.onSubagentSpawned({ + agentId: `sub_${id}`, + agentName, + runInBackground: false, + }); + return component; +} + +function startAgent(component: ToolCallComponent, id: string, agentName: string): void { + component.onSubagentStarted({ + agentId: `sub_${id}`, + agentName, + runInBackground: false, + }); +} + +describe('AgentGroupComponent', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('shows explicit active breakdown, row state, and waiting fallback', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const running = createAgent('call_agent_1', 'inspect project', 'explore', ui); + const waiting = createAgent('call_agent_2', 'write tests', 'coder', ui); + + startAgent(running, 'call_agent_1', 'explore'); + running.appendSubToolCall({ + id: 'sub_call_agent_1:read', + name: 'Read', + args: { path: 'src/a.ts' }, + }); + + group.attach('call_agent_1', running); + group.attach('call_agent_2', waiting); + + const output = renderText(group); + expect(output).toContain('Running 2 agents (1 running, 1 waiting) · 0s'); + expect(output).toContain('explore · inspect project · 0 tools · 0s · Running'); + expect(output).toContain('Using Read (src/a.ts)'); + expect(output).toContain('coder · write tests · 0 tools · 0s · Waiting'); + expect(output).toContain('Waiting to start…'); + expect(output).not.toContain('Initializing…'); + + group.dispose(); + running.dispose(); + waiting.dispose(); + }); + + it('shows the bound model in the row stats once reported', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const running = createAgent('call_agent_1', 'inspect project', 'explore', ui); + startAgent(running, 'call_agent_1', 'explore'); + + group.attach('call_agent_1', running); + expect(renderText(group)).toContain('explore · inspect project · 0 tools'); + + running.updateSubagentMetrics({ modelDisplay: 'Kimi K2.5' }); + // Non-phase updates are throttled; flush the pending refresh. + vi.runOnlyPendingTimers(); + expect(renderText(group)).toContain('explore · inspect project · Kimi K2.5 · 0 tools'); + + group.dispose(); + running.dispose(); + }); + + it('shows the Ctrl+B hint while agents are running and hides it once all are backgrounded', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const a = createAgent('call_agent_1', 'inspect project', 'explore', ui); + const b = createAgent('call_agent_2', 'write tests', 'coder', ui); + startAgent(a, 'call_agent_1', 'explore'); + startAgent(b, 'call_agent_2', 'coder'); + group.attach('call_agent_1', a); + group.attach('call_agent_2', b); + + expect(renderText(group)).toContain('Press Ctrl+B to run in background'); + + a.markBackgrounded(); + expect(renderText(group)).toContain('Press Ctrl+B to run in background'); + + b.markBackgrounded(); + expect(renderText(group)).not.toContain('Press Ctrl+B to run in background'); + + group.dispose(); + a.dispose(); + b.dispose(); + }); + + it('uses still-working fallback for running agents without recent activity', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const running = createAgent('call_agent_1', 'inspect project', 'explore', ui); + const waiting = createAgent('call_agent_2', 'write tests', 'coder', ui); + + startAgent(running, 'call_agent_1', 'explore'); + group.attach('call_agent_1', running); + group.attach('call_agent_2', waiting); + + const output = renderText(group); + expect(output).toContain('Still working…'); + expect(output).toContain('Waiting to start…'); + expect(output).not.toContain('Initializing…'); + + group.dispose(); + running.dispose(); + waiting.dispose(); + }); + + it('refreshes grouped elapsed time from child subagent timers', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const running = createAgent('call_agent_1', 'inspect project', 'explore', ui); + const waiting = createAgent('call_agent_2', 'write tests', 'coder', ui); + + startAgent(running, 'call_agent_1', 'explore'); + group.attach('call_agent_1', running); + group.attach('call_agent_2', waiting); + + expect(renderText(group)).toContain('Running 2 agents (1 running, 1 waiting) · 0s'); + vi.mocked(ui.requestRender).mockClear(); + + vi.advanceTimersByTime(1_200); + + expect(ui.requestRender).toHaveBeenCalled(); + expect(renderText(group)).toContain('Running 2 agents (1 running, 1 waiting) · 1s'); + expect(renderText(group)).toContain('explore · inspect project · 0 tools · 1s · Running'); + + group.dispose(); + running.dispose(); + waiting.dispose(); + }); + + it('keeps terminal rows explicit while mixed agents are still running', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const done = createAgent('call_agent_1', 'inspect project', 'explore', ui); + const running = createAgent('call_agent_2', 'write tests', 'coder', ui); + + startAgent(done, 'call_agent_1', 'explore'); + startAgent(running, 'call_agent_2', 'coder'); + group.attach('call_agent_1', done); + group.attach('call_agent_2', running); + + vi.setSystemTime(12_000); + done.onSubagentCompleted({ resultSummary: 'done' }); + + const mixed = renderText(group); + expect(mixed).toContain('Running 2 agents (1 done, 1 running) · 12s'); + expect(mixed).toContain('explore · inspect project · 0 tools · 12s · ✓ Completed'); + expect(mixed).toContain('coder · write tests · 0 tools · 12s · Running'); + + vi.setSystemTime(15_000); + running.onSubagentFailed({ error: 'review failed' }); + + const terminal = renderText(group); + expect(terminal).toContain('2 agents finished · 15s'); + expect(terminal).toContain('✗ Failed'); + expect(terminal).toContain('Error: review failed'); + expect(terminal).not.toContain('Still working…'); + + group.dispose(); + done.dispose(); + running.dispose(); + }); + + it('renders a detached foreground subagent as backgrounded in the group, even after its ToolResult lands', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = stubTui(); + const group = new AgentGroupComponent(ui); + const a = createAgent('call_agent_1', 'inspect project', 'explore', ui); + const b = createAgent('call_agent_2', 'write tests', 'coder', ui); + startAgent(a, 'call_agent_1', 'explore'); + startAgent(b, 'call_agent_2', 'coder'); + group.attach('call_agent_1', a); + group.attach('call_agent_2', b); + + // Detach `a` (Ctrl+B), then its spawn-success ToolResult lands. + a.markBackgrounded(); + a.setResult({ + tool_call_id: 'call_agent_1', + output: 'agent_id: sub_call_agent_1\nactual_subagent_type: explore\n', + is_error: false, + }); + + const out = renderText(group); + // `a` must show as backgrounded, NOT completed. + expect(out).toContain('◐ backgrounded'); + expect(out).not.toContain('✓ Completed'); + // `b` is still running. + expect(out).toContain('Running'); + + group.dispose(); + a.dispose(); + b.dispose(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/agent-swarm-progress.test.ts b/apps/kimi-code/test/tui/components/messages/agent-swarm-progress.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..475853ca221bd7930074778ce952868863922855 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/agent-swarm-progress.test.ts @@ -0,0 +1,1456 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; + +import { + AgentSwarmProgressComponent, + type AgentSwarmProgressOptions, + agentSwarmDescriptionFromArgs, + agentSwarmGridHeightForTerminalRows, + agentSwarmItemsFromArgs, + agentSwarmPartialItemsCountFromArguments, + agentSwarmPartialItemsFromArguments, + calculateAgentSwarmGridLayout, +} from '#/tui/components/messages/agent-swarm-progress'; +import { AgentSwarmProgressEstimator } from '#/tui/components/messages/agent-swarm-progress-estimator'; +import { currentTheme, darkColors, lightColors } from '#/tui/theme'; +import { setRenderCacheEnabled } from '#/tui/utils/render-cache'; + +const DEFAULT_DESCRIPTION = 'Review changed files'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function createComponent( + options: Partial = {}, +): AgentSwarmProgressComponent { + return new AgentSwarmProgressComponent({ + description: options.description ?? DEFAULT_DESCRIPTION, + requestRender: options.requestRender, + availableGridHeight: options.availableGridHeight, + }); +} + +function renderText(component: AgentSwarmProgressComponent, width = 100): string { + return strip(component.render(width).join('\n')); +} + +function renderLines(component: AgentSwarmProgressComponent, width = 100): string[] { + return renderText(component, width).split('\n'); +} + +function registerSubagents(component: AgentSwarmProgressComponent, count: number): void { + for (let index = 1; index <= count; index += 1) { + component.registerSubagent({ + agentId: `agent-${String(index)}`, + description: `${DEFAULT_DESCRIPTION} #${String(index)} (coder)`, + }); + } +} + +function startSubagents(component: AgentSwarmProgressComponent, count: number): void { + component.markInputComplete(); + for (let index = 1; index <= count; index += 1) { + component.markStarted(`agent-${String(index)}`); + } +} + +afterEach(() => { + vi.useRealTimers(); + currentTheme.setPalette(darkColors); +}); + +describe('calculateAgentSwarmGridLayout', () => { + it('uses a text grid when labels fit within the available height', () => { + const layout = calculateAgentSwarmGridLayout({ + width: 100, + height: 3, + count: 9, + }); + + expect(layout).toMatchObject({ + renderText: true, + columns: 3, + rows: 3, + }); + expect(layout.barCells).toBeGreaterThanOrEqual(6); + expect(layout.cellWidth).toBeGreaterThanOrEqual(22); + }); + + it('adds text columns before falling back to compact bars', () => { + const textLayout = calculateAgentSwarmGridLayout({ + width: 120, + height: 4, + count: 20, + }); + const compactLayout = calculateAgentSwarmGridLayout({ + width: 117, + height: 4, + count: 20, + }); + + expect(textLayout).toMatchObject({ + renderText: true, + columns: 5, + rows: 4, + }); + expect(compactLayout).toMatchObject({ + renderText: false, + columns: 5, + rows: 4, + }); + expect(compactLayout.barCells).toBeGreaterThan(textLayout.barCells); + }); + + it('uses compact bars to satisfy tight height budgets', () => { + const layout = calculateAgentSwarmGridLayout({ + width: 100, + height: 5, + count: 30, + }); + + expect(layout).toMatchObject({ + renderText: false, + columns: 6, + rows: 5, + }); + expect(layout.barCells).toBeGreaterThan(0); + }); + + it('keeps compact rows within the available height even when bars are narrow', () => { + const layout = calculateAgentSwarmGridLayout({ + width: 100, + height: 4, + count: 40, + }); + + expect(layout).toMatchObject({ + renderText: false, + columns: 10, + rows: 4, + }); + expect(layout.barCells).toBe(1); + }); + + it('keeps at least one bar cell when no rows are available', () => { + const layout = calculateAgentSwarmGridLayout({ + width: 20, + height: 0, + count: 4, + }); + + expect(layout).toMatchObject({ + renderText: false, + columns: 2, + rows: 2, + }); + expect(layout.barCells).toBeGreaterThan(0); + }); + + it('derives the grid height left inside the AgentSwarm block', () => { + expect(agentSwarmGridHeightForTerminalRows(undefined)).toBeUndefined(); + expect(agentSwarmGridHeightForTerminalRows(10)).toBe(4); + expect(agentSwarmGridHeightForTerminalRows(20, 5)).toBe(9); + expect(agentSwarmGridHeightForTerminalRows(4)).toBe(0); + }); +}); + +describe('AgentSwarmProgressComponent', () => { + it('renders an orchestrating panel before subagents spawn', () => { + const component = createComponent(); + + const output = renderText(component); + + expect(output).toContain('Agent Swarm'); + expect(output).toContain('Review changed files'); + expect(output).toContain('Orchestrating…'); + expect(output).not.toContain('01'); + }); + + it('shows the bound model display name in the header', () => { + const component = createComponent(); + + component.setModelDisplay('kimi-k2-thinking'); + const lines = renderLines(component); + const headerLine = lines.find((line) => line.includes('Agent Swarm')); + + expect(headerLine).toBeDefined(); + expect(headerLine).toContain('Review changed files ─ kimi-k2-thinking'); + }); + + it('keeps the first reported model when later status updates differ', () => { + const component = createComponent(); + + component.setModelDisplay('kimi-k2-thinking'); + component.setModelDisplay('other-model'); + component.setModelDisplay(''); + + const output = renderText(component); + + expect(output).toContain('kimi-k2-thinking'); + expect(output).not.toContain('other-model'); + }); + + it('repaints from the active palette when the theme changes', () => { + const previousLevel = chalk.level; + chalk.level = 3; // force truecolor so palette differences surface as ANSI + try { + const component = createComponent(); + const titleOf = (): string => { + const line = component.render(100).find((l) => strip(l).includes('Agent Swarm')); + if (line === undefined) throw new Error('title line not found'); + return line; + }; + const before = titleOf(); + + currentTheme.setPalette(lightColors); + const after = titleOf(); + + // Same visible text, different ANSI colours (reads currentTheme live). + expect(strip(after)).toBe(strip(before)); + expect(after).not.toBe(before); + } finally { + chalk.level = previousLevel; + } + }); + + it('renders blank padding around the block without a bottom divider', () => { + const component = createComponent(); + + registerSubagents(component, 1); + const lines = renderLines(component); + + expect(lines[0]).toBe(' '); + expect(lines[1]).toContain('Agent Swarm'); + expect(lines.at(-1)).toBe(' '); + expect(lines.at(-2)).not.toMatch(/^─+$/); + }); + + it('reserves one blank column on the right edge', () => { + const component = createComponent(); + + registerSubagents(component, 1); + startSubagents(component, 1); + + const rendered = component.render(80).map(strip); + const gridLine = rendered.find((line) => line.includes('001 [')); + + expect(rendered.every((line) => visibleWidth(line) <= 79)).toBe(true); + expect(rendered.some((line) => line.includes('Agent Swarm'))).toBe(true); + expect(gridLine).toBeDefined(); + expect(visibleWidth(gridLine ?? '')).toBeLessThanOrEqual(79); + }); + + it('renders spawned subagents as queued rows without empty progress bars', () => { + const component = createComponent(); + + registerSubagents(component, 2); + + const output = renderText(component); + + expect(output).toContain('001 Queued…'); + expect(output).toContain('002 Queued…'); + expect(output).not.toContain('001 ['); + expect(output).not.toContain('002 ['); + expect(output).not.toContain('agents=2'); + }); + + it('fits three queued columns with the narrower gap and minimum cell width', () => { + const component = createComponent(); + + registerSubagents(component, 3); + + const lines = renderLines(component, 97); + const queuedLine = lines.find((line) => line.includes('001 Queued…')); + + expect(queuedLine).toBeDefined(); + expect(queuedLine).toContain('002 Queued…'); + expect(queuedLine).toContain('003 Queued…'); + }); + + it('omits subagent text when the compact grid is needed to fit available height', () => { + const component = createComponent({ + availableGridHeight: () => 5, + }); + + registerSubagents(component, 30); + startSubagents(component, 30); + + const lines = renderLines(component, 102); + const gridLines = lines.filter((line) => /\b\d{3} \[/.test(line)); + + expect(gridLines).toHaveLength(5); + expect(gridLines[0]).toContain('001 ['); + expect(gridLines[0]).toContain('006 ['); + expect(gridLines.join('\n')).not.toContain('Running'); + }); + + it('keeps streamed pending items as text even when compact layout is selected', () => { + const component = createComponent({ + availableGridHeight: () => 5, + }); + + component.updateArgs({ + items: Array.from({ length: 30 }, (_item, index) => `f${String(index + 1)}.ts`), + }); + + const output = renderText(component, 102); + + expect(output).toContain('001 f1.ts'); + expect(output).toContain('006 f6.ts'); + expect(output).not.toContain('001 ['); + }); + + it('prefixes a cancelled running subagent label with the aborted mark without changing the text', () => { + const component = createComponent(); + + registerSubagents(component, 1); + startSubagents(component, 1); + component.appendModelDelta({ agentId: 'agent-1', delta: 'Inspecting src/a.ts' }); + component.markCancelled('agent-1'); + + const output = renderText(component); + const cellLine = output.split('\n').find((line) => line.includes('001 [')); + + expect(cellLine).toBeDefined(); + expect(cellLine).toContain('⊘ Inspecting src/a.ts'); + expect(cellLine).not.toContain('⊘ Aborted.'); + }); + + it('shows a cancelled label without a progress bar for queued subagents', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.markInputComplete(); + component.markCancelled('agent-1'); + + const output = renderText(component); + const cellLine = output.split('\n').find((line) => line.includes('001 ')); + + expect(cellLine).toBeDefined(); + expect(cellLine).toContain('⊘ Cancelled.'); + expect(cellLine).not.toContain('['); + expect(cellLine).not.toContain('⊘ Aborted.'); + }); + + it('renders terminal marks against compact bars when subagent text is hidden', () => { + const component = createComponent({ + availableGridHeight: () => 5, + }); + + registerSubagents(component, 30); + startSubagents(component, 30); + component.markCompleted('agent-1'); + component.markFailed('agent-2', 'Agent timed out'); + component.markCancelled('agent-3'); + + const lines = renderLines(component, 102); + const gridLine = lines.find((line) => line.includes('001 [')); + + expect(gridLine).toBeDefined(); + expect(gridLine).toMatch(/001 \[[^\]]+\]✓ +002 \[[^\]]+\]✗ +003 \[[^\]]+\]⊘/); + expect(gridLine).not.toContain('Completed'); + expect(gridLine).not.toContain('Failed'); + expect(gridLine).not.toContain('Aborted'); + }); + + it('advances from queued when a subagent tool call starts and marks terminal states', () => { + const component = createComponent(); + + registerSubagents(component, 2); + component.recordToolCall({ agentId: 'agent-1', toolCallId: 'call-read' }); + + let output = renderText(component); + expect(output).toContain('001 ['); + expect(output).toContain('Running'); + expect(output).toContain('002 Queued…'); + expect(output).not.toContain('002 ['); + + component.markCompleted('agent-1'); + component.markFailed('agent-2'); + + output = renderText(component); + expect(output).toContain('001 ['); + expect(output).toContain('✓'); + expect(output).toContain('Completed.'); + expect(output).toContain('002 ['); + expect(output).toContain('Failed'); + }); + + it('renders completed subagent output with a success mark', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.markCompleted('agent-1', 'Reviewed imports and found no regressions'); + + const output = renderText(component); + + expect(output).toContain('✓ Reviewed imports and found no regressions'); + expect(output).toContain('Completed.'); + }); + + it('renders failure details from live subagent failures', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.markFailed('agent-1', 'Provider request failed\nRetry budget exhausted'); + + const output = renderText(component); + + expect(output).toContain('✗ Provider request failed Retry budget exhausted'); + expect(output).not.toContain('Failed:'); + }); + + it('renders suspended subagents as rate limited and clears the state when they start again', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.markStarted('agent-1'); + component.markSuspended({ + agentId: 'agent-1', + reason: 'Provider rate limit; subagent requeued for retry.', + }); + + let output = renderText(component); + expect(output).toContain('Rate limited…'); + expect(output).not.toContain('Queued…'); + expect(output).not.toContain('Provider rate limit'); + expect(output).not.toContain('Failed'); + + component.markStarted('agent-1'); + + output = renderText(component); + expect(output).toContain('Running'); + expect(output).not.toContain('Rate limited…'); + }); + + it('renders rate-limited subagents as cancelled when cancelled', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.markStarted('agent-1'); + component.markSuspended({ + agentId: 'agent-1', + reason: 'Provider rate limit; subagent requeued for retry.', + }); + component.markCancelled('agent-1'); + + const cellLine = renderLines(component) + .find((line) => line.includes('001 [')); + + expect(cellLine).toBeDefined(); + expect(cellLine).toContain('⊘ Cancelled.'); + expect(cellLine).not.toContain('Rate limited…'); + }); + + it('renders failure details from AgentSwarm result output', () => { + const component = createComponent(); + + component.updateArgs({ + description: 'Review changed files', + items: ['src/a.ts'], + }); + component.applyResult([ + '', + 'failed: 1', + 'Agent timed out after 30s.', + '', + ].join('\n')); + + const output = renderText(component); + + expect(output).toContain('✗ Agent timed out after 30s.'); + expect(output).not.toContain('Failed:'); + }); + + it('applies no-index AgentSwarm result statuses by tag order', () => { + const component = createComponent(); + + component.updateArgs({ + description: 'Review changed files', + items: ['src/a.ts', 'src/b.ts'], + }); + const applied = component.applyResult([ + '', + 'failed: 1, aborted: 1', + '' + + 'Agent timed out after 30s.', + '' + + 'User interrupted.', + '', + ].join('\n')); + + const output = renderText(component, 120); + + expect(applied).toBe(true); + expect(output).toContain('✗ Agent timed out after 30s.'); + expect(output).toContain('⊘ Cancelled.'); + expect(output).not.toContain('002 ['); + expect(output).not.toContain('Completed.'); + }); + + it('strips nested AgentSwarm prefixes from failure details', () => { + const component = createComponent(); + + component.updateArgs({ + description: 'Review changed files', + items: ['src/a.ts'], + }); + component.applyResult([ + '', + 'failed: 1', + 'agent_swarm: failed', + 'description: Nested review', + 'items: 1', + 'completed: 0', + 'failed: 1', + '', + '[agent 1]', + 'status: failed', + '', + 'subagent error: [provider.rate_limit] 429 request reached user+model max RPM.', + '', + ].join('\n')); + + const output = renderText(component, 120); + + expect(output).toContain('✗ [provider.rate_limit] 429 request reached user+model max RPM.'); + expect(output).not.toContain('agent_swarm:'); + expect(output).not.toContain('Failed:'); + }); + + it('renders completed summaries from AgentSwarm result output', () => { + const component = createComponent(); + + component.updateArgs({ + description: 'Review changed files', + items: ['src/a.ts'], + }); + component.applyResult([ + '', + 'completed: 1', + 'Reviewed src/a.ts and confirmed imports are stable.', + '', + ].join('\n')); + + const output = renderText(component); + + expect(output).toContain('✓ Reviewed src/a.ts and confirmed imports are stable.'); + expect(output).toContain('Completed.'); + }); + + it('shows completed total status when only some subagents fail', () => { + const component = createComponent(); + + component.updateArgs({ + description: 'Review changed files', + items: ['src/a.ts', 'src/b.ts'], + }); + component.applyResult([ + '', + 'completed: 1, failed: 1', + 'Reviewed src/a.ts and confirmed imports are stable.', + 'Agent timed out after 30s.', + '', + ].join('\n')); + + const output = renderText(component, 120); + const totalStatusLine = output.split('\n').find((line) => line.includes('Completed.')); + + expect(totalStatusLine).toBeDefined(); + expect(totalStatusLine).not.toContain('Failed.'); + expect(output).toContain('✓ Reviewed src/a.ts'); + expect(output).toContain('✗ Agent timed out after 30s.'); + }); + + it('uses the latest assistant line as completed output when no summary is available', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.appendModelDelta({ + agentId: 'agent-1', + delta: 'Reviewing src/a.ts\nImports look stable', + }); + component.markCompleted('agent-1'); + + const output = renderText(component); + + expect(output).toContain('✓ Imports look stable'); + expect(output).toContain('Completed.'); + }); + + it('shows latest assistant text after the progress bar with ellipsis truncation', () => { + const component = createComponent(); + + registerSubagents(component, 1); + component.markInputComplete(); + component.recordToolCall({ agentId: 'agent-1', toolCallId: 'call-read' }); + component.appendModelDelta({ + agentId: 'agent-1', + delta: 'Reviewing src/a.ts and checking imports for regressions in detail', + }); + + const output = renderText(component, 44); + expect(output).toContain('001 ['); + expect(output).toContain('Reviewing'); + expect(output).toContain('…'); + }); + + it('uses natural status label width for prompting text', () => { + const prompting = createComponent({ + description: '', + }); + prompting.updateArgs({}, { + streamingArguments: '{"prompt_template":"Review the changed TypeScript files carefully', + }); + + const promptLine = renderLines(prompting, 80) + .find((line) => line.includes('Prompting…')); + expect(promptLine).toBeDefined(); + + const working = createComponent(); + registerSubagents(working, 1); + startSubagents(working, 1); + + const workingLine = renderLines(working, 80) + .find((line) => line.includes('Working…')); + expect(workingLine).toBeDefined(); + + const promptTextIndex = promptLine?.indexOf('Review the changed') ?? -1; + const progressBarIndex = workingLine?.indexOf('━') ?? -1; + expect(promptTextIndex).toBeGreaterThan(0); + expect(progressBarIndex).toBeGreaterThan(0); + expect(promptTextIndex).toBe(visibleWidth(' Prompting… ')); + expect(progressBarIndex).toBe(visibleWidth(' Working… ')); + }); + + it('renders the activity spinner before the total status line', () => { + const component = createComponent(); + + registerSubagents(component, 1); + startSubagents(component, 1); + component.setActivitySpinnerText(() => '🌗'); + + const statusLine = renderLines(component, 80) + .find((line) => line.includes('Working…')); + + expect(statusLine).toBeDefined(); + expect(statusLine?.startsWith(' 🌗 Working…')).toBe(true); + }); + + it('keeps a two-cell placeholder after the AgentSwarm tool call ends', () => { + const component = createComponent(); + + registerSubagents(component, 1); + startSubagents(component, 1); + component.setActivitySpinnerText(() => '🌗'); + component.markToolCallEnded(); + component.setActivitySpinnerText(() => '🌘'); + + const statusLine = renderLines(component, 80) + .find((line) => line.includes('Working…')); + + expect(statusLine).toBeDefined(); + expect(statusLine?.startsWith(' Working…')).toBe(true); + expect(statusLine).not.toContain('🌗'); + expect(statusLine).not.toContain('🌘'); + }); + + it('renders terminal total status lines after the tool call ends', () => { + const completed = createComponent(); + registerSubagents(completed, 1); + completed.markInputComplete(); + completed.markCompleted('agent-1', 'Imports are stable'); + completed.markToolCallEnded(); + + expect(renderLines(completed, 80).some((line) => line.startsWith(' ✓ Completed.'))).toBe(true); + + const failed = createComponent(); + registerSubagents(failed, 1); + failed.markInputComplete(); + failed.markFailed('agent-1', 'Agent timed out'); + failed.markToolCallEnded(); + + expect(renderLines(failed, 80).some((line) => line.startsWith(' ✗ Failed.'))).toBe(true); + + const aborted = createComponent(); + registerSubagents(aborted, 1); + aborted.markInputComplete(); + aborted.markStarted('agent-1'); + aborted.markActiveCancelled(); + aborted.markToolCallEnded(); + + const abortedOutput = renderText(aborted, 80); + expect(abortedOutput).toContain('⊘ Aborted.'); + expect(abortedOutput).not.toContain('Cancelled.'); + }); + + it('reserves one trailing cell for prompting streaming text', () => { + const prompting = createComponent({ + description: '', + }); + prompting.updateArgs({}, { + streamingArguments: '{"prompt_template":"Review every changed TypeScript file and summarize regressions carefully before reporting', + }); + + const promptLine = renderLines(prompting, 50) + .find((line) => line.includes('Prompting…')); + + expect(promptLine).toBeDefined(); + expect(visibleWidth(promptLine ?? '')).toBeLessThan(50); + }); + + it('renders boosted fractional progress ticks without leaking undefined cells', () => { + vi.useFakeTimers(); + const component = createComponent(); + + vi.setSystemTime(0); + registerSubagents(component, 1); + component.markStarted('agent-1'); + for (let index = 0; index < 10; index += 1) { + vi.setSystemTime(1_000 + index * 1_000); + component.recordToolCall({ agentId: 'agent-1', toolCallId: `done-${index}` }); + } + vi.setSystemTime(40_000); + component.markCompleted('agent-1'); + + component.registerSubagent({ + agentId: 'agent-2', + description: `${DEFAULT_DESCRIPTION} #2 (coder)`, + }); + component.markStarted('agent-2'); + for (let index = 0; index < 3; index += 1) { + vi.setSystemTime(45_000 + index * 5_000); + component.recordToolCall({ agentId: 'agent-2', toolCallId: `running-${index}` }); + } + + vi.setSystemTime(60_000); + component.render(100); + vi.setSystemTime(61_000); + const output = renderText(component); + + expect(output).toContain('002 ['); + expect(output).not.toContain('undefined'); + }); + + it('creates pending rows from streamed args items', () => { + const component = createComponent({ + description: '', + }); + + component.updateArgs({ + description: 'Review changed files', + items: ['src/a.ts', 'src/b.ts'], + }); + const output = renderText(component); + + expect(output).toContain('Agent Swarm'); + expect(output).toContain('Review changed files'); + expect(output).toContain('001 src/a.ts'); + expect(output).toContain('002 src/b.ts'); + }); + + it('creates pending rows from resume_agent_ids before streamed args items', () => { + const component = createComponent({ + description: '', + }); + + component.updateArgs({ + description: 'Review changed files', + resume_agent_ids: { + 'agent-old-1': 'continue', + 'agent-old-2': 'continue', + }, + items: ['src/a.ts'], + }); + const output = renderText(component); + + expect(output).toContain('001 (resumed)'); + expect(output).toContain('002 (resumed)'); + expect(output).toContain('003 src/a.ts'); + expect(output).not.toContain('001 ['); + }); + + it('counts partial items before each string is complete', () => { + expect( + agentSwarmPartialItemsCountFromArguments('{"items":["src/a.ts","src/b'), + ).toBe(2); + expect( + agentSwarmPartialItemsCountFromArguments('{"items":["src/a.ts","src/\\"b.ts","src/c'), + ).toBe(3); + expect( + agentSwarmPartialItemsFromArguments('{"items":["src/a.ts","src/\\"b.ts","src/c'), + ).toEqual(['src/a.ts', 'src/"b.ts', 'src/c']); + }); + + it('creates pending rows from partial streaming arguments', () => { + const component = createComponent({ + description: '', + }); + + component.updateArgs({}, { + streamingArguments: '{"description":"Review changed files","items":["src/a.ts","src/b', + }); + const output = renderText(component); + + expect(output).toContain('001 src/a.ts'); + expect(output).toContain('002 src/b'); + }); + + it('creates pending rows from partial streaming resume_agent_ids', () => { + const component = createComponent({ + description: '', + }); + + component.updateArgs({}, { + streamingArguments: + '{"description":"Resume reviews","resume_agent_ids":{"agent-old-1":"continue","agent-old-2":"cont', + }); + const output = renderText(component); + + expect(output).toContain('001 (resumed)'); + expect(output).toContain('002 (resumed)'); + expect(output).not.toContain('003'); + }); + + it('adds subagent rows incrementally as spawn events arrive', () => { + const component = createComponent(); + + registerSubagents(component, 1); + let output = renderText(component); + expect(output).toContain('001 Queued…'); + expect(output).not.toContain('001 ['); + expect(output).not.toContain('002'); + + component.registerSubagent({ + agentId: 'agent-2', + description: `${DEFAULT_DESCRIPTION} #2 (coder)`, + }); + output = renderText(component); + expect(output).toContain('001 Queued…'); + expect(output).toContain('002 Queued…'); + expect(output).not.toContain('001 ['); + expect(output).not.toContain('002 ['); + + component.markInputComplete(); + output = renderText(component); + expect(output).toContain('001 Queued…'); + expect(output).toContain('002 Queued…'); + expect(output).not.toContain('001 ['); + }); + + it('maps subagents by structured swarm indexes when descriptions include issue references', () => { + const component = createComponent({ + description: 'Fix #123', + }); + + component.updateArgs({ + description: 'Fix #123', + items: ['src/a.ts', 'src/b.ts'], + }); + component.registerSubagent({ + agentId: 'agent-2', + description: 'Fix #123 #2 (coder)', + swarmIndex: 2, + }); + component.markStarted('agent-2'); + + const output = renderText(component); + + expect(output).toContain('001 src/a.ts'); + expect(output).toContain('002 ['); + expect(output).not.toContain('123 ['); + }); + + it('extracts description and item list from AgentSwarm args', () => { + const args = { + description: 'Review changed files', + items: ['src/a.ts', 123], + }; + + expect(agentSwarmDescriptionFromArgs(args)).toBe('Review changed files'); + expect(agentSwarmItemsFromArgs(args)).toEqual(['src/a.ts', '123']); + }); +}); + +describe('AgentSwarmProgressComponent render caching', () => { + function createTerminalComponent(): AgentSwarmProgressComponent { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = createComponent(); + registerSubagents(component, 2); + startSubagents(component, 2); + vi.setSystemTime(1_000); + component.markCompleted('agent-1', 'done one'); + component.markCompleted('agent-2', 'done two'); + component.markToolCallEnded(); + // Past the 360ms completion fill window, so the panel is fully static. + vi.setSystemTime(2_000); + return component; + } + + it('returns the identical line array while a terminal swarm is unchanged', () => { + const component = createTerminalComponent(); + + const first = component.render(100); + + expect(component.render(100)).toBe(first); + }); + + it('re-renders when a member changes', () => { + const component = createTerminalComponent(); + const before = component.render(100); + + component.applyResult('updated output'); + const after = component.render(100); + + expect(after).not.toBe(before); + expect(renderText(component)).toContain('updated output'); + }); + + it('re-renders when the width changes', () => { + const component = createTerminalComponent(); + const wide = component.render(100); + + expect(component.render(80)).not.toBe(wide); + }); + + it('re-renders when the available grid height changes', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + let gridHeight: number | undefined = 10; + const component = createComponent({ availableGridHeight: () => gridHeight }); + registerSubagents(component, 1); + startSubagents(component, 1); + vi.setSystemTime(1_000); + component.markCompleted('agent-1', 'done'); + component.markToolCallEnded(); + vi.setSystemTime(2_000); + const before = component.render(100); + + gridHeight = 1; + + expect(component.render(100)).not.toBe(before); + }); + + it('re-renders after invalidate() even when nothing else changed', () => { + const component = createTerminalComponent(); + const before = component.render(100); + + component.invalidate(); + const after = component.render(100); + + expect(after).not.toBe(before); + expect(after.map(strip)).toEqual(before.map(strip)); + }); + + it('bypasses both component and cell caches when the render cache is disabled', () => { + const component = createTerminalComponent(); + const before = component.render(100); + + setRenderCacheEnabled(false); + try { + const after = component.render(100); + expect(after).not.toBe(before); + expect(after.map(strip)).toEqual(before.map(strip)); + const third = component.render(100); + expect(third).not.toBe(after); + expect(third.map(strip)).toEqual(after.map(strip)); + } finally { + setRenderCacheEnabled(true); + } + }); + + it('repaints member cells from the active palette when the theme changes', () => { + const previousLevel = chalk.level; + chalk.level = 3; + try { + const component = createTerminalComponent(); + const cellLineOf = (): string => { + const line = component.render(100).find((l) => strip(l).includes('001 [')); + if (line === undefined) throw new Error('cell line not found'); + return line; + }; + const before = cellLineOf(); + + currentTheme.setPalette(lightColors); + const after = cellLineOf(); + + expect(strip(after)).toBe(strip(before)); + expect(after).not.toBe(before); + } finally { + chalk.level = previousLevel; + } + }); + + it('does not cache while a member is still running', () => { + vi.useFakeTimers(); + const component = createComponent(); + registerSubagents(component, 1); + startSubagents(component, 1); + + expect(component.render(100)).not.toBe(component.render(100)); + }); + + it('does not cache during the completion fill window', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = createComponent(); + registerSubagents(component, 1); + startSubagents(component, 1); + vi.setSystemTime(1_000); + component.markCompleted('agent-1', 'done'); + component.markToolCallEnded(); + + expect(component.render(100)).not.toBe(component.render(100)); + + vi.setSystemTime(2_000); + const settled = component.render(100); + expect(component.render(100)).toBe(settled); + }); +}); + +describe('AgentSwarmProgressComponent terminal state memory', () => { + const WIDE_RENDER_WIDTH = 500; + + function rawCellLine(component: AgentSwarmProgressComponent): string { + const line = component + .render(WIDE_RENDER_WIDTH) + .find((candidate) => strip(candidate).includes('001 [')); + if (line === undefined) throw new Error('cell line not found'); + return line; + } + + function visibleCellText(component: AgentSwarmProgressComponent): string { + return strip(rawCellLine(component)).trimEnd(); + } + + it('bounds completed output text to a few hundred characters', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted('agent-1', `Reviewed imports. ${'x'.repeat(100_000)}`); + + const cellText = visibleCellText(component); + expect(cellText.length).toBeLessThanOrEqual(500); + expect(cellText).not.toContain('…'); + expect(cellText).toContain('✓ Reviewed imports.'); + }); + + it('bounds failure text to a few hundred characters', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markFailed('agent-1', `Provider request failed ${'y'.repeat(100_000)}`); + + const cellText = visibleCellText(component); + expect(cellText.length).toBeLessThanOrEqual(500); + expect(cellText).not.toContain('…'); + expect(cellText).toContain('✗ Provider request failed'); + }); + + it('uses the latest assistant line as the completed label when no output is given', () => { + const component = createComponent(); + registerSubagents(component, 1); + component.appendModelDelta({ + agentId: 'agent-1', + delta: 'Reviewing src/a.ts\nImports look stable', + }); + + component.markCompleted('agent-1'); + + expect(renderText(component)).toContain('✓ Imports look stable'); + }); + + it('bounds the cancelled label of a running member to a few hundred characters', () => { + const component = createComponent(); + registerSubagents(component, 1); + startSubagents(component, 1); + component.appendModelDelta({ agentId: 'agent-1', delta: 'x'.repeat(5_000) }); + + component.markCancelled('agent-1'); + + const cellText = visibleCellText(component); + expect(cellText.length).toBeLessThanOrEqual(500); + expect(cellText).not.toContain('…'); + expect(cellText).toContain(`⊘ ${'x'.repeat(20)}`); + }); + + it('re-renders a member cell with its terminal label after completing', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = createComponent(); + registerSubagents(component, 1); + startSubagents(component, 1); + component.appendModelDelta({ agentId: 'agent-1', delta: 'working on it' }); + expect(renderText(component)).toContain('working on it'); + + vi.setSystemTime(1_000); + component.markCompleted('agent-1', 'done'); + + const output = renderText(component); + expect(output).toContain('✓ done'); + expect(output).not.toContain('working on it'); + }); + + it('bounds the retained label code units when the output carries ANSI sequences', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted('agent-1', `ok${'\u001B[31m'.repeat(10_000)}`); + + const line = rawCellLine(component); + expect(line.length).toBeLessThan(3_000); + expect(strip(line)).toContain('ok'); + expect(line).toContain('\u001B[0m'); + const escapeCount = line.match(/\u001B/g)?.length ?? 0; + const completeSequenceCount = line.match(/\u001B\[[0-9;]*m/g)?.length ?? 0; + expect(escapeCount).toBe(completeSequenceCount); + }); + + it('bounds the retained label code units for a long zero-width grapheme', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted('agent-1', `x${'\u0301'.repeat(50_000)}`); + + const line = rawCellLine(component); + expect(line.length).toBeLessThan(3_000); + expect(strip(line)).toContain('✓ x'); + }); + + it('does not split a surrogate pair at the retained label storage limit', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted( + 'agent-1', + `x${'\u0301'.repeat(1_998)}\u{1F600}${'\u0301'.repeat(5_000)}`, + ); + + const line = rawCellLine(component); + expect(line.length).toBeLessThan(3_000); + expect(line).not.toMatch(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])/); + }); + + it('closes an OSC 8 hyperlink that the storage cap slices through', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted( + 'agent-1', + `\u001B]8;;https://example.com\u0007x${'\u0301'.repeat(5_000)}\u001B]8;;\u0007`, + ); + + const line = rawCellLine(component); + expect(line).toContain('\u001B]8;;https://example.com\u0007'); + expect(line).toContain('\u001B]8;;\u0007'); + }); + + it('resets SGR styling that the storage cap slices through', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted( + 'agent-1', + `\u001B[1m\u001B[31mx${'\u0301'.repeat(5_000)}\u001B[0m`, + ); + + expect(rawCellLine(component)).toContain('\u001B[0m'); + }); + + it('appends the SGR reset after the OSC 8 close when both are sliced', () => { + const component = createComponent(); + registerSubagents(component, 1); + + component.markCompleted( + 'agent-1', + `\u001B]8;;https://example.com\u0007\u001B[1mx${'\u0301'.repeat(5_000)}\u001B]8;;\u0007\u001B[0m`, + ); + + expect(rawCellLine(component)).toContain('\u001B]8;;\u0007\u001B[0m'); + }); + + it('does not split a ZWJ grapheme cluster at the retained label storage limit', () => { + const component = createComponent(); + registerSubagents(component, 1); + + const family = '\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}'; + component.markCompleted( + 'agent-1', + `x${'\u0301'.repeat(1_996)}${family}${'\u0301'.repeat(5_000)}`, + ); + + const line = rawCellLine(component); + expect(line.length).toBeLessThan(3_000); + expect(line).not.toContain('\u200D'); + }); +}); + +describe('AgentSwarmProgressComponent frame timer', () => { + it('batches model deltas onto the frame timer instead of rendering per delta', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const component = createComponent({ requestRender }); + registerSubagents(component, 1); + startSubagents(component, 1); + requestRender.mockClear(); + + component.appendModelDelta({ agentId: 'agent-1', delta: 'line one' }); + component.appendModelDelta({ agentId: 'agent-1', delta: 'line two' }); + component.recordToolCall({ agentId: 'agent-1', toolCallId: 'call-1' }); + + expect(requestRender).not.toHaveBeenCalled(); + + vi.advanceTimersByTime(80); + expect(requestRender).toHaveBeenCalledTimes(1); + }); + + it('starts the frame timer when a delta arrives for a queued member', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const component = createComponent({ requestRender }); + registerSubagents(component, 1); + requestRender.mockClear(); + + component.appendModelDelta({ agentId: 'agent-1', delta: 'hello' }); + + expect(requestRender).not.toHaveBeenCalled(); + vi.advanceTimersByTime(80); + expect(requestRender).toHaveBeenCalledTimes(1); + }); + + it('keeps the frame timer alive while members are running', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const component = createComponent({ requestRender }); + registerSubagents(component, 1); + startSubagents(component, 1); + requestRender.mockClear(); + + vi.advanceTimersByTime(80 * 3); + + expect(requestRender.mock.calls.length).toBeGreaterThanOrEqual(3); + }); + + it('stops the frame timer after the completion fill animation ends', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const component = createComponent({ requestRender }); + registerSubagents(component, 1); + startSubagents(component, 1); + requestRender.mockClear(); + + component.markCompleted('agent-1', 'done'); + vi.advanceTimersByTime(80 * 10); + const callsAfterSettled = requestRender.mock.calls.length; + expect(callsAfterSettled).toBeGreaterThan(0); + + vi.advanceTimersByTime(80 * 5); + expect(requestRender.mock.calls.length).toBe(callsAfterSettled); + }); + + it('stops the frame timer when the tool call ends with an unparsable result', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const component = createComponent({ requestRender }); + registerSubagents(component, 1); + startSubagents(component, 1); + requestRender.mockClear(); + + component.markToolCallEnded(); + expect(component.applyResult('Done')).toBe(false); + vi.advanceTimersByTime(80 * 10); + const callsAfterSettled = requestRender.mock.calls.length; + + vi.advanceTimersByTime(80 * 5); + expect(requestRender.mock.calls.length).toBe(callsAfterSettled); + }); +}); + +describe('AgentSwarmProgressEstimator', () => { + it('counts a started subagent as one progress tick before tool calls arrive', () => { + const estimator = new AgentSwarmProgressEstimator(); + + estimator.markStarted('001', 0); + const estimate = estimator.estimate({ + memberKey: '001', + phase: 'running', + capacityTicks: 56, + nowMs: 1_000, + }); + + expect(estimate.rawTicks).toBe(1); + expect(estimate.displayTicks).toBe(1); + }); + + it('keeps raw tool-call ticks without completed samples and deduplicates calls', () => { + const estimator = new AgentSwarmProgressEstimator(); + + estimator.markStarted('001', 0); + expect( + estimator.recordToolCall({ memberKey: '001', toolCallId: 'read', nowMs: 1_000 }), + ).toEqual({ accepted: true, rawTicks: 2 }); + expect( + estimator.recordToolCall({ memberKey: '001', toolCallId: 'read', nowMs: 2_000 }), + ).toEqual({ accepted: false, rawTicks: 2 }); + + const estimate = estimator.estimate({ + memberKey: '001', + phase: 'running', + capacityTicks: 56, + nowMs: 3_000, + }); + + expect(estimate.rawTicks).toBe(2); + expect(estimate.displayTicks).toBe(2); + expect(estimate.estimatedTotalToolCalls).toBeUndefined(); + expect(estimate.boosted).toBe(false); + }); + + it('does not catch up progress using queued wait before start', () => { + const estimator = new AgentSwarmProgressEstimator({ + catchupTimeMs: 1_000, + maxCatchupTicksPerSecond: 100, + }); + + estimator.markStarted('001', 0); + for (let index = 0; index < 10; index += 1) { + estimator.recordToolCall({ + memberKey: '001', + toolCallId: `done-${index}`, + nowMs: 1_000 + index * 1_000, + }); + } + estimator.markCompleted('001', 40_000); + + estimator.ensureMember('002', 0); + estimator.estimate({ + memberKey: '002', + phase: 'queued', + capacityTicks: 56, + nowMs: 0, + }); + estimator.markStarted('002', 60_000); + + const estimate = estimator.estimate({ + memberKey: '002', + phase: 'running', + capacityTicks: 56, + nowMs: 60_000, + }); + + expect(estimate.rawTicks).toBe(1); + expect(estimate.displayTicks).toBe(1); + expect(estimate.targetTicks).toBeGreaterThan(1); + expect(estimate.boosted).toBe(false); + }); + + it('smoothly catches up toward completed-agent estimates without jumping to them', () => { + const estimator = new AgentSwarmProgressEstimator({ + catchupTimeMs: 1_000, + maxCatchupTicksPerSecond: 100, + }); + + estimator.markStarted('001', 0); + for (let index = 0; index < 10; index += 1) { + estimator.recordToolCall({ + memberKey: '001', + toolCallId: `done-${index}`, + nowMs: 1_000 + index * 1_000, + }); + } + estimator.markCompleted('001', 40_000); + + estimator.markStarted('002', 0); + for (let index = 0; index < 3; index += 1) { + estimator.recordToolCall({ + memberKey: '002', + toolCallId: `running-${index}`, + nowMs: 5_000 + index * 5_000, + }); + } + + const first = estimator.estimate({ + memberKey: '002', + phase: 'running', + capacityTicks: 56, + nowMs: 20_000, + }); + + expect(first.rawTicks).toBe(4); + expect(first.displayTicks).toBe(4); + expect(first.estimatedTotalToolCalls).toBeGreaterThan(4); + expect(first.targetTicks).toBeGreaterThan(4); + expect(estimator.hasPendingCatchup()).toBe(true); + + const second = estimator.estimate({ + memberKey: '002', + phase: 'running', + capacityTicks: 56, + nowMs: 21_000, + }); + + expect(second.displayTicks).toBeGreaterThan(4); + expect(second.displayTicks).toBeLessThan(second.targetTicks ?? 0); + expect(second.boosted).toBe(true); + }); + + it('rebuilds the completed-sample prior as new members complete', () => { + const estimator = new AgentSwarmProgressEstimator(); + + estimator.markStarted('001', 0); + for (let index = 0; index < 10; index += 1) { + estimator.recordToolCall({ + memberKey: '001', + toolCallId: `done-${index}`, + nowMs: 1_000 + index * 1_000, + }); + } + estimator.markCompleted('001', 40_000); + + estimator.markStarted('002', 0); + for (let index = 0; index < 3; index += 1) { + estimator.recordToolCall({ + memberKey: '002', + toolCallId: `running-${index}`, + nowMs: 5_000 + index * 5_000, + }); + } + const before = estimator.estimate({ + memberKey: '002', + phase: 'running', + capacityTicks: 56, + nowMs: 20_000, + }); + + estimator.markCompleted('002', 25_000); + estimator.markStarted('003', 0); + for (let index = 0; index < 3; index += 1) { + estimator.recordToolCall({ + memberKey: '003', + toolCallId: `running-${index}`, + nowMs: 5_000 + index * 5_000, + }); + } + const after = estimator.estimate({ + memberKey: '003', + phase: 'running', + capacityTicks: 56, + nowMs: 20_000, + }); + + expect(before.estimatedTotalToolCalls).toBeDefined(); + expect(after.estimatedTotalToolCalls).toBeDefined(); + expect(after.estimatedTotalToolCalls).not.toBe(before.estimatedTotalToolCalls); + + const repeat = estimator.estimate({ + memberKey: '003', + phase: 'running', + capacityTicks: 56, + nowMs: 20_000, + }); + expect(repeat.estimatedTotalToolCalls).toBe(after.estimatedTotalToolCalls); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/assistant-message.test.ts b/apps/kimi-code/test/tui/components/messages/assistant-message.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb678c49240db7df537a95f8def55a5c3f6d73f8 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/assistant-message.test.ts @@ -0,0 +1,174 @@ +import { Markdown, visibleWidth } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; +import * as cliHighlight from 'cli-highlight'; +import { describe, expect, it, vi } from 'vitest'; + +import { AssistantMessageComponent } from '#/tui/components/messages/assistant-message'; +import { STATUS_BULLET } from '#/tui/constant/symbols'; +import { createMarkdownTheme } from '#/tui/theme/pi-tui-theme'; +import { currentTheme } from '#/tui/theme/theme'; +import { setMarkdownRenderLatex } from '#/tui/utils/markdown-options'; + +import { captureProcessWrite } from '../../../helpers/process'; + +vi.mock('cli-highlight', async () => { + const actual = await vi.importActual('cli-highlight'); + return { + ...actual, + highlight: vi.fn(actual.highlight), + }; +}); + +function strip(text: string): string { + return text + .replaceAll(/\u001B\[[0-9;]*m/g, '') + .replaceAll(/\u001B\]133;[ABC]\u0007/g, ''); +} + +describe('AssistantMessageComponent', () => { + it('defines the shared status bullet as a stable non-emoji glyph', () => { + expect(STATUS_BULLET).toBe('● '); + expect(visibleWidth(STATUS_BULLET)).toBe(2); + }); + + it('uses the stable status bullet without stealing content width', () => { + const component = new AssistantMessageComponent(); + + component.updateContent('abcdef'); + + const lines = component.render(8).map(strip); + expect(lines).toEqual(['', `${STATUS_BULLET}abcdef`]); + expect(visibleWidth(lines[1] ?? '')).toBe(8); + }); + + it('keeps assistant lines within very narrow widths', () => { + const component = new AssistantMessageComponent(); + component.updateContent('abcdef'); + + for (const width of [1, 2, 4, 10, 39]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('renders unknown markdown fence languages as plain text without stderr noise', () => { + const stderr = captureProcessWrite('stderr'); + try { + const theme = createMarkdownTheme(); + expect(theme.highlightCode?.('hello\nworld', 'abcxyz')).toEqual(['hello', 'world']); + expect(stderr.text()).not.toContain('Could not find the language'); + } finally { + stderr.restore(); + } + }); + + it('preserves literal hook result XML in normal assistant text', () => { + const component = new AssistantMessageComponent(); + + component.updateContent('\n{}\n'); + + const text = component.render(80).map(strip).join('\n'); + expect(text).toContain(''); + expect(text).toContain('{}'); + expect(text).toContain(''); + expect(text).not.toContain('UserPromptSubmit hook'); + }); + + it('reuses the same Markdown child across streaming text updates', () => { + const component = new AssistantMessageComponent(); + + component.updateContent('hello'); + const first = (component as any).contentContainer.children[0]; + expect(first).toBeInstanceOf(Markdown); + + component.updateContent('hello world'); + const second = (component as any).contentContainer.children[0]; + + expect(second).toBe(first); + expect(strip(component.render(80).join('\n'))).toContain('hello world'); + }); + + it('does not recreate the Markdown child when the text is unchanged', () => { + const component = new AssistantMessageComponent(); + + component.updateContent('hello'); + const first = (component as any).contentContainer.children[0]; + expect(first).toBeInstanceOf(Markdown); + + component.updateContent('hello'); + const second = (component as any).contentContainer.children[0]; + + expect(second).toBe(first); + }); + + it('rebuilds the Markdown child when transient changes so final render can highlight code', () => { + const component = new AssistantMessageComponent(); + const code = '```ts\nconst x = 1\n```'; + + component.updateContent(code, { transient: true }); + const streaming = (component as any).contentContainer.children[0]; + expect(streaming).toBeInstanceOf(Markdown); + + component.updateContent(code, { transient: false }); + const finalized = (component as any).contentContainer.children[0]; + expect(finalized).toBeInstanceOf(Markdown); + + expect(finalized).not.toBe(streaming); + }); + + it('skips synchronous syntax highlighting in transient markdown themes', () => { + const highlightSpy = vi.mocked(cliHighlight.highlight); + highlightSpy.mockClear(); + const streamingTheme = createMarkdownTheme({ transient: true }); + const finalTheme = createMarkdownTheme(); + const code = 'const x = 1'; + + expect(streamingTheme.highlightCode?.(code, 'typescript')).toEqual([code]); + expect(highlightSpy).not.toHaveBeenCalled(); + + finalTheme.highlightCode?.(code, 'typescript'); + expect(highlightSpy).toHaveBeenCalled(); + }); + + it('highlights diff fences with the palette diff colors', () => { + const previousLevel = chalk.level; + chalk.level = 3; + try { + const theme = createMarkdownTheme(); + expect(theme.highlightCode?.('- removed\n+ added', 'diff')).toEqual([ + chalk.hex(currentTheme.color('diffRemoved'))('- removed'), + chalk.hex(currentTheme.color('diffAdded'))('+ added'), + ]); + } finally { + chalk.level = previousLevel; + } + }); + + it('marks the rendered zone with OSC 133 markers, once across cache hits', () => { + const component = new AssistantMessageComponent(); + component.updateContent('hello'); + + const lines = component.render(80); + expect(lines[0]).toMatch(/^\u001B\]133;A\u0007/); + expect(lines.at(-1)).toMatch(/^\u001B\]133;B\u0007\u001B\]133;C\u0007/); + + const cached = component.render(80); + expect(cached[0]).toBe(lines[0]); + }); + + it('renders LaTeX math by default and keeps raw source when disabled', () => { + const component = new AssistantMessageComponent(); + try { + setMarkdownRenderLatex(true); + component.updateContent('能量公式 $E = mc^2$'); + expect(strip(component.render(80).join('\n'))).toContain('E = mc²'); + + setMarkdownRenderLatex(false); + component.invalidate(); + expect(strip(component.render(80).join('\n'))).toContain('$E = mc^2$'); + } finally { + setMarkdownRenderLatex(true); + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/background-agent-status.test.ts b/apps/kimi-code/test/tui/components/messages/background-agent-status.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e8f395ec87976af33562011bf8a205b97e07a12a --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/background-agent-status.test.ts @@ -0,0 +1,61 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { BackgroundAgentStatusComponent } from '#/tui/components/messages/background-agent-status'; +import { STATUS_BULLET } from '#/tui/constant/symbols'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('BackgroundAgentStatusComponent', () => { + it('renders started/completed with the shared bullet and failed with a red x marker', () => { + const started = new BackgroundAgentStatusComponent({ + phase: 'started', + headline: 'explore agent started in background', + detail: 'Explore project structure', + }); + const completed = new BackgroundAgentStatusComponent({ + phase: 'completed', + headline: 'explore agent completed in background', + detail: 'Explore project structure', + }); + const failed = new BackgroundAgentStatusComponent({ + phase: 'failed', + headline: 'explore agent failed in background', + detail: 'Explore project structure · boom', + }); + + const startedLines = started.render(120).map((line) => strip(line).trimEnd()); + const completedLines = completed.render(120).map((line) => strip(line).trimEnd()); + const failedLines = failed.render(120).map((line) => strip(line).trimEnd()); + + expect(startedLines[0]).toBe(''); + expect(completedLines[0]).toBe(''); + expect(failedLines[0]).toBe(''); + + expect(startedLines[1]).toBe( + `${STATUS_BULLET}explore agent started in background (Explore project structure)`, + ); + expect(completedLines[1]).toBe( + `${STATUS_BULLET}explore agent completed in background (Explore project structure)`, + ); + expect(failedLines[1]).toBe( + '✗ explore agent failed in background (Explore project structure · boom)', + ); + }); + + it('keeps status lines within very narrow widths', () => { + const component = new BackgroundAgentStatusComponent({ + phase: 'started', + headline: 'explore agent started in background', + detail: 'Explore project structure', + }); + + for (const width of [1, 2, 4, 10, 39]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/goal-markers.test.ts b/apps/kimi-code/test/tui/components/messages/goal-markers.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f098cc931935dfe99e43204d507d191599208eb3 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/goal-markers.test.ts @@ -0,0 +1,122 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { SwarmModeMarkerComponent } from '#/tui/components/messages/swarm-markers'; +import { buildGoalMarker, GoalMarkerComponent } from '#/tui/components/messages/goal-markers'; +import type { GoalChange } from '@moonshot-ai/kimi-code-sdk'; + +const ANSI_SGR = /\[[0-9;]*m/g; +function strip(lines: string[]): string { + return lines.join('\n').replaceAll(ANSI_SGR, ''); +} + +describe('buildGoalMarker', () => { + it('builds lifecycle markers for paused / resumed / blocked', () => { + const paused = buildGoalMarker({ kind: 'lifecycle', status: 'paused' } as GoalChange, false); + const resumed = buildGoalMarker({ kind: 'lifecycle', status: 'active' } as GoalChange, false); + const blocked = buildGoalMarker({ kind: 'lifecycle', status: 'blocked' } as GoalChange, false); + expect(strip(paused!.render(80))).toContain('Goal paused'); + expect(strip(resumed!.render(80))).toContain('Goal resumed'); + expect(strip(blocked!.render(80))).toContain('Goal blocked'); + }); + + it('renders user interruption pause and user resume as prominent markers', () => { + const paused = buildGoalMarker( + { kind: 'lifecycle', status: 'paused', reason: 'Paused after interruption' } as GoalChange, + false, + 'runtime', + ); + const resumed = buildGoalMarker( + { kind: 'lifecycle', status: 'active' } as GoalChange, + false, + 'user', + ); + + expect(strip(paused!.render(80))).toBe("\n● Goal paused due to user's interruption"); + expect(strip(resumed!.render(80))).toBe('\n● Goal resumed by the user.'); + expect(strip([...paused!.render(80), ...resumed!.render(80)])).toBe( + "\n● Goal paused due to user's interruption\n\n● Goal resumed by the user.", + ); + }); + + it('does not repeat paused for runtime pause reasons', () => { + const marker = buildGoalMarker( + { kind: 'lifecycle', status: 'paused', reason: 'Paused after runtime error: socket hang up' } as GoalChange, + false, + 'runtime', + ); + + expect(strip(marker!.render(80))).toBe('\n● Goal paused after runtime error: socket hang up'); + }); + + it('keeps long provider pause markers within the terminal width', () => { + const reason = + 'Paused after provider API error: 400 {"error":{"message":"request id: 456043b9-6491-11f1-9425-2221bb1af97c, \\"thinking.enabled\\" is not supported for this model. Use \\"thinking.adaptive\\" and \\"output_config.effort\\" to control thinking behavior.","type":"invalid_request_error"}}'; + const marker = buildGoalMarker( + { kind: 'lifecycle', status: 'paused', reason } as GoalChange, + false, + 'runtime', + ); + + const width = 80; + expect(strip(marker!.render(width))).toContain('Goal paused after provider API error'); + for (const line of marker!.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + }); + + it('attributes model pause and resume markers to the agent', () => { + const paused = buildGoalMarker( + { kind: 'lifecycle', status: 'paused' } as GoalChange, + false, + 'model', + ); + const resumed = buildGoalMarker( + { kind: 'lifecycle', status: 'active' } as GoalChange, + false, + 'model', + ); + + expect(strip(paused!.render(80))).toBe('\n● Goal paused by the agent.'); + expect(strip(resumed!.render(80))).toBe('\n● Goal resumed by the agent.'); + }); + + it('returns null for a completion change (it posts its own message)', () => { + expect( + buildGoalMarker({ kind: 'completion', status: 'complete' } as GoalChange, false), + ).toBeNull(); + }); +}); + +describe('GoalMarkerComponent', () => { + it('hides the reason until expanded, with a ctrl+o hint', () => { + const marker = new GoalMarkerComponent('Goal: no progress', 'still spinning', 'warning'); + const collapsed = strip(marker.render(80)); + expect(collapsed).toContain('Goal: no progress'); + expect(collapsed).toContain('(ctrl+o)'); + expect(collapsed).not.toContain('still spinning'); + + marker.setExpanded(true); + const expanded = strip(marker.render(80)); + expect(expanded).toContain('still spinning'); + expect(expanded).not.toContain('(ctrl+o)'); + }); + + it('renders a single line when there is no reason', () => { + const marker = new GoalMarkerComponent('Goal paused', undefined, 'textDim'); + expect(marker.render(80)).toHaveLength(1); + expect(strip(marker.render(80))).not.toContain('(ctrl+o)'); + }); +}); + +describe('SwarmModeMarkerComponent', () => { + it('keeps marker lines within very narrow widths', () => { + const marker = new SwarmModeMarkerComponent('active'); + + for (const width of [1, 2, 10, 39]) { + for (const line of marker.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/goal-panel.test.ts b/apps/kimi-code/test/tui/components/messages/goal-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..43e1aa8d11b4e4b21952597a42c9d653bee6ef23 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/goal-panel.test.ts @@ -0,0 +1,194 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +import { + buildGoalReportLines, + GoalCompletionMessageComponent, + GoalSetMessageComponent, + GoalStatusMessageComponent, + UpcomingGoalAddedMessageComponent, + goalPanelTitle, +} from '#/tui/components/messages/goal-panel'; +import { STATUS_BULLET } from '#/tui/constant/symbols'; +import { darkColors } from '#/tui/theme/colors'; +import type { GoalSnapshot } from '@moonshot-ai/kimi-code-sdk'; + +const previousChalkLevel = chalk.level; +beforeAll(() => { + chalk.level = 3; +}); +afterAll(() => { + chalk.level = previousChalkLevel; +}); + +const ANSI_SGR = /\u001B\[[0-9;]*m/g; +function strip(lines: string[]): string { + return lines.join('\n').replaceAll(ANSI_SGR, ''); +} + +function goal(overrides: Partial = {}): GoalSnapshot { + return { + goalId: 'g1', + objective: 'Ship the goal status box', + status: 'active', + turnsUsed: 7, + tokensUsed: 128_400, + wallClockMs: 252_000, // 4m12s + budget: { + turnBudget: null, + tokenBudget: null, + wallClockBudgetMs: null, + }, + ...overrides, + } as GoalSnapshot; +} + +function lines(g: GoalSnapshot): string { + return strip(buildGoalReportLines(g)); +} + +describe('buildGoalReportLines', () => { + it('renders the objective as a blockquote and key counters for an active goal', () => { + const out = lines(goal()); + expect(out).toContain('▌ Ship the goal status box'); + expect(out).toContain('Running'); + expect(out).toContain('4m 12s'); + expect(out).toContain('Turns'); + expect(out).toContain('125k'); // formatTokenCount + }); + + it('shows a no-stop-condition note for an unbounded active goal', () => { + expect(lines(goal())).toContain('No stop condition — runs until evaluated complete.'); + }); + + it('shows a Stop row with progress when a turn budget is set', () => { + const out = lines(goal({ budget: { turnBudget: 20, tokenBudget: null, wallClockBudgetMs: null } } as Partial)); + expect(out).toContain('Stop'); + expect(out).toContain('after 20 turns (7/20)'); + expect(out).not.toContain('No stop condition'); + }); + + it('includes the completion criterion when present', () => { + const out = lines(goal({ completionCriterion: 'tests pass' })); + expect(out).toContain('✓ tests pass'); + }); + + it('renders a terminal goal with a Status row and no Stop row', () => { + const out = lines(goal({ status: 'complete', terminalReason: 'all done' })); + expect(out).toContain('Status'); + expect(out).toContain('complete — all done'); + expect(out).not.toContain('No stop condition'); + expect(out).not.toMatch(/^Stop/m); + }); + + it('shows the reason for a paused goal when one exists', () => { + const out = lines(goal({ status: 'paused', terminalReason: 'Paused after provider rate limit' })); + expect(out).toContain('Status'); + expect(out).toContain('paused — Paused after provider rate limit'); + }); + + it('titles the box with the status', () => { + expect(goalPanelTitle(goal())).toBe(' Goal · active '); + expect(goalPanelTitle(goal({ status: 'complete' }))).toBe(' Goal · complete '); + }); + + it('truncates a very long objective with an ellipsis', () => { + const long = 'word '.repeat(200).trim(); + const out = lines(goal({ objective: long })); + expect(out).toContain('…'); + }); +}); + +describe('GoalSetMessageComponent', () => { + it('renders a marker-style lifecycle line without repeating the objective', () => { + const rendered = new GoalSetMessageComponent().render(60); + // Leading blank line separates it from the line above. + expect(rendered[0]).toBe(''); + expect(strip(rendered)).toBe('\n● Goal set'); + }); + + it('renders the marker and label in the primary accent', () => { + const rendered = new GoalSetMessageComponent().render(60); + + expect(rendered[1]).toBe( + chalk.hex(darkColors.primary).bold(STATUS_BULLET) + + chalk.hex(darkColors.primary).bold('Goal set'), + ); + }); + + it('keeps the lifecycle line within narrow widths', () => { + for (const width of [39, 20, 10, 4]) { + for (const line of new GoalSetMessageComponent().render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); + +describe('UpcomingGoalAddedMessageComponent', () => { + it('renders the upcoming-goal confirmation like the goal-set lifecycle line', () => { + const rendered = new UpcomingGoalAddedMessageComponent().render(80); + + expect(strip(rendered)).toBe( + '\n● Upcoming goal added. It will start after the current goal is complete.', + ); + expect(rendered[1]).toBe( + chalk.hex(darkColors.primary).bold(STATUS_BULLET) + + chalk.hex(darkColors.primary).bold( + 'Upcoming goal added. It will start after the current goal is complete.', + ), + ); + }); + + it('wraps the upcoming-goal confirmation within narrow widths', () => { + for (const width of [39, 20, 10, 4]) { + for (const line of new UpcomingGoalAddedMessageComponent().render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); + +describe('GoalStatusMessageComponent', () => { + it('adds a blank line before the status box', () => { + const rendered = new GoalStatusMessageComponent(goal()).render(80); + + expect(rendered[0]).toBe(''); + expect(strip([rendered[1]!])).toContain('╭ Goal · active '); + }); + + it('wraps objective blockquotes without clipping them at 80 columns', () => { + const rendered = new GoalStatusMessageComponent( + goal({ objective: 'word '.repeat(30).trim() }), + ).render(80); + + expect(strip(rendered)).not.toContain('...'); + }); + + it('keeps the status box within narrow widths', () => { + const rendered = new GoalStatusMessageComponent(goal({ objective: '管理飞书日历的技能描述 '.repeat(4).trim() })); + + for (const width of [39, 24, 20, 10]) { + for (const line of rendered.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); + +describe('GoalCompletionMessageComponent', () => { + it('renders the completion headline in green and keeps the stats line indented', () => { + const message = '✓ Goal complete.\nWorked 1 turn over 2m28s, using 766.9k tokens.'; + const rendered = new GoalCompletionMessageComponent(message).render(80); + + expect(rendered[0]).toBe(''); + expect(rendered[1]?.trimEnd()).toBe( + chalk.hex(darkColors.success).bold(STATUS_BULLET) + + chalk.hex(darkColors.success).bold('✓ Goal complete.'), + ); + expect(strip([rendered[2]!]).trimEnd()).toBe( + ' Worked 1 turn over 2m28s, using 766.9k tokens.', + ); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/mcp-status-panel.test.ts b/apps/kimi-code/test/tui/components/messages/mcp-status-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..63b716208e726200878f8ebd651e101b5f851ba5 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/mcp-status-panel.test.ts @@ -0,0 +1,52 @@ +import { describe, expect, it } from 'vitest'; + +import { buildMcpStatusReportLines } from '#/tui/components/messages/mcp-status-panel'; + +function strip(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +describe('buildMcpStatusReportLines', () => { + it('folds a multi-line server error onto one row so the panel box stays intact', () => { + const lines = buildMcpStatusReportLines({ + servers: [ + { + name: 'ghidra', + transport: 'stdio', + status: 'failed', + toolCount: 0, + error: + 'MCP error -32000: Connection closed\nstderr: usage: bridge_mcp_ghidra.py [-h] [--mcp-host MCP_HOST]', + }, + ], + }).map(strip); + + // The box renderer (UsagePanelComponent.render) treats each returned string + // as exactly one row, so an embedded newline would punch through the border. + for (const line of lines) { + expect(line).not.toContain('\n'); + } + + const errorLine = lines.find((line) => line.includes('error:')); + expect(errorLine).toContain( + 'MCP error -32000: Connection closed stderr: usage: bridge_mcp_ghidra.py [-h] [--mcp-host MCP_HOST]', + ); + }); + + it('trims and keeps a single-line error intact', () => { + const lines = buildMcpStatusReportLines({ + servers: [ + { + name: 'ida', + transport: 'http', + status: 'failed', + toolCount: 0, + error: ' fetch failed ', + }, + ], + }).map(strip); + + const errorLine = lines.find((line) => line.includes('error:')); + expect(errorLine).toContain('error: fetch failed'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/notice.test.ts b/apps/kimi-code/test/tui/components/messages/notice.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b915a2b3b7a608a5465f4336e979eda0294d1699 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/notice.test.ts @@ -0,0 +1,72 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { CronMessageComponent } from '#/tui/components/messages/cron-message'; +import { + NoticeMessageComponent, + StatusMessageComponent, +} from '#/tui/components/messages/status-message'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('NoticeComponent', () => { + it('renders top and bottom spacing around the notice copy', () => { + const component = new NoticeMessageComponent( + 'Plan mode: ON', + 'Plan will be created here: /tmp/plans/test-plan.md', + ); + + const lines = component.render(120).map((line) => strip(line)); + expect(lines[0]).toBe(''); + expect(lines[1]).toContain('Plan mode: ON'); + expect(lines[2]).toContain('Plan will be created here: /tmp/plans/test-plan.md'); + }); + + it('indents every line of a multi-line detail, not just the first', () => { + const component = new NoticeMessageComponent('Title', 'First line.\nSecond line.'); + + const lines = component.render(120).map((line) => strip(line)); + const titleColumn = lines.find((line) => line.includes('Title'))?.indexOf('Title'); + const firstColumn = lines.find((line) => line.includes('First line.'))?.indexOf('First line.'); + const secondColumn = lines.find((line) => line.includes('Second line.'))?.indexOf('Second line.'); + expect(titleColumn).toBeDefined(); + expect(firstColumn).toBe(titleColumn); + expect(secondColumn).toBe(titleColumn); + }); +}); + +describe('CronMessageComponent', () => { + it('keeps title, detail, and prompt within narrow widths', () => { + const component = new CronMessageComponent('Please investigate the reminder payload and report back.', { + cron: '*/15 * * * *', + jobId: 'job-with-a-very-long-identifier-for-width-testing', + recurring: true, + missedCount: 3, + stale: true, + }); + + for (const width of [39, 20, 10, 4]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); +}); + +describe('StatusMessageComponent', () => { + it('strips carriage returns so a CRLF line does not render blank', () => { + // A trailing `\r` (e.g. from a CRLF server error page) is zero-width for + // the line wrapper, so padding spaces appended after it would otherwise + // overwrite the visible content. The status component strips `\r`. + const component = new StatusMessageComponent('Error: boom\r\nmore\r', 'error'); + const text = component + .render(120) + .map((line) => strip(line)) + .join('\n'); + expect(text).toContain('Error: boom'); + expect(text).toContain('more'); + expect(text).not.toContain('\r'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/read-group.test.ts b/apps/kimi-code/test/tui/components/messages/read-group.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..be8ed06ebd28ffe7990fd95f46ea8f1d6dd7298f --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/read-group.test.ts @@ -0,0 +1,91 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { ReadGroupComponent } from '#/tui/components/messages/read-group'; +import { ToolCallComponent } from '#/tui/components/messages/tool-call'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function readCall(id: string, path: string, lines: number): ToolCallComponent { + return new ToolCallComponent( + { id, name: 'Read', args: { path } }, + { + tool_call_id: id, + output: Array.from({ length: lines }, (_, i) => `${String(i + 1)}\tline`).join('\n'), + is_error: false, + }, + ); +} + +function makeGroup(): ReadGroupComponent { + const group = new ReadGroupComponent(undefined); + group.attach('r1', readCall('r1', 'src/very/deeply/nested/directory/alpha-component.ts', 120)); + group.attach('r2', readCall('r2', 'src/very/deeply/nested/directory/beta-component.ts', 80)); + return group; +} + +function rows(group: ReadGroupComponent, width: number): string[] { + return group.render(width).map(strip).filter((line) => line.trim().length > 0); +} + +describe('ReadGroupComponent', () => { + it('collapses to a single header row and hides the per-file body until expanded', () => { + const group = makeGroup(); + + const collapsed = rows(group, 100); + expect(collapsed).toHaveLength(1); + expect(collapsed[0]).toContain('Read 2 files · 200 lines'); + expect(collapsed[0]).not.toContain('alpha-component.ts'); + + group.setExpanded(true); + const expanded = rows(group, 100); + expect(expanded[0]).toContain('Read 2 files · 200 lines'); + expect(expanded.join('\n')).toContain('alpha-component.ts · 120 lines'); + expect(expanded.join('\n')).toContain('beta-component.ts · 80 lines'); + + group.setExpanded(false); + expect(rows(group, 100)).toHaveLength(1); + }); + + it('truncates the header to the terminal width instead of wrapping', () => { + const group = makeGroup(); + for (const width of [16, 24]) { + const collapsed = rows(group, width); + expect(collapsed).toHaveLength(1); + expect(visibleWidth(collapsed[0]!)).toBeLessThanOrEqual(width); + expect(collapsed[0]).toContain('…'); + } + }); +}); + +describe('ReadGroupComponent hasHiddenContent', () => { + it('is true once a Read is attached, since the file bodies only render expanded', () => { + expect(new ReadGroupComponent(undefined).hasHiddenContent()).toBe(false); + expect(makeGroup().hasHiddenContent()).toBe(true); + }); +}); + +describe('ReadGroupComponent header on a narrow terminal', () => { + function failedRead(id: string, path: string): ToolCallComponent { + return new ToolCallComponent( + { id, name: 'Read', args: { path } }, + { tool_call_id: id, output: 'ENOENT: no such file or directory', is_error: true }, + ); + } + + it('keeps the failure count visible when the row is cut', () => { + const group = new ReadGroupComponent(undefined); + group.attach('ok', readCall('ok', 'src/very/deeply/nested/directory/alpha-component.ts', 120)); + group.attach('bad', failedRead('bad', 'src/very/deeply/nested/directory/missing.ts')); + + const wide = rows(group, 120); + expect(wide[0]).toContain('Read 2 files · 120 lines · 1 failed'); + + const narrow = rows(group, 26); + expect(visibleWidth(narrow[0]!)).toBeLessThanOrEqual(26); + expect(narrow[0]!.endsWith('1 failed')).toBe(true); + expect(narrow[0]).not.toContain('lines'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/shell-execution.test.ts b/apps/kimi-code/test/tui/components/messages/shell-execution.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c61c43573708a9c2a7564a47a9be58eb320524f3 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/shell-execution.test.ts @@ -0,0 +1,230 @@ +import { describe, expect, it } from 'vitest'; + +import { + ShellExecutionComponent, + shellExecutionResultRenderer, +} from '#/tui/components/messages/shell-execution'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('ShellExecutionComponent', () => { + it('renders shell command previews with prompt indentation', () => { + const component = new ShellExecutionComponent({ + command: 'printf hello\nprintf world', + showCommand: true, + }); + + const output = component.render(100).map((line) => strip(line).trimEnd()); + + expect(output).toContain(' $ printf hello'); + expect(output).toContain(' printf world'); + }); + + it('keeps collapsed shell output short and expands on demand', () => { + const collapsed = new ShellExecutionComponent({ + result: { + tool_call_id: 'call_shell', + output: ['line1', 'line2', 'line3', 'line4', 'line5'].join('\n'), + is_error: false, + }, + }); + + const collapsedOutput = collapsed.render(100).map(strip).join('\n'); + expect(collapsedOutput).toContain('line1'); + expect(collapsedOutput).toContain('line3'); + expect(collapsedOutput).not.toContain('line4'); + expect(collapsedOutput).toContain('… (2 more lines, ctrl+o to expand)'); + + const expanded = new ShellExecutionComponent({ + result: { + tool_call_id: 'call_shell', + output: ['line1', 'line2', 'line3', 'line4', 'line5'].join('\n'), + is_error: false, + }, + expanded: true, + }); + + const expandedOutput = expanded.render(100).map(strip).join('\n'); + expect(expandedOutput).toContain('line4'); + expect(expandedOutput).toContain('line5'); + expect(expandedOutput).not.toContain('ctrl+o to expand'); + }); + + it('renders unbounded command preview when previewLines is undefined', () => { + const cmd = Array.from({ length: 20 }, (_, i) => `step${String(i + 1)}`).join('\n'); + const component = new ShellExecutionComponent({ + command: cmd, + showCommand: true, + commandPreviewLines: undefined, + }); + + const output = component.render(100).map(strip).join('\n'); + expect(output).toContain('$ step1'); + expect(output).toContain('step20'); + }); + + it('does not count trailing empty lines toward the preview cap', () => { + const component = new ShellExecutionComponent({ + result: { + tool_call_id: 'call_shell', + output: 'hello\n\n\n', // 1 content line + 2 trailing empty lines + is_error: false, + }, + }); + + const output = component.render(100).map(strip).join('\n'); + expect(output).toContain('hello'); + expect(output).not.toContain('… (2 more lines'); + }); + + it('preserves internal empty lines while trimming only trailing ones', () => { + const component = new ShellExecutionComponent({ + result: { + tool_call_id: 'call_shell', + output: 'a\n\nb\n\n\n', // 1 internal empty line + 2 trailing empty lines + is_error: false, + }, + }); + + const output = component.render(100).map(strip).join('\n'); + expect(output).toContain('a'); + expect(output).toContain('b'); + expect(output).not.toContain('… (2 more lines'); + }); + + it('truncates long single-line output by wrapped visual lines', () => { + const component = new ShellExecutionComponent({ + result: { + tool_call_id: 'call_shell', + output: 'x'.repeat(500), + is_error: false, + }, + }); + + const out = strip(component.render(20).join('\n')); + expect(out).toContain('x'); + expect(out).not.toContain('x'.repeat(500)); + expect(out).toContain('… ('); + }); + + describe('shellExecutionResultRenderer', () => { + const longCmd = `echo ${'a'.repeat(200)}\necho done`; + + it('renders only the last output line as the outcome row while collapsed', () => { + const components = shellExecutionResultRenderer( + { + id: 'call_1', + name: 'Bash', + args: { command: longCmd }, + }, + { + tool_call_id: 'call_1', + output: 'first\nsecond\nthird\n\nTests 12 passed\n\n', + is_error: false, + }, + { expanded: false }, + ); + + const rendered = components.flatMap((c) => c.render(100)).map(strip); + expect(rendered).toEqual([' … Tests 12 passed']); + }); + + it('identifies a background task by its first metadata line while collapsed', () => { + const components = shellExecutionResultRenderer( + { + id: 'call_1', + name: 'Bash', + args: { command: 'npm run build', run_in_background: true }, + }, + { + tool_call_id: 'call_1', + output: [ + 'task_id: bash-abc123', + 'pid: 12345', + 'description: npm run build', + 'status: running', + 'automatic_notification: true', + 'next_step: The completion arrives automatically in a later turn.', + 'human_shell_hint: The task is visible in the background-task panel.', + ].join('\n'), + is_error: false, + }, + { expanded: false }, + ); + + const rendered = components.flatMap((c) => c.render(100)).map(strip); + expect(rendered).toEqual([' task_id: bash-abc123 …']); + }); + + it('shows a short result whole while collapsed', () => { + const components = shellExecutionResultRenderer( + { id: 'call_1', name: 'Bash', args: { command: 'git status --short' } }, + { tool_call_id: 'call_1', output: ' M src/a.ts\n?? src/b.ts\n', is_error: false }, + { expanded: false }, + ); + const rendered = components.flatMap((c) => c.render(100)).map(strip); + expect(rendered).toEqual([' M src/a.ts', ' ?? src/b.ts']); + }); + + it('renders no outcome row for a successful result without output', () => { + const components = shellExecutionResultRenderer( + { id: 'call_1', name: 'Bash', args: { command: 'true' } }, + { tool_call_id: 'call_1', output: '\n \n', is_error: false }, + { expanded: false }, + ); + expect(components).toEqual([]); + }); + + it('keeps a failing result previewed while collapsed and leaves the command to the call preview', () => { + const components = shellExecutionResultRenderer( + { + id: 'call_1', + name: 'Bash', + args: { command: longCmd }, + }, + { + tool_call_id: 'call_1', + output: 'boom', + is_error: true, + }, + { expanded: false }, + ); + + const rendered = components + .flatMap((c) => c.render(100)) + .map(strip) + .join('\n'); + // Command is owned by ToolCallComponent.buildCallPreview, not the + // renderer — rendering it here too would duplicate it once the result + // lands. + expect(rendered).not.toContain('$ echo'); + expect(rendered).toContain('boom'); + }); + + it('still renders only the result when expanded', () => { + const components = shellExecutionResultRenderer( + { + id: 'call_1', + name: 'Bash', + args: { command: longCmd }, + }, + { + tool_call_id: 'call_1', + output: ['line1', 'line2', 'line3', 'line4', 'line5'].join('\n'), + is_error: false, + }, + { expanded: true }, + ); + + const rendered = components + .flatMap((c) => c.render(300)) + .map(strip) + .join('\n'); + expect(rendered).not.toContain('$ echo'); + expect(rendered).toContain('line4'); + expect(rendered).toContain('line5'); + }); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/shell-run.test.ts b/apps/kimi-code/test/tui/components/messages/shell-run.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..aec0646a191d5f893249e4a5d38950e823cf56d4 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/shell-run.test.ts @@ -0,0 +1,228 @@ +import { afterEach, describe, expect, it } from 'vitest'; + +import { ShellRunComponent } from '#/tui/components/messages/shell-run'; + +function stripTheme(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('ShellRunComponent hardening', () => { + let component: ShellRunComponent | undefined; + + afterEach(() => { + // Always clear the 1s timer so it can't keep the test process alive or + // fire requestRender after the test ends. + component?.dispose(); + component = undefined; + }); + + function create(): ShellRunComponent { + component = new ShellRunComponent(() => {}); + return component; + } + + it('caps the running buffer and never throws on huge streaming output', () => { + const c = create(); + const chunk = 'x'.repeat(50_000); + expect(() => { + for (let i = 0; i < 20; i++) c.append(chunk); + c.render(100); + }).not.toThrow(); + }); + + it('finish switches to the final view and ignores later appends', () => { + const c = create(); + c.finish('final output', '', false); + c.append('should be ignored'); + const rendered = stripTheme(c.render(100).join('\n')); + expect(rendered).toContain('final output'); + expect(rendered).not.toContain('should be ignored'); + }); + + it('finishBackgrounded renders the background hint', () => { + const c = create(); + c.finishBackgrounded(); + const rendered = stripTheme(c.render(100).join('\n')); + expect(rendered).toContain('Moved to background.'); + }); + + it('append / finish are no-ops after dispose', () => { + const c = create(); + c.dispose(); + expect(() => { + c.append('late'); + c.finish('late', '', false); + c.finishBackgrounded(); + c.render(100); + }).not.toThrow(); + }); + + it('does not throw when the render callback throws', () => { + const c = new ShellRunComponent(() => { + throw new Error('render failed'); + }); + component = c; + expect(() => { + c.append('output'); + c.render(100); + }).not.toThrow(); + }); +}); + +describe('ShellRunComponent finished collapse', () => { + let component: ShellRunComponent | undefined; + + afterEach(() => { + component?.dispose(); + component = undefined; + }); + + function create(): ShellRunComponent { + component = new ShellRunComponent(() => {}); + return component; + } + + function rows(n: number): string { + return Array.from({ length: n }, (_, i) => `row-${String(i + 1).padStart(2, '0')}`).join('\n'); + } + + it('collapses finished output to the first 10 visual rows with an expand hint', () => { + const c = create(); + c.finish(rows(30), '', false); + const rendered = stripTheme(c.render(80).join('\n')); + expect(rendered).toContain('… (20 more lines, ctrl+o to expand)'); + expect(rendered).toContain('row-01'); + expect(rendered).toContain('row-10'); + expect(rendered).not.toContain('row-11'); + }); + + it('renders short finished output in full without a hint', () => { + const c = create(); + c.finish(rows(10), '', false); + const rendered = stripTheme(c.render(80).join('\n')); + expect(rendered).toContain('row-01'); + expect(rendered).toContain('row-10'); + expect(rendered).not.toContain('more lines'); + }); + + it('setExpanded toggles the finished view', () => { + const c = create(); + c.finish(rows(30), '', false); + + c.setExpanded(true); + const expanded = stripTheme(c.render(80).join('\n')); + expect(expanded).toContain('row-30'); + expect(expanded).not.toContain('more lines'); + + c.setExpanded(false); + const collapsed = stripTheme(c.render(80).join('\n')); + expect(collapsed).toContain('… (20 more lines, ctrl+o to expand)'); + expect(collapsed).not.toContain('row-11'); + }); + + it('expands the running view via setExpanded', () => { + const c = create(); + c.append(rows(10)); + + c.setExpanded(true); + const expanded = stripTheme(c.render(80).join('\n')); + expect(expanded).toContain('row-01'); + expect(expanded).toContain('row-10'); + expect(expanded).toContain('(ctrl+b to run in background)'); + expect(expanded).not.toContain('+5 lines'); + + c.setExpanded(false); + const collapsed = stripTheme(c.render(80).join('\n')); + expect(collapsed).toContain('+5 lines'); + expect(collapsed).not.toContain('row-01'); + }); + + it('carries the expanded state over to the finished view', () => { + const c = create(); + c.append(rows(10)); + c.setExpanded(true); + + c.finish(rows(30), '', false); + const finished = stripTheme(c.render(80).join('\n')); + expect(finished).toContain('row-30'); + expect(finished).not.toContain('more lines'); + }); + + it('flags a truncated buffer in the expanded running view', () => { + const c = create(); + c.append('x'.repeat(300 * 1024)); + c.setExpanded(true); + const rendered = stripTheme(c.render(80).join('\n')); + expect(rendered).toContain('… (output truncated)'); + }); + + it('keeps the backgrounded view when toggled', () => { + const c = create(); + c.finishBackgrounded(); + c.setExpanded(true); + const rendered = stripTheme(c.render(80).join('\n')); + expect(rendered).toContain('Moved to background.'); + }); + + it('collapses failed output the same way instead of auto-expanding', () => { + const c = create(); + c.finish(rows(30), 'boom', true); + const collapsed = stripTheme(c.render(80).join('\n')); + expect(collapsed).toContain('… (21 more lines, ctrl+o to expand)'); + + c.setExpanded(true); + const expanded = stripTheme(c.render(80).join('\n')); + expect(expanded).toContain('boom'); + }); +}); + +describe('ShellRunComponent hasHiddenContent', () => { + let component: ShellRunComponent | undefined; + + afterEach(() => { + component?.dispose(); + component = undefined; + }); + + function create(): ShellRunComponent { + component = new ShellRunComponent(() => {}); + return component; + } + + it('reports hidden rows while the running tail leaves earlier output behind', () => { + const c = create(); + c.append('one\ntwo\nthree\n'); + expect(c.hasHiddenContent()).toBe(false); + c.append('four\nfive\nsix\nseven\n'); + expect(c.hasHiddenContent()).toBe(true); + }); + + it('follows the finished preview cap after a collapsed render', () => { + const c = create(); + c.finish(Array.from({ length: 20 }, (_, i) => `row ${String(i + 1)}`).join('\n'), '', false); + c.render(100); + expect(c.hasHiddenContent()).toBe(true); + + const short = create(); + short.finish('done', '', false); + short.render(100); + expect(short.hasHiddenContent()).toBe(false); + }); +}); + +describe('ShellRunComponent hasHiddenContent when finished while expanded', () => { + let component: ShellRunComponent | undefined; + + afterEach(() => { + component?.dispose(); + component = undefined; + }); + + it('still reports the rows a collapse would hide, without a prior collapsed render', () => { + component = new ShellRunComponent(() => {}); + component.setExpanded(true); + component.finish(Array.from({ length: 20 }, (_, i) => `row ${String(i + 1)}`).join('\n'), '', false); + component.render(100); + expect(component.hasHiddenContent()).toBe(true); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/status-panel.test.ts b/apps/kimi-code/test/tui/components/messages/status-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..73a29979bbb96c42e64aa1245a5447adb0368d72 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/status-panel.test.ts @@ -0,0 +1,188 @@ +import { describe, expect, it } from 'vitest'; + +import { buildStatusReportLines } from '#/tui/components/messages/status-panel'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('status panel report lines', () => { + it('formats runtime status, context, and managed usage without account or AGENTS.md rows', () => { + const lines = buildStatusReportLines({ + version: '1.2.3', + model: 'k2', + workDir: '/tmp/project', + sessionId: 'ses-1', + sessionTitle: 'Implement status', + thinkingEffort: 'on', + permissionMode: 'manual', + planMode: false, + towerMode: false, + towerAvailable: true, + contextUsage: 0.25, + contextTokens: 2500, + maxContextTokens: 10000, + availableModels: { + k2: { + provider: 'managed:kimi-code', + model: 'kimi-k2', + maxContextSize: 10000, + displayName: 'Kimi K2', + }, + }, + status: { + model: 'k2', + thinkingEffort: 'high', + permission: 'auto', + planMode: true, + contextTokens: 3000, + maxContextTokens: 12000, + contextUsage: 0.25, + }, + managedUsage: { + rows: [ + { + name: '5h limit', + usedRatio: 0.08, + resetAt: new Date(Date.now() + 3600_000).toISOString(), + }, + ], + }, + }).map(strip); + + const output = lines.join('\n'); + expect(output).toContain('>_ Kimi Code (v1.2.3)'); + expect(output).toContain('Model Kimi K2 (thinking high)'); + expect(output).toContain('Directory /tmp/project'); + expect(output).toContain('Permissions Never Ask'); + expect(output).toContain('Plan mode on'); + expect(output).toContain('Session ses-1'); + expect(output).toContain('Title Implement status'); + expect(output).toContain('Context window'); + expect(output).toContain('25%'); + expect(output).toContain('(2.9k / 11.7k)'); + expect(output).toContain('Plan usage'); + expect(output).toContain('5h limit'); + expect(output).toContain('8% used'); + expect(output).not.toContain('Account'); + expect(output).not.toContain('AGENTS.md'); + expect(output).not.toContain('Runtime'); + }); + + it('prefers the fetched status tower mode over the cached value', () => { + const lines = buildStatusReportLines({ + version: '1.2.3', + model: 'k2', + workDir: '/tmp/project', + sessionId: 'ses-1', + sessionTitle: null, + thinkingEffort: 'off', + permissionMode: 'manual', + planMode: false, + towerMode: false, + towerAvailable: true, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + availableModels: {}, + status: { + model: 'k2', + thinkingEffort: 'off', + permission: 'manual', + planMode: false, + towerMode: true, + contextTokens: 0, + maxContextTokens: 0, + contextUsage: 0, + }, + }).map(strip); + + expect(lines.join('\n')).toContain('Tower mode on'); + }); + + it('omits the tower mode row when the experiment is unavailable', () => { + const lines = buildStatusReportLines({ + version: '1.2.3', + model: 'k2', + workDir: '/tmp/project', + sessionId: 'ses-1', + sessionTitle: null, + thinkingEffort: 'off', + permissionMode: 'manual', + planMode: false, + towerMode: false, + towerAvailable: false, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + availableModels: {}, + }).map(strip); + + expect(lines.join('\n')).not.toContain('Tower mode'); + }); + + it('formats extra usage section in status report', () => { + const lines = buildStatusReportLines({ + version: '1.2.3', + model: 'k2', + workDir: '/tmp/project', + sessionId: 'ses-1', + sessionTitle: null, + thinkingEffort: 'off', + permissionMode: 'manual', + planMode: false, + towerMode: false, + towerAvailable: true, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + availableModels: {}, + managedUsage: { + rows: [], + extraUsage: { + balanceCents: 15000, + totalCents: 20000, + monthlyChargeLimitEnabled: true, + monthlyChargeLimitCents: 20000, + monthlyUsedCents: 5000, + currency: 'USD', + }, + }, + }).map(strip); + + const output = lines.join('\n'); + expect(output).toContain('Extra Usage'); + expect(output).toContain('Balance'); + expect(output).toContain('150.00'); + expect(output).toContain('Used this month'); + expect(output).toContain('50.00'); + expect(output).toContain('Monthly limit'); + expect(output).toContain('200.00'); + }); + + it('falls back to app state and shows status load errors as warnings', () => { + const lines = buildStatusReportLines({ + version: '1.2.3', + model: '', + workDir: '/tmp/project', + sessionId: '', + sessionTitle: null, + thinkingEffort: 'off', + permissionMode: 'manual', + planMode: false, + towerMode: false, + towerAvailable: true, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + availableModels: {}, + statusError: 'No active session', + }).map(strip); + + const output = lines.join('\n'); + expect(output).toContain('Model not set'); + expect(output).toContain('Session none'); + expect(output).toContain('Warning No active session'); + expect(output).toContain('No context window data available.'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/step-summary.test.ts b/apps/kimi-code/test/tui/components/messages/step-summary.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..85626c8ae6db2a7f27597e1e84657c5014431236 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/step-summary.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; + +import { StepSummaryComponent } from '#/tui/components/messages/step-summary'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('StepSummaryComponent', () => { + it('renders nothing when empty', () => { + const component = new StepSummaryComponent(); + expect(component.isEmpty).toBe(true); + expect(component.render(80)).toEqual([]); + }); + + it('renders thinking and tool counts without a message part', () => { + const component = new StepSummaryComponent(); + component.addCounts(5, 50); + const out = strip(component.render(80).join('\n')); + expect(out).toContain('thinking 5 times'); + expect(out).toContain('call 50 tools'); + expect(out).not.toContain('messages'); + }); + + it('renders folded assistant message counts and accumulates', () => { + const component = new StepSummaryComponent(); + component.addCounts(0, 0, 3); + component.addCounts(2, 4, 5); + const out = strip(component.render(80).join('\n')); + expect(component.isEmpty).toBe(false); + expect(out).toContain('thinking 2 times'); + expect(out).toContain('call 4 tools'); + expect(out).toContain('8 messages'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/thinking.test.ts b/apps/kimi-code/test/tui/components/messages/thinking.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e04dbd1f7edf0e7b21749b99d8e00e87a6f9b96 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/thinking.test.ts @@ -0,0 +1,92 @@ +import { visibleWidth, type TUI } from '@moonshot-ai/pi-tui'; +import { describe, expect, it, vi } from 'vitest'; + +import { ThinkingComponent } from '#/tui/components/messages/thinking'; +import { STATUS_BULLET } from '#/tui/constant/symbols'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +const longThinking = ['line1', 'line2', 'line3', 'line4', 'line5', 'line6', 'line7'].join('\n'); + +describe('ThinkingComponent', () => { + it('shows the live spinner header before thinking content', () => { + const component = new ThinkingComponent('working it out', true, 'live'); + const out = strip(component.render(80).join('\n')); + + expect(out).toContain('⠋ thinking…'); + expect(out).not.toContain(' ⠋ thinking…'); + expect(out).not.toContain(`${STATUS_BULLET}⠋`); + expect(out).toContain(' working it out'); + }); + + it('keeps live thinking height-limited to the tail', () => { + const component = new ThinkingComponent(longThinking, true, 'live'); + const out = strip(component.render(80).join('\n')); + + expect(out).not.toContain('line1'); + expect(out).not.toContain('line4'); + expect(out).not.toContain('line5'); + expect(out).toContain('line6'); + expect(out).toContain('line7'); + expect(out).not.toContain('ctrl+o to expand'); + }); + + it('animates the live spinner and stops on finalize', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const component = new ThinkingComponent('step', true, 'live', { + requestRender, + } as unknown as TUI); + + expect(strip(component.render(80).join('\n'))).toContain('⠋ thinking…'); + + vi.advanceTimersByTime(80); + expect(requestRender).toHaveBeenCalled(); + expect(strip(component.render(80).join('\n'))).toContain('⠙ thinking…'); + + component.finalize(); + requestRender.mockClear(); + vi.advanceTimersByTime(160); + expect(requestRender).not.toHaveBeenCalled(); + vi.useRealTimers(); + }); + + it('finalizes in place into a collapsed preview', () => { + const component = new ThinkingComponent(longThinking, true, 'live'); + + component.finalize(); + + const out = strip(component.render(80).join('\n')); + expect(out).toContain('line1'); + expect(out).toContain('line2'); + expect(out).not.toContain('line3'); + expect(out).not.toContain('line4'); + expect(out).toContain('… (5 more lines, ctrl+o to expand)'); + }); + + it('expands and collapses after finalization', () => { + const component = new ThinkingComponent(longThinking, true, 'live'); + component.finalize(); + + component.setExpanded(true); + const expanded = strip(component.render(80).join('\n')); + expect(expanded).toContain('line7'); + expect(expanded).not.toContain('ctrl+o to expand'); + + component.setExpanded(false); + const collapsed = strip(component.render(80).join('\n')); + expect(collapsed).not.toContain('line7'); + expect(collapsed).toContain('ctrl+o to expand'); + }); + + it('keeps the finalized truncation footer within the requested render width', () => { + const component = new ThinkingComponent(longThinking, true, 'live'); + component.finalize(); + + for (const line of component.render(37)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(37); + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/tool-call.test.ts b/apps/kimi-code/test/tui/components/messages/tool-call.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..969f0e9be4df9fadfdd48b8dfbabfc08f4bb8d7d --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/tool-call.test.ts @@ -0,0 +1,2723 @@ +import { visibleWidth, type TUI } from '@moonshot-ai/pi-tui'; +import chalk from 'chalk'; +import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest'; + +import { setExperimentalFeatures } from '#/tui/commands/experimental-flags'; +import { ToolCallComponent } from '#/tui/components/messages/tool-call'; +import { STATUS_BULLET } from '#/tui/constant/symbols'; +import { darkColors } from '#/tui/theme/colors'; + +import { captureProcessWrite } from '../../../helpers/process'; + +const ESC = String.fromCodePoint(0x1b); +const BEL = String.fromCodePoint(0x07); + +function strip(text: string): string { + return text + .replaceAll(/\u001B\[[0-9;]*m/g, '') + .replaceAll(new RegExp(`${ESC}\\]8;;[^${BEL}]*${BEL}`, 'g'), ''); +} + +function stubTui(rows: number): TUI { + return { + terminal: { rows }, + requestRender: () => {}, + } as unknown as TUI; +} + +describe('ToolCallComponent', () => { + afterEach(() => { + vi.useRealTimers(); + setExperimentalFeatures([]); + }); + + it('uses the shared non-emoji tool status bullet', () => { + const component = new ToolCallComponent( + { + id: 'call_read_marker', + name: 'Read', + args: { path: 'foo.ts' }, + }, + { + tool_call_id: 'call_read_marker', + output: 'content', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain(`${STATUS_BULLET}Used Read`); + expect(out).not.toContain(`\u23FA Used Read`); + expect(out).not.toContain(`${String.fromCodePoint(0x23fa, 0xfe0e)} Used Read`); + }); + + describe('detach hint for long-running foreground Bash/Agent', () => { + it('shows the Ctrl+B hint after 10s for a running Bash call', () => { + vi.useFakeTimers(); + const component = new ToolCallComponent( + { id: 'call_bash_long', name: 'Bash', args: { command: 'sleep 30' } }, + undefined, + stubTui(30), + ); + + expect(strip(component.render(100).join('\n'))).not.toContain( + 'Press Ctrl+B to run in background', + ); + + vi.advanceTimersByTime(10_000); + expect(strip(component.render(100).join('\n'))).toContain( + 'Press Ctrl+B to run in background', + ); + + component.dispose(); + }); + + it('shows the hint immediately for a running Agent call', () => { + vi.useFakeTimers(); + const component = new ToolCallComponent( + { id: 'call_agent_long', name: 'Agent', args: { description: 'explore' } }, + undefined, + stubTui(30), + ); + + // No timer advancement — Agents advertise Ctrl+B immediately. + expect(strip(component.render(100).join('\n'))).toContain( + 'Press Ctrl+B to run in background', + ); + + component.dispose(); + }); + + it('does not show the hint for non-detachable tools', () => { + vi.useFakeTimers(); + const component = new ToolCallComponent( + { id: 'call_read_long', name: 'Read', args: { path: 'foo.ts' } }, + undefined, + stubTui(30), + ); + + vi.advanceTimersByTime(15_000); + expect(strip(component.render(100).join('\n'))).not.toContain( + 'Press Ctrl+B to run in background', + ); + + component.dispose(); + }); + + it('does not show the hint when the result lands before 10s', () => { + vi.useFakeTimers(); + const component = new ToolCallComponent( + { id: 'call_bash_short', name: 'Bash', args: { command: 'echo hi' } }, + undefined, + stubTui(30), + ); + + vi.advanceTimersByTime(5_000); + component.setResult({ tool_call_id: 'call_bash_short', output: 'hi', is_error: false }); + vi.advanceTimersByTime(10_000); + + expect(strip(component.render(100).join('\n'))).not.toContain( + 'Press Ctrl+B to run in background', + ); + + component.dispose(); + }); + }); + + it('keeps collapsed tool-call lines within very narrow widths', () => { + const component = new ToolCallComponent( + { + id: 'call_narrow_read', + name: 'Read', + args: { path: 'very/long/path/to/foo.ts' }, + }, + { + tool_call_id: 'call_narrow_read', + output: 'content', + is_error: false, + }, + ); + + for (const width of [1, 2, 4, 10, 39]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('keeps collapsed tool results short and expands on demand', () => { + const component = new ToolCallComponent( + { + id: 'call_shell', + name: 'Bash', + args: { command: 'printf output' }, + }, + { + tool_call_id: 'call_shell', + output: ['line1', 'line2', 'line3', 'line4', 'line5'].join('\n'), + is_error: false, + }, + ); + + // Collapsed: the header (command + hidden-line chip) plus one outcome row + // holding the last output line, marked as standing in for the rest. + const collapsedLines = component.render(100).map(strip).filter((line) => line.trim().length > 0); + expect(collapsedLines).toHaveLength(2); + expect(collapsedLines[0]).toContain('Ran a command'); + expect(collapsedLines[0]).toContain('$ printf output'); + expect(collapsedLines[0]).toContain('· 4 more lines'); + expect(collapsedLines[1]).toBe(' … line5'); + + component.setExpanded(true); + + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('line1'); + expect(expanded).toContain('line4'); + expect(expanded).toContain('line5'); + expect(expanded).not.toContain('ctrl+o to expand'); + }); + + it('keeps a failing command\'s output visible while collapsed', () => { + const component = new ToolCallComponent( + { + id: 'call_shell_err', + name: 'Bash', + args: { command: 'false' }, + }, + { + tool_call_id: 'call_shell_err', + output: ['err1', 'err2', 'err3', 'err4', 'err5'].join('\n'), + is_error: true, + }, + ); + + const collapsed = strip(component.render(100).join('\n')); + expect(collapsed).toContain('err1'); + expect(collapsed).toContain('err3'); + expect(collapsed).not.toContain('err4'); + expect(collapsed).toContain('… (2 more lines, ctrl+o to expand)'); + }); + + it('renders live Bash output while the command is running', () => { + const component = new ToolCallComponent( + { + id: 'call_shell_live', + name: 'Bash', + args: { command: 'printf output' }, + }, + undefined, + ); + + component.appendLiveOutput('line1\n'); + component.appendLiveOutput('line2\n'); + + // Collapsed: the header plus the newest live line as the outcome row, + // marked as standing in for the lines above it; the whole live tail waits + // for ctrl+o. + const rows = component.render(100).map(strip).filter((line) => line.trim().length > 0); + expect(rows).toHaveLength(2); + expect(rows[0]).toContain('Running a command'); + expect(rows[0]).toContain('$ printf output'); + expect(rows[1]).toBe(' … line2'); + + component.setExpanded(true); + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('line1'); + expect(expanded).toContain('line2'); + }); + + it('clears live Bash output when the final result arrives', () => { + const component = new ToolCallComponent( + { + id: 'call_shell_live_done', + name: 'Bash', + args: { command: 'printf output' }, + }, + undefined, + ); + + component.appendLiveOutput('streamed-only\n'); + component.setResult({ + tool_call_id: 'call_shell_live_done', + output: 'final-only\n', + is_error: false, + }); + component.setExpanded(true); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Ran a command'); + expect(out).toContain('final-only'); + expect(out).not.toContain('streamed-only'); + }); + + describe('Bash command preview', () => { + const longCommand = Array.from({ length: 15 }, (_, i) => `echo step${String(i + 1)}`).join( + '\n', + ); + + it('keeps a running multi-line command to its first line until expanded', () => { + const component = new ToolCallComponent( + { id: 'call_bash_running', name: 'Bash', args: { command: longCommand } }, + undefined, + ); + + const collapsed = component.render(100).map(strip).filter((line) => line.trim().length > 0); + expect(collapsed).toHaveLength(1); + expect(collapsed[0]).toContain('Running a command'); + expect(collapsed[0]).toContain('$ echo step1…'); + expect(collapsed[0]).not.toContain('echo step2'); + + component.setExpanded(true); + + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('echo step11'); + expect(expanded).toContain('echo step15'); + }); + + it('settles on header plus outcome row after the result lands and shows everything once expanded', () => { + const component = new ToolCallComponent( + { id: 'call_bash_done', name: 'Bash', args: { command: longCommand } }, + undefined, + ); + + component.setResult({ + tool_call_id: 'call_bash_done', + output: 'step a\nstep b\nstep c\ndone', + is_error: false, + }); + + const collapsed = component.render(100).map(strip).filter((line) => line.trim().length > 0); + expect(collapsed).toHaveLength(2); + expect(collapsed[0]).toContain('Ran a command'); + expect(collapsed[0]).toContain('$ echo step1…'); + expect(collapsed[0]).toContain('· 3 more lines'); + expect(collapsed[1]).toBe(' … done'); + + component.setExpanded(true); + // The command is owned by buildCallPreview, so it appears exactly once — + // the result renderer renders the output only. + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('echo step11'); + expect(expanded).toContain('echo step15'); + expect(expanded).toContain('done'); + // Header keeps the truncated first line (`$ echo step1…`); the full + // command body must appear exactly once below it. + expect(expanded.match(/\$ echo step1(?!…)/g)).toHaveLength(1); + }); + + it('carries the command in the header when the command produces no output', () => { + const component = new ToolCallComponent( + { id: 'call_bash_empty', name: 'Bash', args: { command: 'mkdir -p a/b/c\necho done' } }, + { tool_call_id: 'call_bash_empty', output: '', is_error: false }, + ); + + const collapsed = component.render(100).map(strip).filter((line) => line.trim().length > 0); + expect(collapsed).toHaveLength(1); + expect(collapsed[0]).toContain('Ran a command'); + expect(collapsed[0]).toContain('$ mkdir -p a/b/c…'); + + component.setExpanded(true); + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('echo done'); + }); + }); + + describe('NotifyUser card', () => { + beforeEach(() => { + setExperimentalFeatures([{ id: 'notify_user', enabled: true }]); + }); + const message = 'Login module is clean.\n\nThe bug must be in **session expiry**.'; + + it('collapses to a header with the first line and expands to the full message', () => { + const component = new ToolCallComponent( + { id: 'call_notify', name: 'NotifyUser', args: { message } }, + { tool_call_id: 'call_notify', output: 'Update shown to the user.', is_error: false }, + ); + + const collapsed = component.render(100).map(strip).filter((line) => line.trim().length > 0); + expect(collapsed).toHaveLength(1); + expect(collapsed[0]).toContain('Sent you an update'); + expect(collapsed[0]).toContain('Login module is clean.'); + expect(collapsed[0]).not.toContain('session expiry'); + expect(collapsed[0]).not.toContain('Update shown'); + expect(component.hasHiddenContent()).toBe(true); + + component.setExpanded(true); + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('session expiry'); + expect(expanded).not.toContain('Update shown'); + expect(component.hasHiddenContent()).toBe(true); + }); + + it('renders historical calls as ordinary tool records when disabled', () => { + setExperimentalFeatures([]); + const component = new ToolCallComponent( + { id: 'notify-old', name: 'NotifyUser', args: { message: 'Past progress' } }, + { tool_call_id: 'notify-old', output: 'Update shown to the user.', is_error: false }, + ); + const output = strip(component.render(100).join('\n')); + expect(output).toContain('Used NotifyUser'); + expect(output).not.toContain('Sent you an update'); + expect(output).toContain('Update shown to the user.'); + }); + + it('labels the in-flight call as sending', () => { + const component = new ToolCallComponent( + { id: 'call_notify_live', name: 'NotifyUser', args: {}, streamingArguments: '{"mess' }, + undefined, + ); + expect(strip(component.render(100).join('\n'))).toContain('Sending you an update'); + expect(component.hasHiddenContent()).toBe(false); + }); + + it.each([true, false])('preserves a suppressed result when rendering history, enabled: %s', (enabled) => { + setExperimentalFeatures([{ id: 'notify_user', enabled }]); + const output = 'Notifications are disabled; the update was not displayed.'; + const component = new ToolCallComponent( + { id: 'suppressed', name: 'NotifyUser', args: { message } }, + { tool_call_id: 'suppressed', output, is_error: false }, + ); + for (const expanded of [false, true]) { + component.setExpanded(expanded); + const rendered = strip(component.render(150).join('\n')); + expect(rendered).not.toContain('Sent you an update'); + expect(rendered).toContain(output); + if (enabled) expect(rendered).toContain('Update not displayed'); + } + }); + + it('does not claim an unknown successful result was displayed', () => { + const component = new ToolCallComponent( + { id: 'unknown-result', name: 'NotifyUser', args: { message } }, + { tool_call_id: 'unknown-result', output: 'An unrecognized result.', is_error: false }, + ); + const rendered = strip(component.render(150).join('\n')); + expect(rendered).not.toContain('Sent you an update'); + expect(rendered).toContain('An unrecognized result.'); + }); + + it('marks a call whose arguments were cut off by max_tokens', () => { + const component = new ToolCallComponent( + { + id: 'call_notify_cut', + name: 'NotifyUser', + args: {}, + streamingArguments: '{"message": "half an upd', + truncated: true, + }, + undefined, + ); + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Update cut off'); + expect(out).not.toContain('Sending you an update'); + expect(out).toContain('call never executed'); + expect(component.hasHiddenContent()).toBe(false); + }); + }); + + describe('collapsed header width', () => { + it('truncates a long Bash header to the terminal width instead of wrapping', () => { + const command = `pnpm exec vitest run ${'test/very/long/path/'.repeat(6)}spec.test.ts --reporter=verbose`; + const component = new ToolCallComponent( + { id: 'call_bash_narrow', name: 'Bash', args: { command } }, + { tool_call_id: 'call_bash_narrow', output: 'ok', is_error: false }, + ); + for (const width of [40, 60, 80]) { + const rows = component.render(width).map(strip).filter((line) => line.trim().length > 0); + // Header plus the outcome row holding the command's output ("ok"). + expect(rows).toHaveLength(2); + expect(visibleWidth(rows[0]!)).toBeLessThanOrEqual(width); + expect(rows[0]).toContain('Ran a command'); + expect(rows[0]).toContain('…'); + } + }); + + it('truncates a long NotifyUser preview the same way', () => { + setExperimentalFeatures([{ id: 'notify_user', enabled: true }]); + const component = new ToolCallComponent( + { + id: 'call_notify_narrow', + name: 'NotifyUser', + args: { message: `Plan: ${'inspect the parser, '.repeat(8)}then run the suite.` }, + }, + { tool_call_id: 'call_notify_narrow', output: 'Update shown to the user.', is_error: false }, + ); + const rows = component.render(50).map(strip).filter((line) => line.trim().length > 0); + expect(rows).toHaveLength(1); + expect(visibleWidth(rows[0]!)).toBeLessThanOrEqual(50); + expect(rows[0]).toContain('Sent you an update'); + expect(component.hasHiddenContent()).toBe(true); + }); + + it('hands back the same header array while the header is unchanged', () => { + const component = new ToolCallComponent( + { id: 'call_bash_cached', name: 'Bash', args: { command: 'ls' } }, + undefined, + ); + // children[0] is the leading spacer; the header line follows it. The + // card and the gutter reuse a child's output by array identity, so an + // unchanged header must return the very same array across frames. + const header = component.children[1]!; + const first = header.render(100); + expect(header.render(100)).toBe(first); + expect(header.render(80)).not.toBe(first); + + component.setResult({ tool_call_id: 'call_bash_cached', output: 'ok', is_error: false }); + const finished = header.render(100); + expect(finished).not.toBe(first); + expect(strip(finished[0]!)).toContain('Ran a command'); + expect(header.render(100)).toBe(finished); + }); + + it('lets a long Bash command fill a wide terminal and keeps the chip', () => { + const command = + 'git log --oneline -5 origin/main -- apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts'; + const component = new ToolCallComponent( + { id: 'call_bash_wide', name: 'Bash', args: { command } }, + { tool_call_id: 'call_bash_wide', output: 'ok\nok\nok\nok', is_error: false }, + ); + // The command is the flexible middle segment: on a wide terminal it is + // shown in full, on a narrow one it is cut with an ellipsis before the chip. + const wide = component.render(160).map(strip).filter((line) => line.trim().length > 0); + expect(wide).toHaveLength(2); + expect(wide[0]).toContain(`$ ${command}`); + expect(wide[0]).not.toContain('…'); + + const narrow = component.render(70).map(strip).filter((line) => line.trim().length > 0); + expect(narrow).toHaveLength(2); + expect(visibleWidth(narrow[0]!)).toBeLessThanOrEqual(70); + // The command is cut to the remaining width; the hidden-line chip survives. + expect(narrow[0]).toMatch(/\$ git log .*… · 3 more lines$/); + }); + + it('keeps the file name of a long Read path on a narrow terminal', () => { + const path = + '/Users/someone/.kimi-code/sessions/session_5b2c/agents/main/tasks/bash-4g77gs5f/output.log'; + const component = new ToolCallComponent( + { id: 'call_read_narrow', name: 'Read', args: { path } }, + { tool_call_id: 'call_read_narrow', output: '1\ta\n2\tb', is_error: false }, + ); + const rows = component.render(60).map(strip).filter((line) => line.trim().length > 0); + expect(rows).toHaveLength(1); + expect(visibleWidth(rows[0]!)).toBeLessThanOrEqual(60); + expect(rows[0]).toContain('(…'); + expect(rows[0]).toContain('/output.log)'); + expect(rows[0]).toContain('2 lines'); + }); + }); + + it('hides tool output bodies that start with a { + const reminderOutput = + '\nThe task tools have not been used recently.\n'; + const component = new ToolCallComponent( + { + id: 'call_hidden', + name: 'Bash', + args: { command: 'echo hi' }, + }, + { + tool_call_id: 'call_hidden', + output: reminderOutput, + is_error: false, + }, + ); + + const collapsed = strip(component.render(100).join('\n')); + expect(collapsed).toContain(`${STATUS_BULLET}Ran a command`); + expect(collapsed).not.toContain('system-reminder'); + expect(collapsed).not.toContain('task tools'); + + component.setExpanded(true); + const expanded = strip(component.render(100).join('\n')); + expect(expanded).not.toContain('system-reminder'); + expect(expanded).not.toContain('task tools'); + }); + + it('hides { + const component = new ToolCallComponent( + { + id: 'call_hidden_err', + name: 'Bash', + args: { command: 'false' }, + }, + { + tool_call_id: 'call_hidden_err', + output: 'do not show', + is_error: true, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).not.toContain('system-reminder'); + expect(out).not.toContain('do not show'); + }); + + it('renders output that merely starts with a literal tag', () => { + // Tool metadata no longer travels inside `output` (it rides the result's + // `note` side channel), so real output starting with the literal tag — + // a file that contains it, an MCP tool's text — must stay visible. + const component = new ToolCallComponent( + { + id: 'call_literal', + name: 'Bash', + args: { command: 'cat notes.txt' }, + }, + { + tool_call_id: 'call_literal', + output: 'literal text from a user file\nsecond line', + is_error: false, + }, + ); + + component.setExpanded(true); + const out = strip(component.render(100).join('\n')); + expect(out).toContain('literal text from a user file'); + expect(out).toContain('second line'); + }); + + it('renders AgentSwarm results as a one-line summary without raw XML', () => { + const output = [ + '', + 'completed: 1, failed: 1, aborted: 1', + 'Reviewed src/a.ts.', + 'Agent timed out.', + 'User aborted.', + '', + ].join('\n'); + const component = new ToolCallComponent( + { + id: 'call_swarm', + name: 'AgentSwarm', + args: { + description: 'Review changed files', + items: ['src/a.ts', 'src/b.ts', 'src/c.ts'], + }, + }, + { + tool_call_id: 'call_swarm', + output, + is_error: false, + }, + ); + + const out = strip(component.render(120).join('\n')); + + expect(out).toContain('Agent swarm: ✓ 1 completed · ✗ 1 failed · ⊘ 1 aborted'); + expect(out).not.toContain(''); + expect(out).not.toContain('Reviewed src/a.ts.'); + expect(out).not.toContain('Agent timed out.'); + }); + + it('renders an AgentSwarm fallback summary when the result is not structured', () => { + const component = new ToolCallComponent( + { + id: 'call_swarm_failed', + name: 'AgentSwarm', + args: { description: 'Review changed files' }, + }, + { + tool_call_id: 'call_swarm_failed', + output: 'provider request failed', + is_error: true, + }, + ); + + const out = strip(component.render(120).join('\n')); + + expect(out).toContain('Agent swarm: ✗ Failed.'); + expect(out).not.toContain('provider request failed'); + }); + + it('still renders tool output when the body merely contains { + const component = new ToolCallComponent( + { + id: 'call_inline', + name: 'Bash', + args: { command: 'echo hi' }, + }, + { + tool_call_id: 'call_inline', + output: 'first line\nnope', + is_error: false, + }, + ); + + // Successful output only renders once expanded; the point here is that a + // reminder tag mid-body must not suppress the whole output. + component.setExpanded(true); + const out = strip(component.render(100).join('\n')); + expect(out).toContain('first line'); + }); + + it('renders ExitPlanMode plan from result output when args.plan is absent', () => { + const component = new ToolCallComponent( + { + id: 'call_exit', + name: 'ExitPlanMode', + args: {}, + }, + { + tool_call_id: 'call_exit', + output: + 'Exited plan mode. Plan mode deactivated. All tools are now available.\n' + + 'Plan saved to: /tmp/plan.md\n\n' + + '## Approved Plan:\n# File Plan\n\n1. Do the focused fix.', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Current plan'); + expect(out).toContain('File Plan'); + expect(out).toContain('1. Do the focused fix.'); + expect(out).not.toContain('Plan saved to: /tmp/plan.md'); + }); + + it('setPlanInfo injects plan body when args.plan is empty (plan-file mode)', () => { + const component = new ToolCallComponent( + { + id: 'call_exit_async', + name: 'ExitPlanMode', + args: {}, + }, + undefined, + undefined, + ); + + // A fresh tool card only shows the 'Current plan' title; no plan box renders yet. + const before = strip(component.render(100).join('\n')); + expect(before).toContain('Current plan'); + expect(before).not.toContain('Refactor session'); + + component.setPlanInfo({ plan: '# Refactor session\n\n- step', path: '/tmp/refactor.md' }); + + const after = strip(component.render(100).join('\n')); + expect(after).toContain('Refactor session'); + expect(after).toContain('plan:'); + expect(after).toContain('refactor.md'); + // Directory portion of the path must not leak into the visible header. + expect(after).not.toContain('/tmp/refactor.md'); + }); + + it('renders the full plan preview', () => { + const longPlan = `# Refactor session\n\n${Array.from({ length: 40 }, (_, i) => `- step ${String(i + 1)}`).join('\n')}`; + const component = new ToolCallComponent( + { + id: 'call_exit_long', + name: 'ExitPlanMode', + args: { plan: longPlan }, + }, + undefined, + stubTui(24), + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('step 1'); + expect(out).toContain('step 40'); + expect(out).not.toContain('more lines'); + }); + + it('plan preview controls are no-ops for non-ExitPlanMode tool calls', () => { + const component = new ToolCallComponent( + { + id: 'call_bash_plan', + name: 'Bash', + args: { command: 'echo hi' }, + }, + undefined, + undefined, + ); + + component.setPlanInfo({ plan: 'should be ignored', path: '/etc/hosts' }); + + const out = strip(component.render(100).join('\n')); + expect(out).not.toContain('should be ignored'); + expect(out).not.toContain('plan:'); + }); + + it('ctrl+o does not affect the full plan preview', () => { + const longPlan = `# P\n\n${Array.from({ length: 40 }, (_, i) => `- step ${String(i + 1)}`).join('\n')}`; + const component = new ToolCallComponent( + { + id: 'call_exit_isolation', + name: 'ExitPlanMode', + args: { plan: longPlan }, + }, + undefined, + stubTui(24), + ); + component.setExpanded(true); + const out = strip(component.render(100).join('\n')); + expect(out).toContain('step 40'); + expect(out).not.toContain('more lines'); + }); + + it('header chips an Approved status when ExitPlanMode result indicates approval', () => { + const component = new ToolCallComponent( + { + id: 'call_exit_approved', + name: 'ExitPlanMode', + args: {}, + }, + { + tool_call_id: 'call_exit_approved', + output: + 'Exited plan mode. Plan mode deactivated. All tools are now available.\n' + + 'Plan saved to: /tmp/plan.md\n\n' + + '## Approved Plan:\n# Plan body', + is_error: false, + }, + ); + + const header = strip(component.render(100).join('\n')).split('\n')[1] ?? ''; + expect(header).toMatch(/Current plan · Approved\s*$/); + }); + + it('header chips approved option label when the user picked one', () => { + const component = new ToolCallComponent( + { + id: 'call_exit_chosen', + name: 'ExitPlanMode', + args: {}, + }, + { + tool_call_id: 'call_exit_chosen', + output: + 'Exited plan mode. Selected approach: Pragmatic refactor\n' + + 'Execute ONLY the selected approach. Do not execute any unselected alternatives.\n\n' + + 'Plan mode deactivated. All tools are now available.\n' + + 'Plan saved to: /tmp/plan.md\n\n' + + '## Approved Plan:\n# body', + is_error: false, + }, + ); + + const header = strip(component.render(100).join('\n')).split('\n')[1] ?? ''; + expect(header).toContain('Current plan · Approved: Pragmatic refactor'); + }); + + it('header chips Auto-approved when ExitPlanMode was auto-approved without user review', () => { + const component = new ToolCallComponent( + { + id: 'call_exit_auto', + name: 'ExitPlanMode', + args: {}, + }, + { + tool_call_id: 'call_exit_auto', + output: + 'Exited plan mode. Plan mode deactivated. All tools are now available.\n' + + 'Note: this plan was auto-approved without user review — the user has NOT explicitly approved it.\n' + + 'Plan saved to: /tmp/plan.md\n\n' + + '## Plan (auto-approved, not user-reviewed):\n# Auto Plan\n\n1. Do the thing.', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + const header = out.split('\n')[1] ?? ''; + expect(header).toMatch(/Current plan · Auto-approved\s*$/); + // The plan body renders from the auto-approved marker; the engine-side + // note above the marker must not leak into the rendered plan box. + expect(out).toContain('Auto Plan'); + expect(out).toContain('1. Do the thing.'); + expect(out).not.toContain('Note: this plan was auto-approved'); + }); + + it('renders Rejected in the plan box title and keeps revise feedback visible', () => { + const component = new ToolCallComponent( + { + id: 'call_exit_reject_fb', + name: 'ExitPlanMode', + args: { plan: '# Rework Plan\n\n- step 1' }, + }, + { + tool_call_id: 'call_exit_reject_fb', + output: 'User rejected the plan. Feedback:\n\nplease rethink step 2', + is_error: false, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('plan · Rejected'); + expect(out).toContain('↪ Suggestion'); + expect(out).toContain('please rethink step 2'); + }); + + it('renders is_error ExitPlanMode reject in the plan box title without raw error text', () => { + const component = new ToolCallComponent( + { + id: 'call_exit_reject', + name: 'ExitPlanMode', + args: { plan: '# Rejected Plan\n\n- keep investigating' }, + }, + { + tool_call_id: 'call_exit_reject', + output: 'Plan rejected by user. Plan mode remains active.', + is_error: true, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('plan · Rejected'); + expect(out).toContain('Rejected Plan'); + expect(out).not.toContain('Plan rejected by user.'); + expect(out).not.toContain('Plan mode remains active.'); + }); + + it('suppresses EnterPlanMode success body so prompt scaffolding does not leak into the transcript', () => { + const component = new ToolCallComponent( + { + id: 'call_enter', + name: 'EnterPlanMode', + args: { reason: 'plan a refactor' }, + }, + { + tool_call_id: 'call_enter', + output: + 'Plan mode is now active. Your workflow:\n\n' + + 'Plan file: /tmp/plan.md\n\n' + + '1. Use read-only tools (Read, Grep, Glob) to investigate the codebase.\n' + + '2. Design a concrete, step-by-step plan.\n' + + '3. Write the plan to the plan file with Write or Edit.\n' + + '4. When the plan is ready, call ExitPlanMode for user approval.\n\n' + + 'Do NOT edit files other than the plan file while plan mode is active.', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Used EnterPlanMode'); + expect(out).not.toContain('Plan mode is now active'); + expect(out).not.toContain('Plan file:'); + expect(out).not.toContain('read-only tools'); + }); + + it('still surfaces EnterPlanMode error output', () => { + const component = new ToolCallComponent( + { + id: 'call_enter_err', + name: 'EnterPlanMode', + args: {}, + }, + { + tool_call_id: 'call_enter_err', + output: 'Plan mode is already active. Use ExitPlanMode when the plan is ready.', + is_error: true, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Plan mode is already active'); + }); + + it('renders AskUserQuestion with a friendly header instead of the raw tool name', () => { + const component = new ToolCallComponent( + { + id: 'call_question', + name: 'AskUserQuestion', + args: {}, + }, + { + tool_call_id: 'call_question', + output: JSON.stringify({ + answers: { + 'Favorite editor?': 'Vim', + }, + }), + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Collected your answers'); + expect(out).toContain('Favorite editor?'); + expect(out).toContain('Vim'); + expect(out).not.toContain('AskUserQuestion'); + }); + + it('renders background AskUserQuestion as a started task', () => { + const component = new ToolCallComponent( + { + id: 'call_background_question', + name: 'AskUserQuestion', + args: { background: true }, + }, + { + tool_call_id: 'call_background_question', + output: [ + 'task_id: question-aaaaaaaa', + 'description: Which database?', + 'status: running', + ].join('\n'), + is_error: false, + }, + ); + + const collapsed = strip(component.render(100).join('\n')); + expect(collapsed).toContain('Started background question'); + // Three lines of output fit the collapsed card whole. + expect(collapsed).toContain('task_id: question-aaaaaaaa'); + expect(collapsed).toContain('description: Which database?'); + expect(collapsed).toContain('status: running'); + expect(collapsed).not.toContain('Collected your answers'); + + component.setExpanded(true); + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('question-aaaaaaaa'); + }); + + it('renders GetGoal as a goal check without raw JSON', () => { + const component = new ToolCallComponent( + { + id: 'call_get_goal', + name: 'GetGoal', + args: {}, + }, + { + tool_call_id: 'call_get_goal', + output: JSON.stringify({ + goal: { + goalId: 'g1', + objective: 'Ship feature X', + status: 'active', + createdAt: '2026-01-01T00:00:00.000Z', + updatedAt: '2026-01-01T00:00:00.000Z', + startedBy: 'model', + updatedBy: 'model', + turnsUsed: 1, + tokensUsed: 800, + wallClockMs: 5000, + budget: { + tokenBudget: null, + turnBudget: null, + wallClockBudgetMs: null, + remainingTokens: null, + remainingTurns: null, + remainingWallClockMs: null, + tokenBudgetReached: false, + turnBudgetReached: false, + wallClockBudgetReached: false, + overBudget: false, + }, + }, + }), + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Checked goal'); + expect(out).toContain('Goal active: Ship feature X'); + expect(out).not.toContain('Used GetGoal'); + expect(out).not.toContain('"objective"'); + }); + + it('renders SetGoalBudget with a readable budget argument', () => { + const component = new ToolCallComponent( + { + id: 'call_goal_budget', + name: 'SetGoalBudget', + args: { value: 10, unit: 'turns' }, + }, + { + tool_call_id: 'call_goal_budget', + output: 'Goal budget set: 10 turns.', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Set goal budget (10 turns)'); + expect(out).not.toContain('Set goal budget (10 turns) · 10 turns'); + expect(out).not.toContain('Used SetGoalBudget (turns)'); + expect(out).not.toContain('Goal budget set: 10 turns.'); + }); + + it('renders successful SetGoalBudget headers with the primary goal marker', () => { + const previousLevel = chalk.level; + chalk.level = 3; + try { + const component = new ToolCallComponent( + { + id: 'call_goal_budget', + name: 'SetGoalBudget', + args: { value: 10, unit: 'turns' }, + }, + { + tool_call_id: 'call_goal_budget', + output: 'Goal budget set: 10 turns.', + is_error: false, + }, + ); + + const out = component.render(100).join('\n'); + expect(out).toContain(chalk.hex(darkColors.primary)(STATUS_BULLET)); + expect(out).not.toContain(chalk.hex(darkColors.success)(STATUS_BULLET)); + } finally { + chalk.level = previousLevel; + } + }); + + it('renders UpdateGoal as a model-reported status, not a user lifecycle marker', () => { + const component = new ToolCallComponent( + { + id: 'call_update_goal', + name: 'UpdateGoal', + args: { status: 'blocked' }, + }, + { + tool_call_id: 'call_update_goal', + output: 'Goal marked blocked.', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Reported goal blocked'); + expect(out).not.toContain('Updated goal (blocked)'); + expect(out).not.toContain('· blocked'); + expect(out).not.toContain('Goal marked blocked.'); + expect(out).not.toContain('● Goal blocked'); + }); + + it('renders successful UpdateGoal report headers entirely in the primary goal color', () => { + const previousLevel = chalk.level; + chalk.level = 3; + try { + for (const status of ['complete', 'blocked']) { + const component = new ToolCallComponent( + { + id: `call_update_goal_${status}`, + name: 'UpdateGoal', + args: { status }, + }, + { + tool_call_id: `call_update_goal_${status}`, + output: `Goal marked ${status}.`, + is_error: false, + }, + ); + + const out = component.render(100).join('\n'); + expect(out).toContain(chalk.hex(darkColors.primary)(STATUS_BULLET)); + expect(out).not.toContain(chalk.hex(darkColors.success)(STATUS_BULLET)); + } + } finally { + chalk.level = previousLevel; + } + }); + + it('appends a chip to the header once a result arrives', () => { + const component = new ToolCallComponent( + { + id: 'call_read', + name: 'Read', + args: { path: 'foo.ts' }, + }, + { + tool_call_id: 'call_read', + output: '1\tfoo\n2\tbar\n3\tbaz', + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Used Read'); + expect(out).toContain('· 3 lines'); + }); + + it('truncates a long file path from the head so the filename stays visible', () => { + const longPath = + 'apps/kimi-code/src/tui/components/messages/tool-renderers/long-path/example/final-file.ts'; + const component = new ToolCallComponent( + { + id: 'call_long_path', + name: 'Read', + args: { path: longPath }, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('final-file.ts'); + expect(out).toContain('…'); + expect(out).not.toContain('apps/kimi-code/src/tui/components/messages/tool-renderers/long-pa…'); + }); + + it('shows Read paths relative to the active workspace', () => { + const component = new ToolCallComponent( + { + id: 'call_workspace_read', + name: 'Read', + args: { path: '/tmp/proj-a/apps/kimi-code/src/main.ts' }, + }, + { + tool_call_id: 'call_workspace_read', + output: '1\tcontent', + is_error: false, + }, + undefined, + '/tmp/proj-a', + ); + + const out = strip(component.render(100).join('\n')); + const expectedReadPath = + process.platform === 'win32' ? 'apps\\kimi-code\\src\\main.ts' : 'apps/kimi-code/src/main.ts'; + expect(out).toContain(`Used Read (${expectedReadPath})`); + expect(out).not.toContain('/tmp/proj-a/apps'); + expect(component.getReadSnapshot().filePath).toBe(expectedReadPath); + }); + + it('keeps Read paths outside the active workspace absolute', () => { + const component = new ToolCallComponent( + { + id: 'call_external_read', + name: 'Read', + args: { path: '/tmp/proj-ab/src/main.ts' }, + }, + undefined, + undefined, + '/tmp/proj-a', + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Using Read (/tmp/proj-ab/src/main.ts)'); + expect(component.getReadSnapshot().filePath).toBe('/tmp/proj-ab/src/main.ts'); + }); + + it('does not append a chip while a tool is still running', () => { + const component = new ToolCallComponent( + { + id: 'call_pending', + name: 'Read', + args: { path: 'foo.ts' }, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Using Read'); + expect(out).not.toContain('lines'); + }); + + it('renders a single foreground subagent without the generic Agent tool header', () => { + vi.useFakeTimers(); + vi.setSystemTime(10_000); + const component = new ToolCallComponent( + { + id: 'call_agent', + name: 'Agent', + args: { description: 'explore project xxx' }, + }, + undefined, + ); + + component.onSubagentSpawned({ + agentId: 'sub_explore_123456', + agentName: 'explore', + runInBackground: false, + }); + + let out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Queued (explore project xxx) · 0 tools · 0s'); + expect(out).not.toContain('Using Agent'); + expect(out).not.toContain('Used Agent'); + + vi.setSystemTime(20_000); + component.appendSubagentText('think1\nthink2\nthink3', 'thinking'); + component.appendSubagentText('answer1\nanswer2\nanswer3', 'text'); + component.appendSubToolCall({ + id: 'sub_explore_123456:read', + name: 'Read', + args: { path: 'apps/kimi-code/src/tui/utils/background-agent-status.ts' }, + }); + + out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Running (explore project xxx) · 1 tool · 10s'); + expect(out).toContain('Using Read (apps/kimi-code/src/tui/utils/background-agent-status.ts)'); + // Thinking and text are mutually exclusive in the active window: the most + // recently streamed (text) wins, so thinking is hidden entirely. + expect(out).not.toContain('think1'); + expect(out).not.toContain('think2'); + expect(out).not.toContain('think3'); + expect(out).not.toContain('answer1'); + expect(out).toContain('answer2'); + expect(out).toContain('answer3'); + expect(out).toContain('│ answer3'); + + vi.setSystemTime(22_000); + component.onSubagentCompleted({ resultSummary: 'summary fallback' }); + component.setResult({ + tool_call_id: 'call_agent', + output: 'parent duplicate result', + is_error: false, + }); + vi.setSystemTime(30_000); + + out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Completed (explore project xxx) · 1 tool · 12s'); + expect(out).not.toContain('think3'); + expect(out).toContain('│ answer3'); + expect(out).not.toContain('Used Agent'); + expect(out).not.toContain('parent duplicate result'); + expect(out).not.toContain('summary fallback'); + }); + + it('shows the bound model in the subagent header and group snapshot once reported', () => { + vi.useFakeTimers(); + vi.setSystemTime(10_000); + const component = new ToolCallComponent( + { + id: 'call_agent_model', + name: 'Agent', + args: { description: 'explore project' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_model_1', + agentName: 'explore', + runInBackground: false, + }); + + let out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Queued (explore project) · 0 tools'); + expect(out).not.toContain('Kimi K2.5'); + + component.updateSubagentMetrics({ modelDisplay: 'Kimi K2.5' }); + + out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Queued (explore project) · Kimi K2.5 · 0 tools'); + expect(component.getSubagentSnapshot().model).toBe('Kimi K2.5'); + }); + + it('shows Backgrounded after a foreground subagent is detached, even after setResult', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_detach', + name: 'Agent', + args: { description: 'long task' }, + }, + undefined, + stubTui(30), + ); + component.onSubagentSpawned({ + agentId: 'sub_detach_1', + agentName: 'explore', + runInBackground: false, + }); + component.onSubagentStarted({ + agentId: 'sub_detach_1', + agentName: 'explore', + runInBackground: false, + }); + + // Sanity: running before detach. + expect(strip(component.render(120).join('\n'))).toContain('Running'); + + component.markBackgrounded(); + let out = strip(component.render(120).join('\n')); + expect(out).toContain('Backgrounded'); + expect(out).not.toContain('Completed'); + + // The spawn-success ToolResult landing must NOT flip the card to Completed. + component.setResult({ + tool_call_id: 'call_agent_detach', + output: 'agent_id: sub_detach_1\nactual_subagent_type: explore\n', + is_error: false, + }); + out = strip(component.render(120).join('\n')); + expect(out).toContain('Backgrounded'); + expect(out).not.toContain('Completed'); + + component.dispose(); + }); + + it('summarizes subagent tools as a count plus the current tool', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_tools', + name: 'Agent', + args: { description: 'inspect tools' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_tools', + agentName: 'explore', + runInBackground: false, + }); + + for (let i = 1; i <= 4; i++) { + const id = `sub_tools:read-${String(i)}`; + component.appendSubToolCall({ id, name: 'Read', args: { path: `file${String(i)}.ts` } }); + component.finishSubToolCall({ tool_call_id: id, output: 'ok', is_error: false }); + } + component.appendSubToolCall({ + id: 'sub_tools:grep', + name: 'Grep', + args: { pattern: 'auth' }, + }); + + const out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Running (inspect tools) · 5 tools · 0s'); + // Only the current (most recent ongoing) tool appears in the summary line. + expect(out).toContain('Using Grep (auth)'); + // No per-tool activity rows are rendered. + expect(out).not.toContain('file1.ts'); + expect(out).not.toContain('file2.ts'); + expect(out).not.toContain('file3.ts'); + expect(out).not.toContain('file4.ts'); + expect(out).not.toContain('Used Read'); + }); + + it('keeps the subagent tool summary pinned to the most recent tool', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_stable_tools', + name: 'Agent', + args: { description: 'inspect tools' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_tools', + agentName: 'explore', + runInBackground: false, + }); + + for (let i = 1; i <= 5; i++) { + component.appendSubToolCall({ + id: `sub_tools:read-${String(i)}`, + name: 'Read', + args: { path: `file${String(i)}.ts` }, + }); + } + component.appendSubToolCallDelta({ + id: 'sub_tools:read-1', + name: 'Read', + argumentsPart: '{"path":"file1-updated.ts"}', + }); + component.finishSubToolCall({ + tool_call_id: 'sub_tools:read-1', + output: 'ok', + is_error: false, + }); + + const out = strip(component.render(120).join('\n')); + // The updated/finished older tool must not surface in the summary. + expect(out).not.toContain('file1-updated.ts'); + expect(out).not.toContain('file2.ts'); + expect(out).not.toContain('file3.ts'); + expect(out).not.toContain('file4.ts'); + // Only the most recent ongoing tool is shown. + expect(out).toContain('Using Read (file5.ts)'); + }); + + it('wraps the single subagent active window with a hanging gutter', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_wrapped_text', + name: 'Agent', + args: { description: 'inspect wrapping' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_wrapped', + agentName: 'explore', + runInBackground: false, + }); + component.appendSubagentText( + 'output words that should also wrap with a clean hanging indent', + 'text', + ); + + const joined = strip(component.render(34).join('\n')); + // The two-row window drops the head of the wrapped paragraph. + expect(joined).not.toContain('output words that should'); + // Every kept row carries the `│` gutter as a hanging indent. + expect(joined).toContain('│ wrap with a clean hanging'); + expect(joined).toContain('│ indent'); + }); + + it('scrolls single subagent thinking to the last two display rows', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_scroll', + name: 'Agent', + args: { description: 'long think' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_scroll', + agentName: 'explore', + runInBackground: false, + }); + // A single long logical line (no newlines) wraps to many display rows; + // only the last THINKING_PREVIEW_LINES (2) should remain visible. + const segs = Array.from({ length: 30 }, (_, i) => `seg${String(i).padStart(2, '0')}`); + component.appendSubagentText(segs.join(' '), 'thinking'); + + const lines = strip(component.render(40).join('\n')).split('\n'); + const thinkingRows = lines.filter((l) => /seg\d\d/.test(l)); + expect(thinkingRows.length).toBe(2); + expect(lines.join('\n')).toContain('seg29'); + expect(lines.join('\n')).not.toContain('seg00'); + }); + + it('shows a two-row tail of an ongoing subagent Bash output', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_bash_out', + name: 'Agent', + args: { description: 'run bash' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_bash', + agentName: 'explore', + runInBackground: false, + }); + component.appendSubToolCall({ + id: 'sub_bash:cmd', + name: 'Bash', + args: { command: 'ls -la' }, + }); + const output = Array.from({ length: 10 }, (_, i) => `bash-line-${String(i)}`).join('\n'); + component.appendSubToolLiveOutput('sub_bash:cmd', output); + + let out = strip(component.render(120).join('\n')); + expect(out).toContain('Using Bash (ls -la)'); + // The active window keeps only the last two rows of live output. + expect(out).toContain('bash-line-8'); + expect(out).toContain('bash-line-9'); + expect(out).not.toContain('bash-line-7'); + // No ctrl+o promise for the subagent window. + expect(out).not.toContain('ctrl+o'); + + // The global ctrl+o expand toggle must NOT expand the window. + component.setExpanded(true); + out = strip(component.render(120).join('\n')); + expect(out).toContain('bash-line-9'); + expect(out).not.toContain('bash-line-7'); + }); + + it('shows live output for generic subagent tools but not for recognized ones', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_mixed', + name: 'Agent', + args: { description: 'mixed tools' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_mixed', + agentName: 'explore', + runInBackground: false, + }); + // A finished recognized tool: its output body never reaches the window. + component.appendSubToolCall({ + id: 'sub_mixed:read', + name: 'Read', + args: { path: 'foo.ts' }, + }); + component.finishSubToolCall({ + tool_call_id: 'sub_mixed:read', + output: 'recognized-read-body\nhidden-read-line', + is_error: false, + }); + // An ongoing generic (MCP) tool: its live output is the active stream. + component.appendSubToolCall({ + id: 'sub_mixed:mcp', + name: 'mcp__server__do', + args: {}, + }); + const mcpOut = Array.from({ length: 5 }, (_, i) => `mcp-line-${String(i)}`).join('\n'); + component.appendSubToolLiveOutput('sub_mixed:mcp', mcpOut); + + const out = strip(component.render(120).join('\n')); + // Recognized tool output never appears. + expect(out).not.toContain('recognized-read-body'); + // Generic tool output shows as the two-row active window tail. + expect(out).toContain('mcp-line-3'); + expect(out).toContain('mcp-line-4'); + expect(out).not.toContain('mcp-line-2'); + expect(out).not.toContain('ctrl+o'); + }); + + it('renders failed single subagents with the dedicated header and error text', () => { + vi.useFakeTimers(); + vi.setSystemTime(1000); + const component = new ToolCallComponent( + { + id: 'call_agent_failed', + name: 'Agent', + args: { description: 'check failure' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_failed', + agentName: 'explore', + runInBackground: false, + }); + + vi.setSystemTime(4000); + component.onSubagentFailed({ error: 'subagent exceeded max_steps' }); + + const out = strip(component.render(120).join('\n')); + expect(out).toContain('Explore Agent Failed (check failure) · 0 tools · 3s'); + expect(out).toContain('│ subagent exceeded max_steps'); + expect(out).not.toContain('Using Agent'); + expect(out).not.toContain('Used Agent'); + }); + + it('keeps the same card height between running and done', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const component = new ToolCallComponent( + { + id: 'call_agent_height', + name: 'Agent', + args: { description: 'height stable' }, + }, + undefined, + ); + component.onSubagentSpawned({ + agentId: 'sub_height', + agentName: 'explore', + runInBackground: false, + }); + component.appendSubToolCall({ id: 'sub_height:read', name: 'Read', args: { path: 'a.ts' } }); + component.appendSubagentText('short answer', 'text'); + + const runningLines = strip(component.render(120).join('\n')).split('\n').length; + + component.onSubagentCompleted({ resultSummary: 'short answer' }); + component.setResult({ tool_call_id: 'call_agent_height', output: 'done', is_error: false }); + + const doneLines = strip(component.render(120).join('\n')).split('\n').length; + + expect(doneLines).toBe(runningLines); + }); + + describe('background agent terminal state vs spawn-success ToolResult', () => { + // The Agent tool returns a "task spawned" result the moment a + // run_in_background=true call lands. That result is not an error and its + // body says `status: running`, so for backgrounded agents `this.result` + // alone cannot distinguish a successful completion from a failure / lost + // task. The fix is `setBackgroundTaskTerminalStatus`, which overrides the + // result-based derivation with the actual BackgroundTaskInfo status. + const spawnSuccessResult = { + tool_call_id: 'call_bg_agent', + output: [ + 'task_id: agent-deadbeef', + 'status: running', + 'agent_id: agent-0', + 'actual_subagent_type: coder', + 'automatic_notification: true', + ].join('\n'), + is_error: false, + }; + + function makeBackgroundAgentComponent(): ToolCallComponent { + const component = new ToolCallComponent( + { + id: 'call_bg_agent', + name: 'Agent', + args: { + description: 'background agent 1', + run_in_background: true, + }, + }, + spawnSuccessResult, + ); + component.onSubagentSpawned({ + agentId: 'agent-0', + agentName: 'coder', + runInBackground: true, + }); + return component; + } + + it('reads as "done" by default after spawn — the existing behavior the fix replaces', () => { + // This pins the legacy behavior. Without overrides the snapshot + // trusts the spawn-success result and reports phase='done'. The + // 'lost' / 'killed' / 'failed' overrides below must beat this. + const component = makeBackgroundAgentComponent(); + expect(component.getSubagentSnapshot().phase).toBe('done'); + }); + + it('setBackgroundTaskTerminalStatus("lost") flips the snapshot phase to "failed"', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('lost'); + const snap = component.getSubagentSnapshot(); + expect(snap.phase).toBe('failed'); + // The agent-group renderer uses snap.errorText for the "Error:" line. + // The spawn-success ToolResult must NOT leak as the failure message. + expect(snap.errorText).toContain('lost'); + expect(snap.errorText).not.toContain('task_id:'); + }); + + it('setBackgroundTaskTerminalStatus("killed") flips the snapshot phase to "failed"', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('killed'); + const snap = component.getSubagentSnapshot(); + expect(snap.phase).toBe('failed'); + expect(snap.errorText).toContain('killed'); + expect(snap.errorText).not.toContain('task_id:'); + }); + + it('setBackgroundTaskTerminalStatus("failed") flips the snapshot phase to "failed"', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('failed'); + const snap = component.getSubagentSnapshot(); + expect(snap.phase).toBe('failed'); + expect(snap.errorText).toContain('failed'); + expect(snap.errorText).not.toContain('task_id:'); + }); + + it('setBackgroundTaskTerminalStatus("completed") keeps the snapshot phase at "done"', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('completed'); + const snap = component.getSubagentSnapshot(); + expect(snap.phase).toBe('done'); + expect(snap.errorText).toBeUndefined(); + }); + + it('overrides win even when set before the spawn-success result is recorded', () => { + // Order-independence guard: reconcile may run before tool result + // has been replayed back into the component on some boot paths. + const component = new ToolCallComponent( + { + id: 'call_bg_agent', + name: 'Agent', + args: { description: 'background agent A', run_in_background: true }, + }, + undefined, + ); + component.setBackgroundTaskTerminalStatus('lost'); + // Now the spawn-success result lands. + component.setResult({ ...spawnSuccessResult, tool_call_id: 'call_bg_agent' }); + expect(component.getSubagentSnapshot().phase).toBe('failed'); + }); + + // Standalone render path — when only ONE Agent tool call lands in a + // step, the card is never upgraded into an `AgentGroupComponent` and is + // mounted on its own. The standalone header derives its label from + // `getDerivedSubagentPhase()` (separate from `getSubagentSnapshot`). + // Without the override threading into that path AND a header rebuild, + // a lost bg agent keeps the green "✓ Completed" label. + it('standalone render: lost bg agent must show Failed/Lost, not Completed', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('lost'); + const out = strip(component.render(120).join('\n')); + expect(out).not.toContain('Completed'); + expect(out).toMatch(/Failed|Lost/); + // Friendly failure message must reach the rendered card. + expect(out).toContain('lost'); + expect(out).not.toContain('task_id:'); + }); + + it('standalone render: completed bg agent still shows Completed', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('completed'); + const out = strip(component.render(120).join('\n')); + expect(out).toContain('Completed'); + expect(out).not.toMatch(/Failed/); + expect(out).not.toContain('task_id:'); + }); + + // Stable id routing — `tc.subagentAgentId` is left undefined for + // backgrounded agents both live (`handleSubagentSpawned` early-returns + // for `runInBackground`, never calling tc.onSubagentSpawned) and on + // resume (the wire format does not carry a `subagent` block back into + // `applySubagentReplay`). The AgentTool's spawn-success ToolResult, + // however, always carries `agent_id: agent-N` — fall back to parsing + // that so callers asking `getSubagentAgentId` always get the right id, + // and `applyBackgroundTaskTerminalStatus` can route by id instead of + // by description (which collides between unrelated cards). + it('getSubagentAgentId parses agent_id from the spawn-success ToolResult', () => { + const component = new ToolCallComponent( + { + id: 'call_bg_agent', + name: 'Agent', + args: { description: 'background agent 1', run_in_background: true }, + }, + spawnSuccessResult, + ); + // No spawn metadata was wired in — exactly the resume / backgrounded + // case we are guarding against. + expect(component.getSubagentAgentId()).toBe('agent-0'); + }); + + it('getSubagentAgentId still prefers in-memory subagent metadata when set', () => { + // If `setSubagentMeta` / `onSubagentSpawned` did wire an id, that one + // is authoritative — it survived the in-flight phase before any + // ToolResult landed and can disambiguate concurrent calls. + const component = new ToolCallComponent( + { + id: 'call_bg_agent', + name: 'Agent', + args: { description: 'X', run_in_background: true }, + }, + spawnSuccessResult, + ); + component.setSubagentMeta('agent-explicit', 'coder'); + expect(component.getSubagentAgentId()).toBe('agent-explicit'); + }); + + it('getSubagentAgentId returns undefined for non-Agent tool calls even when output looks similar', () => { + const component = new ToolCallComponent( + { + id: 'call_bash', + name: 'Bash', + args: { command: 'echo agent_id: agent-fake' }, + }, + { + tool_call_id: 'call_bash', + output: 'agent_id: agent-fake\nstatus: running', + is_error: false, + }, + ); + expect(component.getSubagentAgentId()).toBeUndefined(); + }); + + it('setBackgroundTaskTerminalStatus errorText overwrites the friendly generic', () => { + // Live failures arrive via `subagent.failed` with the real error from + // the subagent loop. That string is far more informative than the + // generic "Background agent failed" fallback the friendly path emits. + // When the caller supplies errorText it must win, regardless of + // whether the friendly message was written first. + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('failed'); + expect(component.getSubagentSnapshot().errorText).toBe('Background agent failed'); + + component.setBackgroundTaskTerminalStatus('failed', { + errorText: 'subagent exceeded max_steps', + }); + expect(component.getSubagentSnapshot().errorText).toBe('subagent exceeded max_steps'); + }); + + it('setBackgroundTaskTerminalStatus errorText is written even on first call', () => { + const component = makeBackgroundAgentComponent(); + component.setBackgroundTaskTerminalStatus('failed', { + errorText: 'OAuth refresh failed', + }); + expect(component.getSubagentSnapshot().errorText).toBe('OAuth refresh failed'); + }); + + it('setBackgroundTaskTerminalStatus does not overwrite a real onSubagentFailed error with the generic', () => { + const component = makeBackgroundAgentComponent(); + component.onSubagentFailed({ error: 'real crash from subagent' }); + // background.task.terminated event arrives later without an errorText + // override; the friendly generic must NOT clobber the real message. + component.setBackgroundTaskTerminalStatus('failed'); + expect(component.getSubagentSnapshot().errorText).toBe('real crash from subagent'); + }); + }); + + it('scrolls the Write streaming preview to the last COMMAND_PREVIEW_LINES', () => { + const lines: string[] = []; + for (let i = 1; i <= 30; i++) lines.push(`line${String(i)}`); + const escaped = lines.join('\\n'); + const component = new ToolCallComponent( + { + id: 'call_write_stream', + name: 'Write', + args: { file_path: 'foo.ts', content: lines.join('\n') }, + streamingArguments: `{"file_path":"foo.ts","content":"${escaped}`, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Using Write'); + // Streaming preview caps at COMMAND_PREVIEW_LINES (10) and shows the tail. + expect(out).not.toContain('line1'); + expect(out).not.toContain('line20'); + expect(out).toContain('line21'); + expect(out).toContain('line30'); + // Line numbers should reflect actual file positions. + expect(out).toContain(' 21'); + expect(out).toContain(' 30'); + expect(out).not.toContain('ctrl+o to expand'); + }); + + it('switches a streaming tool call to Truncated when the step ended with max_tokens', () => { + const lines: string[] = []; + for (let i = 1; i <= 10; i++) lines.push(`line${String(i)}`); + const escaped = lines.join('\\n'); + const component = new ToolCallComponent( + { + id: 'call_write_truncated', + name: 'Write', + args: { file_path: 'foo.ts', content: lines.join('\n') }, + streamingArguments: `{"file_path":"foo.ts","content":"${escaped}`, + truncated: true, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Truncated Write'); + expect(out).not.toContain('Preparing Write'); + expect(out).toContain('Tool call arguments truncated by max_tokens'); + // The live argument preview must NOT render once the call is + // truncated — leaving the half-streamed Write content on screen + // was the original "preparing write" bug. + expect(out).not.toContain('line1'); + expect(out).not.toContain('line10'); + }); + + it('renders a stable Edit progress placeholder during the streaming delta window', () => { + vi.useFakeTimers(); + vi.setSystemTime(4000); + const oldLines: string[] = []; + const newLines: string[] = []; + for (let i = 1; i <= 20; i++) { + oldLines.push(`old${String(i)}`); + newLines.push(`new${String(i)}`); + } + const oldEscaped = oldLines.join('\\n'); + const newEscaped = newLines.join('\\n'); + const streaming = `{"file_path":"foo.ts","old_string":"${oldEscaped}","new_string":"${newEscaped}`; + const component = new ToolCallComponent( + { + id: 'call_edit_stream', + name: 'Edit', + args: { + file_path: 'foo.ts', + old_string: oldLines.join('\n'), + new_string: newLines.join('\n'), + }, + streamingArguments: streaming, + streamingStartedAtMs: 0, + }, + undefined, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Using Edit'); + expect(out).toContain('foo.ts'); + expect(out).toContain('Preparing changes for foo.ts...'); + expect(out).toContain('4s elapsed'); + expect(out).toMatch(/\d+(?:\.\d+)? (?:B|KB|MB)/); + expect(out).not.toContain('old20'); + expect(out).not.toContain('new20'); + expect(out).not.toMatch(/^\s*\d+\s+[+-]\s/m); + expect(out).not.toContain('ctrl+o to expand'); + }); + + it('caps the Write preview between finalized args and result to keep transcript height stable', () => { + // The wire sequence is: tool.call.delta → ... → tool.call (final + // args, no streamingArguments) → tool.result. Between tool.call and + // tool.result we briefly sit with finalized args and no result yet — + // even without an approval panel, at least one render tick can land + // in this state. The preview must stay capped so the transcript + // height does not balloon and then snap back when the result lands; + // a big shrink triggers pi-tui's full-redraw path which wipes the + // terminal scrollback (history before TUI start). + const lines: string[] = []; + for (let i = 1; i <= 30; i++) lines.push(`line${String(i)}`); + const component = new ToolCallComponent( + { + id: 'call_write_pending', + name: 'Write', + args: { file_path: 'foo.ts', content: lines.join('\n') }, + // No streamingArguments → finalized args; no result yet. + }, + undefined, + ); + const out = strip(component.render(100).join('\n')); + expect(out).toContain('line1'); + expect(out).toContain('line10'); + expect(out).not.toContain('line11'); + expect(out).not.toContain('line25'); + expect(out).toContain('ctrl+o to expand'); + }); + + it('snaps a long Write preview to the collapsed cap when the result arrives', () => { + const lines: string[] = []; + for (let i = 1; i <= 30; i++) lines.push(`line${String(i)}`); + const escaped = lines.join('\\n'); + const component = new ToolCallComponent( + { + id: 'call_write_snap', + name: 'Write', + args: { file_path: 'big.txt', content: lines.join('\n') }, + streamingArguments: `{"file_path":"big.txt","content":"${escaped}"}`, + }, + undefined, + ); + expect(strip(component.render(100).join('\n'))).toContain('line25'); + + component.setResult({ + tool_call_id: 'call_write_snap', + output: 'Wrote big.txt', + is_error: false, + }); + + const after = strip(component.render(100).join('\n')); + expect(after).toContain('line1'); + expect(after).not.toContain('line25'); + expect(after).toContain('ctrl+o to expand'); + }); + + it('refreshes the header when file_path arrives in a later streaming delta', () => { + // First delta: only an opening brace, no file_path yet. + const component = new ToolCallComponent( + { + id: 'call_write_path', + name: 'Write', + args: {}, + streamingArguments: '{', + }, + undefined, + ); + const before = strip(component.render(100).join('\n')); + expect(before).toContain('Using Write'); + expect(before).not.toContain('foo.ts'); + + // Later delta: file_path is now parseable from streamingArguments. + component.updateToolCall({ + id: 'call_write_path', + name: 'Write', + args: { file_path: 'foo.ts' }, + streamingArguments: '{"file_path":"foo.ts","content":"hello', + }); + const after = strip(component.render(100).join('\n')); + expect(after).toContain('foo.ts'); + }); + + it('builds the call preview when finalized args arrive after streaming', () => { + // Mimic the wire sequence: tool.call.delta → ... → tool.call (finalized). + const component = new ToolCallComponent( + { + id: 'call_write_seq', + name: 'Write', + args: { file_path: 'foo.ts', content: 'a\nb' }, + streamingArguments: '{"file_path":"foo.ts","content":"a\\nb', + }, + undefined, + ); + // While streaming, body is rendered live from streamingArguments. + expect(strip(component.render(100).join('\n'))).toMatch(/^\s*1\s+a\s*$/m); + + // Finalized tool.call: streamingArguments is undefined; the body + // re-renders from finalized args, content unchanged. + component.updateToolCall({ + id: 'call_write_seq', + name: 'Write', + args: { file_path: 'foo.ts', content: 'a\nb' }, + }); + const out = strip(component.render(100).join('\n')); + expect(out).toMatch(/^\s*1\s+a\s*$/m); + expect(out).toMatch(/^\s*2\s+b\s*$/m); + }); + + it('builds the Edit diff when finalized args arrive after streaming', () => { + const component = new ToolCallComponent( + { + id: 'call_edit_seq', + name: 'Edit', + args: { file_path: 'foo.ts' }, + streamingArguments: '{"file_path":"foo.ts","old_string":"a\\nb","new_string":"a\\nB', + streamingStartedAtMs: Date.now(), + }, + undefined, + ); + expect(strip(component.render(100).join('\n'))).toContain('Preparing changes'); + expect(strip(component.render(100).join('\n'))).not.toMatch(/^\s*\d+\s+[+-]\s/m); + + component.updateToolCall({ + id: 'call_edit_seq', + name: 'Edit', + args: { file_path: 'foo.ts', old_string: 'a\nb', new_string: 'a\nB' }, + }); + const out = strip(component.render(100).join('\n')); + expect(out).toContain('foo.ts'); + expect(out).toMatch(/^\s*2\s+- b\s*$/m); + expect(out).toMatch(/^\s*2\s+\+ B\s*$/m); + }); + + it('refreshes and stops the Edit streaming progress timer', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + const ui = { requestRender: vi.fn() }; + const component = new ToolCallComponent( + { + id: 'call_edit_timer', + name: 'Edit', + args: { file_path: 'foo.ts' }, + streamingArguments: '{"file_path":"foo.ts","old_string":"a', + streamingStartedAtMs: 0, + }, + undefined, + ui as never, + ); + + expect(strip(component.render(100).join('\n'))).toContain('0s elapsed'); + vi.advanceTimersByTime(1000); + expect(ui.requestRender).toHaveBeenCalled(); + expect(strip(component.render(100).join('\n'))).toContain('1s elapsed'); + + ui.requestRender.mockClear(); + component.setResult({ + tool_call_id: 'call_edit_timer', + output: 'Replaced 1 occurrence in foo.ts', + is_error: false, + }); + vi.advanceTimersByTime(1000); + expect(ui.requestRender).not.toHaveBeenCalled(); + + const componentToDispose = new ToolCallComponent( + { + id: 'call_edit_dispose', + name: 'Edit', + args: { file_path: 'bar.ts' }, + streamingArguments: '{"file_path":"bar.ts","old_string":"a', + streamingStartedAtMs: 0, + }, + undefined, + ui as never, + ); + ui.requestRender.mockClear(); + componentToDispose.dispose(); + vi.advanceTimersByTime(1000); + expect(ui.requestRender).not.toHaveBeenCalled(); + }); + + it('expands the Write call preview when ctrl+o expansion is set', () => { + const lines: string[] = []; + for (let i = 1; i <= 30; i++) lines.push(`line${String(i)}`); + const component = new ToolCallComponent( + { + id: 'call_write_done', + name: 'Write', + args: { file_path: 'big.txt', content: lines.join('\n') }, + }, + { + tool_call_id: 'call_write_done', + output: 'Wrote big.txt', + is_error: false, + }, + ); + + const collapsed = strip(component.render(100).join('\n')); + expect(collapsed).toContain('line1'); + expect(collapsed).toContain('line10'); + expect(collapsed).not.toContain('line25'); + expect(collapsed).toContain('ctrl+o to expand'); + + component.setExpanded(true); + + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('line25'); + expect(expanded).toContain('line30'); + expect(expanded).not.toContain('ctrl+o to expand'); + }); + + it('renders unknown Write file extensions as plain text without stderr noise', () => { + const stderr = captureProcessWrite('stderr'); + try { + const component = new ToolCallComponent( + { + id: 'call_write_unknown_ext', + name: 'Write', + args: { file_path: 'demo.abcxyz', content: 'hello\nworld' }, + }, + { + tool_call_id: 'call_write_unknown_ext', + output: 'Wrote demo.abcxyz', + is_error: false, + }, + ); + + const collapsed = strip(component.render(100).join('\n')); + expect(collapsed).toContain('hello'); + + component.setExpanded(true); + const expanded = strip(component.render(100).join('\n')); + expect(expanded).toContain('world'); + expect(stderr.text()).not.toContain('Could not find the language'); + } finally { + stderr.restore(); + } + }); + + describe('WaitFor header', () => { + const waitForCompletedOutput = [ + 'wait_status: completed', + 'task_id: question-80w0h7nw', + 'waited_ms: 9607', + 'timeout_ms: 300000', + '', + '[finished]', + 'task_id: question-80w0h7nw', + 'description: demo question', + 'status: completed', + 'kind: question', + ].join('\n'); + + it('shows the waiting tense with the task id while pending', () => { + const component = new ToolCallComponent( + { + id: 'call_wait_pending', + name: 'WaitFor', + args: { task_id: 'question-80w0h7nw', timeout: 300 }, + }, + undefined, + stubTui(30), + ); + + expect(strip(component.render(100).join('\n'))).toContain( + 'Waiting for background task (question-80w0h7nw)', + ); + + component.dispose(); + }); + + it('falls back to "any background task" when no task id is given', () => { + const component = new ToolCallComponent( + { id: 'call_wait_any', name: 'WaitFor', args: { timeout: 300 } }, + undefined, + stubTui(30), + ); + + expect(strip(component.render(100).join('\n'))).toContain('Waiting for any background task'); + + component.dispose(); + }); + + it('shows the waited tense with the elapsed chip once completed', () => { + const component = new ToolCallComponent( + { + id: 'call_wait_done', + name: 'WaitFor', + args: { task_id: 'question-80w0h7nw', timeout: 300 }, + }, + { + tool_call_id: 'call_wait_done', + output: waitForCompletedOutput, + is_error: false, + }, + ); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Waited for background task (question-80w0h7nw)'); + expect(out).toContain('10s'); + }); + + it('renders a timeout as its own non-error header', () => { + const component = new ToolCallComponent( + { + id: 'call_wait_timeout', + name: 'WaitFor', + args: { task_id: 'question-80w0h7nw', timeout: 1 }, + }, + { + tool_call_id: 'call_wait_timeout', + output: 'wait_status: timed_out\ntask_id: question-80w0h7nw\nwaited_ms: 1000\ntimeout_ms: 1000', + is_error: false, + }, + ); + + expect(strip(component.render(100).join('\n'))).toContain( + 'Wait timed out (question-80w0h7nw)', + ); + }); + + it('renders errors with the failure tense', () => { + const component = new ToolCallComponent( + { + id: 'call_wait_error', + name: 'WaitFor', + args: { task_id: 'bash-x', timeout: 300 }, + }, + { + tool_call_id: 'call_wait_error', + output: 'Task not found: bash-x', + is_error: true, + }, + ); + + expect(strip(component.render(100).join('\n'))).toContain( + 'Could not wait for background task (bash-x)', + ); + }); + + it('replaces the previous status block when progress arrives with replace', () => { + const component = new ToolCallComponent( + { id: 'call_wait_replace', name: 'WaitFor', args: { timeout: 600 } }, + undefined, + stubTui(30), + ); + + component.appendProgress('Waiting 10s / 600s · 2 background tasks still running', { + replace: true, + }); + component.appendProgress('Waiting 20s / 600s · 1 background task still running', { + replace: true, + }); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('Waiting 20s / 600s'); + expect(out).not.toContain('Waiting 10s / 600s'); + + component.dispose(); + }); + + it('keeps appending status rows when replace is not set', () => { + const component = new ToolCallComponent( + { id: 'call_wait_append', name: 'WaitFor', args: { timeout: 600 } }, + undefined, + stubTui(30), + ); + + component.appendProgress('first status'); + component.appendProgress('second status'); + + const out = strip(component.render(100).join('\n')); + expect(out).toContain('first status'); + expect(out).toContain('second status'); + + component.dispose(); + }); + + it('replaces a sub-tool status row when child progress arrives with replace', () => { + const component = new ToolCallComponent( + { id: 'call_agent_wait', name: 'Agent', args: { description: 'child wait' } }, + undefined, + stubTui(30), + ); + component.onSubagentSpawned({ + agentId: 'sub_wait_1', + agentName: 'coder', + runInBackground: false, + }); + component.appendSubToolCall({ + id: 'sub_wait_1:wait', + name: 'WaitFor', + args: { timeout: 600 }, + }); + + component.appendSubToolLiveOutput( + 'sub_wait_1:wait', + 'Waiting 10s / 600s · 2 background tasks still running\n', + { replace: true }, + ); + component.appendSubToolLiveOutput( + 'sub_wait_1:wait', + 'Waiting 20s / 600s · 1 background task still running\n', + { replace: true }, + ); + + const out = strip(component.render(120).join('\n')); + expect(out).toContain('Waiting 20s / 600s'); + expect(out).not.toContain('Waiting 10s / 600s'); + + component.dispose(); + }); + }); +}); + +describe('ToolCallComponent hasHiddenContent', () => { + function card( + name: string, + args: Record, + output?: string, + isError = false, + ): ToolCallComponent { + return new ToolCallComponent( + { id: 'tc', name, args }, + output === undefined ? undefined : { tool_call_id: 'tc', output, is_error: isError }, + ); + } + + it('is false while a short Bash result is shown whole and true once lines are folded', () => { + expect(card('Bash', { command: 'ls' }, 'a\nb\nc').hasHiddenContent()).toBe(false); + expect(card('Bash', { command: 'ls' }, 'a\nb\nc\nd').hasHiddenContent()).toBe(true); + }); + + it('counts a multi-line command as hidden because only its first line is in the header', () => { + expect(card('Bash', { command: 'echo a\necho b' }, 'ok').hasHiddenContent()).toBe(true); + }); + + it('treats bodies that only render when expanded as hidden', () => { + expect(card('Read', { path: 'a.ts' }, '1\tfoo').hasHiddenContent()).toBe(true); + expect(card('Grep', { pattern: 'x' }, 'a.ts').hasHiddenContent()).toBe(true); + }); + + it('is false for a short failure preview and for suppressed bodies', () => { + expect(card('Bash', { command: 'ls' }, 'boom', true).hasHiddenContent()).toBe(false); + expect(card('AskUserQuestion', {}, 'a\nb\nc\nd\ne').hasHiddenContent()).toBe(false); + }); + + it('follows the live output while running and the result once it lands', () => { + const component = card('Bash', { command: 'ls' }); + expect(component.hasHiddenContent()).toBe(false); + component.appendLiveOutput('one\ntwo\n'); + expect(component.hasHiddenContent()).toBe(true); + component.setResult({ tool_call_id: 'tc', output: 'one\ntwo', is_error: false }); + expect(component.hasHiddenContent()).toBe(false); + component.dispose(); + }); + + it('counts a width-cut outcome row as hidden at that width', () => { + const longLine = 'x'.repeat(120); + const component = card('Bash', { command: 'ls' }, `${longLine}\nshort`); + // Two lines are shown whole, so by line count nothing is hidden… + expect(component.hasHiddenContent()).toBe(false); + // …but at 40 columns the first row is cut and ctrl+o reveals it wrapped. + component.render(40); + expect(component.hasHiddenContent()).toBe(true); + component.render(200); + expect(component.hasHiddenContent()).toBe(false); + component.dispose(); + }); + + it('counts a width-cut Bash command header as hidden, but not a cut key argument', () => { + const bash = card('Bash', { command: `echo ${'a'.repeat(150)}` }, 'ok'); + bash.render(40); + // The full command renders in the body once expanded. + expect(bash.hasHiddenContent()).toBe(true); + bash.dispose(); + + const generic = card('TaskOutput', { task_id: `bg-${'x'.repeat(150)}` }, 'ok'); + generic.render(40); + // The output is shown whole and a cut header argument is not what ctrl+o + // reveals for a generic tool. + expect(generic.hasHiddenContent()).toBe(false); + generic.dispose(); + }); + + it('is false for an ExitPlanMode outcome card and true for a non-outcome result', () => { + const approved = [ + 'Exited plan mode. Selected approach: rebuild the parser', + '', + '## Approved Plan:', + '1. read the grammar', + '2. port the tests', + '3. run the suite', + ].join('\n'); + // The plan is fully rendered by the call preview and the outcome body is + // expansion-independent, so ctrl+o would change nothing. + expect(card('ExitPlanMode', {}, approved).hasHiddenContent()).toBe(false); + // A non-outcome result (an error message) still counts by lines. + expect(card('ExitPlanMode', {}, 'a\nb\nc\nd').hasHiddenContent()).toBe(true); + }); + + it('counts an Edit with distant hunks as hidden when the clustered preview overflows', () => { + const lines = Array.from({ length: 30 }, (_, i) => `line${String(i + 1)}`); + const oldStr = lines.join('\n'); + const distant = [...lines]; + distant[0] = 'line1 changed'; + distant[29] = 'line30 changed'; + // Two changed rows far apart: context rows and the inter-hunk separator + // push the clustered preview past the cap even though added+removed is 2. + expect( + card('Edit', { file_path: 'a.ts', old_string: oldStr, new_string: distant.join('\n') }, 'ok').hasHiddenContent(), + ).toBe(true); + + const nearby = [...lines]; + nearby[0] = 'line1 changed'; + nearby[1] = 'line2 changed'; + expect( + card('Edit', { file_path: 'a.ts', old_string: oldStr, new_string: nearby.join('\n') }, 'ok').hasHiddenContent(), + ).toBe(false); + }); +}); + +describe('ToolCallComponent hasHiddenContent for a solo subagent card', () => { + it('is false because the fixed subagent window never changes with ctrl+o', () => { + const component = new ToolCallComponent( + { id: 'call_agent', name: 'Agent', args: { description: 'explore' } }, + undefined, + ); + component.onSubagentSpawned({ agentId: 'sub_1', agentName: 'explore', runInBackground: false }); + component.setResult({ + tool_call_id: 'call_agent', + output: 'line 1\nline 2\nline 3\nline 4\nline 5', + is_error: false, + }); + expect(component.hasHiddenContent()).toBe(false); + component.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent for width-cut and background results', () => { + function card( + name: string, + args: Record, + output: string, + isError = false, + ): ToolCallComponent { + return new ToolCallComponent( + { id: 'tc', name, args }, + { tool_call_id: 'tc', output, is_error: isError }, + ); + } + + it('follows the line-count rule for a background question', () => { + const legacyBlock = [ + 'task_id: question-aaaaaaaa', + 'description: Which database?', + 'status: running', + 'automatic_notification: true', + 'next_step: Continue your current work.', + 'next_step: Use TaskOutput for a snapshot.', + 'next_step: Use TaskStop only to cancel.', + 'human_shell_hint: The pending question is also visible in /tasks.', + ].join('\n'); + expect(card('AskUserQuestion', { background: true }, legacyBlock).hasHiddenContent()).toBe(true); + const shortBlock = 'task_id: question-aaaaaaaa\nstatus: running\nnext_step: Continue your work.'; + expect(card('AskUserQuestion', { background: true }, shortBlock).hasHiddenContent()).toBe(false); + expect(card('AskUserQuestion', {}, legacyBlock).hasHiddenContent()).toBe(false); + }); + + it('treats a failure whose one long line wraps past the preview as hidden, and keeps that while expanded', () => { + const longError = `Error: ${'x'.repeat(200)}`; + const bash = card('Bash', { command: 'ls' }, longError, true); + expect(bash.hasHiddenContent()).toBe(false); + bash.render(40); + expect(bash.hasHiddenContent()).toBe(true); + bash.setExpanded(true); + bash.render(40); + expect(bash.hasHiddenContent()).toBe(true); + bash.dispose(); + + const generic = card('SomethingUnknown', {}, longError, true); + generic.render(40); + expect(generic.hasHiddenContent()).toBe(true); + generic.dispose(); + }); +}); + +describe('ToolCallComponent with spilled tool output', () => { + it('drops the chip and shows the envelope line for an oversized Read', () => { + const envelope = [ + 'Tool output exceeded 50000 characters; the full output was saved to a file.', + 'tool_name: Read', + 'tool_call_id: call_read_big', + 'output_size_chars: 90000', + 'output_path: /tmp/kimi/tool-output.txt', + 'next_step: Use Read with output_path to page through the saved output, or Grep to search it.', + '', + '[preview: chars [0, 10)]', + '1\tline one', + ].join('\n'); + const component = new ToolCallComponent( + { id: 'call_read_big', name: 'Read', args: { path: 'big.log' } }, + { tool_call_id: 'call_read_big', output: envelope, is_error: false }, + ); + const rows = component.render(120).map(strip).filter((line) => line.trim().length > 0); + expect(rows[0]).toContain('Used Read (big.log)'); + expect(rows[0]).not.toContain('lines'); + expect(rows[1]).toContain('Tool output exceeded 50000 characters'); + component.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent with a capped call preview', () => { + const twelveLines = Array.from({ length: 12 }, (_, i) => `line ${String(i + 1)}`).join('\n'); + + it('counts a capped Write preview as hidden even when the call failed with a short error', () => { + const failed = new ToolCallComponent( + { id: 'call_write', name: 'Write', args: { path: 'a.txt', content: twelveLines } }, + { tool_call_id: 'call_write', output: 'Permission denied', is_error: true }, + ); + expect(failed.hasHiddenContent()).toBe(true); + failed.dispose(); + + const running = new ToolCallComponent( + { id: 'call_write_running', name: 'Write', args: { path: 'a.txt', content: twelveLines } }, + undefined, + ); + expect(running.hasHiddenContent()).toBe(true); + running.dispose(); + + const short = new ToolCallComponent( + { id: 'call_write_short', name: 'Write', args: { path: 'a.txt', content: 'one\ntwo' } }, + { tool_call_id: 'call_write_short', output: 'Permission denied', is_error: true }, + ); + expect(short.hasHiddenContent()).toBe(false); + short.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent for a call truncated by max_tokens', () => { + it('reports nothing to expand, since the card only shows the never-executed note', () => { + const component = new ToolCallComponent( + { + id: 'call_cut', + name: 'Bash', + args: { command: 'echo one\necho two\necho three' }, + truncated: true, + }, + undefined, + ); + expect(component.hasHiddenContent()).toBe(false); + component.render(30); + expect(component.hasHiddenContent()).toBe(false); + component.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent for goal cards', () => { + it('reports nothing to expand for a parsed goal snapshot or a bodiless goal update', () => { + // The tool wraps the snapshot in a `goal` envelope (null when there is no goal). + const snapshot = JSON.stringify( + { + goal: { + goalId: 'g1', + objective: 'Ship the feature', + status: 'active', + turnsUsed: 3, + tokensUsed: 100, + wallClockMs: 1000, + budget: { tokenBudget: null, turnBudget: null, wallClockBudgetMs: null }, + }, + }, + null, + 2, + ); + const getGoal = new ToolCallComponent( + { id: 'call_get_goal', name: 'GetGoal', args: {} }, + { tool_call_id: 'call_get_goal', output: snapshot, is_error: false }, + ); + expect(getGoal.hasHiddenContent()).toBe(false); + getGoal.dispose(); + + const update = new ToolCallComponent( + { id: 'call_update_goal', name: 'UpdateGoal', args: { status: 'paused' } }, + { tool_call_id: 'call_update_goal', output: snapshot, is_error: false }, + ); + expect(update.hasHiddenContent()).toBe(false); + update.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent at the Edit preview cap', () => { + function editCard(lineCount: number): ToolCallComponent { + const oldStr = Array.from({ length: lineCount }, (_, i) => `old ${String(i + 1)}`).join('\n'); + const newStr = Array.from({ length: lineCount }, (_, i) => `new ${String(i + 1)}`).join('\n'); + return new ToolCallComponent( + { id: 'call_edit', name: 'Edit', args: { path: 'a.ts', old_string: oldStr, new_string: newStr } }, + { tool_call_id: 'call_edit', output: 'Edited a.ts', is_error: false }, + ); + } + + it('is false when the body fills the cap exactly, since the header row is not capped', () => { + // 5 replaced lines render as 5 deletions plus 5 additions: 10 body rows. + const exact = editCard(5); + expect(exact.hasHiddenContent()).toBe(false); + exact.dispose(); + // 6 replaced lines are 12 body rows: the capped preview cuts two of them. + const over = editCard(6); + expect(over.hasHiddenContent()).toBe(true); + over.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent for ReadMediaFile', () => { + function mediaCard(output: string): ToolCallComponent { + return new ToolCallComponent( + { id: 'call_media', name: 'ReadMediaFile', args: { path: '/tmp/a.png' } }, + { tool_call_id: 'call_media', output, is_error: false }, + ); + } + + it('is true for a media envelope and follows the line-count rule for anything else', () => { + const envelope = JSON.stringify([ + { type: 'text', text: '' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,iVBORw0KGgo=' } }, + { type: 'text', text: '' }, + ]); + const media = mediaCard(envelope); + expect(media.hasHiddenContent()).toBe(true); + media.dispose(); + + const plain = mediaCard('unsupported format\nfalling back to text'); + expect(plain.hasHiddenContent()).toBe(false); + plain.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent for a search cut short before any row', () => { + it('is false, since the notice renders the same way in both states', () => { + const glob = new ToolCallComponent( + { id: 'call_glob', name: 'Glob', args: { pattern: '**/*.ts' } }, + { tool_call_id: 'call_glob', output: 'Glob timed out after 60s; partial results returned.', is_error: false }, + ); + expect(glob.hasHiddenContent()).toBe(false); + glob.dispose(); + + const grep = new ToolCallComponent( + { id: 'call_grep', name: 'Grep', args: { pattern: 'foo' } }, + { tool_call_id: 'call_grep', output: 'a.ts\nGrep timed out after 30s; partial results returned.', is_error: false }, + ); + expect(grep.hasHiddenContent()).toBe(true); + grep.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent for WaitFor', () => { + it('is true for a parsed wait, whose raw result only appears when expanded', () => { + const component = new ToolCallComponent( + { id: 'call_wait', name: 'WaitFor', args: { timeout: 30 } }, + { + tool_call_id: 'call_wait', + output: 'wait_status: no_tasks\nwaited_ms: 0\ntimeout_ms: 30000', + is_error: false, + }, + ); + expect(component.hasHiddenContent()).toBe(true); + component.dispose(); + }); +}); + +describe('ToolCallComponent hasHiddenContent while arguments stream', () => { + it('is false for Write and Edit, whose streaming previews ignore the toggle, and true for a Bash command', () => { + const content = Array.from({ length: 12 }, (_, i) => `line ${String(i + 1)}`).join('\\n'); + const write = new ToolCallComponent( + { + id: 'call_w', + name: 'Write', + args: { path: 'a.txt', content: content.replaceAll('\\n', '\n') }, + streamingArguments: `{"path":"a.txt","content":"${content}`, + }, + undefined, + ); + expect(write.hasHiddenContent()).toBe(false); + write.dispose(); + + const bash = new ToolCallComponent( + { id: 'call_b', name: 'Bash', args: {}, streamingArguments: '{"command":"pnpm te' }, + undefined, + ); + expect(bash.hasHiddenContent()).toBe(true); + bash.dispose(); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/tool-renderers/chip.test.ts b/apps/kimi-code/test/tui/components/messages/tool-renderers/chip.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..849ce82b7e241c5f7afe2775e62bcc435ebec409 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/tool-renderers/chip.test.ts @@ -0,0 +1,491 @@ +import { describe, expect, it } from 'vitest'; + +import { + computeEditStats, + computeWriteStats, + pickChip, +} from '#/tui/components/messages/tool-renderers/chip'; +import type { ToolCallBlockData, ToolResultBlockData } from '#/tui/types'; + +function strip(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +function call(name: string, args: Record = {}): ToolCallBlockData { + return { id: 'tc', name, args }; +} + +function result(output: string, isError = false): ToolResultBlockData { + return { tool_call_id: 'tc', output, is_error: isError }; +} + +function chipFor(name: string, args: Record, out: ToolResultBlockData): string { + const provider = pickChip(name); + return strip(provider?.(call(name, args), out) ?? ''); +} + +describe('chip registry', () => { + it('Bash has no chip (exit code is not surfaced)', () => { + expect(pickChip('AskUserQuestion')).toBeUndefined(); + }); + + it('Edit chip shows +N -M from args diff', () => { + const c = chipFor( + 'Edit', + { path: 'foo.ts', old_string: 'a\nb\nc', new_string: 'a\nB\nc\nd' }, + result('Replaced 1 occurrence in foo.ts'), + ); + expect(c).toMatch(/\+\d+/); + expect(c).toMatch(/-\d+/); + }); + + it('Write chip shows N lines from content arg', () => { + expect(chipFor('Write', { path: 'a.txt', content: 'a\nb\nc\n' }, result('Wrote a.txt'))).toBe( + '3 lines', + ); + }); + + it('Read chip shows line count', () => { + expect(chipFor('Read', { path: 'a.ts' }, result('1\tfoo\n2\tbar\n3\tbaz'))).toBe('3 lines'); + }); + + it('Read chip handles single line as singular', () => { + expect(chipFor('Read', { path: 'a.ts' }, result('1\tfoo'))).toBe('1 line'); + }); + + it('Grep chip counts files in the default files_with_matches mode', () => { + expect(chipFor('Grep', { pattern: 'foo' }, result('a.ts\nb.ts\nc.ts'))).toBe('3 files'); + expect(chipFor('Grep', { pattern: 'foo' }, result('a.ts'))).toBe('1 file'); + }); + + it('Grep chip counts matches and their files in content mode', () => { + const content = { pattern: 'foo', output_mode: 'content' }; + expect(chipFor('Grep', content, result('src/a.ts:1:foo\nsrc/a.ts:9:foo\nsrc/b.ts:2:foo'))).toBe( + '3 matches across 2 files', + ); + expect(chipFor('Grep', content, result('src/a.ts:1:foo\nsrc/a.ts:9:foo'))).toBe( + '2 matches in 1 file', + ); + // Context lines and group separators are not matches. + expect( + chipFor('Grep', content, result('src/a.ts-1-import x\nsrc/a.ts:2:foo\n--\nsrc/b.ts:5:foo')), + ).toBe('2 matches across 2 files'); + }); + + it('Grep chip sums the per-file counts in count_matches mode', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'count_matches' }, + result('Found 5 total occurrences across 2 files.\nsrc/a.ts:3\nsrc/b.ts:2'), + ), + ).toBe('5 matches across 2 files'); + }); + + it('Grep chip counts files only when unnumbered content rows can be context', () => { + // `-n: false` with context flags: match and context rows are both + // `path:text` (the backend separates fields with ':' unconditionally), + // so an exact match count is unknowable and the chip falls back to files. + const unnumberedContext = { pattern: 'foo', output_mode: 'content', '-n': false, '-C': 1 }; + expect( + chipFor('Grep', unnumberedContext, result('src/a.ts:import x\nsrc/a.ts:foo\nsrc/b.ts:foo')), + ).toBe('2 files'); + // Without context flags every row is a match, so the count stays exact. + const unnumbered = { pattern: 'foo', output_mode: 'content', '-n': false }; + expect(chipFor('Grep', unnumbered, result('src/a.ts:foo\nsrc/a.ts:bar\nsrc/b.ts:foo'))).toBe( + '3 matches across 2 files', + ); + }); + + it('Grep chip leaves the notices out of the count', () => { + expect(chipFor('Grep', { pattern: 'foo' }, result(''))).toBe('no matches'); + expect(chipFor('Grep', { pattern: 'foo' }, result('No matches found'))).toBe('no matches'); + expect( + chipFor( + 'Grep', + { pattern: 'foo' }, + result('a.ts\nb.ts\nResults truncated to 2 lines (total: 9). Use offset=2 to see more.'), + ), + ).toBe('9 files'); + }); + + it('Glob chip leaves the empty-result sentence out of the count', () => { + expect(chipFor('Glob', { pattern: '*.ts' }, result('No matches found'))).toBe('no files'); + }); + + it('Glob chip leaves the backend diagnostics out of the count', () => { + expect( + chipFor( + 'Glob', + { pattern: '**/*.ts' }, + result( + [ + 'Glob timed out after 60s; partial results returned.', + '[stdout truncated at 65536 bytes; results may be incomplete — use a more specific pattern]', + 'Glob completed with warnings; some directories could not be read: EACCES /root', + '[Truncated at 200 matches — use a more specific pattern]', + 'Only the first 200 matches are returned.', + 'a.ts', + 'b.ts', + 'Found 200 matches', + ].join('\n'), + ), + ), + // The timeout and cap notices mark the set incomplete: the count is a lower bound. + ).toBe('2+ files'); + }); + + it('Glob chip shows file count', () => { + expect(chipFor('Glob', { pattern: '**/*.ts' }, result('a.ts\nb.ts'))).toBe('2 files'); + }); + + it.each([ + 'To retrieve all collected matches in one search, omit offset and use head_limit=0.', + 'To remove the match-count limit, omit offset and use head_limit=0.', + ])('counts only paths on a Glob page with continuation notice: %s', (notice) => { + const output = [ + 'Showing matches 1–100 of 347.', + 'Continue with the same search arguments and offset=100.', + notice, + ...Array.from({ length: 100 }, (_, i) => `file-${String(i)}.ts`), + ].join('\n'); + expect(chipFor('Glob', {}, result(output))).toBe('100+ files'); + }); + + it.each([ + 'No more matches at offset=347 in the current result set (347 matches).', + 'No matches collected; search incomplete.', + ])('does not count an empty Glob page as a file: %s', (output) => { + expect(chipFor('Glob', {}, result(output))).toBe(''); + }); + + it('distinguishes the last Glob page from incomplete search results', () => { + expect(chipFor('Glob', {}, result('Showing matches 3–4 of 4.\nc.ts\nd.ts'))).toBe('2 files'); + expect(chipFor('Glob', {}, result('Showing matches 3–4 of 4 collected matches (partial result set).\nc.ts\nd.ts'))).toBe('2+ files'); + }); + + it('keeps notice-like file names and leaves Grep interpretation unchanged', () => { + expect(chipFor('Glob', {}, result('Showing matches.ts\nContinue with.txt\nNo more matches.ts'))).toBe('3 files'); + expect(chipFor('Grep', {}, result('Showing matches 1–2 of 3.'))).toBe('1 file'); + }); + + it('FetchURL chip shows size and is non-empty', () => { + const out = chipFor('FetchURL', { url: 'https://example.com' }, result('hello world')); + expect(out).toMatch(/\d+\s*B/); + }); + + it('WebSearch chip shows result count', () => { + expect(chipFor('WebSearch', { query: 'kimi' }, result('1. Alpha\n2. Beta\n3. Gamma'))).toBe( + '3 results', + ); + }); + + it('Think tool has no chip', () => { + expect(pickChip('Think')).toBeUndefined(); + }); + + it('GetGoal chip shows the current status', () => { + expect(chipFor('GetGoal', {}, result('{"goal":{"status":"active"}}'))).toBe('active'); + }); + + it('GetGoal chip shows when there is no current goal', () => { + expect(chipFor('GetGoal', {}, result('{"goal":null}'))).toBe('no goal'); + }); + + it('CreateGoal chip shows the created status', () => { + expect(chipFor('CreateGoal', { objective: 'Ship feature X' }, result('{"goal":{"status":"active"}}'))).toBe('active'); + }); + + it('SetGoalBudget has no chip because the budget is in the header argument', () => { + expect(pickChip('SetGoalBudget')).toBeUndefined(); + }); + + it('UpdateGoal has no chip because the status is in the header label', () => { + expect(pickChip('UpdateGoal')).toBeUndefined(); + }); + + it('Unknown tools have no chip', () => { + expect(pickChip('SomethingElse')).toBeUndefined(); + }); +}); + +describe('computeWriteStats', () => { + it('returns zero lines for empty content', () => { + expect(computeWriteStats({})).toEqual({ lines: 0 }); + expect(computeWriteStats({ content: '' })).toEqual({ lines: 0 }); + }); + + it('counts a single line with no trailing newline', () => { + expect(computeWriteStats({ content: 'hello' })).toEqual({ lines: 1 }); + }); + + it('ignores trailing newline so "a\\nb\\n" is 2 lines', () => { + expect(computeWriteStats({ content: 'a\nb\n' })).toEqual({ lines: 2 }); + expect(computeWriteStats({ content: 'a\nb' })).toEqual({ lines: 2 }); + }); +}); + +describe('computeEditStats', () => { + it('returns zero when both strings are empty', () => { + expect(computeEditStats({})).toEqual({ added: 0, removed: 0 }); + expect(computeEditStats({ old_string: '', new_string: '' })).toEqual({ + added: 0, + removed: 0, + }); + }); + + it('counts added and removed lines for a replacement', () => { + const stats = computeEditStats({ old_string: 'a\nb\nc', new_string: 'a\nB\nc\nd' }); + expect(stats.added).toBeGreaterThan(0); + expect(stats.removed).toBeGreaterThan(0); + }); + + it('counts only adds when old is empty', () => { + const stats = computeEditStats({ old_string: '', new_string: 'x\ny\nz' }); + expect(stats.added).toBe(3); + expect(stats.removed).toBe(0); + }); +}); + +describe('Bash chip', () => { + it('counts the hidden output lines once they outgrow the collapsed card', () => { + const chip = pickChip('Bash')!; + const call = { id: 'tc', name: 'Bash', args: { command: 'ls' } }; + // One outcome line stands in for the rest, so the chip counts what is hidden. + expect(chip(call, { tool_call_id: 'tc', output: 'a\n\nb\nc\nd\n', is_error: false })).toBe('3 more lines'); + expect(chip(call, { tool_call_id: 'tc', output: 'a\nb\nc\nd\ne', is_error: false })).toBe('4 more lines'); + // Up to three lines are shown whole on the collapsed card, so no chip. + expect(chip(call, { tool_call_id: 'tc', output: 'a\n\nb\nc\n', is_error: false })).toBe(''); + expect(chip(call, { tool_call_id: 'tc', output: 'only', is_error: false })).toBe(''); + expect(chip(call, { tool_call_id: 'tc', output: '', is_error: false })).toBe(''); + }); +}); + +describe('Bash chip on a failed command', () => { + it('stays silent so the error preview trailer owns the hidden-line count', () => { + const chip = pickChip('Bash')!; + const call = { id: 'tc', name: 'Bash', args: { command: 'ls' } }; + expect(chip(call, { tool_call_id: 'tc', output: 'a\nb\nc\nd\ne', is_error: true })).toBe(''); + }); +}); + +describe('Grep chip without line numbers', () => { + it('counts every row as a match but each file once', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'content', '-n': false }, + result('a.ts:foo\na.ts:foo again\nb.ts:foo'), + ), + ).toBe('3 matches across 2 files'); + }); +}); + +describe('Grep chip on paginated and unusual output', () => { + it('uses the count-mode summary total instead of the current page', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'count_matches', head_limit: 2 }, + result( + 'Found 40 total occurrences across 12 files.\nResults truncated to 2 lines (total: 12). Use offset=2 to see more.\na.ts:3\nb.ts:2', + ), + ), + ).toBe('40 matches across 12 files'); + }); + + it('keeps a Windows drive letter inside the path of an unnumbered content row', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'content', '-n': false }, + result('C:/outside/a.ts:foo\nC:/outside/b.ts:foo'), + ), + ).toBe('2 matches across 2 files'); + }); + + it('leaves the continuation lines of a Glob traversal warning out of the file count', () => { + expect( + chipFor( + 'Glob', + { pattern: '**/*.ts' }, + result( + 'Glob completed with warnings; some directories could not be read: rg: /x: Permission denied (os error 13)\nrg: /y: Permission denied (os error 13)\na.ts\nb.ts', + ), + ), + ).toBe('2+ files'); // unreadable directories make the count a lower bound + }); +}); + +describe('Grep chip on an empty count-mode page', () => { + it('keeps the summary totals when the offset is past the last row', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'count_matches', offset: 12 }, + result('Found 40 total occurrences across 12 files.'), + ), + ).toBe('40 matches across 12 files'); + }); +}); + +describe('Bash chip and whitespace-only rows', () => { + it('counts rows the way the outcome rows do, so blank separators never claim hidden lines', () => { + const chip = pickChip('Bash')!; + const call = { id: 'tc', name: 'Bash', args: { command: 'ls' } }; + expect(chip(call, { tool_call_id: 'tc', output: 'a\n \nb\nc', is_error: false })).toBe(''); + expect(chip(call, { tool_call_id: 'tc', output: 'a\n \nb\nc\nd', is_error: false })).toBe( + '3 more lines', + ); + }); +}); + +describe('Grep chip on paginated content results', () => { + const page = 'src/a.ts:1:foo\nsrc/a.ts:9:foo\nsrc/b.ts:2:foo'; + const notice = 'Results truncated to 3 lines (total: 1000). Use offset=3 to see more.'; + + it('reports the tool total and leaves the files out, since only the page is known', () => { + expect( + chipFor('Grep', { pattern: 'foo', output_mode: 'content', head_limit: 3 }, result(`${page}\n${notice}`)), + ).toBe('1000 matches'); + }); + + it('still counts only the page files when context rows make matches uncountable', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'content', '-n': false, '-C': 1, head_limit: 3 }, + result(`src/a.ts:foo\nsrc/a.ts:bar\nsrc/b.ts:foo\n${notice}`), + ), + ).toBe('2 files'); + }); +}); + +describe('Grep and Glob chips on an incomplete result set', () => { + it('marks the counts as lower bounds when Grep timed out or hit its output cap', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo' }, + result( + 'a.ts\nb.ts\nGrep timed out after 30s; partial results returned. Narrow the path, glob, or pattern and retry for complete results.', + ), + ), + ).toBe('2+ files'); + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'count_matches' }, + result( + 'Found 40 total occurrences across 12 files.\na.ts:30\nb.ts:10\n[Output truncated at 1048576 bytes of rg output — the result set is incomplete. Narrow the pattern, path, or glob filters and re-run to recover complete results.]', + ), + ), + ).toBe('40+ matches across 12+ files'); + }); + + it('marks a capped Glob result the same way', () => { + expect( + chipFor( + 'Glob', + { pattern: '**/*.ts' }, + result( + '[Truncated at 1000 matches — use a more specific pattern]\nOnly the first 1000 matches are returned.\na.ts\nb.ts', + ), + ), + ).toBe('2+ files'); + }); +}); + +describe('Grep chip on paginated numbered content with context rows', () => { + it('counts the page rows instead of the pagination total, which includes context rows', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'content', '-C': 1, head_limit: 4 }, + result( + 'src/a.ts-1-import x\nsrc/a.ts:2:foo\nsrc/a.ts-3-export y\n--\nResults truncated to 4 lines (total: 12). Use offset=4 to see more.', + ), + ), + ).toBe('1 match in 1 file'); + }); +}); + +describe('Grep chip with a zero-valued context flag', () => { + it('keeps the exact match count, since -C 0 asks for no context rows', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'content', '-n': false, '-C': 0 }, + result('src/a.ts:foo\nsrc/a.ts:foo again\nsrc/b.ts:foo'), + ), + ).toBe('3 matches across 2 files'); + }); +}); + +describe('Grep chip when -C overrides -A/-B', () => { + it('follows the effective flag, since a defined -C makes the backend drop -A and -B', () => { + expect( + chipFor( + 'Grep', + { pattern: 'foo', output_mode: 'content', '-n': false, '-C': 0, '-A': 2 }, + result('src/a.ts:foo\nsrc/a.ts:foo again\nsrc/b.ts:foo'), + ), + ).toBe('3 matches across 2 files'); + }); +}); + +describe('chips for a search the tool cut short before any row', () => { + it('stay silent so the notice row is not contradicted by an exact-looking count', () => { + expect( + chipFor( + 'Glob', + { pattern: '**/*.ts' }, + result('Glob timed out after 60s; partial results returned.'), + ), + ).toBe(''); + expect( + chipFor( + 'Grep', + { pattern: 'foo' }, + result( + '[Output truncated at 1048576 bytes of rg output — the result set is incomplete. Narrow the pattern, path, or glob filters and re-run to recover complete results.]', + ), + ), + ).toBe(''); + }); +}); + +describe('Glob chip with unreadable directories', () => { + it('reads as a lower bound, since part of the tree was skipped', () => { + expect( + chipFor( + 'Glob', + { pattern: '**/*.ts' }, + result('Glob completed with warnings; some directories could not be read: rg: /x: Permission denied\na.ts\nb.ts'), + ), + ).toBe('2+ files'); + }); +}); + +describe('chips and the per-line spill pointer', () => { + const pointer = + '[Per-line truncation occurred; the complete output was saved to a file.\noutput_path: /tmp/kimi/tool-output.txt\nnext_step: Use Read with output_path to page through the saved output, or Grep to search it.]'; + + it('leave the appended pointer out of line and file counts', () => { + const chip = pickChip('Bash')!; + const call = { id: 'tc', name: 'Bash', args: { command: 'cat x' } }; + expect(chip(call, { tool_call_id: 'tc', output: `a\nb\nc\nd\n${pointer}`, is_error: false })).toBe('3 more lines'); + expect(chipFor('Grep', { pattern: 'foo' }, result(`a.ts\nb.ts\n${pointer}`))).toBe('2 files'); + }); +}); + +describe('chips when every match was a filtered sensitive file', () => { + it('stay silent so the notice row explains the empty listing', () => { + expect( + chipFor('Grep', { pattern: 'secret' }, result('No non-sensitive matches found\nFiltered 2 sensitive file(s): .env, secrets.json')), + ).toBe(''); + expect( + chipFor('Glob', { pattern: '**/.env*' }, result('No non-sensitive matches found (2 sensitive file(s) filtered).')), + ).toBe(''); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/tool-renderers/media.test.ts b/apps/kimi-code/test/tui/components/messages/tool-renderers/media.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb3ec3ac6474f08961e30ce873f01a7df1235055 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/tool-renderers/media.test.ts @@ -0,0 +1,158 @@ +import type { Component } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { + parseReadMediaOutput, + readMediaChip, + readMediaSummary, +} from '#/tui/components/messages/tool-renderers/media'; +import { darkColors } from '#/tui/theme/colors'; +import type { ToolCallBlockData, ToolResultBlockData } from '#/tui/types'; + +function strip(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +function joinRender(components: Component[], width = 100): string { + return components.flatMap((c) => c.render(width)).join('\n'); +} + +function call(name: string, args: Record = {}): ToolCallBlockData { + return { id: 'tc', name, args }; +} + +function result(output: string, isError = false): ToolResultBlockData { + return { tool_call_id: 'tc', output, is_error: isError }; +} + +const ctx = { expanded: false, colors: darkColors }; +const expandedCtx = { expanded: true, colors: darkColors }; + +// 1x1 transparent png base64 (≈70 bytes once decoded) +const PNG_B64 = + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; +const PNG_DATA_URL = `data:image/png;base64,${PNG_B64}`; + +function imageOutput(path: string, b64 = PNG_B64, mime = 'image/png'): string { + return JSON.stringify([ + { type: 'text', text: `` }, + { type: 'image_url', imageUrl: { url: `data:${mime};base64,${b64}` } }, + { type: 'text', text: '' }, + ]); +} + +function videoOutput(path: string, mime = 'video/mp4'): string { + return JSON.stringify([ + { type: 'text', text: `' }, + ]); +} + +describe('parseReadMediaOutput', () => { + it('extracts kind, path, mime type, and bytes from an image data URL', () => { + const m = parseReadMediaOutput(imageOutput('/tmp/a.png')); + expect(m).not.toBeNull(); + expect(m?.kind).toBe('image'); + expect(m?.path).toBe('/tmp/a.png'); + expect(m?.mimeType).toBe('image/png'); + expect(m?.bytes).toBeGreaterThan(0); + }); + + it('extracts video kind and mime', () => { + const m = parseReadMediaOutput(videoOutput('/tmp/a.mp4')); + expect(m?.kind).toBe('video'); + expect(m?.mimeType).toBe('video/mp4'); + }); + + it('captures non-data video URL when uploader was used', () => { + const out = JSON.stringify([ + { type: 'text', text: `' }, + ]); + const m = parseReadMediaOutput(out); + expect(m?.kind).toBe('video'); + expect(m?.url).toBe('https://cdn.example/v/abc'); + expect(m?.bytes).toBeUndefined(); + }); + + it('returns null for non-JSON output', () => { + expect(parseReadMediaOutput('not json')).toBeNull(); + }); + + it('returns null when no media part is present', () => { + expect(parseReadMediaOutput(JSON.stringify([{ type: 'text', text: 'hi' }]))).toBeNull(); + }); +}); + +describe('readMediaChip', () => { + it('returns a compact summary for an image', () => { + const text = strip(readMediaChip(call('ReadMediaFile'), result(imageOutput('/tmp/a.png')))); + expect(text).toMatch(/image/); + expect(text).toContain('image/png'); + expect(text).toMatch(/B|KB|MB/); + }); + + it('returns empty string on error so the truncated body shows the error', () => { + expect(readMediaChip(call('ReadMediaFile'), result('boom', true))).toBe(''); + }); + + it('returns empty string when output is unparseable', () => { + expect(readMediaChip(call('ReadMediaFile'), result('garbage'))).toBe(''); + }); +}); + +describe('readMediaSummary renderer', () => { + it('renders an empty body when collapsed (chip carries the info)', () => { + const out = joinRender( + readMediaSummary(call('ReadMediaFile'), result(imageOutput('/tmp/a.png')), ctx), + ); + expect(out.trim()).toBe(''); + }); + + it('renders path + meta line when expanded — never the base64 blob', () => { + const out = strip( + joinRender( + readMediaSummary(call('ReadMediaFile'), result(imageOutput('/tmp/a.png')), expandedCtx), + ), + ); + expect(out).toContain('/tmp/a.png'); + expect(out).toContain('image/png'); + // Crucially: the base64 must never reach the screen. + expect(out).not.toContain(PNG_B64); + expect(out).not.toContain(PNG_DATA_URL); + }); + + it('falls back to truncated renderer for errors', () => { + const out = strip( + joinRender( + readMediaSummary( + call('ReadMediaFile', { path: '/tmp/x.png' }), + result('File not found', true), + ctx, + ), + ), + ); + expect(out).toContain('File not found'); + }); + + it('falls back to truncated renderer when the output is not the media envelope', () => { + // Collapsed: the fallback renderer's outcome row is the first output line. + const collapsed = strip( + joinRender( + readMediaSummary(call('ReadMediaFile'), result('"some plain string output"'), ctx), + ), + ); + expect(collapsed).toBe(' "some plain string output"'); + const out = strip( + joinRender( + readMediaSummary(call('ReadMediaFile'), result('"some plain string output"'), { + ...ctx, + expanded: true, + }), + ), + ); + expect(out).toContain('some plain string output'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/tool-renderers/registry.test.ts b/apps/kimi-code/test/tui/components/messages/tool-renderers/registry.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..81b488c19457ed51c95116673dbe157c1f8f2c7f --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/tool-renderers/registry.test.ts @@ -0,0 +1,644 @@ +import type { Component } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { + isGenericToolResult, + pickResultRenderer, +} from '#/tui/components/messages/tool-renderers/registry'; +import { darkColors } from '#/tui/theme/colors'; +import type { ToolCallBlockData, ToolResultBlockData } from '#/tui/types'; + +function strip(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +function joinRender(components: Component[], width = 100): string { + return components.flatMap((c) => c.render(width)).join('\n'); +} + +function call(name: string, args: Record = {}): ToolCallBlockData { + return { id: 'tc', name, args }; +} + +function result(output: string, isError = false): ToolResultBlockData { + return { tool_call_id: 'tc', output, is_error: isError }; +} + +const ctx = { expanded: false, colors: darkColors }; +const expandedCtx = { expanded: true, colors: darkColors }; + +function goalOutput(overrides: Record = {}): string { + return JSON.stringify({ + goal: { + goalId: 'g1', + objective: 'Ship feature X', + status: 'active', + createdAt: '2026-01-01T00:00:00.000Z', + updatedAt: '2026-01-01T00:00:00.000Z', + startedBy: 'model', + updatedBy: 'model', + turnsUsed: 2, + tokensUsed: 1234, + wallClockMs: 61000, + budget: { + tokenBudget: null, + turnBudget: null, + wallClockBudgetMs: null, + remainingTokens: null, + remainingTurns: null, + remainingWallClockMs: null, + tokenBudgetReached: false, + turnBudgetReached: false, + wallClockBudgetReached: false, + overBudget: false, + }, + ...overrides, + }, + }); +} + +describe('tool-result registry', () => { + it('falls back to truncated renderer for unknown tools: first line marked, full when expanded', () => { + const renderer = pickResultRenderer('SomethingUnknown'); + const collapsed = strip( + joinRender(renderer(call('SomethingUnknown'), result('\na\nb\nc\nd\ne'), ctx)), + ); + expect(collapsed).toBe(' a …'); + + const expanded = strip( + joinRender(renderer(call('SomethingUnknown'), result('a\nb\nc\nd\ne'), expandedCtx)), + ); + expect(expanded).toContain('a'); + expect(expanded).toContain('e'); + expect(expanded).not.toContain('ctrl+o to expand'); + }); + + it('keeps a failing unknown tool\'s output previewed while collapsed', () => { + const renderer = pickResultRenderer('SomethingUnknown'); + const out = strip( + joinRender( + renderer(call('SomethingUnknown'), result('a\nb\nc\nd\ne', true), ctx), + ), + ); + expect(out).toContain('a'); + expect(out).toContain('c'); + expect(out).not.toContain('\nd'); + expect(out).toContain('… (2 more lines, ctrl+o to expand)'); + }); + + it('uses the shell renderer for Bash: marked last line collapsed, raw output expanded', () => { + const renderer = pickResultRenderer('Bash'); + expect(strip(joinRender(renderer(call('Bash'), result('one\ntwo\nthree\nfour'), ctx)))).toBe( + ' … four', + ); + const out = strip( + joinRender(renderer(call('Bash'), result('one\ntwo\nthree\nfour'), expandedCtx)), + ); + expect(out).toContain('one'); + expect(out).toContain('four'); + }); + + it('Read renders no body when collapsed (header chip carries the count)', () => { + const renderer = pickResultRenderer('Read'); + const out = joinRender( + renderer(call('Read', { path: 'foo.ts' }), result('1\tfoo\n2\tbar'), ctx), + ); + expect(out.trim()).toBe(''); + }); + + it('Read expands to the raw file content when expanded', () => { + const renderer = pickResultRenderer('Read'); + const out = strip( + joinRender(renderer(call('Read', { path: 'foo.ts' }), result('1\tfoo\n2\tbar'), expandedCtx)), + ); + expect(out).toContain('foo'); + expect(out).toContain('bar'); + }); + + it('Grep renders its glance as the outcome row when collapsed', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo' }), + result('src/a.ts\nsrc/b.ts\nsrc/c.ts\nsrc/d.ts\nsrc/e.ts'), + ctx, + ), + ), + ); + expect(out).toBe(' src/a.ts, src/b.ts, src/c.ts, +2 more'); + }); + + it('keeps the "+N more" count when the glance samples overflow the width', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo' }), + result('src/aaaa.ts\nsrc/bbbb.ts\nsrc/cccc.ts\nsrc/dddd.ts\nsrc/eeee.ts'), + ctx, + ), + 40, + ), + ); + // The samples are cut to fit; the count in the fixed tail always survives. + expect(out.endsWith(', +2 more')).toBe(true); + expect(out).toContain('…'); + }); + + it('Grep glance lists path samples above the raw output when expanded', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo' }), + result('src/a.ts\nsrc/b.ts\nsrc/c.ts\nsrc/d.ts\nsrc/e.ts'), + expandedCtx, + ), + ), + ); + expect(out).toContain('src/a.ts, src/b.ts, src/c.ts, +2 more'); + expect(out).toContain('src/d.ts'); + }); + + it('Grep glance strips trailing :line:text in content mode', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo', output_mode: 'content' }), + result('src/a.ts:42: foo()\nsrc/b.ts:7:foo'), + expandedCtx, + ), + ), + ); + expect(out).toContain('src/a.ts:42, src/b.ts:7'); + }); + + it('Grep glance skips the count_matches summary line', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo', output_mode: 'count_matches' }), + result('Found 5 total occurrences across 2 files.\nsrc/a.ts:3\nsrc/b.ts:2'), + ctx, + ), + ), + ); + expect(out).toBe(' src/a.ts:3, src/b.ts:2'); + }); + + it('shows a short unknown-tool output whole while collapsed', () => { + const renderer = pickResultRenderer('SomethingUnknown'); + expect(strip(joinRender(renderer(call('SomethingUnknown'), result('a\nb'), ctx)))).toBe( + ' a\n b', + ); + }); + + it('Grep with empty result renders nothing in collapsed state', () => { + const renderer = pickResultRenderer('Grep'); + const out = joinRender(renderer(call('Grep', { pattern: 'foo' }), result(''), ctx)); + expect(out.trim()).toBe(''); + }); + + it('Glob glance lists path samples when expanded', () => { + const renderer = pickResultRenderer('Glob'); + expect( + strip( + joinRender( + renderer(call('Glob', { pattern: '**/*.ts' }), result('a.ts\nb.ts\nc.ts\nd.ts'), ctx), + ), + ), + ).toBe(' a.ts, b.ts, c.ts, +1 more'); + const out = strip( + joinRender( + renderer( + call('Glob', { pattern: '**/*.ts' }), + result('a.ts\nb.ts\nc.ts\nd.ts'), + expandedCtx, + ), + ), + ); + expect(out).toContain('a.ts'); + expect(out).toContain('b.ts'); + expect(out).toContain('c.ts'); + expect(out).toContain('+1 more'); + }); + + it('keeps Glob pagination notices out of the collapsed path samples', () => { + const output = 'Showing matches 1–2 of 4.\nCharacter limit reached; only complete paths are returned.\nContinue with the same search arguments and offset=2.\na.ts\nb.ts'; + const renderer = pickResultRenderer('Glob'); + expect(strip(joinRender(renderer(call('Glob'), result(output), ctx)))).toBe(' a.ts, b.ts'); + expect(strip(joinRender(renderer(call('Glob'), result(output), expandedCtx)))).toContain('Character limit reached'); + }); + + it.each([ + 'No more matches at offset=347 in the current result set (347 matches).', + 'No matches collected; search incomplete.', + ])('shows a Glob empty-page notice as the outcome: %s', (output) => { + const renderer = pickResultRenderer('Glob'); + expect(strip(joinRender(renderer(call('Glob'), result(output), ctx), 160))).toBe(` ${output}`); + }); + + it('FetchURL renders no body when collapsed', () => { + const renderer = pickResultRenderer('FetchURL'); + const out = joinRender( + renderer(call('FetchURL', { url: 'https://example.com/x' }), result('...'), ctx), + ); + expect(out.trim()).toBe(''); + }); + + it('WebSearch renders no body when collapsed', () => { + const renderer = pickResultRenderer('WebSearch'); + const out = joinRender( + renderer(call('WebSearch', { query: 'kimi' }), result('1. Alpha\n2. Beta'), ctx), + ); + expect(out.trim()).toBe(''); + }); + + it('Edit renders no body when collapsed', () => { + const renderer = pickResultRenderer('Edit'); + const out = joinRender( + renderer( + call('Edit', { path: 'foo.ts', old_string: 'a', new_string: 'b' }), + result('Replaced 1 occurrence in foo.ts'), + ctx, + ), + ); + expect(out.trim()).toBe(''); + }); + + it('Write renders no body when collapsed', () => { + const renderer = pickResultRenderer('Write'); + const out = joinRender( + renderer(call('Write', { path: 'a.txt', content: 'a\nb\n' }), result('Wrote 4 bytes to a.txt'), ctx), + ); + expect(out.trim()).toBe(''); + }); + + it('Think renders no body even with a thought arg', () => { + const renderer = pickResultRenderer('Think'); + const out = joinRender(renderer(call('Think', { thought: 'hello' }), result('Recorded.'), ctx)); + expect(out.trim()).toBe(''); + }); + + it('GetGoal renders a compact goal summary instead of raw JSON', () => { + const renderer = pickResultRenderer('GetGoal'); + const out = strip(joinRender(renderer(call('GetGoal'), result(goalOutput()), ctx))); + expect(out).toContain('Goal active: Ship feature X'); + expect(out).toContain('2 turns'); + expect(out).toContain('1.2k tokens'); + expect(out).toContain('1m 01s'); + expect(out).not.toContain('"objective"'); + expect(out).not.toContain('"budget"'); + }); + + it('GetGoal renders an empty goal without dumping JSON', () => { + const renderer = pickResultRenderer('GetGoal'); + const out = strip(joinRender(renderer(call('GetGoal'), result('{"goal":null}'), ctx))); + expect(out).toContain('No current goal.'); + expect(out).not.toContain('"goal"'); + }); + + it('CreateGoal renders the created goal summary without raw JSON', () => { + const renderer = pickResultRenderer('CreateGoal'); + const out = strip(joinRender(renderer( + call('CreateGoal', { objective: 'Ship feature X' }), + result(goalOutput()), + ctx, + ))); + expect(out).toContain('Goal active: Ship feature X'); + expect(out).not.toContain('"goalId"'); + }); + + it('UpdateGoal success renders no redundant body', () => { + const renderer = pickResultRenderer('UpdateGoal'); + const out = joinRender( + renderer(call('UpdateGoal', { status: 'complete' }), result('Goal marked complete.'), ctx), + ); + expect(out.trim()).toBe(''); + }); + + it('Errors always fall back to truncated renderer regardless of tool', () => { + const renderer = pickResultRenderer('Read'); + const out = strip( + joinRender( + renderer(call('Read', { path: 'foo.ts' }), result('ENOENT: foo.ts not found', true), ctx), + ), + ); + expect(out).toContain('ENOENT: foo.ts not found'); + }); + + it('flags only fallback (truncated) tools as generic results', () => { + expect(isGenericToolResult('SomethingUnknown')).toBe(true); + expect(isGenericToolResult('mcp__server__do')).toBe(true); + expect(isGenericToolResult('Bash')).toBe(false); + expect(isGenericToolResult('Read')).toBe(false); + expect(isGenericToolResult('Grep')).toBe(false); + expect(isGenericToolResult('Edit')).toBe(false); + }); + + it('truncates a failing unknown tool\'s output by wrapped visual lines, not raw newlines', () => { + const renderer = pickResultRenderer('SomethingUnknown'); + const longLine = 'x'.repeat(500); + const out = strip( + joinRender(renderer(call('SomethingUnknown'), result(longLine, true), ctx), 20), + ); + expect(out).toContain('x'); + expect(out).not.toContain(longLine); + expect(out).toContain('… ('); + }); + + const waitForCompletedOutput = [ + 'wait_status: completed', + 'task_id: question-80w0h7nw', + 'waited_ms: 9607', + 'timeout_ms: 300000', + '', + '[finished]', + 'task_id: question-80w0h7nw', + 'description: Pick one so I can demonstrate WaitFor with background questions?', + 'status: completed', + 'kind: question', + '', + '[output]', + '{"answers":{"Pick one":"Beta"}}', + ].join('\n'); + + it('WaitFor completed renders the finished task instead of raw fields', () => { + const renderer = pickResultRenderer('WaitFor'); + const out = strip( + joinRender( + renderer(call('WaitFor', { task_id: 'question-80w0h7nw' }), result(waitForCompletedOutput), ctx), + ), + ); + expect(out).toContain('✓ question-80w0h7nw completed'); + expect(out).toContain('Pick one so I can demonstrate'); + expect(out).not.toContain('waited_ms'); + expect(out).not.toContain('[finished]'); + }); + + it('WaitFor completed expands to the raw timeline output', () => { + const renderer = pickResultRenderer('WaitFor'); + const out = strip( + joinRender( + renderer( + call('WaitFor', { task_id: 'question-80w0h7nw' }), + result(waitForCompletedOutput), + expandedCtx, + ), + ), + ); + expect(out).toContain('[finished]'); + expect(out).toContain('waited_ms: 9607'); + }); + + it('WaitFor completed mentions extras and still-running counts', () => { + const output = [ + 'wait_status: completed', + 'task_id: bash-a1', + 'waited_ms: 1200', + 'timeout_ms: 30000', + '', + '[finished]', + 'task_id: bash-a1', + 'description: main wait', + 'status: failed', + '', + '[completed_during_wait]', + 'task_id: bash-b2', + 'description: side task', + 'status: completed', + '', + '[still_running]', + 'active_background_tasks: 2', + 'task_id: bash-c3', + 'description: slow one', + 'status: running', + '---', + 'task_id: agent-d4', + 'description: another slow one', + 'status: running', + ].join('\n'); + const renderer = pickResultRenderer('WaitFor'); + const out = strip(joinRender(renderer(call('WaitFor', { task_id: 'bash-a1' }), result(output), ctx))); + expect(out).toContain('✗ bash-a1 failed'); + expect(out).toContain('+1 more finished during wait'); + expect(out).toContain('2 background tasks still running'); + }); + + it('WaitFor timed_out lists the still-running tasks without an error tone', () => { + const output = [ + 'wait_status: timed_out', + 'task_id: bash-a1', + 'waited_ms: 30000', + 'timeout_ms: 30000', + 'The wait ended before the task finished.', + '', + '[still_running]', + 'active_background_tasks: 2', + 'task_id: bash-a1', + 'description: bg sleep', + 'status: running', + '---', + 'task_id: agent-b2', + 'description: investigate flaky test', + 'status: running', + ].join('\n'); + const renderer = pickResultRenderer('WaitFor'); + const out = strip(joinRender(renderer(call('WaitFor', { task_id: 'bash-a1' }), result(output), ctx))); + expect(out).toContain('2 background tasks still running'); + expect(out).toContain('bg sleep'); + expect(out).toContain('investigate flaky test'); + expect(out).not.toContain('waited_ms'); + }); + + it('WaitFor no_tasks renders no body in collapsed state', () => { + const renderer = pickResultRenderer('WaitFor'); + const output = 'wait_status: no_tasks\nwaited_ms: 0\ntimeout_ms: 30000'; + const out = joinRender(renderer(call('WaitFor', { timeout: 30 }), result(output), ctx)); + expect(out.trim()).toBe(''); + }); + + it('WaitFor errors fall back to the truncated renderer', () => { + const renderer = pickResultRenderer('WaitFor'); + const out = strip( + joinRender( + renderer(call('WaitFor', { task_id: 'bash-x' }), result('Task not found: bash-x', true), ctx), + ), + ); + expect(out).toContain('Task not found: bash-x'); + }); +}); + +describe('outcome rows', () => { + function plain(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); + } + + it('lists each file once in an unnumbered Grep glance', () => { + const renderer = pickResultRenderer('Grep'); + const out = plain( + joinRender( + renderer( + call('Grep', { pattern: 'foo', output_mode: 'content', '-n': false }), + result('a.ts:foo\na.ts:foo again\nb.ts:foo'), + ctx, + ), + ), + ); + expect(out).toBe(' a.ts, b.ts'); + }); + + it('strips terminal colours from an outcome row', () => { + const renderer = pickResultRenderer('Bash'); + const rows = renderer( + call('Bash', { command: 'pnpm test' }), + result('FAIL src/a.test.ts'), + ctx, + ).flatMap((component) => component.render(100)); + expect(rows).toHaveLength(1); + expect(rows[0]).not.toContain(''); + expect(plain(rows[0] ?? '')).toBe(' FAIL src/a.test.ts'); + }); +}); + +describe('Grep glance on paginated and Windows output', () => { + it('counts "+N more" against the tool-reported file total of a paginated result', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo', head_limit: 4 }), + result( + 'a.ts\nb.ts\nc.ts\nd.ts\nResults truncated to 4 lines (total: 10). Use offset=4 to see more.', + ), + ctx, + ), + ), + ); + expect(out).toBe(' a.ts, b.ts, c.ts, +7 more'); + }); + + it('keeps a Windows drive letter in an unnumbered content glance', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo', output_mode: 'content', '-n': false }), + result('C:/outside/a.ts:foo\nC:/outside/b.ts:foo'), + ctx, + ), + ), + ); + expect(out).toBe(' C:/outside/a.ts, C:/outside/b.ts'); + }); +}); + +const SPILLED_OUTPUT = [ + 'Tool output exceeded 50000 characters; the full output was saved to a file.', + 'tool_name: Grep', + 'tool_call_id: call_1', + 'output_size_chars: 61234', + 'output_path: /tmp/kimi/tool-output.txt', + 'next_step: Use Read with output_path to page through the saved output, or Grep to search it.', + '', + '[preview: chars [0, 20)]', + 'src/a.ts\nsrc/b.ts', +].join('\n'); + +describe('spilled tool output', () => { + it('shows the Grep envelope as a plain outcome row instead of parsing it as results', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip(joinRender(renderer(call('Grep', { pattern: 'foo' }), result(SPILLED_OUTPUT), ctx))); + expect(out).toBe( + ' Tool output exceeded 50000 characters; the full output was saved to a file. …', + ); + }); + + it('leads a spilled Bash result with the envelope line rather than the preview tail', () => { + const renderer = pickResultRenderer('Bash'); + const out = strip(joinRender(renderer(call('Bash', { command: 'cat big.log' }), result(SPILLED_OUTPUT), ctx))); + expect(out).toBe( + ' Tool output exceeded 50000 characters; the full output was saved to a file. …', + ); + }); +}); + +describe('Grep glance on a paginated content result', () => { + it('counts "+N more" against the tool-reported match total', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'foo', output_mode: 'content', head_limit: 3 }), + result( + 'src/a.ts:1:foo\nsrc/a.ts:9:foo\nsrc/b.ts:2:foo\nResults truncated to 3 lines (total: 1000). Use offset=3 to see more.', + ), + ctx, + ), + ), + ); + expect(out).toBe(' src/a.ts:1, src/a.ts:9, src/b.ts:2, +997 more'); + }); +}); + +describe('Edit and Write results render the same way in both states', () => { + it('drops the success acknowledgement even when expanded', () => { + const renderer = pickResultRenderer('Edit'); + const out = joinRender( + renderer( + call('Edit', { path: 'foo.ts', old_string: 'a', new_string: 'b' }), + result('Replaced 1 occurrence in foo.ts'), + expandedCtx, + ), + ); + expect(out.trim()).toBe(''); + const write = pickResultRenderer('Write'); + expect( + joinRender(write(call('Write', { path: 'a.txt', content: 'a' }), result('Appended 1 bytes to a.txt'), expandedCtx)).trim(), + ).toBe(''); + }); + + it('keeps any other successful output as an outcome row in both states', () => { + const renderer = pickResultRenderer('Edit'); + const output = 'No changes to make: old_string and new_string are exactly the same.'; + const collapsed = strip(joinRender(renderer(call('Edit', { path: 'foo.ts' }), result(output), ctx))); + const expanded = strip(joinRender(renderer(call('Edit', { path: 'foo.ts' }), result(output), expandedCtx))); + expect(collapsed).toBe(` ${output}`); + expect(expanded).toBe(collapsed); + }); +}); + +describe('a search the tool cut short before any row', () => { + it('shows the Glob timeout notice instead of an exact-looking empty result', () => { + const renderer = pickResultRenderer('Glob'); + const out = strip( + joinRender( + renderer( + call('Glob', { pattern: '**/*.ts' }), + result('Glob timed out after 60s; partial results returned.'), + ctx, + ), + ), + ); + expect(out).toBe(' Glob timed out after 60s; partial results returned.'); + }); +}); + +describe('a search whose only matches were filtered as sensitive', () => { + it('shows the notice rows instead of an exact-looking empty result', () => { + const renderer = pickResultRenderer('Grep'); + const out = strip( + joinRender( + renderer( + call('Grep', { pattern: 'secret' }), + result('No non-sensitive matches found\nFiltered 2 sensitive file(s): .env, secrets.json'), + ctx, + ), + ), + ); + expect(out).toBe(' No non-sensitive matches found\n Filtered 2 sensitive file(s): .env, secrets.json'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/tool-renderers/truncated.test.ts b/apps/kimi-code/test/tui/components/messages/tool-renderers/truncated.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f6471f46c53318a52a7034e0ba3321cf1bfb694 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/tool-renderers/truncated.test.ts @@ -0,0 +1,90 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { TruncatedOutputComponent } from '#/tui/components/messages/tool-renderers/truncated'; + + +function strip(text: string): string { + return text.replaceAll(/\[[0-9;]*m/g, ''); +} + +describe('TruncatedOutputComponent', () => { + it('indents content and the truncation hint by the configured amount', () => { + const component = new TruncatedOutputComponent(['a', 'b', 'c', 'd', 'e'].join('\n'), { + expanded: false, + isError: false, + maxLines: 2, + indent: 6, + }); + + const lines = strip(component.render(80).join('\n')).split('\n'); + expect(lines[0]?.startsWith(' a')).toBe(true); + expect(lines[1]?.startsWith(' b')).toBe(true); + expect(lines[2]).toBe(' … (3 more lines, ctrl+o to expand)'); + }); + + it('defaults to a two-space indent for both content and hint', () => { + const component = new TruncatedOutputComponent('x\ny\nz', { + expanded: false, + isError: false, + maxLines: 1, + }); + + const lines = strip(component.render(80).join('\n')).split('\n'); + expect(lines[0]?.startsWith(' x')).toBe(true); + expect(lines[1]).toBe(' … (2 more lines, ctrl+o to expand)'); + }); + + it('omits the ctrl+o promise when expandHint is false', () => { + const component = new TruncatedOutputComponent('a\nb\nc\nd', { + expanded: false, + isError: false, + maxLines: 2, + indent: 4, + expandHint: false, + }); + + const lines = strip(component.render(80).join('\n')).split('\n'); + expect(lines[2]).toBe(' … (2 more lines)'); + }); + + it('renders all lines without a hint when expanded', () => { + const component = new TruncatedOutputComponent('a\nb\nc\nd', { + expanded: true, + isError: false, + maxLines: 2, + indent: 4, + }); + + const out = strip(component.render(80).join('\n')); + expect(out).toContain('d'); + expect(out).not.toContain('more lines, ctrl+o'); + }); + + it('keeps the truncation footer within the requested render width', () => { + const output = Array.from({ length: 20 }, (_, i) => `line ${String(i)}`).join('\n'); + const component = new TruncatedOutputComponent(output, { + expanded: false, + isError: false, + maxLines: 3, + indent: 2, + }); + + for (const line of component.render(37)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(37); + } + }); + + it('renders output verbatim, including literal text in file content', () => { + // Tool metadata no longer travels inside `output` (it rides the result's + // `note` side channel), so the renderer must not eat user data that + // merely contains the literal tag. + const component = new TruncatedOutputComponent( + 'literal text from a user file\n', + { expanded: true, isError: false }, + ); + const out = strip(component.render(80).join('\n')); + expect(out).toContain('literal text from a user file'); + expect(out).toContain(''); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/truncated-header-line.test.ts b/apps/kimi-code/test/tui/components/messages/truncated-header-line.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..de3de515889d747570f31d08e4365c5819c5da19 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/truncated-header-line.test.ts @@ -0,0 +1,159 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { + renderHeaderContent, + TruncatedHeaderLine, + type HeaderSegments, +} from '#/tui/components/messages/truncated-header-line'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +const upper = (text: string): string => text.toUpperCase(); + +function segments(text: string, keep: 'head' | 'tail', tail = ' · 3 lines'): HeaderSegments { + return { head: '● Ran a command · $ ', flex: { text, keep }, tail }; +} + +describe('renderHeaderContent', () => { + it('truncates a plain string at the width', () => { + expect(strip(renderHeaderContent('short', 40))).toBe('short'); + const cut = strip(renderHeaderContent('x'.repeat(50), 20)); + expect(visibleWidth(cut)).toBeLessThanOrEqual(20); + expect(cut.endsWith('…')).toBe(true); + }); + + it('lets the middle fill the row and keeps the tail when it fits', () => { + const line = strip(renderHeaderContent(segments('git status --short', 'head'), 80)); + expect(line).toBe('● Ran a command · $ git status --short · 3 lines'); + }); + + it('cuts the middle from its end and still shows the tail on a narrow row', () => { + const command = + 'git log --oneline -5 origin/main -- apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts'; + const line = strip(renderHeaderContent(segments(command, 'head'), 60)); + expect(visibleWidth(line)).toBeLessThanOrEqual(60); + expect(line.startsWith('● Ran a command · $ git log')).toBe(true); + expect(line.endsWith('… · 3 lines')).toBe(true); + }); + + it('keeps the end of a path-like middle behind a leading ellipsis', () => { + const path = + '/Users/someone/.kimi-code/sessions/session_5b2c/agents/main/tasks/bash-4g77gs5f/output.log'; + const line = strip( + renderHeaderContent( + { head: '● Used Read (', flex: { text: path, keep: 'tail' }, tail: ') · 8 lines' }, + 60, + ), + ); + expect(visibleWidth(line)).toBeLessThanOrEqual(60); + expect(line).toContain('(…'); + expect(line.endsWith('/output.log) · 8 lines')).toBe(true); + }); + + it('measures wide characters by cells, not by code units', () => { + const line = strip( + renderHeaderContent(segments('运行全部测试并生成覆盖率报告然后上传', 'head', ''), 30), + ); + expect(visibleWidth(line)).toBeLessThanOrEqual(30); + expect(line.endsWith('…')).toBe(true); + }); + + it('styles the middle after the cut so the ellipsis is styled too', () => { + const line = renderHeaderContent( + { head: 'H ', flex: { text: 'abcdefghij', keep: 'head', style: upper }, tail: ' T' }, + 10, + ); + expect(line).toBe('H ABCDE… T'); + }); + + it('drops the middle before the fixed parts when the row is too narrow for it', () => { + const content = { head: 'HEAD ', flex: { text: 'abcdef', keep: 'head' as const }, tail: ' T' }; + // One spare cell: the middle collapses to an ellipsis between the fixed parts. + expect(renderHeaderContent(content, 8)).toBe('HEAD … T'); + // No spare cell: the middle is dropped outright, both fixed parts stay. + expect(renderHeaderContent(content, 7)).toBe('HEAD T'); + }); + + it('cuts the head from its end so the tail survives when even the fixed parts overflow', () => { + const content = { head: 'HEAD ', flex: { text: 'abcdef', keep: 'head' as const }, tail: ' T' }; + const line = strip(renderHeaderContent(content, 5)); + expect(line).toBe('HE… T'); + // Below two cells for the head there is nothing left to keep: cut from the end. + const tiny = strip(renderHeaderContent(content, 3)); + expect(visibleWidth(tiny)).toBeLessThanOrEqual(3); + expect(tiny.endsWith('…')).toBe(true); + }); + + it('keeps ANSI escape sequences atomic and zero-width when cutting', () => { + const colored = '\x1b[32mabcdef\x1b[0mghijkl'; + // 2 (head) + 5 for the middle: the whole opening sequence plus 4 visible + // cells, then the ellipsis. The sequence is never split or measured. + const line = renderHeaderContent( + { head: 'H ', flex: { text: colored, keep: 'head' }, tail: '' }, + 7, + ); + expect(line).toBe('H \x1b[32mabcd…'); + expect(visibleWidth(line)).toBeLessThanOrEqual(7); + }); + + it('cuts a huge argument without walking it whole', () => { + const huge = `prefix-${'x'.repeat(200_000)}-suffix`; + const head = strip(renderHeaderContent(segments(huge, 'head', ''), 40)); + expect(head.startsWith('● Ran a command · $ prefix-xxx')).toBe(true); + expect(head.endsWith('…')).toBe(true); + expect(visibleWidth(head)).toBeLessThanOrEqual(40); + + const tail = strip(renderHeaderContent(segments(huge, 'tail', ''), 40)); + expect(tail).toContain('$ …'); + expect(tail.endsWith('-suffix')).toBe(true); + expect(visibleWidth(tail)).toBeLessThanOrEqual(40); + }); +}); + +describe('TruncatedHeaderLine', () => { + it('reuses its rendered array across structurally equal headers', () => { + const line = new TruncatedHeaderLine(segments('ls', 'head')); + const first = line.render(80); + line.setText(segments('ls', 'head')); + expect(line.render(80)).toBe(first); + line.setText(segments('ls -la', 'head')); + expect(line.render(80)).not.toBe(first); + }); + + it('reports whether the last render cut the row', () => { + const command = + 'git log --oneline -5 origin/main -- apps/kimi-code/test/tui/kimi-tui-message-flow.test.ts'; + const line = new TruncatedHeaderLine(segments(command, 'head')); + expect(line.wasTruncated()).toBe(false); + line.render(160); + expect(line.wasTruncated()).toBe(false); + line.render(60); + expect(line.wasTruncated()).toBe(true); + line.render(160); + expect(line.wasTruncated()).toBe(false); + }); +}); + +describe('graphemes that pack many code units into a cell', () => { + // A ZWJ family emoji: 2 cells, 11 UTF-16 code units. + const family = '\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}'; + + it('never assumes a cut from code-unit length alone', () => { + const text = family.repeat(10); + expect(visibleWidth(text)).toBe(20); + const line = renderHeaderContent({ head: '', flex: { text, keep: 'head' }, tail: '' }, 20); + expect(line).toBe(text); + const tailKept = renderHeaderContent({ head: '', flex: { text, keep: 'tail' }, tail: '' }, 20); + expect(tailKept).toBe(text); + }); + + it('keeps whole emoji clusters at the tail when it does have to cut', () => { + const text = `${'x'.repeat(30)}${family.repeat(5)}`; + const line = renderHeaderContent({ head: '', flex: { text, keep: 'tail' }, tail: '' }, 9); + expect(line).toBe(`…${family.repeat(4)}`); + expect(visibleWidth(line)).toBe(9); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/usage-panel.test.ts b/apps/kimi-code/test/tui/components/messages/usage-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d46b78e061469503b27ebeaef7703e253a255d18 --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/usage-panel.test.ts @@ -0,0 +1,312 @@ +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { buildUsageReportLines, UsagePanelComponent } from '#/tui/components/messages/usage-panel'; +import { currentTheme, darkColors, lightColors } from '#/tui/theme'; + +afterEach(() => { + currentTheme.setPalette(darkColors); +}); + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('UsagePanelComponent', () => { + it('formats session, context, and managed usage sections', () => { + // Freeze the clock so the resetAt fixture is an exact hour out — with a + // live clock the elapsed milliseconds floor the diff down to 59m. + vi.useFakeTimers(); + vi.setSystemTime(new Date('2026-07-28T00:00:00Z')); + try { + const lines = buildUsageReportLines({ + sessionUsage: { + byModel: { + kimi: { + inputOther: 1000, + inputCacheRead: 500, + inputCacheCreation: 500, + output: 250, + }, + }, + }, + contextUsage: 0.25, + contextTokens: 2500, + maxContextTokens: 10000, + managedUsage: { + rows: [ + { + name: 'daily', + usedRatio: 0.2, + resetAt: new Date(Date.now() + 3600_000).toISOString(), + }, + ], + }, + }).map(strip); + + expect(lines).toContain('Session usage'); + expect(lines).toContain(' kimi input 2k output 250 total 2.2k'); + expect(lines).toContain('Context window'); + expect(lines.join('\n')).toContain('25%'); + expect(lines).toContain('Plan usage'); + expect(lines.join('\n')).toContain('daily'); + expect(lines.join('\n')).toContain('20% used'); + expect(lines.join('\n')).toContain('resets in 1h'); + } finally { + vi.useRealTimers(); + } + }); + + it('renders plan usage rows with their names and the monthly breakdown line', () => { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { + rows: [ + { name: '5h limit', usedRatio: 0.2 }, + { + name: 'Monthly limit', + usedRatio: 0.4, + breakdown: { kimiRatio: 0.15, codeRatio: 0.25 }, + }, + ], + }, + }).map(strip); + + const output = lines.join('\n'); + expect(output).toContain('5h limit'); + expect(output).toContain('Monthly limit'); + expect(output).toContain('40% used'); + expect(output).toContain('kimi 15% · code 25%'); + }); + + it('shows "reset" when the reset timestamp is already in the past', () => { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { + rows: [ + { + name: 'daily', + usedRatio: 0.1, + resetAt: new Date(Date.now() - 60_000).toISOString(), + }, + ], + }, + }).map(strip); + + expect(lines.join('\n')).toContain('reset'); + expect(lines.join('\n')).not.toContain('resets in'); + }); + + it('formats extra usage with a monthly limit', () => { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { + rows: [], + extraUsage: { + balanceCents: 10000, + totalCents: 20000, + monthlyChargeLimitEnabled: true, + monthlyChargeLimitCents: 20000, + monthlyUsedCents: 5000, + currency: 'USD', + }, + }, + }).map(strip); + + const output = lines.join('\n'); + expect(lines).toContain('Extra Usage'); + expect(output).toContain('Balance'); + expect(output).toContain('100.00'); + expect(output).toContain('Used this month'); + expect(output).toContain('50.00'); + expect(output).toContain('Monthly limit'); + expect(output).toContain('200.00'); + // bar row contains block glyphs but no percentage text + expect(output).toContain('░'); + }); + + it('formats extra usage without a monthly limit and omits the progress bar', () => { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { + rows: [], + extraUsage: { + balanceCents: 18208, + totalCents: 40000, + monthlyChargeLimitEnabled: false, + monthlyChargeLimitCents: 0, + monthlyUsedCents: 21792, + currency: 'CNY', + }, + }, + }).map(strip); + + const output = lines.join('\n'); + expect(lines).toContain('Extra Usage'); + expect(output).toContain('Balance'); + expect(output).toContain('¥182.08'); + expect(output).toContain('Used this month'); + expect(output).toContain('¥217.92'); + expect(output).toContain('Monthly limit'); + expect(output).toContain('Unlimited'); + expect(output).not.toContain('░'); + expect(output).not.toContain('█'); + }); + + it('omits the extra usage section when extraUsage is omitted or null', () => { + for (const extraUsage of [undefined, null]) { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { rows: [], extraUsage }, + }).map(strip); + + expect(lines).not.toContain('Extra Usage'); + } + }); + + it('formats extra usage with CNY currency', () => { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { + rows: [], + extraUsage: { + balanceCents: 10000, + totalCents: 20000, + monthlyChargeLimitEnabled: true, + monthlyChargeLimitCents: 20000, + monthlyUsedCents: 5000, + currency: 'CNY', + }, + }, + }).map(strip); + + const output = lines.join('\n'); + expect(output).toContain('Balance'); + expect(output).toContain('100.00'); + expect(output).toContain('Used this month'); + expect(output).toContain('50.00'); + expect(output).toContain('Monthly limit'); + expect(output).toContain('200.00'); + }); + + it('aligns the currency symbol and decimal point across extra usage rows', () => { + const lines = buildUsageReportLines({ + sessionUsage: { byModel: {} }, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + managedUsage: { + rows: [], + extraUsage: { + balanceCents: 15901, + totalCents: 300000, + monthlyChargeLimitEnabled: true, + monthlyChargeLimitCents: 300000, + monthlyUsedCents: 24099, + currency: 'CNY', + }, + }, + }).map(strip); + + const extraRows = lines.filter((line) => line.includes('¥')); + expect(extraRows).toHaveLength(3); + // The currency symbol stays in one column... + expect(new Set(extraRows.map((line) => line.indexOf('¥'))).size).toBe(1); + // ...and the right-aligned numeric parts end in the same column, so the + // decimal points line up across rows. + expect(new Set(extraRows.map((line) => line.length)).size).toBe(1); + }); + + it('shows an empty-hint instead of an error when there is no session yet', async () => { + const { showUsage } = await import('#/tui/commands/info'); + const added: string[] = []; + const host = { + session: undefined, + state: { + appState: { + model: 'kimi', + availableModels: {}, + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 1_000_000, + }, + transcriptContainer: { + addChild: (component: { render(width: number): string[] }) => { + added.push(...component.render(80).map(strip)); + }, + }, + ui: { requestRender: () => {} }, + }, + }; + + await showUsage(host as never); + + const output = added.join('\n'); + expect(output).toContain('No token usage recorded yet.'); + expect(output).not.toContain('No active session'); + }); + + it('wraps preformatted usage lines in a bordered panel', () => { + const component = new UsagePanelComponent(() => ['Session usage'], 'primary'); + const output = component.render(80).map(strip); + + expect(output[0]).toContain(' Usage '); + expect(output[1]).toContain('Session usage'); + }); + + it('truncates lines wider than the terminal so the panel never overflows', () => { + const longLine = 'error: ' + 'x'.repeat(200); + const component = new UsagePanelComponent(() => [longLine], 'primary'); + const width = 60; + + const output = component.render(width); + + for (const line of output) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + }); + + it('keeps the bordered panel within narrow terminal widths', () => { + const component = new UsagePanelComponent(() => ['Session usage', ' kimi input 2.0k'], 'primary'); + + for (const width of [39, 24, 20, 10, 4, 1]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('rebuilds its body from the active palette on invalidate', () => { + // Emit the resolved palette value as visible text so the assertion holds + // regardless of chalk's colour level in the test environment. + const component = new UsagePanelComponent(() => [`text=${currentTheme.color('text')}`], 'primary'); + const bodyOf = (): string => { + const line = component.render(80).map(strip).find((l) => l.includes('text=')); + if (line === undefined) throw new Error('body line not found'); + return line; + }; + + expect(bodyOf()).toContain(darkColors.text); + currentTheme.setPalette(lightColors); + component.invalidate(); + expect(bodyOf()).toContain(lightColors.text); + }); +}); diff --git a/apps/kimi-code/test/tui/components/messages/user-message.test.ts b/apps/kimi-code/test/tui/components/messages/user-message.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f8a1d1aec06d7eb238ea9c5990654e11aaab81e --- /dev/null +++ b/apps/kimi-code/test/tui/components/messages/user-message.test.ts @@ -0,0 +1,121 @@ +import { resetCapabilitiesCache, setCapabilities, visibleWidth } from '@moonshot-ai/pi-tui'; +import { afterEach, describe, expect, it } from 'vitest'; + +import { UserMessageComponent } from '#/tui/components/messages/user-message'; +import type { ImageAttachment } from '#/tui/utils/image-attachment-store'; + +function stripAnsi(text: string): string { + return text + .replaceAll(/\u001B\[[0-9;]*m/g, '') + .replaceAll(/\u001B\]133;[ABC]\u0007/g, ''); +} + +describe('UserMessageComponent', () => { + afterEach(() => { + resetCapabilitiesCache(); + }); + + it('renders video placeholders as plain text, not inline image escapes', () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: true }); + + const component = new UserMessageComponent( + 'please inspect [video #1 sample.mov]', + [], + ); + + const out = stripAnsi(component.render(80).join('\n')); + + expect(out).toContain('[video #1 sample.mov]'); + expect(out).not.toContain('\u001B_G'); + expect(out).not.toContain('\u001B]1337;File='); + }); + + it('keeps user lines within very narrow widths', () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: true }); + + const component = new UserMessageComponent('please inspect the attached output', []); + + for (const width of [1, 2, 4, 10, 39]) { + for (const line of component.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('does not truncate inline image escape sequences', () => { + setCapabilities({ images: 'kitty', trueColor: true, hyperlinks: true }); + + // Minimal 2000x1302 PNG bytes so the inline Kitty sequence is long enough + // to exceed a typical terminal width if treated as visible text. + const pngSignature = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); + const ihdrLength = new Uint8Array([0x00, 0x00, 0x00, 0x0d]); + const ihdrType = new Uint8Array([0x49, 0x48, 0x44, 0x52]); + const widthBytes = new Uint8Array([ + (2000 >> 24) & 0xff, + (2000 >> 16) & 0xff, + (2000 >> 8) & 0xff, + 2000 & 0xff, + ]); + const heightBytes = new Uint8Array([ + (1302 >> 24) & 0xff, + (1302 >> 16) & 0xff, + (1302 >> 8) & 0xff, + 1302 & 0xff, + ]); + const rest = new Uint8Array([0x08, 0x02, 0x00, 0x00, 0x00]); + const bytes = new Uint8Array([ + ...pngSignature, + ...ihdrLength, + ...ihdrType, + ...widthBytes, + ...heightBytes, + ...rest, + ]); + + const attachment: ImageAttachment = { + id: 1, + kind: 'image', + bytes, + mime: 'image/png', + width: 2000, + height: 1302, + placeholder: '[image #1 (2000×1302)]', + }; + + const component = new UserMessageComponent('', [attachment]); + const lines = component.render(80); + + const imageLine = lines.find((l) => l.includes('\u001B_G')); + expect(imageLine).toBeDefined(); + expect(imageLine).not.toContain('\u001B[0m'); + expect(imageLine).not.toContain('…'); + expect(imageLine).toContain('\u001B\\'); // intact Kitty terminator + }); + + it('omits the sparkles bullet when an empty bullet is provided', () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: true }); + + const withBullet = stripAnsi(new UserMessageComponent('hello', []).render(80).join('\n')); + expect(withBullet).toContain('✨'); + expect(withBullet).toContain('hello'); + + const lines = new UserMessageComponent('$ ls', [], '').render(80).map(stripAnsi); + const contentLine = lines.find((l) => l.includes('$ ls')); + expect(contentLine).toBeDefined(); + expect(stripAnsi(lines.join('\n'))).not.toContain('✨'); + // The `$` sits at the leading column where the bullet used to be. + expect(contentLine?.startsWith('$ ls')).toBe(true); + }); + + it('marks the rendered zone with OSC 133 markers, once across cache hits', () => { + setCapabilities({ images: null, trueColor: true, hyperlinks: true }); + const component = new UserMessageComponent('hello', []); + + const lines = component.render(80); + expect(lines[0]).toMatch(/^\u001B\]133;A\u0007/); + expect(lines[lines.length - 1]).toMatch(/^\u001B\]133;B\u0007\u001B\]133;C\u0007/); + + const cached = component.render(80); + expect(cached[0]).toBe(lines[0]); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/footer-bg-agents.test.ts b/apps/kimi-code/test/tui/components/panels/footer-bg-agents.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..101cd191163913319daeed1c389aea4fc233b3fb --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/footer-bg-agents.test.ts @@ -0,0 +1,106 @@ +import { describe, expect, it } from 'vitest'; + +import { FooterComponent } from '#/tui/components/chrome/footer'; +import type { AppState } from '#/tui/types'; + +const ANSI_SGR = /\[[0-9;]*m/g; +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function baseState(overrides: Partial = {}): AppState { + return { + model: 'k2', + workDir: '/tmp/proj', + additionalDirs: [], + sessionId: 'sess_1', + permissionMode: 'manual', + planMode: false, + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 200_000, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + theme: 'dark', + version: 'test', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + availableModels: {}, + ...overrides, + } as AppState; +} + +describe('FooterComponent — background task / agent badges', () => { + it('omits both badges when counts are 0', () => { + const footer = new FooterComponent(baseState()); + const [line1] = footer.render(120); + expect(line1).toBeDefined(); + expect(strip(line1!)).not.toMatch(/tasks? running/); + expect(strip(line1!)).not.toMatch(/agents? running/); + }); + + it('renders the task badge alone when only bash tasks are running', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: 1, agentTasks: 0 }); + const out = strip(footer.render(120)[0]!); + expect(out).toMatch(/\[1 task running\]/); + expect(out).not.toMatch(/agents? running/); + }); + + it('renders the agent badge alone when only agent tasks are running', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: 0, agentTasks: 1 }); + const out = strip(footer.render(120)[0]!); + expect(out).toMatch(/\[1 agent running\]/); + expect(out).not.toMatch(/tasks? running/); + }); + + it('renders both badges side by side when both are non-zero', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: 2, agentTasks: 3 }); + const out = strip(footer.render(120)[0]!); + expect(out).toMatch(/\[2 tasks running\]/); + expect(out).toMatch(/\[3 agents running\]/); + // Task badge appears before agent badge in the line. + expect(out.indexOf('2 tasks')).toBeLessThan(out.indexOf('3 agents')); + }); + + it('pluralizes correctly across both badges', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: 1, agentTasks: 1 }); + const out = strip(footer.render(120)[0]!); + expect(out).toMatch(/\[1 task running\]/); + expect(out).toMatch(/\[1 agent running\]/); + }); + + it('updates badges live via setBackgroundCounts', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: 2, agentTasks: 1 }); + expect(strip(footer.render(120)[0]!)).toMatch(/\[2 tasks running\]/); + footer.setBackgroundCounts({ bashTasks: 0, agentTasks: 0 }); + const after = strip(footer.render(120)[0]!); + expect(after).not.toMatch(/tasks? running/); + expect(after).not.toMatch(/agents? running/); + }); + + it('clamps negative counts to 0', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: -5, agentTasks: -2 }); + const out = strip(footer.render(120)[0]!); + expect(out).not.toMatch(/tasks? running/); + expect(out).not.toMatch(/agents? running/); + }); + + it('drops the badges when terminal is too narrow to fit them', () => { + const footer = new FooterComponent(baseState()); + footer.setBackgroundCounts({ bashTasks: 4, agentTasks: 3 }); + // Extremely narrow width: footer primary content fills the line, so leftLine wins. + const [line1] = footer.render(20); + expect(line1).toBeDefined(); + expect(strip(line1!)).not.toMatch(/\[4 tasks running\]/); + expect(strip(line1!)).not.toMatch(/\[3 agents running\]/); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/footer-context.test.ts b/apps/kimi-code/test/tui/components/panels/footer-context.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..100f5f6a3bae8ff55b1f1e77918ec2329d491011 --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/footer-context.test.ts @@ -0,0 +1,209 @@ +import { describe, it, expect } from 'vitest'; +import chalk from 'chalk'; + +import { FooterComponent, formatFooterGitBadge, buildWeightedTips } from '#/tui/components/chrome/footer'; +import { darkColors } from '#/tui/theme/colors'; +import type { AppState } from '#/tui/types'; + +const ANSI_SGR = /\u001B\[[0-9;]*m/g; +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function hexToSgr(hex: string): string { + const value = hex.replace(/^#/, ''); + const r = Number.parseInt(value.slice(0, 2), 16); + const g = Number.parseInt(value.slice(2, 4), 16); + const b = Number.parseInt(value.slice(4, 6), 16); + return `\u001B[38;2;${String(r)};${String(g)};${String(b)}m`; +} + +function baseState(overrides: Partial = {}): AppState { + return { + model: 'k2', + workDir: '/tmp', + additionalDirs: [], + sessionId: 'sess_1', + permissionMode: 'manual', + planMode: false, + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + theme: 'dark', + version: 'test', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + availableModels: {}, + ...overrides, + } as AppState; +} + +describe('FooterComponent — context NaN resilience', () => { + it('NaN usage → renders 0% (never literal "NaN%")', () => { + const fc = new FooterComponent(baseState({ contextUsage: Number.NaN })); + const out = strip(fc.render(120).join('')); + expect(out).not.toMatch(/NaN/); + expect(out).toMatch(/context: 0%/); + }); + + it('undefined-ish (coerced) usage → renders 0%', () => { + const fc = new FooterComponent( + baseState({ contextUsage: undefined as unknown as number }), + ); + const out = strip(fc.render(120).join('')); + expect(out).not.toMatch(/NaN/); + expect(out).toMatch(/context: 0%/); + }); + + it('clamps ratios above 1.0 → renders 100%', () => { + const fc = new FooterComponent(baseState({ contextUsage: 1.5 })); + const out = strip(fc.render(120).join('')); + expect(out).toMatch(/context: 100%/); + }); + + it('ratio 0.427 → renders 43% (ceiled whole percent)', () => { + const fc = new FooterComponent(baseState({ contextUsage: 0.427 })); + const out = strip(fc.render(200).join('')); + expect(out).toMatch(/context: 43%/); + }); + + it('tiny non-zero usage → renders 1% (ceil floor)', () => { + const fc = new FooterComponent(baseState({ contextUsage: 0.0004 })); + const out = strip(fc.render(200).join('')); + expect(out).toMatch(/context: 1%/); + }); + + it('valid tokens/maxTokens → percent from tokens, counts in 1024 units', () => { + const fc = new FooterComponent( + baseState({ + contextUsage: 0.427, + contextTokens: 430_080, + maxContextTokens: 1_048_576, + }), + ); + const out = strip(fc.render(200).join('')); + expect(out).toMatch(/context: 42% \(420k\/1M\)/); + }); + + it('tokens provided but max=0 → falls back to percent-only, no division-by-zero artefact', () => { + const fc = new FooterComponent( + baseState({ contextUsage: 0, contextTokens: 500, maxContextTokens: 0 }), + ); + const out = strip(fc.render(200).join('')); + expect(out).not.toMatch(/Infinity|NaN/); + expect(out).toMatch(/context: 0%/); + // With maxTokens=0, token-count annotation is suppressed. + expect(out).not.toMatch(/\(500\//); + }); + + it('setState updates visible model and context values', () => { + const footer = new FooterComponent(baseState({ model: 'k2', contextUsage: 0 })); + + footer.setState(baseState({ model: 'kimi-k2-5', contextUsage: 0.5 })); + + const out = strip(footer.render(200).join('')); + expect(out).toContain('kimi-k2-5'); + expect(out).not.toContain(' k2 '); + expect(out).toMatch(/context: 50%/); + }); + + it('shows "thinking" label when thinking is enabled, hides it when disabled', () => { + const on = new FooterComponent(baseState({ model: 'k2', thinkingEffort: 'on' })); + const off = new FooterComponent(baseState({ model: 'k2', thinkingEffort: 'off' })); + + expect(strip(on.render(120)[0]!)).toContain('thinking'); + expect(strip(off.render(120)[0]!)).not.toContain('thinking'); + }); + + it('renders transient hints on the context line', () => { + const footer = new FooterComponent(baseState()); + + footer.setTransientHint('Press Ctrl-C again to exit'); + + const [, line2] = footer.render(120); + expect(strip(line2 ?? '')).toContain('Press Ctrl-C again to exit'); + expect(strip(line2 ?? '')).toContain('context: 0%'); + }); + + it('highlights the pull request badge separately from git status text', () => { + const previousLevel = chalk.level; + chalk.level = 3; + try { + const out = formatFooterGitBadge( + { + branch: 'feature/footer', + dirty: false, + ahead: 0, + behind: 0, + diffAdded: 0, + diffDeleted: 0, + pullRequest: { + number: 6, + url: 'https://github.com/acme/repo/pull/6', + }, + }, + darkColors, + ); + + const primaryIndex = out.indexOf(hexToSgr(darkColors.primary)); + const statusIndex = out.indexOf(hexToSgr(darkColors.textDim)); + const badgeIndex = out.indexOf('[PR#6]'); + expect(statusIndex).toBeGreaterThanOrEqual(0); + expect(primaryIndex).toBeGreaterThanOrEqual(0); + expect(primaryIndex).toBeLessThan(badgeIndex); + expect(strip(out)).toContain('feature/footer '); + expect(strip(out)).toContain('[PR#6]'); + } finally { + chalk.level = previousLevel; + } + }); +}); + +describe('buildWeightedTips — weighted rotation', () => { + it('repeats higher-priority tips more often (length = sum of weights)', () => { + const seq = buildWeightedTips([ + { text: 'a' }, // weight 1 (default) + { text: 'b', priority: 3 }, + { text: 'c', priority: 2 }, + ]); + + const count = (t: string) => seq.filter((x) => x.text === t).length; + expect(seq).toHaveLength(6); + expect(count('a')).toBe(1); + expect(count('b')).toBe(3); + expect(count('c')).toBe(2); + expect(count('b')).toBeGreaterThan(count('a')); + }); + + it('keeps duplicates spread out — no tip sits next to itself', () => { + const seq = buildWeightedTips([ + { text: 'a' }, + { text: 'b', priority: 3 }, + { text: 'c', priority: 2 }, + ]); + + for (let i = 1; i < seq.length; i++) { + expect(seq[i]!.text).not.toBe(seq[i - 1]!.text); + } + }); + + it('preserves array order when all weights are the default (1)', () => { + const seq = buildWeightedTips([{ text: 'x' }, { text: 'y' }, { text: 'z' }]); + expect(seq.map((t) => t.text)).toEqual(['x', 'y', 'z']); + }); + + it('clamps non-positive / fractional priorities to a weight of at least 1', () => { + const seq = buildWeightedTips([ + { text: 'a', priority: 0 }, + { text: 'b', priority: -5 }, + { text: 'c', priority: 1.9 }, + ]); + expect(seq).toHaveLength(3); + expect(seq.map((t) => t.text).toSorted()).toEqual(['a', 'b', 'c']); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/footer-goal-badge.test.ts b/apps/kimi-code/test/tui/components/panels/footer-goal-badge.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..982be065795da35f5c7ba4aaf18129b2b772bd80 --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/footer-goal-badge.test.ts @@ -0,0 +1,128 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import { FooterComponent } from '#/tui/components/chrome/footer'; +import type { GoalSnapshot } from '@moonshot-ai/kimi-code-sdk'; +import type { AppState } from '#/tui/types'; + +const ANSI_SGR = /\[[0-9;]*m/g; +function strip(text: string): string { + return text.replaceAll(ANSI_SGR, ''); +} + +function baseState(overrides: Partial = {}): AppState { + return { + model: 'k2', + workDir: '/tmp/proj', + additionalDirs: [], + sessionId: 'sess_1', + permissionMode: 'manual', + planMode: false, + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 200_000, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + theme: 'dark', + version: 'test', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + availableModels: {}, + ...overrides, + } as AppState; +} + +function goal(overrides: Partial = {}): GoalSnapshot { + return { + goalId: 'g1', + objective: 'Ship it', + status: 'active', + turnsUsed: 7, + tokensUsed: 1234, + wallClockMs: 245_000, // 4m05s + budget: { + turnBudget: null, + tokenBudget: null, + wallClockBudgetMs: null, + }, + ...overrides, + } as GoalSnapshot; +} + +describe('FooterComponent — goal badge', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('omits the badge when there is no goal', () => { + const footer = new FooterComponent(baseState({ goal: null })); + expect(strip(footer.render(160)[0]!)).not.toContain('[goal'); + }); + + it('shows status, elapsed, and a raw turn count for an unbounded active goal', () => { + const footer = new FooterComponent(baseState({ goal: goal() })); + const out = strip(footer.render(160)[0]!); + expect(out).toContain('[goal'); + expect(out).toContain('active'); + expect(out).toContain('4m'); + expect(out).toContain('7 turns'); + // No N/M when no turn budget is set. + expect(out).not.toMatch(/\d+\/\d+ turns/); + }); + + it('keeps counting elapsed time for an active goal between snapshots', () => { + vi.useFakeTimers(); + vi.setSystemTime(0); + + const footer = new FooterComponent( + baseState({ goal: goal({ wallClockMs: 0, turnsUsed: 0 }) }), + ); + + expect(strip(footer.render(160)[0]!)).toContain('0s'); + vi.setSystemTime(2_500); + expect(strip(footer.render(160)[0]!)).toContain('3s'); + }); + + it('requests a repaint while an active goal timer is visible', () => { + vi.useFakeTimers(); + const onRefresh = vi.fn(); + + new FooterComponent(baseState({ goal: goal({ wallClockMs: 0 }) }), onRefresh); + + vi.advanceTimersByTime(1_000); + expect(onRefresh).toHaveBeenCalledTimes(1); + }); + + it('shows used/limit turns only when a turn budget is set', () => { + const footer = new FooterComponent( + baseState({ goal: goal({ budget: { turnBudget: 20, tokenBudget: null, wallClockBudgetMs: null } } as Partial) }), + ); + expect(strip(footer.render(160)[0]!)).toContain('7/20 turns'); + }); + + it('shows a paused badge', () => { + const footer = new FooterComponent(baseState({ goal: goal({ status: 'paused' }) })); + expect(strip(footer.render(160)[0]!)).toContain('paused'); + }); + + it('shows a blocked badge (resumable, still present)', () => { + const footer = new FooterComponent(baseState({ goal: goal({ status: 'blocked' }) })); + const out = strip(footer.render(160)[0]!); + expect(out).toContain('[goal'); + expect(out).toContain('blocked'); + }); + + it('hides the badge for a completed goal', () => { + const footer = new FooterComponent(baseState({ goal: goal({ status: 'complete' }) })); + expect(strip(footer.render(160)[0]!)).not.toContain('[goal'); + }); + + it('singularizes a single turn', () => { + const footer = new FooterComponent(baseState({ goal: goal({ turnsUsed: 1 }) })); + const out = strip(footer.render(160)[0]!); + expect(out).toContain('1 turn'); + expect(out).not.toContain('1 turns'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/help-panel.test.ts b/apps/kimi-code/test/tui/components/panels/help-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..52f94430b84b8a31717c688a426b62961e8534fb --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/help-panel.test.ts @@ -0,0 +1,103 @@ +import { describe, it, expect, vi } from 'vitest'; + +import type { KimiSlashCommand } from '#/tui/commands/index'; +import { HelpPanelComponent } from '#/tui/components/dialogs/help-panel'; + +function cmd(name: string, description: string, aliases: string[] = []): KimiSlashCommand { + return { + name, + aliases, + description, + }; +} + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('HelpPanelComponent', () => { + it('renders keyboard shortcuts + slash commands sections', () => { + const panel = new HelpPanelComponent({ + commands: [cmd('exit', 'Exit', ['quit', 'q'])], + onClose: () => {}, + }); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/help/); + expect(out).toMatch(/Keyboard shortcuts/); + expect(out).toMatch(/Shift-Tab/); + expect(out).toMatch(/Ctrl-O/); + expect(out).toMatch(/Shift-Enter \/ Ctrl-J/); + expect(out).toMatch(/Slash commands/); + expect(out).toMatch(/\/exit \(\/quit, \/q\)/); + expect(out).toMatch(/Exit/); + }); + + it('sorts unprefixed commands before skill commands and by name within each group', () => { + const panel = new HelpPanelComponent({ + commands: [ + cmd('zebra', 'Z'), + cmd('skill:bravo', 'B'), + cmd('alpha', 'A'), + cmd('mcp-config', 'M'), + ], + onClose: () => {}, + }); + const out = strip(panel.render(80).join('\n')); + const alphaIdx = out.indexOf('/alpha'); + const mcpConfigIdx = out.indexOf('/mcp-config'); + const zebraIdx = out.indexOf('/zebra'); + const skillBravoIdx = out.indexOf('/skill:bravo'); + expect(alphaIdx).toBeGreaterThan(-1); + expect(alphaIdx).toBeLessThan(mcpConfigIdx); + expect(mcpConfigIdx).toBeLessThan(zebraIdx); + expect(zebraIdx).toBeLessThan(skillBravoIdx); + }); + + it('Escape fires onClose', () => { + const onClose = vi.fn(); + const panel = new HelpPanelComponent({ + commands: [], + onClose, + }); + panel.handleInput('\u001B'); // Esc + expect(onClose).toHaveBeenCalledTimes(1); + }); + + it('q / Enter also close the panel', () => { + const onClose = vi.fn(); + const panel = new HelpPanelComponent({ + commands: [], + onClose, + }); + panel.handleInput('q'); + panel.handleInput('\r'); + expect(onClose).toHaveBeenCalledTimes(2); + }); + + it('clips to maxVisible with a "showing X-Y of Z" tail', () => { + const many = Array.from({ length: 30 }, (_, i) => cmd(`cmd${String(i)}`, `Desc ${String(i)}`)); + const panel = new HelpPanelComponent({ + commands: many, + onClose: () => {}, + maxVisible: 6, + }); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/showing 1-6 of/); + }); + + it('arrow keys shift the scroll window', () => { + const many = Array.from({ length: 30 }, (_, i) => cmd(`cmd${String(i)}`, 'd')); + const panel = new HelpPanelComponent({ + commands: many, + onClose: () => {}, + maxVisible: 6, + }); + panel.handleInput('\u001B[B'); // ↓ + panel.handleInput('\u001B[B'); // ↓ + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/showing 3-8 of/); + panel.handleInput('\u001B[A'); // ↑ + const out2 = strip(panel.render(80).join('\n')); + expect(out2).toMatch(/showing 2-7 of/); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/notify-panel.test.ts b/apps/kimi-code/test/tui/components/panels/notify-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f47abbefdc6afff164cd70544349761fd38cda5 --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/notify-panel.test.ts @@ -0,0 +1,296 @@ +import { describe, expect, it } from 'vitest'; + +import { + NotifyPanelComponent, + type NotifyEntry, +} from '#/tui/components/chrome/notify-panel'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function render(panel: NotifyPanelComponent, width = 80): string[] { + return panel.render(width).map(strip); +} + +/** Line 0 is a blank spacer separating the box from the scrolling transcript. */ +function titleOf(panel: NotifyPanelComponent, width = 80): string { + return render(panel, width)[1]!; +} + +function entry(id: string, text: string, agentId = 'main', agentName?: string): NotifyEntry { + return { id, agentId, agentName, time: 0, text }; +} + +function listRows(count: number, prefix = 'row'): string { + return Array.from({ length: count }, (_, i) => `- ${prefix} ${String(i + 1)}`).join('\n'); +} + +describe('NotifyPanelComponent', () => { + it('returns no lines when empty (so the layout slot collapses)', () => { + const panel = new NotifyPanelComponent(); + expect(panel.render(80)).toEqual([]); + expect(panel.isEmpty()).toBe(true); + expect(panel.focus()).toBe(false); + }); + + it('renders the update in a padded, bordered box with the channel tab', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'Login module is clean; the bug is in **session expiry**.')); + const lines = render(panel); + + expect(lines[0]).toBe(''); + expect(lines[1]).toMatch(/^╭/); + expect(lines[1]).toContain('main'); + expect(lines[1]).toContain('Updates 1/1'); + expect(lines[1]).toContain('ctrl+n page'); + expect(lines[1]).toMatch(/─╮$/); + expect(lines[2]).toMatch(/^│\s*│$/); + expect(lines[3]).toMatch(/^│ /); + expect(lines[3]).toContain('Login module is clean; the bug is in session expiry.'); + expect(lines.at(-2)).toMatch(/^│\s*│$/); + expect(lines.at(-1)).toMatch(/^╰─+╯$/); + }); + + it('updates an entry in place and flattens entries in display order', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'Reading the')); + panel.upsert(entry('tc-1', 'Reading the parser first.')); + expect(panel.getEntries().map((item) => item.text)).toEqual(['Reading the parser first.']); + expect(render(panel).join('\n')).toContain('Reading the parser first.'); + }); + + it('follows the latest activity across channels while unfocused', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'main phase one')); + panel.upsert(entry('tc-2', 'main phase two')); + expect(titleOf(panel)).toContain('Updates 2/2'); + + panel.upsert(entry('a0:c1', 'explore finding', 'a0', 'explore')); + const lines = render(panel); + expect(lines[1]).toContain('main'); + expect(lines[1]).toContain('explore'); + expect(lines[1]).toContain('Updates 1/1'); + expect(lines.join('\n')).toContain('explore finding'); + expect(lines.join('\n')).not.toContain('main phase'); + }); + + it('switches channels with prev/nextChannel and pages inside a channel', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'main one')); + panel.upsert(entry('tc-2', 'main two')); + panel.upsert(entry('a0:c1', 'explore one', 'a0', 'explore')); + + expect(panel.focus()).toBe(true); + expect(panel.nextChannel()).toBe(false); + + expect(panel.prevChannel()).toBe(true); + expect(titleOf(panel)).toContain('Updates 2/2'); + expect(render(panel).join('\n')).toContain('main two'); + + expect(panel.prevPage()).toBe(true); + expect(titleOf(panel)).toContain('Updates 1/2'); + expect(render(panel).join('\n')).toContain('main one'); + expect(panel.prevPage()).toBe(false); + + expect(panel.nextPage()).toBe(true); + expect(render(panel).join('\n')).toContain('main two'); + }); + + it('collects an unread dot on background channels while focused, cleared on visit', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'main one')); + panel.upsert(entry('a0:c1', 'explore one', 'a0', 'explore')); + + panel.focus(); + panel.prevChannel(); + expect(titleOf(panel)).not.toContain('●'); + + panel.upsert(entry('a0:c2', 'explore two', 'a0', 'explore')); + expect(titleOf(panel)).toContain('explore●'); + expect(render(panel).join('\n')).toContain('main one'); + + expect(panel.nextChannel()).toBe(true); + expect(titleOf(panel)).not.toContain('●'); + expect(titleOf(panel)).toContain('Updates 2/2'); + expect(render(panel).join('\n')).toContain('explore two'); + }); + + it('dedups repeated channel labels with a counter', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('a1:c1', 'first explore', 'a1', 'explore')); + panel.upsert(entry('a2:c1', 'second explore', 'a2', 'explore')); + + expect(panel.getChannels().map((ch) => ch.label)).toEqual(['explore', 'explore(2)']); + }); + + it('labels channels by raw agent id when no name is known', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('a9:c1', 'mystery worker', 'agent-9')); + expect(panel.getChannels().map((ch) => ch.label)).toEqual(['agent-9']); + expect(titleOf(panel)).toContain('agent-9'); + }); + + it('renders every row of a long entry — adaptive height, no truncation', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', listRows(30))); + const text = render(panel).join('\n'); + expect(text).toContain('row 1'); + expect(text).toContain('row 30'); + expect(text).not.toContain('later lines'); + expect(text).not.toContain('more lines'); + }); + + it('renders focus state: highlighted hints, blur restores', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'phase one')); + + expect(titleOf(panel)).toContain('ctrl+n page'); + panel.focus(); + expect(titleOf(panel)).toContain('← → agent · ↑ ↓ update · esc close'); + panel.blur(); + expect(panel.blur()).toBe(false); + expect(titleOf(panel)).toContain('ctrl+n page'); + }); + + it('folds to a one-line preview stub when the turn ends, expands on focus', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'phase one intro\n\n- detail one\n- detail two')); + panel.setEnded(true); + + const collapsed = render(panel); + expect(collapsed).toHaveLength(2); + expect(collapsed[0]).toBe(''); + expect(collapsed[1]).toContain('▸'); + expect(collapsed[1]).toContain('main'); + expect(collapsed[1]).toContain('1 update'); + expect(collapsed[1]).toContain('phase one intro'); + expect(collapsed[1]).toContain('ctrl+n'); + expect(collapsed[1]).not.toContain('detail one'); + expect(collapsed[1]).not.toMatch(/[╭╮╰╯│]/); + + panel.focus(); + const expanded = render(panel); + expect(expanded.join('\n')).toContain('detail one'); + expect(expanded.length).toBeGreaterThan(2); + + panel.blur(); + expect(render(panel)).toHaveLength(2); + }); + + it('stays expanded when the turn ends while the user is reading, folds on blur', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'phase one')); + panel.focus(); + panel.setEnded(true); + + expect(render(panel).join('\n')).toContain('phase one'); + + panel.blur(); + expect(render(panel)).toHaveLength(2); + }); + + it('unfolds and undims when a fresh update arrives after the turn ended', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'done with phase one')); + panel.setEnded(true); + expect(render(panel)).toHaveLength(2); + + panel.upsert(entry('tc-2', 'fresh turn update')); + const lines = render(panel); + expect(lines.join('\n')).toContain('fresh turn update'); + expect(lines[1]).not.toContain('turn ended'); + }); + + it('removes an entry and drops empty channels', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'main one')); + panel.upsert(entry('a0:c1', 'explore one', 'a0', 'explore')); + + expect(panel.remove('a0:c1')).toBe(true); + expect(panel.getChannels().map((ch) => ch.label)).toEqual(['main']); + expect(panel.remove('missing')).toBe(false); + }); + + it('clamps the page when the newest entry is removed', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'first')); + panel.upsert(entry('tc-2', 'second')); + expect(titleOf(panel)).toContain('Updates 2/2'); + + expect(panel.remove('tc-2')).toBe(true); + expect(titleOf(panel)).toContain('Updates 1/1'); + expect(panel.nextPage()).toBe(false); + }); + + it('releases focus when removal empties the panel', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'only')); + expect(panel.focus()).toBe(true); + + expect(panel.remove('tc-1')).toBe(true); + expect(panel.isEmpty()).toBe(true); + expect(panel.isFocused()).toBe(false); + expect(panel.prevPage()).toBe(false); + expect(panel.nextPage()).toBe(false); + }); + + it('clears the unread count when a retracted entry was unread', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'main one')); + panel.upsert(entry('a0:c1', 'explore one', 'a0', 'explore')); + expect(panel.focus()).toBe(true); + + panel.upsert(entry('tc-2', 'main two')); + const before = panel.getChannels().find((ch) => ch.label === 'main'); + expect(before?.unread).toBe(1); + + expect(panel.remove('tc-2')).toBe(true); + const after = panel.getChannels().find((ch) => ch.label === 'main'); + expect(after?.unread).toBe(0); + }); + + it('keeps the unread count when a retracted entry was already read', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'main one')); + panel.upsert(entry('a0:c1', 'explore one', 'a0', 'explore')); + expect(panel.focus()).toBe(true); + + panel.upsert(entry('tc-2', 'delegation')); + expect(panel.getChannels().find((ch) => ch.label === 'main')?.unread).toBe(1); + + expect(panel.prevChannel()).toBe(true); + expect(panel.nextChannel()).toBe(true); + panel.upsert(entry('tc-3', 'main three')); + expect(panel.getChannels().find((ch) => ch.label === 'main')?.unread).toBe(1); + + expect(panel.remove('tc-2')).toBe(true); + expect(panel.getChannels().find((ch) => ch.label === 'main')?.unread).toBe(1); + }); + + it('dims to a stub and notes the ended turn, and clears wholesale', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', 'done with phase one')); + panel.setEnded(true); + expect(render(panel)).toHaveLength(2); + expect(titleOf(panel)).toContain('ctrl+n'); + + panel.clear(); + expect(panel.isEmpty()).toBe(true); + expect(panel.render(80)).toEqual([]); + + panel.upsert(entry('tc-2', 'fresh turn')); + expect(titleOf(panel)).not.toContain('turn ended'); + }); + + it('never renders wider than the requested width', () => { + const panel = new NotifyPanelComponent(); + panel.upsert(entry('tc-1', `${'word '.repeat(60)}\n\n- a very long bullet ${'x'.repeat(120)}`)); + panel.upsert(entry('a1:c1', listRows(12, 'later'), 'a1', 'explore')); + for (const width of [24, 40, 80]) { + for (const line of panel.render(width)) { + expect(strip(line).length).toBeLessThanOrEqual(width); + } + } + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/plan-box.test.ts b/apps/kimi-code/test/tui/components/panels/plan-box.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d970bb80f5a545b5d05931ddaf0db40a6efaaea --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/plan-box.test.ts @@ -0,0 +1,118 @@ +import { pathToFileURL } from 'node:url'; + +import { visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { PlanBoxComponent } from '#/tui/components/messages/plan-box'; +import { darkColors } from '#/tui/theme/colors'; +import { createMarkdownTheme } from '#/tui/theme/pi-tui-theme'; + +const ESC = String.fromCodePoint(0x1b); +const BEL = String.fromCodePoint(0x07); + +// Strip CSI styling and OSC 8 hyperlink sequences from rendered output so +// visible text can be matched directly. +function strip(text: string): string { + return text + .replaceAll(new RegExp(`${ESC}\\[[0-9;]*m`, 'g'), '') + .replaceAll(new RegExp(`${ESC}\\]8;;[^${BEL}]*${BEL}`, 'g'), ''); +} + +const theme = createMarkdownTheme(); + +describe('PlanBoxComponent', () => { + it('falls back to bare " plan " title when no path is provided', () => { + const box = new PlanBoxComponent('# Hello', theme, darkColors.success); + const out = strip(box.render(60).join('\n')); + const top = out.split('\n')[0]!; + expect(top).toContain('┌ plan '); + expect(top).not.toContain('plan:'); + }); + + it('renders " plan: " in the top border without the directory prefix', () => { + const box = new PlanBoxComponent( + '# Hello', + theme, + darkColors.success, + '/tmp/projects/foo/.kimi-code/plans/very-long-slug-name.md', + ); + const out = strip(box.render(80).join('\n')); + const top = out.split('\n')[0]!; + expect(top).toContain(' plan: very-long-slug-name.md '); + expect(top).not.toContain('/tmp/'); + expect(top).not.toContain('…/'); + }); + + it('renders a status chip in the top border', () => { + const box = new PlanBoxComponent('# Hello', theme, darkColors.success, undefined, { + status: { label: 'Rejected', colorHex: darkColors.error }, + }); + const out = strip(box.render(60).join('\n')); + const top = out.split('\n')[0]!; + expect(top).toContain(' plan · Rejected '); + }); + + it('keeps path status title to the basename without leaking directories', () => { + const box = new PlanBoxComponent( + '# Hello', + theme, + darkColors.success, + '/tmp/projects/foo/.kimi-code/plans/rejected-plan.md', + { + status: { label: 'Rejected', colorHex: darkColors.error }, + }, + ); + const out = strip(box.render(80).join('\n')); + const top = out.split('\n')[0]!; + expect(top).toContain(' plan: rejected-plan.md · Rejected '); + expect(top).not.toContain('/tmp/'); + expect(top).not.toContain('…/'); + }); + + it('wraps the basename in an OSC 8 hyperlink targeting file://', () => { + const box = new PlanBoxComponent('# Hello', theme, darkColors.success, '/tmp/plan.md'); + const top = box.render(60)[0]!; + expect(top).toContain(`${ESC}]8;;${pathToFileURL('/tmp/plan.md').href}${BEL}plan.md${ESC}]8;;${BEL}`); + // After stripping OSC + CSI, visible width must respect the requested render width. + expect(strip(top).length).toBeLessThanOrEqual(60); + }); + + it('skips the hyperlink for non-absolute paths but still shows the basename', () => { + const box = new PlanBoxComponent('# Hello', theme, darkColors.success, 'relative/plan.md'); + const top = box.render(60)[0]!; + expect(top).not.toContain(`${ESC}];`); + expect(strip(top)).toContain(' plan: plan.md '); + }); + + it('degrades to bare " plan " when even the basename does not fit', () => { + const box = new PlanBoxComponent('# Hello', theme, darkColors.success, '/tmp/plan.md'); + const out = strip(box.render(14).join('\n')); + const top = out.split('\n')[0]!; + expect(top).toContain(' plan '); + expect(top).not.toContain('plan:'); + }); + + it('keeps every line within narrow widths', () => { + const box = new PlanBoxComponent( + '# Hello\n\n' + 'step with a fairly long description '.repeat(4), + theme, + darkColors.success, + '/tmp/projects/foo/.kimi-code/plans/very-long-slug-name.md', + ); + + for (const width of [39, 14, 10, 8, 4, 1]) { + for (const line of box.render(width)) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + } + }); + + it('renders all plan lines without a truncation footer', () => { + const plan = Array.from({ length: 30 }, (_, i) => `- step ${String(i + 1)}`).join('\n'); + const box = new PlanBoxComponent(plan, theme, darkColors.success); + const out = strip(box.render(80).join('\n')); + expect(out).toContain('step 1'); + expect(out).toContain('step 30'); + expect(out).not.toContain('more lines'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panels/todo-panel.test.ts b/apps/kimi-code/test/tui/components/panels/todo-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee6dcbb1c6b87bee33d7e366d4c6519342bf82ef --- /dev/null +++ b/apps/kimi-code/test/tui/components/panels/todo-panel.test.ts @@ -0,0 +1,383 @@ +import { describe, it, expect } from 'vitest'; + +import { + TodoPanelComponent, + formatHiddenCounts, + selectVisibleTodos, + type TodoItem, +} from '#/tui/components/chrome/todo-panel'; + +function strip(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('TodoPanelComponent', () => { + it('returns no lines when empty (so the layout slot collapses)', () => { + const panel = new TodoPanelComponent(); + expect(panel.render(80)).toEqual([]); + expect(panel.isEmpty()).toBe(true); + }); + + it('renders a Todo header + one row per entry', () => { + const panel = new TodoPanelComponent(); + panel.setTodos([ + { title: 'Investigate parser', status: 'done' }, + { title: 'Add tests', status: 'in_progress' }, + { title: 'Open PR', status: 'pending' }, + ]); + const lines = panel.render(80).map(strip); + const joined = lines.join('\n'); + expect(joined).toMatch(/Todo/); + expect(joined).toMatch(/✓ Investigate parser/); + expect(joined).toMatch(/● Add tests/); + expect(joined).toMatch(/○ Open PR/); + }); + + it('setTodos replaces the list (not appends)', () => { + const panel = new TodoPanelComponent(); + panel.setTodos([{ title: 'old', status: 'pending' }]); + panel.setTodos([{ title: 'new', status: 'in_progress' }]); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/● new/); + expect(out).not.toMatch(/old/); + }); + + it('clear() wipes the list and reverts to empty', () => { + const panel = new TodoPanelComponent(); + panel.setTodos([{ title: 'x', status: 'pending' }]); + panel.clear(); + expect(panel.isEmpty()).toBe(true); + expect(panel.render(80)).toEqual([]); + }); + + it('defensive copy: external mutation does not leak into the panel', () => { + const panel = new TodoPanelComponent(); + const source: TodoItem[] = [{ title: 'foo', status: 'pending' }]; + panel.setTodos(source); + source[0] = { title: 'hacked', status: 'done' }; + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/○ foo/); + expect(out).not.toMatch(/hacked/); + }); + + it('renders all todos and no overflow footer when count <= 5', () => { + const panel = new TodoPanelComponent(); + panel.setTodos([ + { title: 'a', status: 'done' }, + { title: 'b', status: 'in_progress' }, + { title: 'c', status: 'pending' }, + { title: 'd', status: 'pending' }, + { title: 'e', status: 'pending' }, + ]); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/a/); + expect(out).toMatch(/e/); + expect(out).not.toMatch(/\+\d+ more/); + }); + + it('appends "+N more" footer when count > 5', () => { + const panel = new TodoPanelComponent(); + panel.setTodos([ + { title: 't0', status: 'done' }, + { title: 't1', status: 'in_progress' }, + { title: 't2', status: 'pending' }, + { title: 't3', status: 'pending' }, + { title: 't4', status: 'pending' }, + { title: 't5', status: 'pending' }, + { title: 't6', status: 'pending' }, + ]); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/\+2 more/); + }); + + const many = (n: number): TodoItem[] => + Array.from({ length: n }, (_, i) => ({ title: `t${i}`, status: 'pending' as const })); + + it('hasOverflow() is false when count <= 5 and true when count > 5', () => { + const panel = new TodoPanelComponent(); + panel.setTodos(many(5)); + expect(panel.hasOverflow()).toBe(false); + panel.setTodos(many(6)); + expect(panel.hasOverflow()).toBe(true); + }); + + it('collapsed footer advertises "ctrl+t to expand"', () => { + const panel = new TodoPanelComponent(); + panel.setTodos(many(7)); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/\+2 more/); + expect(out).toMatch(/ctrl\+t to expand/); + }); + + it('collapsed footer shows hidden status distribution', () => { + const panel = new TodoPanelComponent(); + panel.setTodos([ + ...Array.from({ length: 6 }, (_, i) => ({ + title: `ip${i}`, + status: 'in_progress' as const, + })), + ...Array.from({ length: 3 }, (_, i) => ({ title: `d${i}`, status: 'done' as const })), + ...Array.from({ length: 3 }, (_, i) => ({ title: `p${i}`, status: 'pending' as const })), + ]); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/\+7 more \(3 done · 1 in progress · 3 pending\)/); + expect(out).toMatch(/ctrl\+t to expand/); + }); + + it('collapsed footer omits zero-count statuses', () => { + const panel = new TodoPanelComponent(); + panel.setTodos( + Array.from({ length: 8 }, (_, i) => ({ title: `d${i}`, status: 'done' as const })), + ); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/\+3 more \(3 done\)/); + expect(out).not.toMatch(/0 in progress/); + expect(out).not.toMatch(/0 pending/); + }); + + it('expanded footer does not include status distribution', () => { + const panel = new TodoPanelComponent(); + panel.setTodos( + Array.from({ length: 8 }, (_, i) => ({ title: `d${i}`, status: 'done' as const })), + ); + panel.setExpanded(true); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/all 8 items · ctrl\+t to collapse/); + expect(out).not.toMatch(/\d+ done ·/); + }); + + it('renders every todo with a collapse hint when expanded', () => { + const panel = new TodoPanelComponent(); + panel.setTodos(many(7)); + panel.setExpanded(true); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/t0/); + expect(out).toMatch(/t6/); + expect(out).not.toMatch(/\+\d+ more/); + expect(out).toMatch(/ctrl\+t to collapse/); + }); + + it('toggleExpanded() flips between collapsed and expanded', () => { + const panel = new TodoPanelComponent(); + panel.setTodos(many(7)); + expect(strip(panel.render(80).join('\n'))).toMatch(/\+2 more/); + panel.toggleExpanded(); + expect(strip(panel.render(80).join('\n'))).toMatch(/ctrl\+t to collapse/); + panel.toggleExpanded(); + expect(strip(panel.render(80).join('\n'))).toMatch(/\+2 more/); + }); + + it('setTodos() keeps the expanded state across list updates', () => { + const panel = new TodoPanelComponent(); + panel.setTodos(many(7)); + panel.setExpanded(true); + panel.setTodos([ + { title: 'u0', status: 'pending' }, + { title: 'u1', status: 'pending' }, + { title: 'u2', status: 'pending' }, + { title: 'u3', status: 'pending' }, + { title: 'u4', status: 'pending' }, + { title: 'u5', status: 'pending' }, + { title: 'u6', status: 'pending' }, + ]); + const out = strip(panel.render(80).join('\n')); + expect(out).toMatch(/u6/); + expect(out).toMatch(/ctrl\+t to collapse/); + }); + + it('clear() resets the expanded state', () => { + const panel = new TodoPanelComponent(); + panel.setTodos(many(7)); + panel.setExpanded(true); + panel.clear(); + panel.setTodos(many(7)); + expect(strip(panel.render(80).join('\n'))).toMatch(/\+2 more/); + }); +}); + +describe('selectVisibleTodos', () => { + const T = (title: string, status: TodoItem['status']): TodoItem => ({ title, status }); + + it('returns all items unchanged when count <= 5', () => { + const todos: TodoItem[] = [ + T('a', 'done'), + T('b', 'in_progress'), + T('c', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows).toEqual(todos); + expect(hidden).toBe(0); + }); + + it('with 1 in_progress: shows 1 done before + in_progress + 3 pending after', () => { + const todos: TodoItem[] = [ + T('d1', 'done'), + T('d2', 'done'), + T('d3', 'done'), + T('ip', 'in_progress'), + T('p1', 'pending'), + T('p2', 'pending'), + T('p3', 'pending'), + T('p4', 'pending'), + T('p5', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['d3', 'ip', 'p1', 'p2', 'p3']); + expect(hidden).toBe(4); + }); + + it('with 1 in_progress and no done before: fills with pending after', () => { + const todos: TodoItem[] = [ + T('ip', 'in_progress'), + T('p1', 'pending'), + T('p2', 'pending'), + T('p3', 'pending'), + T('p4', 'pending'), + T('p5', 'pending'), + T('p6', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['ip', 'p1', 'p2', 'p3', 'p4']); + expect(hidden).toBe(2); + }); + + it('with 1 in_progress and few pending after: expands done before', () => { + const todos: TodoItem[] = [ + T('d1', 'done'), + T('d2', 'done'), + T('d3', 'done'), + T('d4', 'done'), + T('d5', 'done'), + T('ip', 'in_progress'), + T('p1', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['d3', 'd4', 'd5', 'ip', 'p1']); + expect(hidden).toBe(2); + }); + + it('all pending: shows first 5', () => { + const todos: TodoItem[] = Array.from({ length: 8 }, (_, i) => T(`p${i}`, 'pending')); + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['p0', 'p1', 'p2', 'p3', 'p4']); + expect(hidden).toBe(3); + }); + + it('all done: shows last 5', () => { + const todos: TodoItem[] = Array.from({ length: 8 }, (_, i) => T(`d${i}`, 'done')); + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['d3', 'd4', 'd5', 'd6', 'd7']); + expect(hidden).toBe(3); + }); + + it('mixed done+pending without in_progress: 1 done + 4 pending', () => { + const todos: TodoItem[] = [ + T('d1', 'done'), + T('d2', 'done'), + T('d3', 'done'), + T('p1', 'pending'), + T('p2', 'pending'), + T('p3', 'pending'), + T('p4', 'pending'), + T('p5', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['d3', 'p1', 'p2', 'p3', 'p4']); + expect(hidden).toBe(3); + }); + + it('multiple in_progress: all included up to MAX cap', () => { + const todos: TodoItem[] = [ + T('ip1', 'in_progress'), + T('ip2', 'in_progress'), + T('ip3', 'in_progress'), + T('p1', 'pending'), + T('p2', 'pending'), + T('p3', 'pending'), + T('p4', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['ip1', 'ip2', 'ip3', 'p1', 'p2']); + expect(hidden).toBe(2); + }); + + it('no in_progress, interleaved done/pending order: still picks MAX items', () => { + const todos: TodoItem[] = [ + T('p0', 'pending'), + T('d0', 'done'), + T('p1', 'pending'), + T('d1', 'done'), + T('p2', 'pending'), + T('d2', 'done'), + T('p3', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.length).toBe(5); + expect(hidden).toBe(2); + expect(rows.filter((r) => r.status === 'pending').length).toBe(4); + expect(rows.filter((r) => r.status === 'done').length).toBe(1); + }); + + it('done appearing after in_progress is still treated as recent context', () => { + const todos: TodoItem[] = [ + T('ip', 'in_progress'), + T('p1', 'pending'), + T('d1', 'done'), + T('p2', 'pending'), + T('p3', 'pending'), + T('p4', 'pending'), + T('p5', 'pending'), + ]; + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.length).toBe(5); + expect(hidden).toBe(2); + expect(rows.some((r) => r.status === 'in_progress')).toBe(true); + expect(rows.some((r) => r.status === 'done')).toBe(true); + }); + + it('more than 5 in_progress: caps at 5 keeping the earliest', () => { + const todos: TodoItem[] = Array.from({ length: 7 }, (_, i) => + T(`ip${i}`, 'in_progress'), + ); + const { rows, hidden } = selectVisibleTodos(todos); + expect(rows.map((r) => r.title)).toEqual(['ip0', 'ip1', 'ip2', 'ip3', 'ip4']); + expect(hidden).toBe(2); + }); + + it('returns hiddenCounts reflecting the hidden items', () => { + const todos: TodoItem[] = [ + ...Array.from({ length: 6 }, (_, i) => T(`ip${i}`, 'in_progress')), + ...Array.from({ length: 3 }, (_, i) => T(`d${i}`, 'done')), + ...Array.from({ length: 3 }, (_, i) => T(`p${i}`, 'pending')), + ]; + const { hidden, hiddenCounts } = selectVisibleTodos(todos); + expect(hidden).toBe(7); + expect(hiddenCounts).toEqual({ done: 3, in_progress: 1, pending: 3 }); + }); + + it('returns zero hiddenCounts when count <= 5', () => { + const todos: TodoItem[] = [T('a', 'done'), T('b', 'in_progress'), T('c', 'pending')]; + const { hidden, hiddenCounts } = selectVisibleTodos(todos); + expect(hidden).toBe(0); + expect(hiddenCounts).toEqual({ done: 0, in_progress: 0, pending: 0 }); + }); +}); + +describe('formatHiddenCounts', () => { + it('formats all three statuses in done / in progress / pending order', () => { + expect(formatHiddenCounts({ done: 2, in_progress: 1, pending: 3 })).toBe( + '2 done · 1 in progress · 3 pending', + ); + }); + + it('omits zero-count statuses', () => { + expect(formatHiddenCounts({ done: 5, in_progress: 0, pending: 0 })).toBe('5 done'); + expect(formatHiddenCounts({ done: 0, in_progress: 2, pending: 3 })).toBe( + '2 in progress · 3 pending', + ); + }); + + it('returns empty string when all counts are zero', () => { + expect(formatHiddenCounts({ done: 0, in_progress: 0, pending: 0 })).toBe(''); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panes/activity-pane.test.ts b/apps/kimi-code/test/tui/components/panes/activity-pane.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..314c7a18a86a4af62bc79a7da9272384b30537d1 --- /dev/null +++ b/apps/kimi-code/test/tui/components/panes/activity-pane.test.ts @@ -0,0 +1,113 @@ +import { Text, visibleWidth } from '@moonshot-ai/pi-tui'; +import { describe, expect, it } from 'vitest'; + +import { ActivityPaneComponent } from '#/tui/components/panes/activity-pane'; + +function createMockSpinner(initialText = 'working') { + const spinner = new Text(initialText, 0, 0); + let tip = ''; + let availableWidth = 0; + const update = () => { + const fullText = initialText + tip; + spinner.setText(availableWidth > 0 && visibleWidth(fullText) > availableWidth ? initialText : fullText); + }; + return { + spinner: Object.assign(spinner, { + setTip(value: string) { + tip = value; + update(); + }, + setAvailableWidth(width: number) { + availableWidth = width; + update(); + }, + }) as unknown as import('#/tui/components/chrome/moon-loader').MoonLoader, + getTip: () => tip, + }; +} + +describe('ActivityPaneComponent', () => { + it('renders waiting loader after a spacer', () => { + const { spinner } = createMockSpinner('loading'); + const component = new ActivityPaneComponent({ + mode: 'waiting', + spinner, + }); + + expect(component.render(80).map((line) => line.trimEnd())).toEqual(['', 'loading']); + }); + + it('renders composing spinner after a spacer', () => { + const { spinner } = createMockSpinner('working'); + const component = new ActivityPaneComponent({ + mode: 'composing', + spinner, + }); + + expect(component.render(80).map((line) => line.trimEnd())).toEqual(['', 'working']); + }); + + it('renders the detail line under the waiting spinner', () => { + const { spinner } = createMockSpinner('working'); + const component = new ActivityPaneComponent({ + mode: 'waiting', + spinner, + detail: '429 · rate limited', + }); + + const lines = component + .render(80) + .map((line) => line.replaceAll(/\u001B\[[0-9;]*m/g, '').trimEnd()); + expect(lines).toEqual(['', 'working', ' 429 · rate limited']); + }); + + it.each(['waiting', 'tool', 'composing'] as const)( + 'renders %s spinner with tip after a spacer', + (mode) => { + const { spinner } = createMockSpinner('working'); + const component = new ActivityPaneComponent({ + mode, + spinner, + tip: 'ctrl+s: steer mid-turn', + }); + + expect(component.render(80).map((line) => line.trimEnd())).toEqual([ + '', + 'working · Tip: ctrl+s: steer mid-turn', + ]); + }, + ); + + it.each(['waiting', 'tool', 'composing'] as const)( + 'does not render a tip for %s when none is provided', + (mode) => { + const { spinner } = createMockSpinner('working'); + const component = new ActivityPaneComponent({ + mode, + spinner, + }); + + expect(component.render(80).map((line) => line.trimEnd())).toEqual(['', 'working']); + }, + ); + + it('renders nothing for hidden and thinking modes', () => { + expect(new ActivityPaneComponent({ mode: 'hidden' }).render(80)).toEqual([]); + expect(new ActivityPaneComponent({ mode: 'thinking' }).render(80)).toEqual([]); + }); + + it.each(['waiting', 'tool', 'composing'] as const)( + 'hides the tip for %s when the terminal is too narrow', + (mode) => { + const { spinner } = createMockSpinner('working'); + const component = new ActivityPaneComponent({ + mode, + spinner, + tip: 'ctrl+s: steer mid-turn', + }); + + // Width 8 is exactly the width of "working" (no spinner frame in the mock). + expect(component.render(8).map((line) => line.trimEnd())).toEqual(['', 'working']); + }, + ); +}); diff --git a/apps/kimi-code/test/tui/components/panes/queue-pane.test.ts b/apps/kimi-code/test/tui/components/panes/queue-pane.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f9a0117799b485db8a069103b85123af543085c --- /dev/null +++ b/apps/kimi-code/test/tui/components/panes/queue-pane.test.ts @@ -0,0 +1,122 @@ +import { describe, expect, it } from 'vitest'; + +import { QueuePaneComponent } from '#/tui/components/panes/queue-pane'; + +function stripAnsi(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +describe('QueuePaneComponent', () => { + it('renders queued messages with the steer hint', () => { + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: true, + messages: [ + { text: 'first message' }, + { text: '/skill:review src/app.ts' }, + ], + }); + + const output = stripAnsi(component.render(120).join('\n')); + + expect(output).toContain('❯ first message'); + expect(output).toContain('❯ /skill:review src/app.ts'); + expect(output).toContain('ctrl-s to steer immediately'); + }); + + it('renders compaction hint when waiting for compaction', () => { + const component = new QueuePaneComponent({ + isCompacting: true, + isStreaming: false, + canSteerImmediately: true, + messages: [{ text: 'after compact' }], + }); + + const output = stripAnsi(component.render(120).join('\n')); + + expect(output).toContain('will send after compaction'); + }); + + it('omits the steer hint when immediate steering is disabled', () => { + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: false, + messages: [{ text: 'after init' }], + }); + + const output = stripAnsi(component.render(120).join('\n')); + + expect(output).toContain('will send after current task'); + expect(output).not.toContain('ctrl-s to steer immediately'); + }); + + it('truncates long messages to a single line', () => { + const longText = 'a'.repeat(200); + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: true, + messages: [{ text: longText }], + }); + + const lines = component.render(30); + expect(lines).toHaveLength(3); // border + message + hint + const messageLine = stripAnsi(lines[1] as string); + expect(messageLine).not.toContain('a'.repeat(30)); + expect(messageLine.endsWith('…')).toBe(true); + }); + + it('collapses multiline text into a single line', () => { + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: true, + messages: [{ text: 'line one\nline two\nline three' }], + }); + + const lines = component.render(120); + expect(lines).toHaveLength(3); // border + message + hint + const messageLine = stripAnsi(lines[1] as string); + expect(messageLine).toContain('line one line two line three'); + expect(messageLine).not.toContain('\n'); + }); + + it('renders bash queued items with a $ prompt to distinguish them from text', () => { + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: false, + messages: [{ text: 'ls -la', mode: 'bash' }], + }); + + const output = stripAnsi(component.render(120).join('\n')); + expect(output).toContain('❯ $ ls -la'); + }); + + it('omits the steer hint when every queued item is a bash command', () => { + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: true, + messages: [{ text: 'ls', mode: 'bash' }], + }); + + const output = stripAnsi(component.render(120).join('\n')); + expect(output).not.toContain('ctrl-s to steer immediately'); + expect(output).toContain('will send after current task'); + }); + + it('keeps the steer hint when at least one queued item is steerable', () => { + const component = new QueuePaneComponent({ + isCompacting: false, + isStreaming: true, + canSteerImmediately: true, + messages: [{ text: 'ls', mode: 'bash' }, { text: 'focus on tests' }], + }); + + const output = stripAnsi(component.render(120).join('\n')); + expect(output).toContain('ctrl-s to steer immediately'); + }); +}); diff --git a/apps/kimi-code/test/tui/components/panes/survey-panel.test.ts b/apps/kimi-code/test/tui/components/panes/survey-panel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..177d87b951657938c400718947469b5b1ee204bc --- /dev/null +++ b/apps/kimi-code/test/tui/components/panes/survey-panel.test.ts @@ -0,0 +1,76 @@ +import chalk from 'chalk'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { visibleWidth } from '@moonshot-ai/pi-tui'; + +import { + SurveyPanelComponent, + type SurveyPanelView, +} from '#/tui/components/panes/survey-panel'; + +function stripAnsi(text: string): string { + return text.replaceAll(/\u001B\[[0-9;]*m/g, ''); +} + +function render(view: SurveyPanelView, width: number): string[] { + return new SurveyPanelComponent(view).render(width).map(stripAnsi); +} + +describe('SurveyPanelComponent', () => { + const previousChalkLevel = chalk.level; + + beforeEach(() => { + chalk.level = 3; + }); + + afterEach(() => { + chalk.level = previousChalkLevel; + }); + + it('renders the question and the four options on one line', () => { + const lines = render({ phase: 'open' }, 80); + expect(lines).toHaveLength(2); + expect(lines[0]).toContain('●'); + expect(lines[0]).toContain('How is Kimi doing this session? (optional)'); + expect(lines[1]).toBe(' 1: Bad 2: Fine 3: Good 0: Dismiss'); + }); + + it('folds the options onto their own lines when narrow', () => { + const lines = render({ phase: 'open' }, 30); + expect(lines[0]).toContain('How is Kimi doing this'); + expect(lines[1]).toContain('session? (optional)'); + expect(lines.slice(2)).toEqual([' 1: Bad', ' 2: Fine', ' 3: Good', ' 0: Dismiss']); + }); + + it('keeps only the title line at extreme widths, without hard-breaking', () => { + const width = 10; + const lines = render({ phase: 'open' }, width); + expect(lines.length).toBeGreaterThan(0); + for (const line of lines) { + expect(visibleWidth(line)).toBeLessThanOrEqual(width); + } + expect(lines.join('\n')).not.toContain('1: Bad'); + expect(lines[0]).toContain('●'); + }); + + it('renders the pending line with the chosen rating and the undo hint', () => { + const lines = render({ phase: 'pending', response: 'bad' }, 80); + expect(lines).toEqual(['● Feedback: Bad · [escape: undo]']); + }); + + it('renders the thanks line', () => { + const lines = render({ phase: 'thanks' }, 80); + expect(lines).toEqual(['● Thanks for your feedback!']); + }); + + it('highlights the hovered option', () => { + const plain = new SurveyPanelComponent({ phase: 'open' }).render(80)[1]!; + const hovered = new SurveyPanelComponent({ phase: 'open', hoverIndex: 2 }).render(80)[1]!; + expect(stripAnsi(hovered)).toBe(stripAnsi(plain)); + expect(hovered).not.toBe(plain); + expect(hovered).toContain('3: Good'); + }); + + it('renders a single blank line when the terminal cannot hold a column', () => { + expect(render({ phase: 'open' }, 0)).toEqual(['']); + }); +}); diff --git a/apps/kimi-code/test/tui/config.test.ts b/apps/kimi-code/test/tui/config.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..020bca5296df46605c4a96ddcd4e6a9ad03c9ba2 --- /dev/null +++ b/apps/kimi-code/test/tui/config.test.ts @@ -0,0 +1,296 @@ +import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { + DEFAULT_TUI_CONFIG, + INVALID_TUI_CONFIG_MESSAGE, + loadTuiConfig, + parseTuiConfig, + saveTuiConfig, + TuiConfigParseError, +} from '#/tui/config'; + +let dir: string; +let filePath: string; + +beforeEach(() => { + dir = join(tmpdir(), `kimi-tui-config-${Date.now()}-${Math.random().toString(36).slice(2)}`); + mkdirSync(dir, { recursive: true }); + filePath = join(dir, 'tui.toml'); +}); + +afterEach(() => { + rmSync(dir, { recursive: true, force: true }); +}); + +describe('TUI config', () => { + it('creates the default config when the file does not exist', async () => { + const result = await loadTuiConfig(filePath); + + expect(result).toEqual(DEFAULT_TUI_CONFIG); + const text = readFileSync(filePath, 'utf-8'); + expect(text).toContain('Client preferences for kimi-code.'); + expect(text).toContain('theme = "auto"'); + expect(text).toContain('cache_expiry_hint = true'); + expect(text).toContain('disable_feedback_survey = false'); + expect(text).toContain('command = ""'); + expect(text).toContain('[upgrade]'); + expect(text).toContain('auto_install = true'); + expect(text).toContain('[notifications]'); + expect(text).toContain('enabled = true'); + expect(text).toContain('notification_condition = "unfocused"'); + }); + + it('parses valid TOML', () => { + const config = parseTuiConfig(` +theme = "light" + +[editor] +command = "code --wait" + +[notifications] +enabled = false +notification_condition = "always" + +[upgrade] +auto_install = false +`); + + expect(config).toEqual({ + theme: 'light', + renderLatex: true, + disablePasteBurst: false, + cacheExpiryHint: true, + disableFeedbackSurvey: false, + editorCommand: 'code --wait', + notifications: { enabled: false, condition: 'always' }, + upgrade: { autoInstall: false }, + statusLine: { items: null, command: null }, + }); + }); + + it('parses disable_paste_burst', () => { + const config = parseTuiConfig(` +theme = "dark" +disable_paste_burst = true +`); + + expect(config.disablePasteBurst).toBe(true); + }); + + it('defaults render_latex to true and parses false', () => { + expect(parseTuiConfig('').renderLatex).toBe(true); + + const config = parseTuiConfig(` +render_latex = false +`); + + expect(config.renderLatex).toBe(false); + }); + + it('parses cache_expiry_hint', () => { + const config = parseTuiConfig(` +theme = "dark" +cache_expiry_hint = false +`); + + expect(config.cacheExpiryHint).toBe(false); + }); + + it('defaults disable_feedback_survey to false and parses true', () => { + expect(parseTuiConfig('').disableFeedbackSurvey).toBe(false); + + const config = parseTuiConfig(` +disable_feedback_survey = true +`); + + expect(config.disableFeedbackSurvey).toBe(true); + }); + + it('normalizes an empty editor command to auto-detect', () => { + const config = parseTuiConfig(` +[editor] +command = " " +`); + + expect(config).toEqual({ + theme: 'auto', + renderLatex: true, + disablePasteBurst: false, + cacheExpiryHint: true, + disableFeedbackSurvey: false, + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + statusLine: { items: null, command: null }, + }); + }); + + it('falls back to default notifications when the section is omitted', () => { + const config = parseTuiConfig(`theme = "dark"`); + + expect(config.notifications).toEqual({ enabled: true, condition: 'unfocused' }); + expect(config.upgrade).toEqual({ autoInstall: true }); + }); + + it('throws TuiConfigParseError with fallback when parsing fails, leaving the file untouched', async () => { + writeFileSync(filePath, '[[[', 'utf-8'); + + const error = await loadTuiConfig(filePath).then( + () => null, + (error: unknown) => error, + ); + + expect(error).toBeInstanceOf(TuiConfigParseError); + expect((error as TuiConfigParseError).message).toBe(INVALID_TUI_CONFIG_MESSAGE); + expect((error as TuiConfigParseError).fallback).toEqual(DEFAULT_TUI_CONFIG); + expect(readFileSync(filePath, 'utf-8')).toBe('[[['); + }); + + it('saves and reloads the normalized config', async () => { + await saveTuiConfig( + { + theme: 'light', + disablePasteBurst: false, + cacheExpiryHint: true, + editorCommand: 'vim', + notifications: { enabled: false, condition: 'always' }, + upgrade: { autoInstall: false }, + statusLine: { items: null, command: null }, + }, + filePath, + ); + + expect(await loadTuiConfig(filePath)).toEqual({ + theme: 'light', + renderLatex: true, + disablePasteBurst: false, + cacheExpiryHint: true, + disableFeedbackSurvey: false, + editorCommand: 'vim', + notifications: { enabled: false, condition: 'always' }, + upgrade: { autoInstall: false }, + statusLine: { items: null, command: null }, + }); + }); + + it('round-trips a disable_feedback_survey opt-out', async () => { + await saveTuiConfig( + { ...DEFAULT_TUI_CONFIG, disableFeedbackSurvey: true }, + filePath, + ); + + expect(readFileSync(filePath, 'utf-8')).toContain('disable_feedback_survey = true'); + expect((await loadTuiConfig(filePath)).disableFeedbackSurvey).toBe(true); + }); + + it('escapes special characters in a custom theme name so the TOML round-trips', async () => { + const theme = 'weird"name\\with-quote'; + await saveTuiConfig( + { + theme, + disablePasteBurst: DEFAULT_TUI_CONFIG.disablePasteBurst, + cacheExpiryHint: DEFAULT_TUI_CONFIG.cacheExpiryHint, + editorCommand: null, + notifications: DEFAULT_TUI_CONFIG.notifications, + upgrade: DEFAULT_TUI_CONFIG.upgrade, + statusLine: DEFAULT_TUI_CONFIG.statusLine, + }, + filePath, + ); + + expect((await loadTuiConfig(filePath)).theme).toBe(theme); + }); +}); + +describe('TUI config status_line', () => { + it('defaults to null when the section is omitted', () => { + const config = parseTuiConfig(`theme = "dark"`); + + expect(config.statusLine).toEqual({ items: null, command: null }); + }); + + it('parses items and command', () => { + const config = parseTuiConfig(` +[status_line] +items = ["model", "git", "cwd"] +command = "~/.kimi-code/statusline.sh" +`); + + expect(config.statusLine).toEqual({ + items: ['model', 'git', 'cwd'], + command: '~/.kimi-code/statusline.sh', + }); + }); + + it('skips unknown items with a warning instead of failing the whole file', () => { + const config = parseTuiConfig(` +[status_line] +items = ["model", "wat", "git"] +`); + + expect(config.statusLine?.items).toEqual(['model', 'git']); + }); + + it('routes unknown-item warnings through the provided callback instead of stderr', () => { + const warnings: string[] = []; + const config = parseTuiConfig( + ` +[status_line] +items = ["model", "wat", "git"] +`, + (message) => warnings.push(message), + ); + + expect(config.statusLine?.items).toEqual(['model', 'git']); + expect(warnings).toEqual(['[tui.toml] ignoring unknown status_line item: wat']); + }); + + it('normalizes an empty command to null', () => { + const config = parseTuiConfig(` +[status_line] +command = " " +`); + + expect(config.statusLine?.command).toBeNull(); + }); + + it('documents status_line in the rendered template', async () => { + await saveTuiConfig(DEFAULT_TUI_CONFIG, filePath); + + const text = readFileSync(filePath, 'utf-8'); + expect(text).toContain('[status_line]'); + expect(text).toContain('items'); + expect(text).toContain('command'); + }); +}); + +describe('TUI config status_line round-trip', () => { + it('preserves an active status_line across save and reload', async () => { + await saveTuiConfig( + { + ...DEFAULT_TUI_CONFIG, + statusLine: { items: ['model', 'git'], command: '~/.kimi-code/statusline.sh' }, + }, + filePath, + ); + + const reloaded = await loadTuiConfig(filePath); + expect(reloaded.statusLine).toEqual({ + items: ['model', 'git'], + command: '~/.kimi-code/statusline.sh', + }); + }); + + it('keeps the status_line section commented out when unset', async () => { + await saveTuiConfig(DEFAULT_TUI_CONFIG, filePath); + + const text = readFileSync(filePath, 'utf-8'); + expect(text).toContain('# [status_line]'); + expect(text).toContain('# items ='); + expect(text).toContain('# command ='); + }); +}); diff --git a/apps/kimi-code/test/tui/constant/tips.test.ts b/apps/kimi-code/test/tui/constant/tips.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..de0f69ef3dae5cb32e281b0ad4443175a6e78bc2 --- /dev/null +++ b/apps/kimi-code/test/tui/constant/tips.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from 'vitest'; + +import { ALL_TIPS, WORKING_TIPS } from '#/tui/constant/tips'; + +describe('tips constants', () => { + it('ALL_TIPS is non-empty', () => { + expect(ALL_TIPS.length).toBeGreaterThan(0); + }); + + it('tip texts are unique across ALL_TIPS', () => { + const texts = ALL_TIPS.map((tip) => tip.text); + expect(new Set(texts).size).toBe(texts.length); + }); + + it('every tip has a non-empty text', () => { + for (const tip of ALL_TIPS) { + expect(tip.text.length).toBeGreaterThan(0); + } + }); + + it('every tip has valid optional properties', () => { + for (const tip of ALL_TIPS) { + if (tip.priority !== undefined) { + expect(tip.priority).toBeGreaterThan(0); + } + if (tip.solo !== undefined) { + expect(typeof tip.solo).toBe('boolean'); + } + } + }); + + it('WORKING_TIPS is non-empty', () => { + expect(WORKING_TIPS.length).toBeGreaterThan(0); + }); + + it('every working tip is included in ALL_TIPS', () => { + for (const workingTip of WORKING_TIPS) { + expect(ALL_TIPS.some((tip) => tip.text === workingTip.text)).toBe(true); + } + }); + + it('shared working tips match ALL_TIPS priority and solo values', () => { + for (const workingTip of WORKING_TIPS) { + const allTip = ALL_TIPS.find((tip) => tip.text === workingTip.text); + expect(allTip).toBeDefined(); + expect(allTip?.priority).toBe(workingTip.priority); + expect(allTip?.solo).toBe(workingTip.solo); + } + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/auth-flow.test.ts b/apps/kimi-code/test/tui/controllers/auth-flow.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa5bdb4c0278af10e3ec5b9df454fa7ff4b89f77 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/auth-flow.test.ts @@ -0,0 +1,128 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { + AuthFlowController, + type AuthFlowHost, +} from '#/tui/controllers/auth-flow'; + +function makeHost( + options: { + withSession?: boolean; + defaultModel?: string; + boundModel?: string; + } = {}, +) { + const appState = { + workDir: '/tmp/work', + additionalDirs: [] as string[], + planMode: false, + model: 'old-model', + thinkingEffort: 'off', + }; + const session = + options.withSession === true + ? { + id: 'ses-live', + getStatus: vi.fn(async () => ({ model: options.boundModel ?? 'old-model' })), + setModel: vi.fn(async () => ({ model: 'k2', providerName: 'managed' })), + setThinking: vi.fn(async () => {}), + } + : undefined; + const host = { + state: { appState }, + session, + harness: { + createSession: vi.fn(async () => ({ id: 'ses-new', summary: { title: null } })), + getConfig: vi.fn(async () => ({ + defaultModel: options.defaultModel, + models: { k2: { provider: 'managed:kimi-code', model: 'kimi-k2', maxContextSize: 200_000 } }, + providers: {}, + })), + }, + options: { startup: {} }, + setAppState: vi.fn((patch: Record) => Object.assign(appState, patch)), + setStartupReady: vi.fn(), + resetSessionRuntime: vi.fn(), + setSession: vi.fn(async (next: unknown) => { + (host as { session: unknown }).session = next; + }), + syncRuntimeState: vi.fn(async () => {}), + appendStartupNotice: vi.fn(), + hydrateLazyConfigDefaults: vi.fn(async () => {}), + sessionEventHandler: { startSubscription: vi.fn() }, + fetchSessions: vi.fn(async () => {}), + updateTerminalTitle: vi.fn(), + refreshSkillCommands: vi.fn(async () => {}), + refreshPluginCommands: vi.fn(async () => {}), + } as unknown as AuthFlowHost & { + session: unknown; + harness: { + createSession: ReturnType; + getConfig: ReturnType; + }; + setAppState: ReturnType; + }; + return { host, appState, session }; +} + +describe('activateModelAfterLogin', () => { + it('reports an engine-tracked switch when the pick changes the bound alias', async () => { + const { host, session } = makeHost({ withSession: true }); + const authFlow = new AuthFlowController(host); + + const engineTrackedSwitch = await authFlow.activateModelAfterLogin('k2', 'high'); + + expect(engineTrackedSwitch).toBe(true); + expect(session!.setModel).toHaveBeenCalledWith('k2'); + expect(session!.setThinking).toHaveBeenCalledWith('high'); + }); + + it('reports no engine switch when the live session already binds the alias', async () => { + const { host, session } = makeHost({ withSession: true, boundModel: 'k2' }); + const authFlow = new AuthFlowController(host); + + // setModel is an alias no-op here, so neither engine emits model_switch — + // callers must stay the producer. The effort still goes through + // setThinking, whose thinking_toggle is the engine's own event. + const engineTrackedSwitch = await authFlow.activateModelAfterLogin('k2', 'high'); + + expect(engineTrackedSwitch).toBe(false); + expect(session!.setModel).toHaveBeenCalledWith('k2'); + expect(session!.setThinking).toHaveBeenCalledWith('high'); + }); + + it('only patches app state and reports no engine switch on the session-less v2 path', async () => { + const { host, appState } = makeHost(); + const authFlow = new AuthFlowController(host); + + const engineTrackedSwitch = await authFlow.activateModelAfterLogin('k2', 'high'); + + expect(engineTrackedSwitch).toBe(false); + expect(host.harness.createSession).not.toHaveBeenCalled(); + expect(appState.model).toBe('k2'); + expect(appState).toMatchObject({ lazySessionThinking: 'high' }); + }); +}); + +describe('refreshConfigAfterLogin', () => { + it('reports false without activating when no default model is configured', async () => { + const { host } = makeHost({ withSession: true }); + const authFlow = new AuthFlowController(host); + + const engineTrackedSwitch = await authFlow.refreshConfigAfterLogin(); + + expect(engineTrackedSwitch).toBe(false); + }); + + it('propagates the activation result for the persisted default model', async () => { + const live = makeHost({ withSession: true, defaultModel: 'k2' }); + const reachedLive = await new AuthFlowController(live.host).refreshConfigAfterLogin(); + expect(reachedLive).toBe(true); + expect(live.session!.setModel).toHaveBeenCalledWith('k2'); + + const lazy = makeHost({ defaultModel: 'k2' }); + const reachedLazy = await new AuthFlowController(lazy.host).refreshConfigAfterLogin(); + expect(reachedLazy).toBe(false); + expect(lazy.host.harness.createSession).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/cache-hint-controller.test.ts b/apps/kimi-code/test/tui/controllers/cache-hint-controller.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0dd31542447e99d590c72b70ece8b50ed3f30fa4 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/cache-hint-controller.test.ts @@ -0,0 +1,791 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + CacheHintController, + type CacheHintHost, +} from '#/tui/controllers/cache-hint-controller'; +import type { CacheHintConfig } from '#/utils/cache-hint-config'; +import type { ExtractionResult } from '#/tui/utils/image-placeholder'; + +const peekMock = vi.fn<() => CacheHintConfig | undefined>(() => undefined); +const getMock = vi.fn(async (): Promise => undefined); + +vi.mock('#/utils/cache-hint-config', () => ({ + peekCacheHintConfig: () => peekMock(), + getCacheHintConfig: (...args: unknown[]) => getMock(...(args as [])), + refreshCacheHintConfigInBackground: () => undefined, + resetCacheHintConfigCache: () => undefined, +})); + +const CONFIG: CacheHintConfig = { + version: 1, + config: { 'kimi-k2': { min_tokens_to_hint: 100000, cache_duration: 600 } }, +}; + +function makeHost( + overrides: { + session?: unknown; + appState?: Record; + createNewSessionFails?: boolean; + } = {}, +) { + const state = { + activeDialog: null as string | null, + appState: { + model: 'k2', + availableModels: { k2: { model: 'kimi-k2', provider: 'managed:kimi-code' } }, + availableProviders: { 'managed:kimi-code': { oauth: { key: 'kimi-code' } } }, + sessionId: 's1', + streamingPhase: 'idle', + isCompacting: false, + contextTokens: 150000, + cacheExpiryHint: true, + ...overrides.appState, + }, + }; + const host: CacheHintHost = { + harness: { auth: { getCachedAccessToken: vi.fn(async () => 'tok') } } as never, + session: (overrides.session ?? { id: 's1' }) as never, + state: state as never, + track: vi.fn(), + setAppState: vi.fn((patch) => Object.assign(state.appState, patch)), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + recallStashedMedia: vi.fn(), + showError: vi.fn(), + createNewSession: vi.fn(async () => { + if (overrides.createNewSessionFails !== true) state.appState.sessionId = 's2'; + }), + sendNormalUserInput: vi.fn(async () => undefined), + sendInlineSkillUserInput: vi.fn(async () => undefined), + }; + return { host, state }; +} + +function resumeSession(replayTimes: number[], tokenCount: number, updatedAt = 0) { + return { + id: 's1', + summary: { updatedAt }, + getResumeState: () => ({ + agents: { + main: { + replay: replayTimes.map((time) => ({ type: 'message', time })), + context: { tokenCount }, + }, + }, + }), + }; +} + +async function flush(times = 20): Promise { + for (let i = 0; i < times; i++) await new Promise((r) => setImmediate(r)); +} + +function uploadedExtraction(fileId: string, byte: number): ExtractionResult { + const path = `/tmp/${fileId}.png`; + return { + parts: [ + { type: 'text', text: `` }, + { + type: 'image_url', + imageUrl: { url: `kimi-file://${fileId}?path=${encodeURIComponent(path)}` }, + }, + ], + hasMedia: true, + imageAttachmentIds: [1], + videoAttachmentIds: [], + imageSnapshots: [{ bytes: new Uint8Array([byte]), mime: 'image/png', width: 640, height: 480 }], + }; +} + +beforeEach(() => { + peekMock.mockReset().mockReturnValue(undefined); + getMock.mockReset().mockResolvedValue(undefined); + vi.useRealTimers(); +}); + +describe('CacheHintController scenario 2 (idle submit)', () => { + it('does not intercept a fresh submit (no activity baseline)', () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(false); + }); + + it('does not intercept when idle for less than the coarse floor', () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(false); + expect(peekMock).not.toHaveBeenCalled(); + }); + + it('does not intercept when the provider is not OAuth-managed', () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost({ + appState: { + availableProviders: { 'managed:kimi-code': {} }, // apiKey form: no oauth + }, + }); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(false); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + vi.restoreAllMocks(); + }); + + it('does not cold-fetch for providers that can never match a rule', async () => { + // Config cache cold (peek returns undefined by default): without the + // applicability gate this submit would be swallowed for a fetch that can + // never produce a hint. + const { host } = makeHost({ + appState: { + availableProviders: { 'managed:kimi-code': {} }, // apiKey form: no oauth + }, + }); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(false); + await flush(); + expect(getMock).not.toHaveBeenCalled(); + vi.restoreAllMocks(); + }); + + it('swallows a cold-cache submit, fetches, and releases when no rule matches', async () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + await flush(); + expect(getMock).toHaveBeenCalled(); + // Fetch resolved without a matching rule → the message is released. + expect(host.sendNormalUserInput).toHaveBeenCalledWith('hello', undefined); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + vi.restoreAllMocks(); + }); + + it('releases a stashed inline-skill submit through the inline-skill path', async () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + const activations = [{ skillName: 'review' }]; + expect(controller.maybeInterceptOnSubmit('check /skill:review', undefined, activations)).toBe( + true, + ); + await flush(); + vi.restoreAllMocks(); + + expect(host.sendInlineSkillUserInput).toHaveBeenCalledWith( + 'check /skill:review', + activations, + undefined, + ); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('fetches on a cold-cache submit and shows the dialog when a rule matches', async () => { + getMock.mockResolvedValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + await vi.waitFor(() => { + expect(host.mountEditorReplacement).toHaveBeenCalled(); + }); + expect(host.track).toHaveBeenCalledWith( + 'cache_hint_shown', + expect.objectContaining({ scene: 'idle' }), + ); + vi.restoreAllMocks(); + }); + + it('serializes cold-cache submits so they keep their order', async () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + expect(controller.maybeInterceptOnSubmit('world')).toBe(true); + await flush(); + vi.restoreAllMocks(); + + expect(host.sendNormalUserInput).toHaveBeenCalledTimes(2); + expect( + (host.sendNormalUserInput as ReturnType).mock.calls.map((c) => c[0]), + ).toEqual(['hello', 'world']); + }); + + it('restores chained submits instead of sending when the dialog is dismissed', async () => { + getMock.mockResolvedValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + expect(controller.maybeInterceptOnSubmit('world')).toBe(true); + await vi.waitFor(() => { + expect(host.mountEditorReplacement).toHaveBeenCalled(); + }); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B'); // dismiss the first dialog + await flush(); + + // Nothing was sent; both inputs are back in the editor, newline-joined. + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(host.restoreInputText).toHaveBeenLastCalledWith('hello\nworld'); + }); + + it('releases stashed media with recall semantics when the dialog is dismissed', async () => { + getMock.mockResolvedValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + const extraction = uploadedExtraction('file-1', 1); + + expect(controller.maybeInterceptOnSubmit('describe [image #1 (1×1)]', extraction)).toBe(true); + await vi.waitFor(() => { + expect(host.mountEditorReplacement).toHaveBeenCalled(); + }); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B'); // dismiss + await flush(); + + // Nothing was sent; the draft is back in the editor and the stash's + // retains go through recall — without this the retain count never + // returns to zero and the upload can never be lease-deleted. + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(host.restoreInputText).toHaveBeenCalledWith('describe [image #1 (1×1)]'); + expect(host.recallStashedMedia).toHaveBeenCalledWith(extraction); + }); + + it('hands the stashed input back when the session switched during the fetch', async () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + (host as unknown as { session: unknown }).session = { id: 's2' }; + await flush(); + vi.restoreAllMocks(); + + expect(host.restoreInputText).toHaveBeenCalledWith('hello'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('releases instead of mounting when a foreground operation started during the fetch', async () => { + getMock.mockResolvedValue(CONFIG); + const { host, state } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + // A foreground operation (turn / /compact) kicked off mid-fetch. + state.appState.streamingPhase = 'waiting'; + await flush(); + vi.restoreAllMocks(); + + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('hello', undefined); + }); + + it('intercepts and shows the dialog when all conditions hold', () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(host.track).toHaveBeenCalledWith( + 'cache_hint_shown', + expect.objectContaining({ scene: 'idle', model: 'k2' }), + ); + vi.restoreAllMocks(); + }); + + it('does not advance the cache baseline at turn begin (the prompt may fail pre-model)', () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + // A send begins a turn but fails before any model request — the expired + // baseline must survive, so the retry still intercepts. + controller.onTurnBegin(); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + vi.restoreAllMocks(); + }); + + it('does not intercept twice in the same idle cycle', () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + expect(controller.maybeInterceptOnSubmit('again')).toBe(false); + vi.restoreAllMocks(); + }); + + it('resends the stashed input on continue', async () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + controller.maybeInterceptOnSubmit('hello'); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B[B'); // down → new + dialog.handleInput('\u001B[B'); // down → continue + dialog.handleInput('\r'); + await flush(); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('hello', undefined); + expect(host.track).toHaveBeenCalledWith('cache_hint_action', { + action: 'continue', + scene: 'idle', + }); + }); + + it('restores the input on Esc without sending', async () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + controller.maybeInterceptOnSubmit('hello'); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B'); + await flush(); + expect(host.restoreInputText).toHaveBeenCalledWith('hello'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('compacts then resends once compaction engages', async () => { + peekMock.mockReturnValue(CONFIG); + const compact = vi.fn(async () => undefined); + const { host, state } = makeHost({ session: { id: 's1', compact } }); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + controller.maybeInterceptOnSubmit('hello'); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\r'); // compact (default) + // The engine flips isCompacting asynchronously via the started event. + setTimeout(() => { + state.appState.isCompacting = true; + }, 10); + await vi.waitFor(() => { + expect(host.sendNormalUserInput).toHaveBeenCalledWith('hello', undefined); + }); + expect(compact).toHaveBeenCalledWith({}); + }); + + it('starts a new session and resends', async () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + controller.maybeInterceptOnSubmit('hello'); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B[B'); // down → new + dialog.handleInput('\r'); + await flush(); + expect(host.createNewSession).toHaveBeenCalled(); + expect(host.sendNormalUserInput).toHaveBeenCalledWith('hello', undefined); + }); + + it('resends an uploaded image inline after starting a new session', async () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + const extraction = uploadedExtraction('file-1', 1); + + controller.maybeInterceptOnSubmit('describe [image #1 (1×1)]', extraction); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B[B'); + dialog.handleInput('\r'); + await flush(); + + const resend = vi.mocked(host.sendNormalUserInput).mock.calls[0]?.[1]; + expect(resend?.imageAttachmentIds).toEqual([]); + expect(resend?.parts).toContainEqual({ + type: 'image_url', + imageUrl: { url: 'data:image/png;base64,AQ==' }, + }); + }); + + it('resends every chained uploaded image inline after starting a new session', async () => { + getMock.mockResolvedValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + + expect(controller.maybeInterceptOnSubmit('first', uploadedExtraction('file-1', 1))).toBe(true); + expect(controller.maybeInterceptOnSubmit('second', uploadedExtraction('file-2', 2))).toBe(true); + await vi.waitFor(() => { + expect(host.mountEditorReplacement).toHaveBeenCalled(); + }); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B[B'); + dialog.handleInput('\r'); + await flush(); + + const sendCalls = ( + host.sendNormalUserInput as unknown as { + mock: { calls: Array<[string, ExtractionResult | undefined]> }; + } + ).mock.calls; + const imageUrls = sendCalls.map(([, extraction]) => { + const imagePart = extraction?.parts.find((part) => part.type === 'image_url'); + return imagePart?.type === 'image_url' ? imagePart.imageUrl.url : undefined; + }); + expect(imageUrls).toEqual([ + 'data:image/png;base64,AQ==', + 'data:image/png;base64,Ag==', + ]); + }); + + it('keeps the input when new-session creation fails', async () => { + peekMock.mockReturnValue(CONFIG); + const { host, state } = makeHost({ createNewSessionFails: true }); + const controller = new CacheHintController(host); + controller.recordActivity(); + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + controller.maybeInterceptOnSubmit('hello'); + vi.restoreAllMocks(); + + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B[B'); + dialog.handleInput('\r'); + await flush(); + expect(state.appState.sessionId).toBe('s1'); + expect(host.restoreInputText).toHaveBeenCalledWith('hello'); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); +}); + +describe('CacheHintController cache-break detection', () => { + const u = (inputCacheRead: number) => ({ + inputOther: 100, + output: 50, + inputCacheRead, + inputCacheCreation: 0, + }); + + it('does not judge the first measured step', () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.noteStepUsage(u(10000)); + expect(host.track).not.toHaveBeenCalled(); + }); + + it('records cache activity on a completed step, even one without usage', () => { + peekMock.mockReturnValue(CONFIG); + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.recordActivity(); + // 20 min later a step completes — the provider round trip refreshed the + // server-side cache… + vi.spyOn(Date, 'now').mockReturnValue(Date.now() + 1200_000); + controller.noteStepUsage(undefined); + // …so a submit right after is fresh and must not be intercepted. + expect(controller.maybeInterceptOnSubmit('hello')).toBe(false); + vi.restoreAllMocks(); + }); + + it('reports a drop beyond the ratio and token gates with both usages', () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.noteStepUsage(u(10000)); + controller.noteStepUsage(u(7000)); + + expect(host.track).toHaveBeenCalledWith( + 'cache_break_detected', + expect.objectContaining({ + prev_model: 'k2', + curr_model: 'k2', + prev_input_cache_read: 10000, + curr_input_cache_read: 7000, + cache_read_drop_ratio: 0.3, + }), + ); + }); + + it('stays quiet within the ratio gate or under the token threshold', () => { + const a = makeHost(); + const controllerA = new CacheHintController(a.host); + controllerA.noteStepUsage(u(100000)); + controllerA.noteStepUsage(u(96000)); // 4% drop — inside the ratio gate + expect(a.host.track).not.toHaveBeenCalled(); + + const b = makeHost(); + const controllerB = new CacheHintController(b.host); + controllerB.noteStepUsage(u(4000)); + controllerB.noteStepUsage(u(2500)); // drop 1500 ≤ 2000 — under the token threshold + expect(b.host.track).not.toHaveBeenCalled(); + }); + + it('skips unmeasured usage without touching the baseline', () => { + const { host } = makeHost(); + const controller = new CacheHintController(host); + controller.noteStepUsage(u(10000)); + controller.noteStepUsage(undefined); + controller.noteStepUsage({ inputOther: 0, output: 0, inputCacheRead: 0, inputCacheCreation: 0 }); + controller.noteStepUsage(u(5000)); + expect(host.track).toHaveBeenCalledWith( + 'cache_break_detected', + expect.objectContaining({ prev_input_cache_read: 10000, curr_input_cache_read: 5000 }), + ); + }); + + it('resets the baseline on compaction, but records a mid-session model/effort switch', () => { + const { host, state } = makeHost(); + const controller = new CacheHintController(host); + controller.noteStepUsage(u(10000)); + controller.resetCacheBreakBaseline(); + controller.noteStepUsage(u(100)); // post-compaction drop is expected + expect(host.track).not.toHaveBeenCalled(); + + // A model switch busts the cache key — that drop IS the signal to record. + controller.noteStepUsage(u(10000)); + state.appState.model = 'other-model'; + controller.noteStepUsage(u(100)); + expect(host.track).toHaveBeenCalledWith( + 'cache_break_detected', + expect.objectContaining({ + prev_model: 'k2', + curr_model: 'other-model', + prev_input_cache_read: 10000, + curr_input_cache_read: 100, + }), + ); + }); +}); + +describe('CacheHintController scenario 1 (resume)', () => { + /** maybeShowOnResume awaits the user's choice; dismiss the dialog once mounted. */ + async function showOnResumeAndDismiss( + controller: CacheHintController, + host: CacheHintHost, + ): Promise { + const pending = controller.maybeShowOnResume(); + await vi.waitFor(() => { + expect(host.mountEditorReplacement).toHaveBeenCalled(); + }); + const dialog = (host.mountEditorReplacement as ReturnType).mock.calls[0]![0] as { + handleInput: (data: string) => void; + }; + dialog.handleInput('\u001B'); + await pending; + } + + it('shows the dialog on resume when idle beyond cache_duration', async () => { + getMock.mockResolvedValue(CONFIG); + const session = resumeSession([Date.now() - 1200_000], 150000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + await showOnResumeAndDismiss(controller, host); + expect(host.track).toHaveBeenCalledWith( + 'cache_hint_shown', + expect.objectContaining({ scene: 'resume' }), + ); + }); + + it('shows at most once per session', async () => { + getMock.mockResolvedValue(CONFIG); + const session = resumeSession([Date.now() - 1200_000], 150000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + await showOnResumeAndDismiss(controller, host); + await controller.maybeShowOnResume(); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + }); + + it('falls back to summary.updatedAt when there are no replay records', async () => { + getMock.mockResolvedValue(CONFIG); + const session = resumeSession([], 150000, Date.now() - 1200_000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + await showOnResumeAndDismiss(controller, host); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + }); + + it('drops the dialog when the session switched during the config fetch', async () => { + let resolveFetch!: (config: CacheHintConfig) => void; + getMock.mockImplementation( + () => + new Promise((res) => { + resolveFetch = res; + }), + ); + const session = resumeSession([Date.now() - 1200_000], 150000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + const pending = controller.maybeShowOnResume(); + await flush(); // let the fetch start (resolveFetch gets assigned) + (host as unknown as { session: unknown }).session = { id: 'other-session' }; + resolveFetch(CONFIG); + await pending; + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('drops the dialog when a turn started during the config fetch', async () => { + let resolveFetch!: (config: CacheHintConfig) => void; + getMock.mockImplementation( + () => + new Promise((res) => { + resolveFetch = res; + }), + ); + const session = resumeSession([Date.now() - 1200_000], 150000); + const { host, state } = makeHost({ session }); + const controller = new CacheHintController(host); + + const pending = controller.maybeShowOnResume(); + await flush(); + // The user sent the first prompt while the fetch was in flight. + state.appState.streamingPhase = 'waiting'; + resolveFetch(CONFIG); + await pending; + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('re-evaluates against fresh activity when a turn completed during the config fetch', async () => { + let resolveFetch!: (config: CacheHintConfig) => void; + getMock.mockImplementation( + () => + new Promise((res) => { + resolveFetch = res; + }), + ); + // Idle long past the window when the resume check started… + const session = resumeSession([Date.now() - 1200_000], 150000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + const pending = controller.maybeShowOnResume(); + await flush(); // let the fetch start (resolveFetch gets assigned) + // …but the user's first prompt ran to completion while the config was in + // flight, refreshing the server-side cache — the stale replay timestamp + // must not trigger the dialog. + controller.recordActivity(); + resolveFetch(CONFIG); + await pending; + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('ignores local-only state records when computing the resume idle time', async () => { + getMock.mockResolvedValue(CONFIG); + const oldMessage = { type: 'message', time: Date.now() - 1200_000 }; + const recentStateRecord = { type: 'permission_updated', time: Date.now() - 5000 }; + const session = { + id: 's1', + summary: { updatedAt: 0 }, + getResumeState: () => ({ + agents: { + main: { replay: [oldMessage, recentStateRecord], context: { tokenCount: 150000 } }, + }, + }), + }; + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + // The recent permission change must not mask the expired cache. + await showOnResumeAndDismiss(controller, host); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + }); + + it('skips when the config cannot be resolved', async () => { + const session = resumeSession([Date.now() - 1200_000], 150000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + await controller.maybeShowOnResume(); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('skips small sessions below the token threshold', async () => { + getMock.mockResolvedValue(CONFIG); + const session = resumeSession([Date.now() - 1200_000], 50_000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + await controller.maybeShowOnResume(); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + }); + + it('seeds the activity baseline when the resume check skips inside the cache window', async () => { + getMock.mockResolvedValue(CONFIG); + peekMock.mockReturnValue(CONFIG); + const now = Date.now(); + // 9 minutes into a 10-minute cache window — nothing to show on resume. + const session = resumeSession([now - 540_000], 150000); + const { host } = makeHost({ session }); + const controller = new CacheHintController(host); + + await controller.maybeShowOnResume(); + expect(host.mountEditorReplacement).not.toHaveBeenCalled(); + + // Two minutes later the window has expired; the seeded baseline lets the + // idle-submit path catch it instead of waving the prompt through. + vi.spyOn(Date, 'now').mockReturnValue(now + 660_000); + expect(controller.maybeInterceptOnSubmit('hello')).toBe(true); + expect(host.mountEditorReplacement).toHaveBeenCalledOnce(); + expect(host.track).toHaveBeenCalledWith( + 'cache_hint_shown', + expect.objectContaining({ scene: 'idle' }), + ); + vi.restoreAllMocks(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/clipboard-image-hint.test.ts b/apps/kimi-code/test/tui/controllers/clipboard-image-hint.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2bc4c5b4edc44162c385b461d3ef654936b099e0 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/clipboard-image-hint.test.ts @@ -0,0 +1,672 @@ +import type { TUI } from '@moonshot-ai/pi-tui'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + ClipboardImageHintController, + type ClipboardImageHintHost, +} from '#/tui/controllers/clipboard-image-hint'; +import type { FooterComponent } from '#/tui/components/chrome/footer'; +import { TERMINAL_FOCUS_IN, TERMINAL_FOCUS_OUT } from '#/tui/utils/terminal-focus'; +import { clipboardHasImage } from '#/utils/clipboard/clipboard-has-image'; + +vi.mock('#/utils/clipboard/clipboard-has-image', () => ({ + clipboardHasImage: vi.fn(async () => false), +})); + +type FakeTUI = TUI & { emitInput(data: string): void }; + +interface FakeFooter { + hint: string | null; + setTransientHint(hint: string | null): void; + getTransientHint(): string | null; +} + +function createFakeFooter(): FooterComponent { + const footer: FakeFooter = { + hint: null, + setTransientHint(hint: string | null): void { + this.hint = hint; + }, + getTransientHint(): string | null { + return this.hint; + }, + }; + return footer as unknown as FooterComponent; +} + +function createFakeTUI(): FakeTUI { + const listeners = new Set<(data: string) => { consume?: boolean; data?: string } | undefined>(); + return { + addInputListener: vi.fn((listener) => { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; + }), + emitInput: (data: string) => { + for (const listener of listeners) { + listener(data); + } + }, + requestRender: vi.fn(), + } as unknown as FakeTUI; +} + +function createFakeTUIWithConsumingFocusTracker(): FakeTUI { + const listeners = new Set<(data: string) => { consume?: boolean; data?: string } | undefined>(); + return { + addInputListener: vi.fn((listener) => { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; + }), + emitInput: (data: string) => { + for (const listener of listeners) { + const result = listener(data); + if (result?.consume) return; + } + }, + requestRender: vi.fn(), + } as unknown as FakeTUI; +} + +// Drive the controller through its first clipboard observation with an empty +// clipboard. The first observation only establishes a baseline and never shows +// a hint, leaving the controller armed and ready for the next new image. +async function primeEmptyBaseline(ui: FakeTUI): Promise { + vi.mocked(clipboardHasImage).mockResolvedValue(false); + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); +} + +// Simulate the user returning to the terminal and let the debounced check fire. +async function focusReturnAndFlush(ui: FakeTUI): Promise { + ui.emitInput(TERMINAL_FOCUS_OUT); + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); +} + +describe('ClipboardImageHintController', () => { + let platformSpy: ReturnType | undefined; + + beforeEach(() => { + vi.useFakeTimers(); + vi.clearAllMocks(); + vi.mocked(clipboardHasImage).mockResolvedValue(false); + platformSpy = vi.spyOn(process, 'platform', 'get').mockReturnValue('darwin'); + }); + + afterEach(() => { + platformSpy?.mockRestore(); + vi.useRealTimers(); + }); + + it('does not show a hint for an image already in the clipboard at startup', async () => { + vi.mocked(clipboardHasImage).mockResolvedValue(true); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // Startup baseline observes the image already present; the focus check + // runs too but must stay quiet for that same image. + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + + // One call is the startup baseline; the second is the focus check. + expect(clipboardHasImage).toHaveBeenCalledTimes(2); + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + }); + + it('shows hint when a new image is copied during the session', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + expect(footer.getTransientHint()).toMatch(/Ctrl\+V/); + + controller.stop(); + }); + + it('shows hint for the first image copied after startup when startup baseline was empty', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await vi.advanceTimersByTimeAsync(0); + expect(clipboardHasImage).toHaveBeenCalledTimes(1); + expect(footer.getTransientHint()).toBeNull(); + + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + expect(footer.getTransientHint()).toMatch(/Ctrl\+V/); + + controller.stop(); + }); + + it('does not show hint when model does not support images', async () => { + vi.mocked(clipboardHasImage).mockResolvedValue(true); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => false, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + }); + + it('does not repeat the hint for the same lingering image', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // Establish the baseline and show a hint for the first image. + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + + // The same image is still in the clipboard: focusing again must not nag. + vi.mocked(clipboardHasImage).mockClear(); + footer.setTransientHint(null); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toBeNull(); + expect(clipboardHasImage).toHaveBeenCalledTimes(1); + + controller.stop(); + }); + + it('shows the hint again for a new image after the clipboard is cleared', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // Establish the baseline, then show a hint for the first image. + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + + // Clipboard cleared: the empty check re-arms the controller. + vi.mocked(clipboardHasImage).mockResolvedValue(false); + footer.setTransientHint(null); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toBeNull(); + + // A genuinely new image: hint shows again. + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + + controller.stop(); + }); + + it('clears the hint after the display duration', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).not.toBeNull(); + + await vi.advanceTimersByTimeAsync(4000); + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + }); + + it('cancels a pending debounced check when focus is lost', async () => { + vi.mocked(clipboardHasImage).mockResolvedValue(true); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await vi.advanceTimersByTimeAsync(0); + vi.mocked(clipboardHasImage).mockClear(); + + ui.emitInput(TERMINAL_FOCUS_IN); + ui.emitInput(TERMINAL_FOCUS_OUT); + await vi.advanceTimersByTimeAsync(1000); + + expect(clipboardHasImage).not.toHaveBeenCalled(); + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + }); + + it('handles rapid focus churn without duplicate checks or hints', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + vi.mocked(clipboardHasImage).mockClear(); + + for (let i = 0; i < 5; i++) { + ui.emitInput(TERMINAL_FOCUS_OUT); + ui.emitInput(TERMINAL_FOCUS_IN); + } + + await vi.advanceTimersByTimeAsync(1000); + + expect(clipboardHasImage).toHaveBeenCalledTimes(1); + expect(footer.getTransientHint()).not.toBeNull(); + + controller.stop(); + }); + + it('ignores stale clipboard read result when focus is lost', async () => { + vi.mocked(clipboardHasImage).mockImplementation( + () => new Promise((resolve) => setTimeout(() => { resolve(true); }, 1500)), + ); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + // One call is the startup baseline; the second is the debounced focus check. + expect(clipboardHasImage).toHaveBeenCalledTimes(2); + + ui.emitInput(TERMINAL_FOCUS_OUT); + await vi.advanceTimersByTimeAsync(1500); + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + }); + + it('ignores a pending clipboard read result after stop', async () => { + let resolveDeferred: (value: boolean) => void = () => {}; + vi.mocked(clipboardHasImage).mockImplementation( + () => new Promise((resolve) => { + resolveDeferred = resolve; + }), + ); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + // One call is the startup baseline; the second is the debounced focus check. + expect(clipboardHasImage).toHaveBeenCalledTimes(2); + + controller.stop(); + resolveDeferred(true); + await vi.advanceTimersByTimeAsync(0); + expect(footer.getTransientHint()).toBeNull(); + }); + + it('clears a displayed hint when stopped', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).not.toBeNull(); + + controller.stop(); + expect(footer.getTransientHint()).toBeNull(); + expect(host.requestRender).toHaveBeenCalled(); + }); + + it('does not clear a hint set by another caller when stopped', async () => { + vi.mocked(clipboardHasImage).mockResolvedValue(true); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const requestRender = vi.fn(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender, + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // First observation only establishes the baseline and sets no hint. + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + const otherHint = 'Other hint'; + footer.setTransientHint(otherHint); + + const requestRenderCalls = requestRender.mock.calls.length; + controller.stop(); + expect(footer.getTransientHint()).toBe(otherHint); + expect(host.requestRender).toHaveBeenCalledTimes(requestRenderCalls); + }); + + it('uses only the latest clipboard read result after focus churn', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // Establish an empty baseline with a normal resolved read first. + await primeEmptyBaseline(ui); + + const deferreds: Array<{ resolve: (value: boolean) => void; promise: Promise }> = []; + vi.mocked(clipboardHasImage).mockImplementation(() => { + let resolve: (value: boolean) => void = () => {}; + const promise = new Promise((res) => { + resolve = res; + }); + deferreds.push({ resolve, promise }); + return promise; + }); + + ui.emitInput(TERMINAL_FOCUS_OUT); + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + expect(deferreds).toHaveLength(1); + + ui.emitInput(TERMINAL_FOCUS_OUT); + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + expect(deferreds).toHaveLength(2); + + deferreds[0]!.resolve(true); + await vi.advanceTimersByTimeAsync(0); + expect(footer.getTransientHint()).toBeNull(); + + deferreds[1]!.resolve(true); + await vi.advanceTimersByTimeAsync(0); + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + + controller.stop(); + }); + + it('keeps the existing auto-clear timer when a re-check exits early', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).not.toBeNull(); + + // Trigger a re-check that exits early because the clipboard is now empty. + vi.mocked(clipboardHasImage).mockResolvedValue(false); + await focusReturnAndFlush(ui); + + // The previous hint should still be visible because its auto-clear timer + // was preserved through the re-check. + expect(footer.getTransientHint()).not.toBeNull(); + + // Advance the remaining original display duration and verify it expires. + await vi.advanceTimersByTimeAsync(3000); + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + }); + + it('does not clear a matching hint owned by another caller after auto-clear', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + const hintText = footer.getTransientHint(); + expect(hintText).not.toBeNull(); + + await vi.advanceTimersByTimeAsync(4000); + expect(footer.getTransientHint()).toBeNull(); + + // Another caller sets the same hint text the controller previously used. + footer.setTransientHint(hintText); + + controller.stop(); + expect(footer.getTransientHint()).toBe(hintText); + }); + + it('re-establishes the baseline after stop and restart', async () => { + vi.mocked(clipboardHasImage).mockResolvedValue(true); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // Image already present at start: baseline only, no hint. + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + expect(footer.getTransientHint()).toBeNull(); + + controller.stop(); + controller.start(); + + // After restart the image is still present: baseline again, no hint. + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toBeNull(); + + // Clipboard cleared: re-arms the controller. + vi.mocked(clipboardHasImage).mockResolvedValue(false); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toBeNull(); + + // A genuinely new image: hint shows. + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + + controller.stop(); + }); + + it('observes focus events even when another listener consumes them', async () => { + const footer = createFakeFooter(); + const ui = createFakeTUIWithConsumingFocusTracker(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + // Register a second listener that consumes focus events, like installTerminalFocusTracking. + const consumedEvents: string[] = []; + ui.addInputListener((data) => { + if (data === TERMINAL_FOCUS_IN || data === TERMINAL_FOCUS_OUT) { + consumedEvents.push(data); + return { consume: true }; + } + return undefined; + }); + + // Baseline observation (consumed), then a new image on the next focus. + vi.mocked(clipboardHasImage).mockResolvedValue(false); + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + + vi.mocked(clipboardHasImage).mockResolvedValue(true); + ui.emitInput(TERMINAL_FOCUS_OUT); + ui.emitInput(TERMINAL_FOCUS_IN); + await vi.advanceTimersByTimeAsync(1000); + + expect(consumedEvents).toEqual([TERMINAL_FOCUS_IN, TERMINAL_FOCUS_OUT, TERMINAL_FOCUS_IN]); + expect(footer.getTransientHint()).toMatch(/Image in clipboard/); + + controller.stop(); + }); + + it('shows Alt+V shortcut on Windows', async () => { + platformSpy?.mockRestore(); + vi.spyOn(process, 'platform', 'get').mockReturnValue('win32'); + + const footer = createFakeFooter(); + const ui = createFakeTUI(); + const host: ClipboardImageHintHost = { + ui, + footer, + getModelSupportsImage: () => true, + requestRender: vi.fn(), + }; + + const controller = new ClipboardImageHintController(host); + controller.start(); + + await primeEmptyBaseline(ui); + vi.mocked(clipboardHasImage).mockResolvedValue(true); + await focusReturnAndFlush(ui); + + expect(footer.getTransientHint()).toMatch(/Alt\+V/); + + controller.stop(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/editor-keyboard-image-paste.test.ts b/apps/kimi-code/test/tui/controllers/editor-keyboard-image-paste.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea3fecf222d96974e92a9d2d36418e4a162303c1 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/editor-keyboard-image-paste.test.ts @@ -0,0 +1,548 @@ +/** + * Clipboard image paste → attachment store, with ingestion-time compression. + * + * Tests pin: + * - an oversized pasted image is downsampled while building the attachment, + * so the stored bytes, the `[image #N (W×H)]` placeholder, and the eventual + * submitted image all agree on the compressed size + * - the pre-compression original is recorded on the attachment in memory — + * never persisted at paste time, because the session whose + * media-originals dir it belongs in may not exist yet; dispatch-time + * caption resolution owns persistence (see image-placeholder tests) + * - a within-budget paste is stored byte-for-byte (fast path), with no + * original recorded + * - on the v2 engine the final bytes are uploaded to the daemon file store + * with a crash-recovery TTL, and the attachment carries the returned id + * and expiry; an upload failure leaves the paste on the inline fallback + */ + +import { existsSync } from 'node:fs'; +import { mkdtemp, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { Jimp } from 'jimp'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + EditorKeyboardController, + type EditorKeyboardHost, +} from '#/tui/controllers/editor-keyboard'; +import { ImageAttachmentStore } from '#/tui/utils/image-attachment-store'; +import { parseImageMeta } from '#/utils/image/image-mime'; +import { ImageLimits, type KimiHarness } from '@moonshot-ai/kimi-code-sdk'; + +// vitest hoists vi.mock/vi.hoisted above the imports above, so the mock still +// applies to the editor-keyboard module that pulls in readClipboardMedia. +const { readClipboardMedia } = vi.hoisted(() => ({ readClipboardMedia: vi.fn() })); + +vi.mock('#/utils/clipboard/clipboard-image', async (importActual) => { + const actual = await importActual(); + return { ...actual, readClipboardMedia }; +}); + +interface PasteHarness { + readonly store: ImageAttachmentStore; + readonly track: ReturnType; + /** Invoke the paste handler, then wait for the background ingestion to settle. */ + pasteImage(): Promise; + /** Invoke the paste handler only — background ingestion may still be pending. */ + pasteImageRaw(): Promise; +} + +function createPasteHarness( + options: { + sessionDir?: string; + imageLimits?: ImageLimits; + uploadFile?: ( + data: Uint8Array, + opts: { name: string; mimeType?: string; expiresInSec?: number }, + ) => Promise<{ id: string }>; + } = {}, +): PasteHarness { + const editor: Record unknown) | undefined> = { + setHistoryFilter: vi.fn() as unknown as (...args: never[]) => unknown, + }; + const store = new ImageAttachmentStore(); + const track = vi.fn(); + const host = { + state: { + editor, + activeDialog: null, + appState: { streamingPhase: 'idle', isCompacting: false }, + footer: { setTransientHint: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: + options.sessionDir === undefined + ? undefined + : { summary: { sessionDir: options.sessionDir } }, + btwPanelController: { closeOrCancel: vi.fn(() => false) }, + track, + showError: vi.fn(), + openUndoSelector: vi.fn(), + cancelRunningShellCommand: vi.fn(), + } as unknown as EditorKeyboardHost; + if (options.imageLimits !== undefined || options.uploadFile !== undefined) { + (host as unknown as { harness: KimiHarness }).harness = { + imageLimits: options.imageLimits, + uploadFile: options.uploadFile, + } as unknown as KimiHarness; + } + + const controller = new EditorKeyboardController(host, store); + controller.install(); + + const pasteImageRaw = (): Promise => { + const handler = editor['onPasteImage']; + if (handler === undefined) throw new Error('onPasteImage handler not installed'); + return (handler as () => Promise)(); + }; + + return { + store, + track, + async pasteImage() { + await pasteImageRaw(); + for (let id = 1; id <= store.size(); id++) { + await store.get(id)?.pending; + } + }, + pasteImageRaw, + }; +} + +async function solidPng(width: number, height: number): Promise { + return new Uint8Array( + await new Jimp({ width, height, color: 0x3366ccff }).getBuffer('image/png'), + ); +} + +async function solidJpeg(width: number, height: number): Promise { + return new Uint8Array( + await new Jimp({ width, height, color: 0x3366ccff }).getBuffer('image/jpeg', { quality: 90 }), + ); +} + +/** Typed `uploadFile` stub so `mock.calls` keeps the (data, options) tuple. */ +function uploadFileMock(id: string) { + return vi.fn(async ( + _data: Uint8Array, + _opts: { name: string; mimeType?: string; expiresInSec?: number }, + ) => ({ id, expires_at: '2030-01-02T03:04:05.000Z' })); +} + +/** + * Insert a minimal EXIF APP1 segment carrying only an Orientation tag right + * after the JPEG SOI marker (jimp itself never writes EXIF). + */ +function withExifOrientation(jpeg: Uint8Array, orientation: number): Uint8Array { + // TIFF body, little-endian: 8-byte header + IFD0 with a single entry. + const tiff = Buffer.alloc(26); + tiff.write('II', 0, 'latin1'); + tiff.writeUInt16LE(42, 2); + tiff.writeUInt32LE(8, 4); // offset of IFD0 + tiff.writeUInt16LE(1, 8); // one directory entry + tiff.writeUInt16LE(0x0112, 10); // tag: Orientation + tiff.writeUInt16LE(3, 12); // type: SHORT + tiff.writeUInt32LE(1, 14); // count + tiff.writeUInt16LE(orientation, 18); // value, left-aligned in the 4-byte field + tiff.writeUInt32LE(0, 22); // no next IFD + const exifBody = Buffer.concat([Buffer.from('Exif\0\0', 'latin1'), tiff]); + const app1Header = Buffer.alloc(4); + app1Header.writeUInt16BE(0xff_e1, 0); + app1Header.writeUInt16BE(exifBody.length + 2, 2); + return new Uint8Array( + Buffer.concat([ + Buffer.from(jpeg.subarray(0, 2)), // SOI + app1Header, + exifBody, + Buffer.from(jpeg.subarray(2)), + ]), + ); +} + +describe('clipboard image paste compression', () => { + beforeEach(() => { + readClipboardMedia.mockReset(); + }); + + it('downsamples an oversized pasted image before storing it', async () => { + const big = await solidPng(3600, 1800); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: big, mimeType: 'image/png' }); + + const { store, pasteImage } = createPasteHarness(); + await pasteImage(); + + expect(store.size()).toBe(1); + const att = store.get(1); + expect(att?.kind).toBe('image'); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + + // Stored metadata reflects the compressed size. + expect(Math.max(att.width, att.height)).toBeLessThanOrEqual(2000); + expect(att.placeholder).toContain('2000×1000'); + + // The stored bytes decode to the compressed dimensions — the thumbnail and + // the submitted image both read from these bytes, so they cannot diverge. + const dims = parseImageMeta(att.bytes); + expect(dims).not.toBeNull(); + expect(Math.max(dims!.width, dims!.height)).toBeLessThanOrEqual(3000); + }); + + it('honors the harness [image] max_edge_px when pasting', async () => { + const big = await solidPng(3600, 1800); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: big, mimeType: 'image/png' }); + + const { store, pasteImage } = createPasteHarness({ + imageLimits: new ImageLimits(process.env, { maxEdgePx: 800 }), + }); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + // The harness [image] config — not the built-in 2000px — drives ingestion. + expect(Math.max(att.width, att.height)).toBe(800); + expect(att.placeholder).toContain('800×400'); + const dims = parseImageMeta(att.bytes); + expect(dims).not.toBeNull(); + expect(Math.max(dims!.width, dims!.height)).toBe(800); + }); + + it('records the pre-compression original in memory for an oversized paste', async () => { + const big = await solidPng(3600, 1800); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: big, mimeType: 'image/png' }); + + const { store, pasteImage } = createPasteHarness(); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.original).toBeDefined(); + expect(att.original?.bytes).toEqual(big); + expect(att.original?.width).toBe(3600); + expect(att.original?.height).toBe(1800); + expect(att.original?.byteLength).toBe(big.length); + expect(att.original?.mime).toBe('image/png'); + + // Nothing is persisted at paste time — dispatch-time caption resolution + // owns that, once the session (and its media-originals dir) is known. + expect(att.original?.path).toBeUndefined(); + }); + + it('does not persist the original at paste time, even with a known session', async () => { + const sessionDir = await mkdtemp(join(tmpdir(), 'kimi-paste-session-')); + const big = await solidPng(3600, 1800); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: big, mimeType: 'image/png' }); + + const { store, pasteImage } = createPasteHarness({ sessionDir }); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.original?.bytes).toEqual(big); + expect(att.original?.path).toBeUndefined(); + expect(existsSync(join(sessionDir, 'media-originals'))).toBe(false); + await rm(sessionDir, { recursive: true, force: true }); + }); + + it('stores a within-budget paste byte-for-byte', async () => { + const small = await solidPng(80, 80); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: small, mimeType: 'image/png' }); + + const { store, pasteImage } = createPasteHarness(); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.width).toBe(80); + expect(att.height).toBe(80); + expect(att.bytes).toBe(small); // identity: no re-encode on the fast path + expect(att.original).toBeUndefined(); + }); + + it( + 'records an EXIF-rotated compressed original in display space', + async () => { + // Orientation 6 (rotate 90° CW): the header says 3600x400, but the image + // decodes to 400x3600 — the space the compressed bytes and any later + // ReadMediaFile region readback live in. The recorded original (which + // drives the submit-time compression caption) must match that space, or + // the caption contradicts the sent image's aspect and region coordinates + // land axis-swapped. (Kept narrow: pure-JS decode+rotate+encode of a + // larger frame can outlast the test timeout on slow CI runners.) + const portrait = withExifOrientation(await solidJpeg(3600, 400), 6); + readClipboardMedia.mockResolvedValue({ + kind: 'image', + bytes: portrait, + mimeType: 'image/jpeg', + }); + + const { store, pasteImage } = createPasteHarness(); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.original?.width).toBe(400); + expect(att.original?.height).toBe(3600); + // The compressed attachment itself keeps the portrait aspect. + expect(att.width).toBeLessThan(att.height); + }, + 15_000, + ); + + it('stores display-space dimensions for an EXIF-rotated untouched paste', async () => { + // Within budgets → sent byte-for-byte, but the placeholder and metadata + // must still describe the display (rotated) space. + const portrait = withExifOrientation(await solidJpeg(120, 80), 6); + readClipboardMedia.mockResolvedValue({ + kind: 'image', + bytes: portrait, + mimeType: 'image/jpeg', + }); + + const { store, pasteImage } = createPasteHarness(); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.bytes).toBe(portrait); // fast path — untouched + expect(att.original).toBeUndefined(); + expect(att.width).toBe(80); + expect(att.height).toBe(120); + expect(att.placeholder).toContain('80×120'); + }); + + it('emits image_compress telemetry tagged tui_paste through host.track', async () => { + const big = await solidPng(3600, 1800); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: big, mimeType: 'image/png' }); + + const { track, pasteImage } = createPasteHarness(); + await pasteImage(); + + const compressCalls = track.mock.calls.filter(([event]) => event === 'image_compress'); + expect(compressCalls).toHaveLength(1); + const props = compressCalls[0]![1] as Record; + expect(props['source']).toBe('tui_paste'); + expect(props['outcome']).toBe('compressed'); + }); + + it('uploads final bytes with a crash-recovery TTL while the staging lease owns normal cleanup', async () => { + const small = await solidPng(80, 80); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: small, mimeType: 'image/png' }); + const uploadFile = uploadFileMock('file-1'); + + const { store, pasteImage } = createPasteHarness({ uploadFile }); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.fileId).toBe('file-1'); + expect(att.fileExpiresAt).toBe(Date.parse('2030-01-02T03:04:05.000Z')); + expect(uploadFile).toHaveBeenCalledTimes(1); + const [data, opts] = uploadFile.mock.calls[0]!; + expect(new Uint8Array(data)).toEqual(small); + expect(opts).toEqual({ + name: 'pasted-image.png', + mimeType: 'image/png', + expiresInSec: 60 * 60, + }); + // The bytes stay on the attachment for the inline fallback / cache copy. + expect(att.bytes).toBe(small); + }); + + it('uploads the compressed bytes when paste-time compression changed them (v2)', async () => { + const big = await solidPng(3600, 1800); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: big, mimeType: 'image/png' }); + const uploadFile = uploadFileMock('file-9'); + + const { store, pasteImage } = createPasteHarness({ uploadFile }); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.fileId).toBe('file-9'); + // The upload carries exactly what the attachment stores — the compressed + // bytes, not the clipboard original. + const [data] = uploadFile.mock.calls[0]!; + expect(data).toBe(att.bytes); + expect(att.bytes).not.toBe(big); + }); + + it('keeps the paste on the inline fallback when the daemon upload fails (v2)', async () => { + const small = await solidPng(80, 80); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: small, mimeType: 'image/png' }); + const uploadFile = vi.fn( + async ( + _data: Uint8Array, + _opts: { name: string; mimeType?: string; expiresInSec?: number }, + ): Promise<{ id: string }> => { + throw new Error('daemon down'); + }, + ); + + const { store, pasteImage } = createPasteHarness({ uploadFile }); + await pasteImage(); // must not throw + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.fileId).toBeUndefined(); + expect(att.bytes).toBe(small); + }); + + it('settles the paste callback before the background daemon upload completes (v2)', async () => { + const small = await solidPng(80, 80); + readClipboardMedia.mockResolvedValue({ kind: 'image', bytes: small, mimeType: 'image/png' }); + let resolveUpload!: (meta: { id: string }) => void; + const uploadFile = vi.fn( + ( + _data: Uint8Array, + _opts: { name: string; mimeType?: string; expiresInSec?: number }, + ): Promise<{ id: string }> => + new Promise<{ id: string }>((resolve) => { + resolveUpload = resolve; + }), + ); + + const { store, pasteImageRaw } = createPasteHarness({ uploadFile }); + // The handler returns once the placeholder is in the editor; the upload + // is still unresolved here — typing is never held behind it. + await pasteImageRaw(); + + const att = store.get(1); + if (att?.kind !== 'image') throw new Error('expected image attachment'); + expect(att.placeholder).toBe('[image #1 (80×80)]'); + expect(att.fileId).toBeUndefined(); + expect(att.pending).toBeDefined(); + + resolveUpload({ id: 'file-late' }); + await att.pending; + + expect(att.fileId).toBe('file-late'); + expect(att.pending).toBeUndefined(); + }); +}); + +describe('clipboard video paste upload', () => { + beforeEach(() => { + readClipboardMedia.mockReset(); + }); + + async function withSourceVideo(run: (sourcePath: string) => Promise): Promise { + const dir = await mkdtemp(join(tmpdir(), 'paste-video-')); + try { + const sourcePath = join(dir, 'clip.mp4'); + await writeFile(sourcePath, 'video-bytes'); + await run(sourcePath); + } finally { + await rm(dir, { recursive: true, force: true }); + } + } + + it('uploads the pasted video to the daemon file store (v2)', async () => { + await withSourceVideo(async (sourcePath) => { + readClipboardMedia.mockResolvedValue({ + kind: 'video', + mimeType: 'video/mp4', + filename: 'clip.mp4', + sourcePath, + }); + const uploadFile = uploadFileMock('file-v1'); + + const { store, pasteImage } = createPasteHarness({ uploadFile }); + await pasteImage(); + + const att = store.get(1); + if (att?.kind !== 'video') throw new Error('expected video attachment'); + expect(att.placeholder).toBe('[video #1 clip.mp4]'); + expect(att.fileId).toBe('file-v1'); + expect(att.fileExpiresAt).toBe(Date.parse('2030-01-02T03:04:05.000Z')); + expect(att.pending).toBeUndefined(); + const [data, opts] = uploadFile.mock.calls[0]!; + expect(new Uint8Array(data)).toEqual(new TextEncoder().encode('video-bytes')); + expect(opts).toEqual({ name: 'clip.mp4', mimeType: 'video/mp4', expiresInSec: 60 * 60 }); + }); + }); + + it('settles the paste callback before the background upload completes (v2)', async () => { + await withSourceVideo(async (sourcePath) => { + readClipboardMedia.mockResolvedValue({ + kind: 'video', + mimeType: 'video/mp4', + filename: 'clip.mp4', + sourcePath, + }); + let resolveUpload!: (meta: { id: string }) => void; + const uploadFile = vi.fn( + ( + _data: Uint8Array, + _opts: { name: string; mimeType?: string; expiresInSec?: number }, + ): Promise<{ id: string }> => + new Promise<{ id: string }>((resolve) => { + resolveUpload = resolve; + }), + ); + + const { store, pasteImageRaw } = createPasteHarness({ uploadFile }); + // The handler returns once the placeholder is in the editor; the upload + // is still unresolved here — typing is never held behind it. + await pasteImageRaw(); + + const att = store.get(1); + if (att?.kind !== 'video') throw new Error('expected video attachment'); + expect(att.fileId).toBeUndefined(); + expect(att.pending).toBeDefined(); + + // The upload starts once the source file has been read in the + // background; only then can it be resolved. + await vi.waitFor(() => { + expect(uploadFile).toHaveBeenCalled(); + }); + resolveUpload({ id: 'file-vlate' }); + await att.pending; + + expect(att.fileId).toBe('file-vlate'); + expect(att.pending).toBeUndefined(); + }); + }); + + it('leaves the video without a fileId when the daemon upload fails (v2)', async () => { + await withSourceVideo(async (sourcePath) => { + readClipboardMedia.mockResolvedValue({ + kind: 'video', + mimeType: 'video/mp4', + filename: 'clip.mp4', + sourcePath, + }); + const uploadFile = vi.fn(async (): Promise<{ id: string }> => { + throw new Error('daemon down'); + }); + + const { store, pasteImage } = createPasteHarness({ uploadFile }); + await pasteImage(); // must not throw + + const att = store.get(1); + if (att?.kind !== 'video') throw new Error('expected video attachment'); + expect(att.fileId).toBeUndefined(); + expect(att.pending).toBeUndefined(); + }); + }); + + it('leaves the video without a fileId when the source file vanished (v2)', async () => { + readClipboardMedia.mockResolvedValue({ + kind: 'video', + mimeType: 'video/mp4', + filename: 'clip.mp4', + sourcePath: '/tmp/kimi-paste-vanished-source.mp4', + }); + const uploadFile = uploadFileMock('file-v1'); + + const { store, pasteImage } = createPasteHarness({ uploadFile }); + await pasteImage(); + + expect(uploadFile).not.toHaveBeenCalled(); + const att = store.get(1); + if (att?.kind !== 'video') throw new Error('expected video attachment'); + expect(att.fileId).toBeUndefined(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/editor-keyboard.test.ts b/apps/kimi-code/test/tui/controllers/editor-keyboard.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e89b48f1b8bd26933c22c98369d563f95bb9f985 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/editor-keyboard.test.ts @@ -0,0 +1,745 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { DOUBLE_ESC_WINDOW_MS } from '#/tui/constant/kimi-tui'; +import { + EditorKeyboardController, + type EditorKeyboardHost, +} from '#/tui/controllers/editor-keyboard'; +import type { ImageAttachmentStore } from '#/tui/utils/image-attachment-store'; + +interface Harness { + readonly host: EditorKeyboardHost; + readonly editor: Record unknown) | undefined>; + readonly openUndoSelector: ReturnType; + readonly cancelRunningShellCommand: ReturnType; + readonly cancelCompaction: ReturnType; + readonly btwCancelRunning: ReturnType; + readonly btwCloseOrCancel: ReturnType; + readonly survey: { + readonly handlePreInput: ReturnType boolean>>; + readonly handleSubmit: ReturnType boolean>>; + readonly handleEditorChange: ReturnType void>>; + readonly closeSilently: ReturnType void>>; + }; +} + +function createHarness(options: { streamingPhase?: string; isCompacting?: boolean } = {}): Harness { + const editor: Record unknown) | undefined> = { + setHistoryFilter: vi.fn() as unknown as (...args: never[]) => unknown, + setInputMode: vi.fn() as unknown as (...args: never[]) => unknown, + getText: vi.fn(() => '') as unknown as (...args: never[]) => unknown, + setText: vi.fn() as unknown as (...args: never[]) => unknown, + }; + const openUndoSelector = vi.fn(); + const cancelRunningShellCommand = vi.fn(); + const cancelCompaction = vi.fn(async () => {}); + const btwCancelRunning = vi.fn(() => false); + const btwCloseOrCancel = vi.fn(() => false); + const survey = { + handlePreInput: vi.fn<(data: string) => boolean>(() => false), + handleSubmit: vi.fn<(text: string) => boolean>(() => false), + handleEditorChange: vi.fn<(text: string) => void>(() => {}), + closeSilently: vi.fn<() => void>(() => {}), + }; + const session = { cancel: vi.fn(async () => {}), cancelCompaction }; + + const host = { + state: { + editor, + activeDialog: null, + appState: { + streamingPhase: options.streamingPhase ?? 'idle', + isCompacting: options.isCompacting ?? false, + editorCommand: null, + }, + footer: { setTransientHint: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session, + btwPanelController: { cancelRunning: btwCancelRunning, closeOrCancel: btwCloseOrCancel }, + surveyController: survey, + openUndoSelector, + cancelRunningShellCommand, + updateEditorBorderHighlight: vi.fn(), + updateGoalLengthWarning: vi.fn(), + handleUserInput: vi.fn(), + track: vi.fn(), + openExternalEditor: vi.fn(), + showError: vi.fn(), + stop: vi.fn(), + } as unknown as EditorKeyboardHost; + + const controller = new EditorKeyboardController( + host, + undefined as unknown as ImageAttachmentStore, + ); + controller.install(); + + return { + host, + editor, + openUndoSelector, + cancelRunningShellCommand, + cancelCompaction, + btwCancelRunning, + btwCloseOrCancel, + survey, + }; +} + +function pressEscape(editor: Harness['editor']): void { + const handler = editor['onEscape']; + if (handler === undefined) throw new Error('onEscape handler not installed'); + (handler as () => void)(); +} + +function pressCtrlC(editor: Harness['editor']): void { + const handler = editor['onCtrlC']; + if (handler === undefined) throw new Error('onCtrlC handler not installed'); + (handler as () => void)(); +} + +function pressCtrlD(editor: Harness['editor']): void { + const handler = editor['onCtrlD']; + if (handler === undefined) throw new Error('onCtrlD handler not installed'); + (handler as () => void)(); +} + +function pressNonEscape(editor: Harness['editor']): void { + const handler = editor['onNonEscapeInput']; + if (handler === undefined) throw new Error('onNonEscapeInput handler not installed'); + (handler as () => void)(); +} + +describe('EditorKeyboardController double-Esc undo', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it('opens the undo selector when Esc is pressed twice within the window while idle', () => { + const { editor, openUndoSelector } = createHarness(); + + pressEscape(editor); + expect(openUndoSelector).not.toHaveBeenCalled(); + + pressEscape(editor); + expect(openUndoSelector).toHaveBeenCalledOnce(); + }); + + it('does nothing for a single Esc while idle', () => { + const { editor, openUndoSelector } = createHarness(); + + pressEscape(editor); + + expect(openUndoSelector).not.toHaveBeenCalled(); + }); + + it('does not trigger when the second Esc arrives after the window expires', () => { + const { editor, openUndoSelector } = createHarness(); + + pressEscape(editor); + vi.advanceTimersByTime(DOUBLE_ESC_WINDOW_MS + 1); + pressEscape(editor); + + expect(openUndoSelector).not.toHaveBeenCalled(); + }); + + it('does not trigger when another key is pressed between the two Esc presses', () => { + const { editor, openUndoSelector } = createHarness(); + + pressEscape(editor); + pressNonEscape(editor); + pressEscape(editor); + + expect(openUndoSelector).not.toHaveBeenCalled(); + }); + + it('does not trigger undo while streaming; Esc cancels the stream instead', () => { + const { editor, host, openUndoSelector, cancelRunningShellCommand } = createHarness({ + streamingPhase: 'waiting', + }); + + pressEscape(editor); + pressEscape(editor); + + expect(openUndoSelector).not.toHaveBeenCalled(); + expect(cancelRunningShellCommand).toHaveBeenCalled(); + const session = host.session as unknown as { cancel: ReturnType }; + expect(session.cancel).toHaveBeenCalled(); + }); +}); + +describe('EditorKeyboardController btw panel priority', () => { + it('Esc closes the btw panel first while compacting, without cancelling compaction', () => { + const { editor, btwCloseOrCancel, cancelCompaction } = createHarness({ isCompacting: true }); + btwCloseOrCancel.mockReturnValue(true); + + pressEscape(editor); + + expect(btwCloseOrCancel).toHaveBeenCalledOnce(); + expect(cancelCompaction).not.toHaveBeenCalled(); + }); + + it('Esc cancels compaction on the next press once the btw panel is gone', () => { + const { editor, btwCloseOrCancel, cancelCompaction } = createHarness({ isCompacting: true }); + btwCloseOrCancel.mockReturnValueOnce(true); + + pressEscape(editor); + expect(cancelCompaction).not.toHaveBeenCalled(); + + pressEscape(editor); + expect(cancelCompaction).toHaveBeenCalledOnce(); + }); + + it('Esc cancels compaction directly when no btw panel is open', () => { + const { editor, btwCloseOrCancel, cancelCompaction } = createHarness({ isCompacting: true }); + + pressEscape(editor); + + expect(btwCloseOrCancel).toHaveBeenCalledOnce(); + expect(cancelCompaction).toHaveBeenCalledOnce(); + }); + + it('Ctrl+C cancels a running btw question first while compacting', () => { + const { editor, btwCancelRunning, cancelCompaction } = createHarness({ isCompacting: true }); + btwCancelRunning.mockReturnValue(true); + + pressCtrlC(editor); + + expect(btwCancelRunning).toHaveBeenCalledOnce(); + expect(cancelCompaction).not.toHaveBeenCalled(); + }); + + it('Ctrl+C closes an idle btw panel while compacting, without cancelling compaction', () => { + const { editor, btwCloseOrCancel, cancelCompaction } = createHarness({ isCompacting: true }); + btwCloseOrCancel.mockReturnValue(true); + + pressCtrlC(editor); + + expect(btwCloseOrCancel).toHaveBeenCalledOnce(); + expect(cancelCompaction).not.toHaveBeenCalled(); + }); + + it('Ctrl+C cancels compaction when no btw panel is open', () => { + const { editor, btwCancelRunning, btwCloseOrCancel, cancelCompaction } = createHarness({ + isCompacting: true, + }); + + pressCtrlC(editor); + + expect(btwCancelRunning).toHaveBeenCalledOnce(); + expect(btwCloseOrCancel).toHaveBeenCalledOnce(); + expect(cancelCompaction).toHaveBeenCalledOnce(); + }); +}); + +describe('EditorKeyboardController shell history recall', () => { + type Recall = (entry: string, direction: 1 | -1) => string | undefined; + type Mock = ReturnType; + + it('installs a filter that allows shell entries only in bash mode', () => { + const { editor } = createHarness(); + const setHistoryFilter = editor['setHistoryFilter'] as unknown as Mock; + expect(setHistoryFilter).toHaveBeenCalledOnce(); + const [filter] = setHistoryFilter.mock.calls[0] as [(entry: string) => boolean]; + + (editor as unknown as { inputMode: string }).inputMode = 'prompt'; + expect(filter('!cmd')).toBe(true); + expect(filter('hello')).toBe(true); + + (editor as unknown as { inputMode: string }).inputMode = 'bash'; + expect(filter('!cmd')).toBe(true); + expect(filter('hello')).toBe(false); + }); + + it('locks the filter to the browse-entry mode once browsing starts', () => { + const { editor } = createHarness(); + const setHistoryFilter = editor['setHistoryFilter'] as unknown as Mock; + const [filter] = setHistoryFilter.mock.calls[0] as [(entry: string) => boolean]; + const save = editor['onHistoryDraftSave'] as unknown as () => unknown; + + // Enter browse from prompt mode, then simulate landing on a shell entry + // (which flips inputMode to bash). The filter should stay locked to prompt + // and keep allowing plain entries. + (editor as unknown as { inputMode: string }).inputMode = 'prompt'; + save(); + (editor as unknown as { inputMode: string }).inputMode = 'bash'; + + expect(filter('hello')).toBe(true); + expect(filter('!cmd')).toBe(true); + }); + + it('strips the leading ! and switches to bash mode when recalling a shell entry', () => { + const { editor } = createHarness(); + const onRecall = editor['onRecall'] as unknown as Recall; + + const result = onRecall('!cmd', -1); + + expect(result).toBe('cmd'); + expect(editor['setInputMode'] as unknown as Mock).toHaveBeenCalledWith('bash'); + }); + + it('keeps plain entries as-is and switches to prompt mode', () => { + const { editor } = createHarness(); + const onRecall = editor['onRecall'] as unknown as Recall; + + const result = onRecall('hello', -1); + + expect(result).toBeUndefined(); + expect(editor['setInputMode'] as unknown as Mock).toHaveBeenCalledWith('prompt'); + }); + + it('saves the current input mode as the history draft host state', () => { + const { editor } = createHarness(); + const save = editor['onHistoryDraftSave'] as unknown as () => unknown; + + (editor as unknown as { inputMode: string }).inputMode = 'prompt'; + expect(save()).toBe('prompt'); + + (editor as unknown as { inputMode: string }).inputMode = 'bash'; + expect(save()).toBe('bash'); + }); + + it('restores the input mode from the saved draft host state', () => { + const { editor } = createHarness(); + const restore = editor['onHistoryDraftRestore'] as unknown as (state: unknown) => void; + + restore('prompt'); + + expect(editor['setInputMode'] as unknown as Mock).toHaveBeenCalledWith('prompt'); + }); +}); + +describe('EditorKeyboardController input changes', () => { + function installExpandedText( + editor: Harness['editor'], + expanded: string, + ): ReturnType { + const getExpandedText = vi.fn(() => expanded); + editor['getExpandedText'] = getExpandedText as unknown as (...args: never[]) => unknown; + return getExpandedText; + } + + it('forwards text changes to the border highlight and goal length warning', () => { + const { host, editor } = createHarness(); + installExpandedText(editor, '/goal Ship feature X'); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + onChange('/goal Ship feature X'); + + expect(host.updateEditorBorderHighlight).toHaveBeenCalledWith('/goal Ship feature X'); + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith('/goal Ship feature X'); + }); + + it('measures the goal length warning on paste-expanded text, not the collapsed marker', () => { + const { host, editor } = createHarness(); + const expanded = `/goal ${'x'.repeat(4001)}`; + installExpandedText(editor, expanded); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + // The visible text only holds the collapsed paste marker. + onChange('/goal [paste #1 +4000 chars]'); + + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith(expanded); + }); + + it('expands a leading paste marker because its content may start with /goal', () => { + const { host, editor } = createHarness(); + const expanded = `/goal ${'x'.repeat(4001)}`; + const getExpandedText = installExpandedText(editor, expanded); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + onChange('[paste #1 +4000 chars]'); + + expect(getExpandedText).toHaveBeenCalled(); + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith(expanded); + }); + + it('expands a paste that can complete a partially typed /goal command', () => { + const { host, editor } = createHarness(); + const expanded = `/goal ${'x'.repeat(4001)}`; + const getExpandedText = installExpandedText(editor, expanded); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + // Visible text is `/go[paste #1 …]`; the paste completes the command. + onChange('/go[paste #1 +3999 chars]'); + + expect(getExpandedText).toHaveBeenCalled(); + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith(expanded); + }); + + it('skips paste expansion entirely for non-goal input', () => { + const { host, editor } = createHarness(); + const getExpandedText = installExpandedText(editor, 'whatever'); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + onChange('just a normal prompt'); + onChange('/help'); + + expect(getExpandedText).not.toHaveBeenCalled(); + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith(undefined); + }); + + it('gates on trimmed text because submit trims leading whitespace', () => { + const { host, editor } = createHarness(); + const expanded = `/goal ${'x'.repeat(4001)}`; + const getExpandedText = installExpandedText(editor, expanded); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + onChange(` /goal ${'x'.repeat(4001)}`); + + expect(getExpandedText).toHaveBeenCalled(); + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith(expanded); + }); + + it('skips the goal length warning in bash mode', () => { + const { host, editor } = createHarness(); + const getExpandedText = installExpandedText(editor, '/goal x'); + (editor as unknown as { inputMode: string }).inputMode = 'bash'; + const onChange = editor['onChange'] as unknown as (text: string) => void; + + onChange('/goal x'); + + expect(getExpandedText).not.toHaveBeenCalled(); + expect(host.updateGoalLengthWarning).toHaveBeenCalledWith(undefined); + }); +}); + +describe('EditorKeyboardController Shift-Tab plan toggle', () => { + function createShiftTabHarness(options: { sessionless?: boolean } = {}) { + const editor: Record unknown) | undefined> = { + setHistoryFilter: vi.fn() as unknown as (...args: never[]) => unknown, + }; + const handlePlanToggle = vi.fn(); + const track = vi.fn(); + const showError = vi.fn(); + const ensureSession = vi.fn(async (): Promise<{ id: string } | undefined> => ({ id: 'ses-lazy' })); + const host = { + state: { + editor, + activeDialog: null, + appState: { streamingPhase: 'idle', isCompacting: false, planMode: false }, + footer: { setTransientHint: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: options.sessionless ? undefined : { cancel: vi.fn(async () => {}) }, + ensureSession, + handlePlanToggle, + track, + showError, + btwPanelController: { cancelRunning: vi.fn(), closeOrCancel: vi.fn() }, + } as unknown as EditorKeyboardHost; + + new EditorKeyboardController(host, undefined as unknown as ImageAttachmentStore).install(); + const onShiftTab = editor['onShiftTab'] as unknown as () => void; + return { onShiftTab, handlePlanToggle, track, showError, ensureSession }; + } + + it('toggles plan mode directly with an active session', () => { + const { onShiftTab, handlePlanToggle, ensureSession } = createShiftTabHarness(); + + onShiftTab(); + + expect(ensureSession).not.toHaveBeenCalled(); + expect(handlePlanToggle).toHaveBeenCalledWith(true); + }); + + it('lazy-creates the session before toggling on v2 when session-less', async () => { + const { onShiftTab, ensureSession, handlePlanToggle, track } = createShiftTabHarness({ + sessionless: true, + }); + + onShiftTab(); + expect(handlePlanToggle).not.toHaveBeenCalled(); + + await vi.waitFor(() => { + expect(handlePlanToggle).toHaveBeenCalledWith(true); + }); + expect(ensureSession).toHaveBeenCalledOnce(); + expect(track).toHaveBeenCalledWith('shortcut_plan_toggle', { enabled: true }); + }); + + it('does not toggle when the lazy creation fails on v2', async () => { + const { onShiftTab, ensureSession, handlePlanToggle } = createShiftTabHarness({ + sessionless: true, + }); + ensureSession.mockResolvedValue(undefined); + + onShiftTab(); + await new Promise((resolve) => setImmediate(resolve)); + + expect(handlePlanToggle).not.toHaveBeenCalled(); + }); +}); + +/** + * Ctrl-S steering of the TUI queue: plain-text items steer as messages, + * slash-skill items fire as real activations into the running turn (never as + * literal text), grouped inline-skill submissions stay queued for the drain + * path, bash items stay queued — all in queue order. + */ +describe('EditorKeyboardController Ctrl-S steering', () => { + function createCtrlSHarness(options: { + editorText: string; + queued: Array>; + skillCommandMap?: Map; + }) { + const steerMessage = vi.fn(); + const steerSkillActivation = vi.fn(); + const updateQueueDisplay = vi.fn(); + const setText = vi.fn(); + const editor: Record unknown) | undefined> = { + setHistoryFilter: vi.fn() as unknown as (...args: never[]) => unknown, + setInputMode: vi.fn() as unknown as (...args: never[]) => unknown, + getText: vi.fn(() => options.editorText) as unknown as (...args: never[]) => unknown, + setText: setText as unknown as (...args: never[]) => unknown, + inputMode: 'prompt' as unknown as (...args: never[]) => unknown, + }; + const host = { + state: { + editor, + activeDialog: null, + queuedMessages: options.queued, + appState: { streamingPhase: 'waiting', isCompacting: false, model: 'k2' }, + footer: { setTransientHint: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: { id: 's1' }, + skillCommandMap: options.skillCommandMap ?? new Map(), + steerMessage, + steerSkillActivation, + updateQueueDisplay, + validateMediaCapabilities: vi.fn(() => true), + showError: vi.fn(), + track: vi.fn(), + btwPanelController: { + cancelRunning: vi.fn(() => false), + closeOrCancel: vi.fn(() => false), + }, + } as unknown as EditorKeyboardHost; + const controller = new EditorKeyboardController( + host, + undefined as unknown as ImageAttachmentStore, + ); + controller.install(); + const onCtrlS = editor['onCtrlS']; + if (onCtrlS === undefined) throw new Error('onCtrlS handler not installed'); + return { + host, + editor, + setText, + steerMessage, + steerSkillActivation, + updateQueueDisplay, + onCtrlS: onCtrlS as () => void, + }; + } + + it('steers text as a message, skill items as activations, and keeps bash queued', () => { + const { host, steerMessage, steerSkillActivation, updateQueueDisplay, onCtrlS } = + createCtrlSHarness({ + editorText: '', + queued: [ + { text: 'queued text', agentId: 'main' }, + { + text: '/tower status', + agentId: 'main', + mode: 'skill', + skillName: 'tower', + skillArgs: 'status', + }, + { text: '!ls', agentId: 'main', mode: 'bash' }, + ], + }); + + onCtrlS(); + + expect(steerMessage).toHaveBeenCalledWith(host.session, [ + { text: 'queued text', parts: undefined, imageAttachmentIds: undefined }, + ]); + expect(steerSkillActivation).toHaveBeenCalledWith(host.session, 'tower', 'status'); + expect(host.state.queuedMessages).toEqual([{ text: '!ls', agentId: 'main', mode: 'bash' }]); + expect(updateQueueDisplay).toHaveBeenCalled(); + }); + + it('steers plain queued messages but keeps grouped inline-skill submissions queued', () => { + const { host, steerMessage, updateQueueDisplay, onCtrlS } = createCtrlSHarness({ + editorText: '', + queued: [ + { text: 'plain note', agentId: 'main' }, + { + text: 'check /skill:review', + agentId: 'main', + inlineSkillActivations: [{ skillName: 'review' }], + }, + ], + }); + + onCtrlS(); + + expect(steerMessage).toHaveBeenCalledWith(host.session, [ + { text: 'plain note', parts: undefined, imageAttachmentIds: undefined }, + ]); + expect(host.state.queuedMessages).toEqual([ + { + text: 'check /skill:review', + agentId: 'main', + inlineSkillActivations: [{ skillName: 'review' }], + }, + ]); + expect(updateQueueDisplay).toHaveBeenCalled(); + }); + + it('stops steering at the first bundle so later messages keep FIFO order', () => { + const { host, steerMessage, onCtrlS } = createCtrlSHarness({ + editorText: '', + queued: [ + { text: 'earlier note', agentId: 'main' }, + { + text: 'check /skill:review', + agentId: 'main', + inlineSkillActivations: [{ skillName: 'review' }], + }, + { text: 'later note', agentId: 'main' }, + ], + }); + + onCtrlS(); + + expect(steerMessage).toHaveBeenCalledWith(host.session, [ + { text: 'earlier note', parts: undefined, imageAttachmentIds: undefined }, + ]); + expect(host.state.queuedMessages).toEqual([ + { + text: 'check /skill:review', + agentId: 'main', + inlineSkillActivations: [{ skillName: 'review' }], + }, + { text: 'later note', agentId: 'main' }, + ]); + }); + + it('steers nothing when a bundle leads the queue', () => { + const { host, steerMessage, onCtrlS } = createCtrlSHarness({ + editorText: '', + queued: [ + { + text: 'check /skill:review', + agentId: 'main', + inlineSkillActivations: [{ skillName: 'review' }], + }, + { text: 'later note', agentId: 'main' }, + ], + }); + + onCtrlS(); + + expect(steerMessage).not.toHaveBeenCalled(); + expect(host.state.queuedMessages).toHaveLength(2); + }); + + it('leaves an editor draft with inline skill tokens in the editor for the grouped path', () => { + const { host, setText, steerMessage, onCtrlS } = createCtrlSHarness({ + editorText: 'check /skill:review', + queued: [{ text: 'plain note', agentId: 'main' }], + skillCommandMap: new Map([['skill:review', 'review']]), + }); + + onCtrlS(); + + expect(steerMessage).toHaveBeenCalledWith(host.session, [ + { text: 'plain note', parts: undefined, imageAttachmentIds: undefined }, + ]); + expect(setText).not.toHaveBeenCalled(); + expect(host.state.queuedMessages).toEqual([]); + }); +}); + +describe('EditorKeyboardController survey wiring', () => { + it('clears the pending undo-escape sequence only when the survey consumes Escape', () => { + const { editor, openUndoSelector, survey } = createHarness(); + const onPreInput = editor['onPreInput'] as unknown as (data: string) => boolean; + + pressEscape(editor); + survey.handlePreInput.mockReturnValueOnce(true); + onPreInput('\u001B'); + pressEscape(editor); + expect(openUndoSelector).not.toHaveBeenCalled(); + + pressEscape(editor); + pressEscape(editor); + expect(openUndoSelector).toHaveBeenCalledOnce(); + }); + + it('clears a pending exit when Escape arrives through the survey pre-input hook', () => { + const { host, editor } = createHarness(); + const onPreInput = editor['onPreInput'] as unknown as (data: string) => boolean; + + pressCtrlD(editor); + onPreInput('\u001B'); + pressCtrlD(editor); + + expect(host.stop).not.toHaveBeenCalled(); + }); + + it('routes raw keys to the survey pre-input hook first', () => { + const { editor, survey } = createHarness(); + const onPreInput = editor['onPreInput'] as unknown as (data: string) => boolean; + + survey.handlePreInput.mockReturnValueOnce(true); + expect(onPreInput('\u001B[D')).toBe(true); + expect(survey.handlePreInput).toHaveBeenCalledWith('\u001B[D'); + + survey.handlePreInput.mockReturnValueOnce(false); + expect(onPreInput('x')).toBe(false); + }); + + it('forwards editor text changes to the survey', () => { + const { editor, survey } = createHarness(); + const onChange = editor['onChange'] as unknown as (text: string) => void; + + onChange('1'); + + expect(survey.handleEditorChange).toHaveBeenCalledWith('1'); + }); + + it('lets the survey intercept a submit instead of sending it', () => { + const { host, editor, survey } = createHarness(); + const onSubmit = editor['onSubmit'] as unknown as (text: string) => void; + + survey.handleSubmit.mockReturnValueOnce(true); + onSubmit('1'); + + expect(survey.handleSubmit).toHaveBeenCalledWith('1'); + expect(host.handleUserInput).not.toHaveBeenCalled(); + }); + + it('sends the submit when the survey passes it through', () => { + const { host, editor, survey } = createHarness(); + const onSubmit = editor['onSubmit'] as unknown as (text: string) => void; + + survey.handleSubmit.mockReturnValueOnce(false); + onSubmit('hello'); + + expect(host.handleUserInput).toHaveBeenCalledWith('hello'); + }); + + it('closes the survey silently when the external editor opens', () => { + vi.stubEnv('VISUAL', ''); + vi.stubEnv('EDITOR', ''); + try { + const { editor, survey } = createHarness(); + const onOpenExternalEditor = editor['onOpenExternalEditor'] as unknown as () => void; + + onOpenExternalEditor(); + + expect(survey.closeSilently).toHaveBeenCalled(); + } finally { + vi.unstubAllEnvs(); + } + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/notify.test.ts b/apps/kimi-code/test/tui/controllers/notify.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..32515fef3e86f37ac645977641fbf3e9c8528475 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/notify.test.ts @@ -0,0 +1,752 @@ +import type { Event, ResumedSessionState } from '@moonshot-ai/kimi-code-sdk'; +import { + Container, + Text, + TuiMainScreen, + TuiAltScreen, + VStack, + ScrollView, + type Terminal, +} from '@moonshot-ai/pi-tui'; +import { CustomEditor } from '#/tui/components/editor/custom-editor'; +import { describe, expect, it, vi } from 'vitest'; + +import { NotifyPanelComponent } from '#/tui/components/chrome/notify-panel'; +import { NotifyController } from '#/tui/controllers/notify'; + +function makeHarness(enabled = true, fullscreen = false) { + let input: ((data: string) => void) | undefined; + const terminal: Terminal = { + start: (onInput) => { + input = onInput; + }, + stop: () => {}, + drainInput: async () => {}, + write: () => {}, + columns: 100, + rows: 24, + kittyProtocolActive: false, + moveBy: () => {}, + hideCursor: () => {}, + showCursor: () => {}, + clearLine: () => {}, + clearFromCursor: () => {}, + clearScreen: () => {}, + setTitle: () => {}, + setProgress: () => {}, + }; + const ui = fullscreen ? new TuiAltScreen(terminal) : new TuiMainScreen(terminal); + const editor = new CustomEditor(ui); + editor.setText('unsent draft'); + const transcript = new Text('earlier output\n'.repeat(80), 0, 0); + const notifyPanel = new NotifyPanelComponent(); + const notifyPanelContainer = new Container(); + const requestRender = vi.spyOn(ui, 'requestRender').mockImplementation(() => {}); + const root = new VStack(); + root.addChild(new ScrollView(transcript, { primary: true })); + root.addChild(notifyPanelContainer); + root.addChild(editor); + if (ui instanceof TuiAltScreen) ui.setLayoutRoot(root); + else { + ui.addChild(transcript); + ui.addChild(notifyPanelContainer); + ui.addChild(editor); + } + ui.setFocus(editor); + const controller = new NotifyController({ + notifyPanel, + notifyPanelContainer, + ui, + editor, + } as never); + controller.setEnabled(enabled); + editor.onPageNotify = () => controller.toggleFocus(); + editor.onNotifyPanelKey = (key) => controller.handlePanelKey(key); + const emit = ( + type: string, + fields: Record = {}, + agentId = 'main', + turnId = 1, + ) => { + controller.handleEvent({ type, sessionId: 's1', agentId, turnId, ...fields } as Event); + }; + if (enabled) emit('turn.started'); + requestRender.mockClear(); + const send = (id: string, message: string, agentId = 'main', turnId = 1) => { + emit( + 'tool.call.started', + { toolCallId: id, name: 'NotifyUser', args: { message } }, + agentId, + turnId, + ); + emit('tool.result', { toolCallId: id, output: 'Update shown to the user.' }, agentId, turnId); + }; + const texts = () => notifyPanel.getEntries().map((entry) => entry.text); + const rendered = () => notifyPanel.render(150).join('\n'); + return { + controller, + ui, + editor, + root, + input: (data: string) => input?.(data), + emit, + send, + texts, + rendered, + notifyPanel, + notifyPanelContainer, + requestRender, + }; +} + +function snapshot(): ResumedSessionState { + return { + sessionMetadata: { agents: {} }, + agents: { + main: { config: { profileName: 'agent' }, background: [], replay: [] }, + 'agent-1': { config: { profileName: 'coder' }, background: [], replay: [] }, + }, + } as unknown as ResumedSessionState; +} + +describe('NotifyController', () => { + it('does nothing when disabled, including replay, layout and keyboard', () => { + const h = makeHarness(false); + h.emit('turn.started'); + h.emit('subagent.spawned', { subagentId: 'agent-1', subagentName: 'coder' }); + h.send('n1', 'invisible'); + h.controller.restore(snapshot()); + expect(h.texts()).toEqual([]); + expect(h.notifyPanelContainer.children).toEqual([]); + expect(h.controller.toggleFocus()).toBe(false); + expect(h.requestRender).not.toHaveBeenCalled(); + }); + + it('waits for the successful result before displaying authoritative arguments', () => { + const h = makeHarness(); + h.emit('tool.call.delta', { + toolCallId: 'n1', + name: 'NotifyUser', + argumentsPart: '{"message":"Reading the', + }); + expect(h.texts()).toEqual([]); + h.emit('tool.call.delta', { toolCallId: 'n1', argumentsPart: ' parser."}' }); + expect(h.texts()).toEqual([]); + h.emit('tool.call.started', { + toolCallId: 'n1', + name: 'NotifyUser', + args: { message: 'Parser reviewed.' }, + }); + expect(h.texts()).toEqual([]); + expect(h.notifyPanelContainer.children).toEqual([]); + h.emit('tool.result', { toolCallId: 'n1', output: 'Update shown to the user.' }); + expect(h.texts()).toEqual(['Parser reviewed.']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + }); + + it.each([ + { output: 'Permission denied', isError: true }, + { output: 'Update shown to the user.', synthetic: true }, + { output: 'Notifications are disabled; the update was not displayed.' }, + { output: 'Unrecognized success' }, + ])('never displays rejected, suppressed or unconfirmed updates: %j', (result) => { + const h = makeHarness(); + h.emit('tool.call.delta', { + toolCallId: 'blocked', + name: 'NotifyUser', + argumentsPart: '{"message":"Private finding', + }); + expect(h.notifyPanelContainer.children).toEqual([]); + h.emit('tool.call.started', { + toolCallId: 'blocked', + name: 'NotifyUser', + args: { message: 'Private finding' }, + }); + expect(h.notifyPanelContainer.children).toEqual([]); + h.emit('tool.result', { toolCallId: 'blocked', ...result }); + expect(h.texts()).toEqual([]); + expect(h.notifyPanelContainer.children).toEqual([]); + }); + + it.each([false, true])( + 'keeps a foreground descendant alive under a background parent, detached later: %s', + (detachLater) => { + const h = makeHarness(); + h.emit('subagent.spawned', { + subagentId: 'agent-7', + parentAgentId: 'main', + subagentName: 'coder', + runInBackground: !detachLater, + }); + h.emit('turn.started', {}, 'agent-7'); + h.emit( + 'subagent.spawned', + { + subagentId: 'agent-29', + parentAgentId: 'agent-7', + subagentName: 'coder', + runInBackground: false, + }, + 'agent-7', + ); + h.emit('turn.started', {}, 'agent-29'); + h.emit( + 'tool.call.started', + { toolCallId: 'pending-child', name: 'NotifyUser', args: { message: 'Child finding' } }, + 'agent-29', + ); + if (detachLater) + h.emit('background.task.started', { + info: { kind: 'agent', agentId: 'agent-7', status: 'running' }, + }); + h.emit('turn.ended', { reason: 'completed' }); + h.emit( + 'tool.result', + { toolCallId: 'pending-child', output: 'Update shown to the user.' }, + 'agent-29', + ); + h.send('later-child', 'More child findings', 'agent-29'); + expect(h.texts()).toEqual(['Child finding', 'More child findings']); + h.emit('turn.ended', { reason: 'completed' }, 'agent-29'); + h.send('late-event', 'Stale finding', 'agent-29'); + expect(h.texts()).toEqual(['Child finding', 'More child findings']); + }, + ); + + it('clears updates at each new main turn but not at child turn boundaries', () => { + const h = makeHarness(); + h.emit('turn.started'); + h.send('same', 'first turn'); + h.emit('turn.ended', { reason: 'completed' }); + for (const [i, kind] of ['user', 'cron_job', 'background_task'].entries()) { + h.emit('turn.started', { origin: { kind } }, 'main', i + 2); + expect(h.texts()).toEqual([]); + h.send('same', kind, 'main', i + 2); + h.emit('turn.started', {}, 'agent-1', i + 2); + expect(h.texts()).toEqual([kind]); + h.emit('turn.ended', { reason: 'completed' }, 'main', i + 2); + } + expect(h.texts()).toEqual(['background_task']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + }); + + it('isolates identical call ids by agent and labels channels by agent name', () => { + const h = makeHarness(); + h.emit('subagent.spawned', { + subagentId: 'agent-1', + subagentName: 'explore', + description: 'Authentication checks', + runInBackground: false, + }); + h.send('same', 'main findings'); + h.send('same', 'child findings', 'agent-1'); + expect(h.texts()).toEqual(['main findings', 'child findings']); + expect(h.notifyPanel.getEntries()[0]!.agentId).toBe('main'); + expect(h.notifyPanel.getEntries()[1]!.agentId).toBe('agent-1'); + expect(h.rendered()).toContain('explore'); + expect(h.rendered()).not.toContain('Authentication checks'); + h.emit('subagent.completed', { subagentId: 'agent-1' }); + expect(h.rendered()).toContain('explore'); + }); + + it('keeps background agents working after the main agent ends', () => { + const h = makeHarness(); + h.emit('turn.started'); + h.emit('subagent.spawned', { + subagentId: 'agent-1', + subagentName: 'coder', + description: 'Run tests', + runInBackground: true, + }); + h.emit('turn.started', {}, 'agent-1'); + h.send('n1', 'main done'); + h.emit('turn.ended', { reason: 'completed' }); + expect(h.rendered()).toContain('ctrl+n'); + h.controller.toggleFocus(); + expect(h.rendered()).toContain('main done'); + h.send('n2', 'background finding', 'agent-1'); + expect(h.texts()).toEqual(['main done', 'background finding']); + expect(h.rendered()).toContain('coder●'); + h.controller.handlePanelKey('right'); + expect(h.rendered()).toContain('background finding'); + h.emit('subagent.completed', { subagentId: 'agent-1' }); + expect(h.rendered()).toContain('background finding'); + }); + + it('keeps child turns active until their own end events, including detached tasks', () => { + const h = makeHarness(); + for (const subagentId of ['agent-7', 'agent-29']) { + h.emit('subagent.spawned', { subagentId, subagentName: 'coder', runInBackground: false }); + h.emit('turn.started', {}, subagentId); + h.emit( + 'tool.call.started', + { + toolCallId: 'pending', + name: 'NotifyUser', + args: { message: 'Working' }, + }, + subagentId, + ); + } + h.emit('background.task.started', { + info: { kind: 'agent', agentId: 'agent-29', status: 'running' }, + }); + h.emit('turn.ended', { reason: 'completed' }); + expect(h.texts()).toEqual([]); + h.emit('turn.ended', { reason: 'cancelled' }, 'agent-7'); + h.emit( + 'tool.result', + { toolCallId: 'pending', output: 'Update shown to the user.' }, + 'agent-7', + ); + expect(h.texts()).toEqual([]); + h.emit( + 'tool.result', + { toolCallId: 'pending', output: 'Update shown to the user.' }, + 'agent-29', + ); + expect(h.texts()).toEqual(['Working']); + expect(h.rendered()).toContain('coder'); + }); + + it('uses real agent ids regardless of creation order, updates or turn boundaries', () => { + const h = makeHarness(); + for (const subagentId of ['agent-7', 'agent-29', 'agent-105']) { + h.emit('subagent.spawned', { + subagentId, + subagentName: 'coder', + description: 'The same long task description for every worker', + runInBackground: true, + }); + } + h.send('b', 'Second worker reports first', 'agent-29'); + h.send('c', 'Third worker reports next', 'agent-105'); + h.send('a', 'First worker reports last', 'agent-7'); + expect(h.notifyPanel.getChannels().map((ch) => ch.label)).toEqual([ + 'coder', + 'coder(2)', + 'coder(3)', + ]); + h.emit('background.task.started', { + info: { kind: 'agent', agentId: 'agent-29', description: 'Changed task', status: 'running' }, + }); + h.emit('subagent.started', { subagentId: 'agent-29' }); + h.emit('turn.started', {}, 'main', 2); + h.send('again', 'Second worker continues', 'agent-29'); + expect(h.rendered()).toContain('coder'); + expect(h.rendered()).not.toContain('Changed task'); + h.controller.clear(); + h.send('c-again', 'Third worker continues', 'agent-105'); + expect(h.notifyPanel.getEntries()[0]!.agentId).toBe('agent-105'); + expect(h.rendered()).toContain('coder'); + h.controller.reset(); + h.send('new-session', 'A new session', 'agent-105'); + expect(h.notifyPanel.getEntries()[0]!.agentId).toBe('agent-105'); + expect(h.rendered()).toContain('agent-105'); + }); + + it('uses the same agent id before lifecycle metadata arrives and after toggling the feature', () => { + const h = makeHarness(); + h.send('first', 'Early update', 'agent-29'); + h.emit('subagent.spawned', { subagentId: 'agent-29', subagentName: 'coder' }); + h.send('second', 'Later update', 'agent-29'); + expect(h.rendered()).toContain('agent-29'); + h.controller.setEnabled(false); + h.emit('subagent.spawned', { subagentId: 'hidden', subagentName: 'coder' }); + h.controller.setEnabled(true); + h.send('third', 'After enabling', 'agent-29'); + expect(h.rendered()).toContain('agent-29'); + }); + + it.each([ + 'tool.result', + 'turn.step.interrupted', + 'turn.step.retrying', + 'turn.step.completed', + 'turn.ended', + 'subagent.failed', + ])('retracts only unfinished child updates on %s', (type) => { + const h = makeHarness(); + h.send('kept', 'delivered', 'agent-1'); + h.emit('turn.step.started', { step: 2 }, 'agent-1'); + h.emit( + 'tool.call.started', + { toolCallId: 'failed', name: 'NotifyUser', args: { message: 'unfinished' } }, + 'agent-1', + ); + h.emit( + type, + { + toolCallId: 'failed', + isError: true, + reason: 'failed', + step: 2, + finishReason: 'max_tokens', + subagentId: 'agent-1', + }, + 'agent-1', + ); + h.emit('tool.result', { toolCallId: 'failed', output: 'Update shown to the user.' }, 'agent-1'); + expect(h.texts()).toEqual(['delivered']); + }); + + it('ignores duplicate and late events for completed or withdrawn calls', () => { + const h = makeHarness(); + h.send('done', 'Confirmed update'); + h.emit('tool.call.delta', { + toolCallId: 'done', + name: 'NotifyUser', + argumentsPart: '{"message":"stale partial', + }); + expect(h.texts()).toEqual(['Confirmed update']); + h.emit('tool.call.delta', { + toolCallId: 'cut', + name: 'NotifyUser', + argumentsPart: '{"message":"unfinished', + }); + h.emit('turn.step.completed', { step: 0, finishReason: 'max_tokens' }); + h.emit('tool.call.started', { + toolCallId: 'cut', + name: 'NotifyUser', + args: { message: 'late start' }, + }); + expect(h.texts()).toEqual(['Confirmed update']); + }); + + it('retains independent agent status when the main turn ends', () => { + const h = makeHarness(); + h.emit('turn.started'); + h.emit('turn.started', {}, 'independent-1'); + h.send('note', 'Checking another question', 'independent-1'); + h.emit('turn.ended', { reason: 'completed' }); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + }); + + it('clears only entries on clear, and all session state on reset', () => { + const h = makeHarness(); + h.emit('subagent.spawned', { + subagentId: 'agent-1', + subagentName: 'coder', + description: 'Tests', + runInBackground: true, + }); + h.send('n1', 'earlier'); + h.controller.clear(); + h.send('n2', 'later', 'agent-1'); + expect(h.texts()).toEqual(['later']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + h.controller.reset(); + h.send('n3', 'another session'); + expect(h.texts()).toEqual(['another session']); + expect(h.rendered()).toContain('another session'); + }); + + it('disabling removes state and re-enabling does not replay buffered events', () => { + const h = makeHarness(); + h.send('n1', 'enabled'); + h.controller.setEnabled(false); + h.requestRender.mockClear(); + h.send('n2', 'disabled'); + h.controller.restore(snapshot()); + expect(h.notifyPanelContainer.children).toEqual([]); + expect(h.requestRender).not.toHaveBeenCalled(); + h.controller.setEnabled(true); + expect(h.texts()).toEqual([]); + h.send('n3', 'enabled again'); + expect(h.texts()).toEqual(['enabled again']); + }); + + it('starts with an empty panel when a session is restored', () => { + const h = makeHarness(); + h.send('old', 'previous session'); + h.controller.restore(snapshot()); + expect(h.texts()).toEqual([]); + expect(h.notifyPanelContainer.children).toEqual([]); + }); + + it('restores background metadata and status independently of agent enumeration order', () => { + const state = snapshot(); + Object.assign(state.agents['main']!, { + background: [ + { kind: 'agent', agentId: 'agent-1', description: 'Background tests', status: 'running' }, + ], + }); + const h = makeHarness(); + h.controller.restore(state); + expect(h.texts()).toEqual([]); + h.send('fresh', 'New background progress', 'agent-1'); + expect(h.rendered()).toContain('agent-1'); + h.emit('turn.ended', { reason: 'completed' }); + h.send('later', 'Still working', 'agent-1'); + expect(h.texts()).toEqual(['New background progress', 'Still working']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + }); + it('labels channels of subagents restored from a snapshot by subagent type', () => { + const state = snapshot(); + Object.assign(state.agents['main']!, { + background: [ + { + kind: 'agent', + agentId: 'agent-1', + subagentType: 'explore', + description: 'Search the codebase', + status: 'running', + }, + { + kind: 'agent', + agentId: 'agent-2', + subagentType: 'coder', + description: 'Finished task', + status: 'completed', + }, + ], + }); + const h = makeHarness(); + h.controller.restore(state); + h.send('fresh', 'Progress from a resumed subagent', 'agent-1'); + expect(h.notifyPanel.getChannels().map((ch) => ch.label)).toEqual(['explore']); + h.send('late', 'Settled before resume', 'agent-2'); + expect(h.notifyPanel.getChannels().map((ch) => ch.label)).toEqual(['explore', 'agent-2']); + }); + it.each([false, true])( + 'focuses and pages with the keyboard in regular/fullscreen mode without touching the editor: %s', + (fullscreen) => { + const h = makeHarness(true, fullscreen); + h.send('first', 'update one'); + h.send('second', 'update two'); + h.send('third', 'update three'); + h.ui.start(); + try { + h.ui.renderNow(); + const editorCursor = h.editor.getCursor(); + const root = h.ui instanceof TuiAltScreen ? h.ui.getLayoutRoot() : [...h.ui.children]; + expect(h.rendered()).toContain('Updates 3/3'); + h.input('\u000E'); + expect(h.rendered()).toContain('esc close'); + h.input('\u001B[A'); + expect(h.rendered()).toContain('Updates 2/3'); + h.input('\u001B[A'); + expect(h.rendered()).toContain('Updates 1/3'); + h.input('\u001B[B'); + expect(h.rendered()).toContain('Updates 2/3'); + h.rendered(); + h.emit('turn.ended', { reason: 'completed' }); + expect(h.rendered()).toContain('Updates 2/3'); + expect(h.rendered()).toContain('update two'); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + expect(h.ui.getFocusedComponent()).toBe(h.editor); + expect(h.editor.getText()).toBe('unsent draft'); + expect(h.editor.getCursor()).toEqual(editorCursor); + if (h.ui instanceof TuiAltScreen) expect(h.ui.getLayoutRoot()).toBe(root); + else expect(h.ui.children).toEqual(root); + h.input('\u001B'); + expect(h.rendered()).toContain('ctrl+n'); + expect(h.rendered()).toContain('update two'); + expect(h.rendered()).not.toContain('update three'); + h.emit('turn.started', {}, 'main', 2); + expect(h.texts()).toEqual([]); + expect(h.notifyPanelContainer.children).toEqual([]); + } finally { + h.ui.stop(); + } + }, + ); + + it('ignores delayed turn boundaries without erasing the new turn messages', () => { + const h = makeHarness(); + h.send('old', 'old turn'); + h.emit('turn.started', {}, 'main', 2); + h.send('new', 'new turn', 'main', 2); + h.emit('turn.started', {}, 'main', 1); + h.emit('turn.ended', { reason: 'completed' }, 'main', 1); + expect(h.texts()).toEqual(['new turn']); + h.emit('turn.ended', { reason: 'completed' }, 'main', 2); + expect(h.texts()).toEqual(['new turn']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + }); + + it('retains more than 100 calls and the complete body, including concurrent notifications', () => { + const h = makeHarness(); + for (let i = 0; i < 150; i++) + h.emit('tool.call.started', { + toolCallId: String(i), + name: 'NotifyUser', + args: { message: `update ${i}` }, + }); + expect(h.texts()).toHaveLength(0); + for (let i = 0; i < 150; i++) + h.emit('tool.result', { toolCallId: String(i), output: 'Update shown to the user.' }); + const long = 'complete body '.repeat(2000); + h.send('long', long); + expect(h.texts()).toHaveLength(151); + expect(h.texts()[0]).toBe('update 0'); + expect(h.texts().at(-1)).toBe(long); + h.emit('turn.ended', { reason: 'completed' }); + expect(h.texts()).toHaveLength(151); + h.emit('tool.call.delta', { + toolCallId: '0', + name: 'NotifyUser', + argumentsPart: '{"message":"late fragment', + }); + expect(h.texts()[0]).toBe('update 0'); + }); + + it('disabling clears retained messages and focus without touching input focus', () => { + const h = makeHarness(); + h.send('done', 'done update'); + h.controller.toggleFocus(); + h.emit('turn.ended', { reason: 'completed' }); + h.controller.setEnabled(false); + expect(h.ui.getFocusedComponent()).toBe(h.editor); + expect(h.texts()).toEqual([]); + expect(h.controller.toggleFocus()).toBe(false); + expect(h.controller.handlePanelKey('left')).toBe(false); + }); + + it('mirrors Agent and AgentSwarm delegations into the panel immediately', () => { + const h = makeHarness(); + h.emit('tool.call.started', { + toolCallId: 'a1', + name: 'Agent', + args: { description: '调研 example 项目', subagent_type: 'explore', prompt: '…' }, + }); + expect(h.texts()).toEqual(['▸ Delegated to explore: **调研 example 项目**']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + + h.emit('tool.call.started', { + toolCallId: 'a2', + name: 'AgentSwarm', + args: { items: [{ prompt: 'x' }, { prompt: 'y' }, { prompt: 'z' }] }, + }); + expect(h.texts()).toEqual([ + '▸ Delegated to explore: **调研 example 项目**', + '▸ Delegated to a swarm of 3 subagents', + ]); + }); + + it('counts resumed subagents in AgentSwarm delegation entries', () => { + const h = makeHarness(); + h.emit('tool.call.started', { + toolCallId: 'a1', + name: 'AgentSwarm', + args: { resume_agent_ids: { 'agent-1': 'continue the review', 'agent-2': 'keep going' } }, + }); + expect(h.texts()).toEqual(['▸ Delegated to a swarm of 2 subagents']); + + h.emit('tool.call.started', { + toolCallId: 'a2', + name: 'AgentSwarm', + args: { items: ['x', 'y'], resume_agent_ids: { 'agent-3': 'resume' } }, + }); + expect(h.texts()).toEqual([ + '▸ Delegated to a swarm of 2 subagents', + '▸ Delegated to a swarm of 3 subagents', + ]); + }); + + it('retracts delegation entries when the launch fails or is interrupted', () => { + const h = makeHarness(); + h.emit('tool.call.started', { + toolCallId: 'a1', + name: 'Agent', + args: { description: 'keep me', subagent_type: 'explore', prompt: '…' }, + }); + h.emit('tool.call.started', { + toolCallId: 'a2', + name: 'AgentSwarm', + args: { items: ['x', 'y'] }, + }); + h.emit('tool.call.started', { + toolCallId: 'a3', + name: 'Agent', + args: { description: 'interrupted', prompt: '…' }, + }); + expect(h.texts()).toHaveLength(3); + + h.emit('tool.result', { toolCallId: 'a2', isError: true, output: 'swarm validation failed' }); + expect(h.texts()).toEqual([ + '▸ Delegated to explore: **keep me**', + '▸ Delegated to subagent: **interrupted**', + ]); + + h.emit('tool.result', { toolCallId: 'a3', synthetic: true, output: '' }); + expect(h.texts()).toEqual(['▸ Delegated to explore: **keep me**']); + + h.emit('tool.result', { toolCallId: 'a1', output: 'subagent finished' }); + expect(h.texts()).toEqual(['▸ Delegated to explore: **keep me**']); + expect(h.notifyPanelContainer.children).toEqual([h.notifyPanel]); + }); + + it('releases panel focus when a retraction empties the panel', () => { + const h = makeHarness(); + h.emit('tool.call.started', { + toolCallId: 'a1', + name: 'Agent', + args: { description: 'doomed launch', prompt: '…' }, + }); + expect(h.controller.toggleFocus()).toBe(true); + + h.emit('tool.result', { toolCallId: 'a1', isError: true, output: 'unknown profile' }); + expect(h.notifyPanel.isEmpty()).toBe(true); + expect(h.notifyPanel.isFocused()).toBe(false); + expect(h.notifyPanelContainer.children).toEqual([]); + expect(h.controller.handlePanelKey('up')).toBe(false); + expect(h.controller.handlePanelKey('down')).toBe(false); + }); + + it('keeps the delegation entry when another agent errors with the same tool call id', () => { + const h = makeHarness(); + h.emit('tool.call.started', { + toolCallId: 'a1', + name: 'Agent', + args: { description: 'keep me', subagent_type: 'explore', prompt: '…' }, + }); + h.emit('subagent.spawned', { subagentId: 'agent-9', subagentName: 'coder' }); + + h.emit('tool.result', { toolCallId: 'a1', isError: true, output: 'subagent tool failed' }, 'agent-9'); + expect(h.texts()).toEqual(['▸ Delegated to explore: **keep me**']); + }); + + it('folds the panel to a one-line preview stub when the main turn ends', () => { + const h = makeHarness(); + h.send('n1', 'phase report intro\n\n- detail A'); + h.emit('turn.ended', { reason: 'completed' }); + expect(h.rendered()).toContain('ctrl+n'); + expect(h.rendered()).toContain('phase report intro'); + expect(h.rendered()).not.toContain('detail A'); + + h.controller.toggleFocus(); + expect(h.rendered()).toContain('detail A'); + h.controller.handlePanelKey('escape'); + expect(h.rendered()).toContain('ctrl+n'); + expect(h.rendered()).not.toContain('detail A'); + }); + + it('re-collapses the panel once the last background agent completes', () => { + const h = makeHarness(); + h.emit('subagent.spawned', { subagentId: 'agent-1', subagentName: 'explore' }); + h.emit('turn.ended', { reason: 'completed' }); + + h.send('s1', 'bg intro\n\n- bg detail', 'agent-1'); + expect(h.rendered()).toContain('bg detail'); + + h.emit('subagent.completed', { subagentId: 'agent-1' }); + expect(h.rendered()).toContain('ctrl+n'); + expect(h.rendered()).toContain('bg intro'); + expect(h.rendered()).not.toContain('bg detail'); + }); + + it('keeps the panel expanded while a background agent is still running', () => { + const h = makeHarness(); + h.emit('subagent.spawned', { subagentId: 'agent-1', subagentName: 'explore' }); + h.emit('subagent.spawned', { subagentId: 'agent-2', subagentName: 'coder' }); + h.emit('turn.ended', { reason: 'completed' }); + + h.send('s1', 'bg intro\n\n- bg detail', 'agent-1'); + h.emit('subagent.completed', { subagentId: 'agent-1' }); + expect(h.rendered()).toContain('bg detail'); + + h.emit('subagent.completed', { subagentId: 'agent-2' }); + expect(h.rendered()).not.toContain('bg detail'); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/plugin-update-notifier.test.ts b/apps/kimi-code/test/tui/controllers/plugin-update-notifier.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7bc0c5f6656b799bf2193aa7089fcbcb7d197c0 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/plugin-update-notifier.test.ts @@ -0,0 +1,301 @@ +import { mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import type { PluginSummary } from '@moonshot-ai/kimi-code-sdk'; + +import { kimiCodePluginMarketplaceUrl } from '#/constant/app'; +import { + PluginUpdateNotifier, + type PluginUpdateNotifierSession, +} from '#/tui/controllers/plugin-update-notifier'; +import type { PluginMarketplace } from '#/utils/plugin-marketplace'; +import { readPluginUpdateNoticeState } from '#/utils/plugin-update-notice-state'; + +function makePluginSummary(overrides: Partial = {}): PluginSummary { + return { + id: 'kimi-datasource', + displayName: 'Kimi Datasource', + version: '3.3.0', + enabled: true, + state: 'ok', + skillCount: 0, + mcpServerCount: 1, + enabledMcpServerCount: 1, + hookCount: 0, + commandCount: 0, + hasErrors: false, + source: 'zip-url', + originalSource: 'https://code.kimi.com/kimi-code/plugins/official/kimi-datasource.zip', + ...overrides, + }; +} + +function makeMarketplaceEntry( + id: string, + displayName: string, + version: string, +): PluginMarketplace['plugins'][number] { + return { + id, + displayName, + source: `https://code.kimi.com/kimi-code/plugins/official/${id}.zip`, + tier: 'official', + version, + }; +} + +function makeMarketplace(version = '3.4.0'): PluginMarketplace { + return { + source: kimiCodePluginMarketplaceUrl(), + plugins: [makeMarketplaceEntry('kimi-datasource', 'Kimi Datasource', version)], + }; +} + +interface HarnessOptions { + readonly marketplace?: PluginMarketplace; + readonly installed?: readonly PluginSummary[]; + readonly mcpServers?: readonly string[]; + readonly loadMarketplace?: () => Promise; +} + +function makeHarness(options: HarnessOptions = {}) { + const session: PluginUpdateNotifierSession = { + listMcpServers: vi.fn(async () => + (options.mcpServers ?? ['plugin-kimi-datasource:data']).map((name) => ({ name })), + ), + listPlugins: vi.fn(async () => options.installed ?? [makePluginSummary()]), + }; + const notify = vi.fn(); + const loadMarketplace = vi.fn( + options.loadMarketplace ?? (async () => options.marketplace ?? makeMarketplace()), + ); + return { session, notify, loadMarketplace }; +} + +const DATASOURCE_TOOL = 'mcp__plugin-kimi-datasource_data__call_data_source_tool'; +const EXPECTED_MESSAGE = + 'Update detected: Kimi Datasource 3.4.0 is available. ' + + 'Run /plugins to install the latest version from the Official Marketplace.'; + +describe('PluginUpdateNotifier', () => { + let tempDir: string; + let stateFile: string; + + beforeEach(async () => { + tempDir = await mkdtemp(join(tmpdir(), 'plugin-update-notifier-')); + stateFile = join(tempDir, 'plugin-notices.json'); + }); + + afterEach(async () => { + await rm(tempDir, { recursive: true, force: true }); + }); + + function makeNotifier(harness: ReturnType) { + return new PluginUpdateNotifier({ + getSession: () => harness.session, + workDir: tempDir, + notify: harness.notify, + loadMarketplace: harness.loadMarketplace, + stateFile, + }); + } + + it('notifies once after a plugin MCP tool completes, then stays silent for that version', async () => { + const harness = makeHarness(); + const notifier = makeNotifier(harness); + + await notifier.handleMcpToolCompleted(DATASOURCE_TOOL); + expect(harness.notify).toHaveBeenCalledWith(EXPECTED_MESSAGE); + + harness.notify.mockClear(); + // Follow-up checks run but hit the persisted "already notified" record + // instead of notifying again. + await notifier.handleMcpToolCompleted(DATASOURCE_TOOL); + expect(harness.notify).not.toHaveBeenCalled(); + await notifier.handlePluginCommandCompleted('kimi-datasource'); + expect(harness.notify).not.toHaveBeenCalled(); + }); + + it('ignores non-plugin tool names without touching the session', async () => { + const harness = makeHarness(); + const notifier = makeNotifier(harness); + + await notifier.handleMcpToolCompleted('Bash'); + await notifier.handleMcpToolCompleted('mcp__github__create_issue'); + + expect(harness.session.listMcpServers).not.toHaveBeenCalled(); + expect(harness.notify).not.toHaveBeenCalled(); + }); + + it('does not notify when the installed version is up to date', async () => { + const harness = makeHarness({ installed: [makePluginSummary({ version: '3.4.0' })] }); + const notifier = makeNotifier(harness); + + await notifier.handleMcpToolCompleted(DATASOURCE_TOOL); + expect(harness.session.listPlugins).toHaveBeenCalled(); + expect(harness.notify).not.toHaveBeenCalled(); + }); + + it('does not notify for plugins absent from the marketplace', async () => { + const harness = makeHarness({ installed: [makePluginSummary({ id: 'local-only' })] }); + const notifier = makeNotifier(harness); + + await notifier.handlePluginCommandCompleted('local-only'); + // No marketplace entry — the check bails before even listing plugins. + expect(harness.session.listPlugins).not.toHaveBeenCalled(); + expect(harness.notify).not.toHaveBeenCalled(); + }); + + it('does not notify when the catalog is not the official marketplace', async () => { + const harness = makeHarness({ + marketplace: { + source: 'https://example.test/custom-marketplace.json', + plugins: [makeMarketplaceEntry('kimi-datasource', 'Kimi Datasource', '3.4.0')], + }, + }); + const notifier = makeNotifier(harness); + + await notifier.handlePluginCommandCompleted('kimi-datasource'); + // A custom catalog may advertise anything under any id — the check bails + // before comparing versions. + expect(harness.session.listPlugins).not.toHaveBeenCalled(); + expect(harness.notify).not.toHaveBeenCalled(); + }); + + it('does not notify for a same-id fork installed from a local path', async () => { + const harness = makeHarness({ + installed: [ + makePluginSummary({ source: 'local-path', originalSource: undefined }), + ], + }); + const notifier = makeNotifier(harness); + + await notifier.handlePluginCommandCompleted('kimi-datasource'); + // Provenance is not official, so the marketplace version is irrelevant. + expect(harness.notify).not.toHaveBeenCalled(); + }); + + it('resolves plugin tools whose qualified name core truncated before the separator', async () => { + // Server part exactly 50 chars: the 64-char truncation cuts the whole + // `__` separator and tool name, leaving `mcp___`. + const serverName = `plugin-kimi-datasource:${'s'.repeat(27)}`; + const sanitized = `plugin-kimi-datasource_${'s'.repeat(27)}`; + expect(`mcp__${sanitized}`.length).toBe(55); + const truncatedToolName = `mcp__${sanitized}_a1b2c3d4`; + + const harness = makeHarness({ mcpServers: [serverName] }); + const notifier = makeNotifier(harness); + + await notifier.handleMcpToolCompleted(truncatedToolName); + expect(harness.notify).toHaveBeenCalledWith(EXPECTED_MESSAGE); + }); + + it('notifies after a plugin command turn ends', async () => { + const harness = makeHarness(); + const notifier = makeNotifier(harness); + + await notifier.handlePluginCommandCompleted('kimi-datasource'); + expect(harness.notify).toHaveBeenCalledWith(EXPECTED_MESSAGE); + // Plugin commands resolve the plugin id directly — no MCP server lookup. + expect(harness.session.listMcpServers).not.toHaveBeenCalled(); + }); + + it('reminds again when the marketplace advertises a newer version', async () => { + const first = makeHarness({ marketplace: makeMarketplace('3.4.0') }); + const notifier = makeNotifier(first); + + await notifier.handlePluginCommandCompleted('kimi-datasource'); + expect(first.notify).toHaveBeenCalledTimes(1); + + // A new notifier (fresh app run) against the same state file stays silent + // for the already-notified version… + const second = makeHarness({ marketplace: makeMarketplace('3.4.0') }); + const secondNotifier = makeNotifier(second); + await secondNotifier.handlePluginCommandCompleted('kimi-datasource'); + expect(second.notify).not.toHaveBeenCalled(); + + // …but reminds once the marketplace moves to a newer version. + const third = makeHarness({ marketplace: makeMarketplace('3.5.0') }); + const thirdNotifier = makeNotifier(third); + await thirdNotifier.handlePluginCommandCompleted('kimi-datasource'); + expect(third.notify).toHaveBeenCalledWith( + 'Update detected: Kimi Datasource 3.5.0 is available. ' + + 'Run /plugins to install the latest version from the Official Marketplace.', + ); + }); + + it('swallows marketplace failures and retries on the next invocation', async () => { + let attempts = 0; + const harness = makeHarness({ + loadMarketplace: async () => { + attempts += 1; + if (attempts === 1) throw new Error('offline'); + return makeMarketplace(); + }, + }); + const notifier = makeNotifier(harness); + + await notifier.handlePluginCommandCompleted('kimi-datasource'); + expect(harness.loadMarketplace).toHaveBeenCalledTimes(1); + expect(harness.notify).not.toHaveBeenCalled(); + + await notifier.handlePluginCommandCompleted('kimi-datasource'); + expect(harness.notify).toHaveBeenCalledWith(EXPECTED_MESSAGE); + }); + + it('refreshes the memoized MCP server map when a lookup misses', async () => { + const harness = makeHarness({ mcpServers: [] }); + let servers: readonly string[] = []; + harness.session.listMcpServers = vi.fn(async () => servers.map((name) => ({ name }))); + const notifier = makeNotifier(harness); + + // The plugin's MCP server is not registered yet (the plugin gets + // installed later in the same app run, applied on /reload or /new). + await notifier.handleMcpToolCompleted(DATASOURCE_TOOL); + expect(harness.session.listMcpServers).toHaveBeenCalled(); + expect(harness.notify).not.toHaveBeenCalled(); + + // After the reload the new server shows up; the next completion must + // refresh the memoized map instead of silently staying unresolved. + servers = ['plugin-kimi-datasource:data']; + await notifier.handleMcpToolCompleted(DATASOURCE_TOOL); + expect(harness.notify).toHaveBeenCalledWith(EXPECTED_MESSAGE); + }); + + it('keeps every notified plugin when a turn uses two outdated plugins', async () => { + const harness = makeHarness({ + marketplace: { + source: kimiCodePluginMarketplaceUrl(), + plugins: [ + makeMarketplaceEntry('kimi-datasource', 'Kimi Datasource', '3.4.0'), + makeMarketplaceEntry('another-plugin', 'Another Plugin', '2.0.0'), + ], + }, + installed: [ + makePluginSummary(), + makePluginSummary({ + id: 'another-plugin', + displayName: 'Another Plugin', + version: '1.0.0', + }), + ], + }); + const notifier = makeNotifier(harness); + + await Promise.all([ + notifier.handlePluginCommandCompleted('kimi-datasource'), + notifier.handlePluginCommandCompleted('another-plugin'), + ]); + + expect(harness.notify).toHaveBeenCalledTimes(2); + // Both entries must survive in the persisted state — no lost update. + const state = await readPluginUpdateNoticeState(stateFile); + expect(state.notified).toEqual({ + 'kimi-datasource': '3.4.0', + 'another-plugin': '2.0.0', + }); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-background-task.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-background-task.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ed5e1752822402d60c5b6bd05d4067a33f46c7e --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-background-task.test.ts @@ -0,0 +1,293 @@ +import type { Event } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { + SubAgentEventHandler, + type SubagentLifecycleEvent, +} from '#/tui/controllers/subagent-event-handler'; +import { getBuiltInPalette } from '#/tui/theme'; + +function makeStreamingUIStub() { + return { + getToolComponent: vi.fn(() => undefined), + getActiveToolCall: vi.fn(() => undefined), + onToolCallStart: vi.fn(), + getTurnContext: vi.fn(() => ({ turnId: 1, step: 0 })), + removeToolComponentIfInactive: vi.fn(), + applyBackgroundTaskTerminalStatus: vi.fn(), + markSubagentBackgrounded: vi.fn(), + setTurnId: vi.fn(), + flushNow: vi.fn(), + setTodoList: vi.fn(), + resetToolUi: vi.fn(), + clearNotifyPanel: vi.fn(), + markNotifyPanelEnded: vi.fn(), + finalizeTurn: vi.fn(), + }; +} + +function makeSubagentHandler() { + const backgroundTasks = new Map(); + const transcriptedTerminal = new Set(); + const host = { + state: { + appState: { availableModels: {} }, + ui: { requestRender: vi.fn() }, + transcriptContainer: { addChild: vi.fn() }, + }, + streamingUI: makeStreamingUIStub(), + appendTranscriptEntry: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + updateActivityPane: vi.fn(), + }; + const handler = new SubAgentEventHandler(host as never, { + backgroundTasks, + backgroundTaskTranscriptedTerminal: transcriptedTerminal, + syncBackgroundAgentBadge: vi.fn(), + }); + return { handler, backgroundTasks, host, transcriptedTerminal }; +} + +function spawnEvent(subagentId: string, runInBackground: boolean): SubagentLifecycleEvent { + return { + sessionId: 's1', + agentId: 'main', + type: 'subagent.spawned', + subagentId, + subagentName: 'explore', + parentToolCallId: `tc-${subagentId}`, + description: `task ${subagentId}`, + runInBackground, + } as unknown as SubagentLifecycleEvent; +} + +function completedEvent(subagentId: string): SubagentLifecycleEvent { + return { + sessionId: 's1', + agentId: 'main', + type: 'subagent.completed', + subagentId, + parentToolCallId: `tc-${subagentId}`, + resultSummary: 'done', + } as unknown as SubagentLifecycleEvent; +} + +function cancelledEvent(subagentId: string): SubagentLifecycleEvent { + return { + sessionId: 's1', + agentId: 'main', + type: 'subagent.cancelled', + subagentId, + parentToolCallId: `tc-${subagentId}`, + } as unknown as SubagentLifecycleEvent; +} + +describe('SubAgentEventHandler — background agent cancelled transcript', () => { + function agentTask(subagentId: string) { + return { + taskId: `task-${subagentId}`, + kind: 'agent', + agentId: subagentId, + description: `task ${subagentId}`, + status: 'running', + startedAt: 0, + } as never; + } + + it('appends a stopped transcript entry when a background agent is cancelled', () => { + const { handler, backgroundTasks, host, transcriptedTerminal } = makeSubagentHandler(); + backgroundTasks.set('task-a1', agentTask('a1')); + handler.handleLifecycleEvent(spawnEvent('a1', true)); + (host.appendTranscriptEntry as ReturnType).mockClear(); + + handler.handleLifecycleEvent(cancelledEvent('a1')); + + const appended = (host.appendTranscriptEntry as ReturnType).mock.calls.map( + ([entry]) => entry as { content: string }, + ); + expect(appended).toHaveLength(1); + expect(appended[0]!.content).toContain('stopped'); + expect(transcriptedTerminal.has('task-a1')).toBe(true); + expect(handler.backgroundAgentMetadata.has('a1')).toBe(false); + expect(host.streamingUI.applyBackgroundTaskTerminalStatus).toHaveBeenCalledWith({ + agentId: 'a1', + description: 'task a1', + status: 'killed', + }); + }); + + it('does not append a second entry when the task was already transcripted', () => { + const { handler, backgroundTasks, host, transcriptedTerminal } = makeSubagentHandler(); + backgroundTasks.set('task-a1', agentTask('a1')); + transcriptedTerminal.add('task-a1'); + handler.handleLifecycleEvent(spawnEvent('a1', true)); + (host.appendTranscriptEntry as ReturnType).mockClear(); + + handler.handleLifecycleEvent(cancelledEvent('a1')); + + expect(host.appendTranscriptEntry).not.toHaveBeenCalled(); + expect(handler.backgroundAgentMetadata.has('a1')).toBe(false); + }); + + it('delivers a terminal status to a non-swarm foreground tool card when a subagent is cancelled', () => { + const { handler, host } = makeSubagentHandler(); + const tc = { onSubagentSpawned: vi.fn(), onSubagentFailed: vi.fn() }; + (host.streamingUI.getToolComponent as ReturnType).mockReturnValue(tc); + handler.handleLifecycleEvent(spawnEvent('a1', false)); + + handler.handleLifecycleEvent(cancelledEvent('a1')); + + expect(tc.onSubagentFailed).toHaveBeenCalledWith({ error: 'Aborted by the user' }); + expect(host.streamingUI.removeToolComponentIfInactive).toHaveBeenCalledWith('tc-a1'); + }); +}); + +describe('SubAgentEventHandler — activity record pruning', () => { + it('drops the record of a foreground-only subagent at terminal state', () => { + const { handler } = makeSubagentHandler(); + handler.handleLifecycleEvent(spawnEvent('a1', false)); + handler.activityStore.applyEvent({ + sessionId: 's1', + agentId: 'a1', + type: 'turn.step.started', + turnId: 1, + step: 0, + } as Event); + expect(handler.activityStore.get('a1')).toBeDefined(); + + handler.handleLifecycleEvent(completedEvent('a1')); + + expect(handler.activityStore.get('a1')).toBeUndefined(); + }); + + it('keeps the record of a spawn-time background agent even before the task syncs', () => { + const { handler } = makeSubagentHandler(); + handler.handleLifecycleEvent(spawnEvent('a2', true)); + handler.activityStore.applyEvent({ + sessionId: 's1', + agentId: 'a2', + type: 'turn.step.started', + turnId: 1, + step: 0, + } as Event); + + // No background.task.started has populated the task map yet. + handler.handleLifecycleEvent(completedEvent('a2')); + + const record = handler.activityStore.get('a2'); + expect(record?.status).toBe('completed'); + expect(record?.resultSummary).toBe('done'); + }); +}); + +function makeSessionEventHost() { + const host = { + state: { + appState: { + sessionId: 's1', + workDir: '/tmp/wd', + streamingPhase: 'idle', + availableModels: {}, + }, + queuedMessages: [], + queuedMessageDispatchPending: false, + theme: { palette: getBuiltInPalette('dark') }, + toolOutputExpanded: false, + todoPanel: { getTodos: vi.fn(() => []) }, + transcriptContainer: { addChild: vi.fn() }, + tasksBrowser: undefined, + footer: { setBackgroundCounts: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: { id: 's1' }, + aborted: false, + sessionEventUnsubscribe: undefined, + streamingUI: makeStreamingUIStub(), + requireSession: vi.fn(), + setAppState: vi.fn(), + patchLivePane: vi.fn(), + resetLivePane: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + recordSessionActivity: vi.fn(), + noteStepUsage: vi.fn(), + noteCompactionFinished: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + appendTranscriptEntry: vi.fn(), + sendNormalUserInput: vi.fn(), + sendQueuedMessage: vi.fn(), + shiftQueuedMessage: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + tasksBrowserController: { repaint: vi.fn(), refreshOutputViewer: vi.fn() }, + }; + return host as never; +} + +describe('SessionEventHandler — background.task.terminated', () => { + function terminatedEvent(agentId: string, status: string): Event { + return { + sessionId: 's1', + agentId: 'main', + type: 'background.task.terminated', + info: { + taskId: `task-${agentId}`, + kind: 'agent', + agentId, + description: 'bg task', + status, + startedAt: 0, + endedAt: 1, + }, + } as unknown as Event; + } + + it('marks a still-running record failed when an agent is stopped without subagent.failed', () => { + const handler = new SessionEventHandler(makeSessionEventHost()); + handler.subAgentEventHandler.activityStore.ensureRecord({ + agentId: 'agent-9', + agentName: 'explore', + parentToolCallId: 'tc-9', + }); + + handler.handleEvent(terminatedEvent('agent-9', 'killed'), vi.fn()); + + expect(handler.subAgentEventHandler.activityStore.get('agent-9')?.status).toBe('failed'); + }); + + it('does not overwrite a record that already reached terminal state with a summary', () => { + const handler = new SessionEventHandler(makeSessionEventHost()); + const store = handler.subAgentEventHandler.activityStore; + store.ensureRecord({ agentId: 'agent-8', agentName: 'explore', parentToolCallId: 'tc-8' }); + store.markCompleted('agent-8', 'final summary'); + + handler.handleEvent(terminatedEvent('agent-8', 'completed'), vi.fn()); + + const record = store.get('agent-8'); + expect(record?.status).toBe('completed'); + expect(record?.resultSummary).toBe('final summary'); + }); + + it('drops foreground-only records when the main turn ends (aborted subagents emit no lifecycle event)', () => { + const handler = new SessionEventHandler(makeSessionEventHost()); + const store = handler.subAgentEventHandler.activityStore; + store.ensureRecord({ agentId: 'agent-7', agentName: 'explore', parentToolCallId: 'tc-7' }); + + handler.handleEvent( + { + sessionId: 's1', + agentId: 'main', + type: 'turn.ended', + turnId: 1, + reason: 'cancelled', + } as Event, + vi.fn(), + ); + + expect(store.get('agent-7')).toBeUndefined(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-compaction.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-compaction.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..75f3146c10571076065fe582f46f2af6908df320 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-compaction.test.ts @@ -0,0 +1,99 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { getBuiltInPalette } from '#/tui/theme'; + +function makeHost() { + const host = { + state: { + appState: { + sessionId: 's1', + streamingPhase: 'waiting', + isCompacting: true, + model: 'kimi-model', + permissionMode: 'auto', + }, + queuedMessages: [], + queuedMessageDispatchPending: false, + theme: { palette: getBuiltInPalette('dark') }, + toolOutputExpanded: false, + todoPanel: { getTodos: vi.fn(() => []) }, + transcriptContainer: { addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: { id: 's1' }, + aborted: false, + sessionEventUnsubscribe: undefined, + streamingUI: { + setTurnId: vi.fn(), + flushNow: vi.fn(), + resetToolUi: vi.fn(), + clearNotifyPanel: vi.fn(), + markNotifyPanelEnded: vi.fn(), + finalizeTurn: vi.fn(), + hasActiveTurn: vi.fn(() => false), + hasThinkingDraft: vi.fn(() => false), + flushThinkingToTranscript: vi.fn(), + appendAssistantDelta: vi.fn(), + scheduleFlush: vi.fn(), + beginCompaction: vi.fn(), + endCompaction: vi.fn(), + cancelCompaction: vi.fn(), + }, + requireSession: vi.fn(), + setAppState: vi.fn((patch: Record) => + Object.assign(host.state.appState, patch), + ), + patchLivePane: vi.fn(), + resetLivePane: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + recordSessionActivity: vi.fn(), + noteStepUsage: vi.fn(), + noteCompactionFinished: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + appendTranscriptEntry: vi.fn(), + sendNormalUserInput: vi.fn(), + sendQueuedMessage: vi.fn(), + shiftQueuedMessage: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + surveyController: { notifyCompactionFinished: vi.fn() }, + tasksBrowserController: {}, + }; + return { host: host as any }; +} + +const compactionCompleted = { + type: 'compaction.completed', + sessionId: 's1', + agentId: 'main', + result: { summary: 'summary', tokensBefore: 100, tokensAfter: 10, compactedCount: 1 }, +} as const; + +const compactionCancelled = { + type: 'compaction.cancelled', + sessionId: 's1', + agentId: 'main', +} as const; + +describe('SessionEventHandler compaction cache bookkeeping', () => { + it('records activity and resets the cache-break baseline after a completed compaction', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(compactionCompleted, vi.fn()); + expect(host.recordSessionActivity).toHaveBeenCalledOnce(); + expect(host.noteCompactionFinished).toHaveBeenCalledOnce(); + }); + + it('keeps both baselines after a cancelled compaction (context was not cut)', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(compactionCancelled, vi.fn()); + expect(host.noteCompactionFinished).not.toHaveBeenCalled(); + expect(host.recordSessionActivity).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-goal-queue.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-goal-queue.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ab9cfd541f4c54cde680837bbf94e8c4235a5ca --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-goal-queue.test.ts @@ -0,0 +1,544 @@ +import { describe, expect, it, beforeEach, vi } from 'vitest'; + +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { getBuiltInPalette } from '#/tui/theme'; +import { readGoalQueue, removeGoalQueueItem, restoreGoalQueueItem } from '#/tui/goal-queue-store'; + +vi.mock('#/tui/goal-queue-store', () => ({ + readGoalQueue: vi.fn(async () => ({ + goals: [{ id: 'q1', objective: 'Ship queued goal', createdAt: '', updatedAt: '' }], + })), + removeGoalQueueItem: vi.fn(async () => ({ goals: [] })), + restoreGoalQueueItem: vi.fn(async () => ({ + goals: [{ id: 'q1', objective: 'Ship queued goal', createdAt: '', updatedAt: '' }], + })), +})); + +function fakeGoalSnapshot(objective: string, status: 'active' | 'blocked' | 'paused' | 'complete') { + return { + goalId: 'g1', + objective, + status, + turnsUsed: 1, + tokensUsed: 10, + wallClockMs: 100, + budget: { + tokenBudget: null, + turnBudget: 20, + wallClockBudgetMs: null, + remainingTokens: null, + remainingTurns: 19, + remainingWallClockMs: null, + tokenBudgetReached: false, + turnBudgetReached: false, + wallClockBudgetReached: false, + overBudget: false, + }, + }; +} + +function makeHost(options: { createGoalRejects?: boolean } = {}) { + const session = { + createGoal: vi.fn(async () => { + if (options.createGoalRejects === true) throw new Error('create failed'); + return fakeGoalSnapshot('Ship queued goal', 'active'); + }), + cancelGoal: vi.fn(async () => fakeGoalSnapshot('Ship queued goal', 'active')), + }; + const host = { + state: { + appState: { + sessionId: 's1', + streamingPhase: 'waiting', + model: 'kimi-model', + permissionMode: 'auto', + }, + queuedMessages: [], + queuedMessageDispatchPending: false, + theme: { palette: getBuiltInPalette('dark') }, + toolOutputExpanded: false, + todoPanel: { getTodos: vi.fn(() => []) }, + transcriptContainer: { addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session, + aborted: false, + sessionEventUnsubscribe: undefined, + streamingUI: { + setTurnId: vi.fn(), + flushNow: vi.fn(), + resetToolUi: vi.fn(), + clearNotifyPanel: vi.fn(), + markNotifyPanelEnded: vi.fn(), + finalizeTurn: vi.fn(), + hasActiveTurn: vi.fn(() => false), + hasThinkingDraft: vi.fn(() => false), + flushThinkingToTranscript: vi.fn(), + appendAssistantDelta: vi.fn(), + scheduleFlush: vi.fn(), + beginCompaction: vi.fn(), + endCompaction: vi.fn(), + cancelCompaction: vi.fn(), + }, + requireSession: vi.fn(() => session), + setAppState: vi.fn(), + patchLivePane: vi.fn(), + resetLivePane: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + recordSessionActivity: vi.fn(), + noteStepUsage: vi.fn(), + noteCompactionFinished: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + appendTranscriptEntry: vi.fn(), + sendNormalUserInput: vi.fn(), + sendQueuedMessage: vi.fn(), + shiftQueuedMessage: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + surveyController: { notifyCompactionFinished: vi.fn() }, + tasksBrowserController: {}, + }; + host.setAppState.mockImplementation((patch: Record) => { + Object.assign(host.state.appState, patch); + }); + host.streamingUI.finalizeTurn.mockImplementation(() => { + host.setAppState({ streamingPhase: 'idle' }); + }); + return { host: host as any, session }; +} + +function sendQueuedViaHost(host: ReturnType['host'], session: unknown) { + return (item: unknown) => { + host.sendQueuedMessage(session as never, item as never); + }; +} + +function completionEvent() { + return { + type: 'goal.updated', + sessionId: 's1', + agentId: 'main', + snapshot: fakeGoalSnapshot('Current goal', 'complete'), + change: { + kind: 'completion', + status: 'complete', + stats: { turnsUsed: 1, tokensUsed: 10, wallClockMs: 100 }, + }, + } as const; +} + +function clearedEvent() { + return { + type: 'goal.updated', + sessionId: 's1', + agentId: 'main', + snapshot: null, + } as const; +} + +function turnEndedEvent() { + return { + type: 'turn.ended', + sessionId: 's1', + agentId: 'main', + turnId: 1, + reason: 'completed', + } as const; +} + +function compactionCompletedEvent() { + return { + type: 'compaction.completed', + sessionId: 's1', + agentId: 'main', + result: { + summary: 'summary', + tokensBefore: 100, + tokensAfter: 10, + compactedCount: 1, + }, + } as const; +} + +function modelBlockedEvent() { + return { + type: 'goal.updated', + sessionId: 's1', + agentId: 'main', + snapshot: fakeGoalSnapshot('Blocked goal', 'blocked'), + change: { kind: 'lifecycle', status: 'blocked' }, + } as const; +} + +function addedTranscriptText(host: ReturnType['host']): string { + const component = host.state.transcriptContainer.addChild.mock.calls.at(-1)?.[0]; + return component.render(80).join('\n').replaceAll(/\[[0-9;]*m/g, ''); +} + +describe('SessionEventHandler goal queue promotion', () => { + beforeEach(() => { + vi.mocked(readGoalQueue).mockClear(); + vi.mocked(removeGoalQueueItem).mockClear(); + vi.mocked(restoreGoalQueueItem).mockClear(); + }); + + it('starts the next queued goal after the completion turn ends', async () => { + const { host, session } = makeHost(); + const handler = new SessionEventHandler(host); + + handler.handleEvent(completionEvent(), vi.fn()); + expect(session.createGoal).not.toHaveBeenCalled(); + handler.handleEvent(clearedEvent(), vi.fn()); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + + handler.handleEvent(turnEndedEvent(), sendQueuedViaHost(host, session)); + + await vi.waitFor(() => { + expect(session.createGoal).toHaveBeenCalledWith({ + objective: 'Ship queued goal', + replace: false, + }); + }); + expect(removeGoalQueueItem).toHaveBeenCalledWith(session, { goalId: 'q1' }); + expect(host.sendQueuedMessage).toHaveBeenCalledWith(session, { + text: 'Ship queued goal', + }); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + }); + + it('waits for queued user input to drain before promoting the next queued goal', async () => { + const { host, session } = makeHost(); + host.state.queuedMessages = [{ text: 'queued user turn' }]; + host.setAppState.mockImplementation((patch: Record) => { + Object.assign(host.state.appState, patch); + }); + host.shiftQueuedMessage.mockImplementation(() => host.state.queuedMessages.shift()); + host.streamingUI.finalizeTurn.mockImplementation((sendQueued: (item: unknown) => void) => { + const next = host.shiftQueuedMessage(); + if (next !== undefined) { + host.setAppState({ streamingPhase: 'idle' }); + setTimeout(() => { + sendQueued(next); + }, 0); + return; + } + host.setAppState({ streamingPhase: 'idle' }); + }); + host.sendQueuedMessage.mockImplementation((_session: unknown, item: { text: string }) => { + if (item.text === 'queued user turn') { + host.setAppState({ streamingPhase: 'waiting' }); + } + }); + const handler = new SessionEventHandler(host); + const sendQueued = sendQueuedViaHost(host, session); + + handler.handleEvent(completionEvent(), sendQueued); + handler.handleEvent(clearedEvent(), sendQueued); + handler.handleEvent(turnEndedEvent(), sendQueued); + + await vi.waitFor(() => { + expect(host.sendQueuedMessage).toHaveBeenCalledWith(session, { text: 'queued user turn' }); + }); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(session.createGoal).not.toHaveBeenCalled(); + + handler.handleEvent(turnEndedEvent(), sendQueued); + + await vi.waitFor(() => { + expect(session.createGoal).toHaveBeenCalledWith({ + objective: 'Ship queued goal', + replace: false, + }); + }); + expect(host.sendQueuedMessage).toHaveBeenLastCalledWith(session, { text: 'Ship queued goal' }); + }); + + it('defers queued-goal promotion while a queued message is mid-dispatch', async () => { + const { host, session } = makeHost(); + host.state.appState.streamingPhase = 'idle'; + host.state.queuedMessages = []; + // The queue looks empty and the phase is idle, but a shifted queued message + // is still awaiting its deferred send. Promotion must not jump ahead of it. + host.state.queuedMessageDispatchPending = true; + const handler = new SessionEventHandler(host); + + handler.requestQueuedGoalPromotion(); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(session.createGoal).not.toHaveBeenCalled(); + + // Once the queued message has been dispatched, the flag clears and the + // promotion proceeds on the next retry. + host.state.queuedMessageDispatchPending = false; + handler.retryQueuedGoalPromotion(); + await vi.waitFor(() => { + expect(session.createGoal).toHaveBeenCalledWith({ + objective: 'Ship queued goal', + replace: false, + }); + }); + }); + + it('waits for a queued user input drained after compaction before promoting the next queued goal', async () => { + const { host, session } = makeHost(); + host.state.appState.isCompacting = true; + host.state.queuedMessages = [{ text: 'queued user turn' }]; + host.shiftQueuedMessage.mockImplementation(() => host.state.queuedMessages.shift()); + const handler = new SessionEventHandler(host); + host.setAppState.mockImplementation((patch: Record) => { + const busyChanged = 'streamingPhase' in patch || 'isCompacting' in patch; + Object.assign(host.state.appState, patch); + if (busyChanged) handler.retryQueuedGoalPromotion(); + }); + host.sendQueuedMessage.mockImplementation((_session: unknown, item: { text: string }) => { + if (item.text === 'queued user turn') { + host.setAppState({ streamingPhase: 'waiting' }); + } + }); + const sendQueued = sendQueuedViaHost(host, session); + + handler.requestQueuedGoalPromotion(); + handler.handleEvent(compactionCompletedEvent(), sendQueued); + + await vi.waitFor(() => { + expect(host.sendQueuedMessage).toHaveBeenCalledWith(session, { text: 'queued user turn' }); + }); + expect(session.createGoal).not.toHaveBeenCalled(); + + handler.handleEvent(turnEndedEvent(), sendQueued); + + await vi.waitFor(() => { + expect(session.createGoal).toHaveBeenCalledWith({ + objective: 'Ship queued goal', + replace: false, + }); + }); + const sendQueuedCalls = host.sendQueuedMessage.mock.calls as Array<[unknown, { text?: string }]>; + const userMessageIndex = sendQueuedCalls.findIndex( + ([, item]) => item.text === 'queued user turn', + ); + expect(userMessageIndex).toBeGreaterThanOrEqual(0); + expect(host.sendQueuedMessage).toHaveBeenLastCalledWith(session, { text: 'Ship queued goal' }); + const userMessageOrder = host.sendQueuedMessage.mock.invocationCallOrder[userMessageIndex]!; + const goalCreateOrder = session.createGoal.mock.invocationCallOrder[0]!; + expect(userMessageOrder).toBeLessThan(goalCreateOrder); + }); + + it('leaves the queued goal in place when the next goal cannot start', async () => { + const { host, session } = makeHost({ createGoalRejects: true }); + const handler = new SessionEventHandler(host); + + handler.handleEvent(completionEvent(), vi.fn()); + handler.handleEvent(clearedEvent(), vi.fn()); + handler.handleEvent(turnEndedEvent(), vi.fn()); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('create failed')); + }); + expect(removeGoalQueueItem).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(host.sendQueuedMessage).not.toHaveBeenCalled(); + expect(session.createGoal).toHaveBeenCalledOnce(); + }); + + it('retries the queued goal on a later idle event after startup fails', async () => { + const { host, session } = makeHost(); + session.createGoal.mockRejectedValueOnce(new Error('create failed')); + const handler = new SessionEventHandler(host); + const sendQueued = sendQueuedViaHost(host, session); + + handler.handleEvent(completionEvent(), sendQueued); + handler.handleEvent(clearedEvent(), sendQueued); + handler.handleEvent(turnEndedEvent(), sendQueued); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('create failed')); + }); + expect(removeGoalQueueItem).not.toHaveBeenCalled(); + expect(host.sendQueuedMessage).not.toHaveBeenCalled(); + + handler.handleEvent(turnEndedEvent(), sendQueued); + + await vi.waitFor(() => { + expect(session.createGoal).toHaveBeenCalledTimes(2); + }); + expect(removeGoalQueueItem).toHaveBeenCalledWith(session, { goalId: 'q1' }); + expect(host.sendQueuedMessage).toHaveBeenCalledWith(session, { text: 'Ship queued goal' }); + }); + + it('does not send the queued objective when removal fails after goal creation', async () => { + vi.mocked(removeGoalQueueItem).mockRejectedValueOnce(new Error('remove failed')); + const { host, session } = makeHost(); + const handler = new SessionEventHandler(host); + + handler.handleEvent(completionEvent(), vi.fn()); + handler.handleEvent(clearedEvent(), vi.fn()); + handler.handleEvent(turnEndedEvent(), vi.fn()); + + await vi.waitFor(() => { + expect(host.showError).toHaveBeenCalledWith(expect.stringContaining('could not be removed')); + }); + expect(session.createGoal).toHaveBeenCalledWith({ + objective: 'Ship queued goal', + replace: false, + }); + expect(session.cancelGoal).toHaveBeenCalledOnce(); + expect(restoreGoalQueueItem).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(host.sendQueuedMessage).not.toHaveBeenCalled(); + }); + + it('restores the queued goal and cancels the started goal when the session changes before send', async () => { + const { host, session } = makeHost(); + vi.mocked(removeGoalQueueItem).mockImplementationOnce(async () => { + host.session = undefined; + return { goals: [] }; + }); + const handler = new SessionEventHandler(host); + + handler.handleEvent(completionEvent(), vi.fn()); + handler.handleEvent(clearedEvent(), vi.fn()); + handler.handleEvent(turnEndedEvent(), sendQueuedViaHost(host, session)); + + await vi.waitFor(() => { + expect(restoreGoalQueueItem).toHaveBeenCalledWith(session, { + id: 'q1', + objective: 'Ship queued goal', + createdAt: '', + updatedAt: '', + }); + }); + expect(session.cancelGoal).toHaveBeenCalledOnce(); + expect(host.sendQueuedMessage).not.toHaveBeenCalled(); + }); + + it('restores and cancels when the host becomes busy before sending the promoted goal', async () => { + const { host, session } = makeHost(); + vi.mocked(removeGoalQueueItem).mockImplementationOnce(async () => { + host.setAppState({ streamingPhase: 'waiting' }); + return { goals: [] }; + }); + const handler = new SessionEventHandler(host); + + handler.handleEvent(completionEvent(), vi.fn()); + handler.handleEvent(clearedEvent(), vi.fn()); + handler.handleEvent(turnEndedEvent(), sendQueuedViaHost(host, session)); + + await vi.waitFor(() => { + expect(restoreGoalQueueItem).toHaveBeenCalledWith(session, { + id: 'q1', + objective: 'Ship queued goal', + createdAt: '', + updatedAt: '', + }); + }); + expect(session.cancelGoal).toHaveBeenCalledOnce(); + expect(host.sendQueuedMessage).not.toHaveBeenCalled(); + }); + + it('shows a notice when a blocked goal has queued goals', async () => { + const { host, session } = makeHost(); + const handler = new SessionEventHandler(host); + const event = { + type: 'goal.updated', + sessionId: 's1', + agentId: 'main', + snapshot: fakeGoalSnapshot('Blocked goal', 'blocked'), + change: { kind: 'lifecycle', status: 'blocked', reason: 'waiting for access' }, + } as const; + + handler.handleEvent(event, vi.fn()); + + await vi.waitFor(() => { + expect(host.showNotice).toHaveBeenCalledWith( + 'Goal blocked.', + 'The next queued goal will start only after this goal is complete.', + ); + }); + expect(session.createGoal).not.toHaveBeenCalled(); + }); + + it('does not render a duplicate marker for a model-reported blocked goal', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + + handler.handleEvent(modelBlockedEvent(), vi.fn()); + + expect(host.state.transcriptContainer.addChild).not.toHaveBeenCalled(); + }); + + it('renders a blocked fallback when the model does not explain the blocked goal', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + + handler.handleEvent(modelBlockedEvent(), vi.fn()); + handler.handleEvent(turnEndedEvent(), vi.fn()); + + expect(addedTranscriptText(host)).toBe(' ◦ Goal blocked'); + }); + + it('does not render a blocked fallback after the model explains the blocked goal', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + + handler.handleEvent(modelBlockedEvent(), vi.fn()); + handler.handleEvent( + { + type: 'assistant.delta', + sessionId: 's1', + agentId: 'main', + turnId: 1, + delta: 'I am blocked because I need credentials.', + }, + vi.fn(), + ); + handler.handleEvent(turnEndedEvent(), vi.fn()); + + expect(host.state.transcriptContainer.addChild).not.toHaveBeenCalled(); + }); + + it('does not render a blocked fallback after earlier assistant text in the same turn', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + + handler.handleEvent( + { + type: 'assistant.delta', + sessionId: 's1', + agentId: 'main', + turnId: 1, + delta: 'I am blocked because I need credentials.', + }, + vi.fn(), + ); + handler.handleEvent(modelBlockedEvent(), vi.fn()); + handler.handleEvent(turnEndedEvent(), vi.fn()); + + expect(host.state.transcriptContainer.addChild).not.toHaveBeenCalled(); + }); + + it('does not promote on paused or cancelled updates', async () => { + const { host, session } = makeHost(); + const handler = new SessionEventHandler(host); + const paused = { + type: 'goal.updated', + sessionId: 's1', + agentId: 'main', + snapshot: fakeGoalSnapshot('Paused goal', 'paused'), + change: { kind: 'lifecycle', status: 'paused' }, + } as const; + + handler.handleEvent(paused, vi.fn()); + handler.handleEvent(clearedEvent(), vi.fn()); + + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(session.createGoal).not.toHaveBeenCalled(); + expect(host.sendNormalUserInput).not.toHaveBeenCalled(); + expect(host.sendQueuedMessage).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-notify.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-notify.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5b846b313dcd38a345096aa2143ea265a219579 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-notify.test.ts @@ -0,0 +1,116 @@ +import { Container } from '@moonshot-ai/pi-tui'; +import { NotifyPanelComponent } from '#/tui/components/chrome/notify-panel'; +import type { Event } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { getBuiltInPalette } from '#/tui/theme'; + +function makeHost() { + const host = { + state: { + notifyPanel: new NotifyPanelComponent(), + notifyPanelContainer: new Container(), + appState: { + sessionId: 's1', + streamingPhase: 'idle', + isCompacting: false, + model: 'kimi-model', + permissionMode: 'auto', + stepRetry: null, + }, + queuedMessages: [], + queuedMessageDispatchPending: false, + theme: { palette: getBuiltInPalette('dark') }, + toolOutputExpanded: false, + todoPanel: { getTodos: vi.fn(() => []) }, + transcriptContainer: { addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: { id: 's1' }, + aborted: false, + sessionEventUnsubscribe: undefined, + streamingUI: { + setTurnId: vi.fn(), + setStep: vi.fn(), + flushNow: vi.fn(), + resetToolUi: vi.fn(), + clearNotifyPanel: vi.fn(), + markNotifyPanelEnded: vi.fn(), + finalizeTurn: vi.fn(), + finalizeLiveTextBuffers: vi.fn(), + completeToolResult: vi.fn(), + getTurnContext: vi.fn(() => ({ turnId: '1', step: 0 })), + }, + requireSession: vi.fn(), + setAppState: vi.fn((patch: Record) => + Object.assign(host.state.appState, patch), + ), + patchLivePane: vi.fn(), + resetLivePane: vi.fn(), + updateActivityPane: vi.fn(), + updateQueueDisplay: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + recordSessionActivity: vi.fn(), + noteStepUsage: vi.fn(), + noteCompactionFinished: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + appendTranscriptEntry: vi.fn(), + sendNormalUserInput: vi.fn(), + sendQueuedMessage: vi.fn(), + shiftQueuedMessage: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + tasksBrowserController: {}, + }; + return { host: host as any }; +} + +function turnStarted(origin: Record): Event { + return { + sessionId: 's1', + agentId: 'main', + type: 'turn.started', + turnId: 1, + origin, + } as unknown as Event; +} + +function turnEnded(): Event { + return { + sessionId: 's1', + agentId: 'main', + type: 'turn.ended', + turnId: 1, + reason: 'completed', + } as unknown as Event; +} + +describe('SessionEventHandler — update panel lifecycle', () => { + it.each(['user', 'cron_job', 'background_task'])('clears old updates at a new main %s turn', (kind) => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.notifications.setEnabled(true); + handler.notifications.handleEvent({ type: 'tool.call.started', sessionId: 's1', agentId: 'main', turnId: 0, toolCallId: 'n1', name: 'NotifyUser', args: { message: 'Earlier finding' } } as Event); + handler.notifications.handleEvent({ type: 'tool.result', sessionId: 's1', agentId: 'main', turnId: 0, toolCallId: 'n1', output: 'Update shown to the user.' } as Event); + handler.handleEvent(turnStarted({ kind }), vi.fn()); + handler.handleEvent(turnEnded(), vi.fn()); + expect(host.state.notifyPanel.getEntries().map((entry: { text: string }) => entry.text)).toEqual([]); + expect(host.streamingUI.clearNotifyPanel).not.toHaveBeenCalled(); + }); + + it('collects child notifications before child routing without changing the main turn', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.notifications.setEnabled(true); + handler.handleEvent({ type: 'tool.call.started', sessionId: 's1', agentId: 'worker-1', turnId: 9, toolCallId: 'n1', name: 'NotifyUser', args: { message: 'Child finding' } } as Event, vi.fn()); + handler.handleEvent({ type: 'tool.result', sessionId: 's1', agentId: 'worker-1', turnId: 9, toolCallId: 'n1', output: 'Update shown to the user.' } as Event, vi.fn()); + expect(host.state.notifyPanel.getEntries()[0]).toMatchObject({ agentId: 'worker-1', text: 'Child finding' }); + expect(host.streamingUI.setTurnId).not.toHaveBeenCalled(); + expect(host.streamingUI.completeToolResult).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-plugin-updates.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-plugin-updates.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d55a6e247d135bba7ae6bbc04305656dd811e6b --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-plugin-updates.test.ts @@ -0,0 +1,192 @@ +import { describe, expect, it, vi } from 'vitest'; + +import type { PluginUpdateNotifier } from '#/tui/controllers/plugin-update-notifier'; +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { getBuiltInPalette } from '#/tui/theme'; + +const DATASOURCE_TOOL = 'mcp__plugin-kimi-datasource_data__call_data_source_tool'; + +function makeHost() { + const streamingUI = { + setTurnId: vi.fn(), + flushNow: vi.fn(), + resetToolUi: vi.fn(), + clearNotifyPanel: vi.fn(), + markNotifyPanelEnded: vi.fn(), + setStep: vi.fn(), + finalizeTurn: vi.fn(), + getTurnContext: vi.fn(() => ({ turnId: 1, step: 0 })), + registerToolCall: vi.fn(), + completeToolResult: vi.fn(), + setTodoList: vi.fn(), + }; + const host = { + state: { + appState: { + sessionId: 's1', + streamingPhase: 'waiting', + model: 'kimi-model', + permissionMode: 'auto', + }, + queuedMessages: [], + queuedMessageDispatchPending: false, + theme: { palette: getBuiltInPalette('dark') }, + toolOutputExpanded: false, + todoPanel: { getTodos: vi.fn(() => []) }, + transcriptContainer: { addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: {}, + aborted: false, + sessionEventUnsubscribe: undefined, + streamingUI, + requireSession: vi.fn(() => ({})), + setAppState: vi.fn(), + patchLivePane: vi.fn(), + resetLivePane: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + updateActivityPane: vi.fn(), + track: vi.fn(), + recordSessionActivity: vi.fn(), + noteStepUsage: vi.fn(), + noteCompactionFinished: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + appendTranscriptEntry: vi.fn(), + sendNormalUserInput: vi.fn(), + sendQueuedMessage: vi.fn(), + shiftQueuedMessage: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + tasksBrowserController: {}, + surveyController: { notifyToolCallStarted: vi.fn() }, + }; + return { host: host as never, streamingUI }; +} + +function makeNotifier() { + return { + handleMcpToolCompleted: vi.fn(), + handlePluginCommandCompleted: vi.fn(), + }; +} + +function toolCallStarted(name: string) { + return { + type: 'tool.call.started', + sessionId: 's1', + agentId: 'main', + turnId: 1, + toolCallId: 't1', + name, + args: {}, + } as never; +} + +function toolResult() { + return { + type: 'tool.result', + sessionId: 's1', + agentId: 'main', + turnId: 1, + toolCallId: 't1', + output: 'ok', + } as never; +} + +function turnEnded(reason: string, turnId = 1) { + return { + type: 'turn.ended', + sessionId: 's1', + agentId: 'main', + turnId, + reason, + } as never; +} + +function pluginCommandTurnStarted() { + return { + type: 'turn.started', + sessionId: 's1', + agentId: 'main', + turnId: 2, + origin: { + kind: 'plugin_command', + activationId: 'a1', + pluginId: 'kimi-datasource', + commandName: 'setup', + trigger: 'user-slash', + }, + } as never; +} + +const sendQueued = (): void => {}; + +describe('SessionEventHandler plugin update notices', () => { + it('reports plugin MCP usage only when the turn ends', () => { + const { host, streamingUI } = makeHost(); + const notifier = makeNotifier(); + streamingUI.completeToolResult.mockReturnValue({ name: DATASOURCE_TOOL, args: {} }); + const handler = new SessionEventHandler(host, notifier as unknown as PluginUpdateNotifier); + + handler.handleEvent(toolCallStarted(DATASOURCE_TOOL), sendQueued); + handler.handleEvent(toolResult(), sendQueued); + // The tool result alone must not trigger the notice mid-turn. + expect(notifier.handleMcpToolCompleted).not.toHaveBeenCalled(); + + handler.handleEvent(turnEnded('completed'), sendQueued); + expect(notifier.handleMcpToolCompleted).toHaveBeenCalledTimes(1); + expect(notifier.handleMcpToolCompleted).toHaveBeenCalledWith(DATASOURCE_TOOL); + }); + + it('skips the notice for a cancelled turn and clears the buffer', () => { + const { host, streamingUI } = makeHost(); + const notifier = makeNotifier(); + streamingUI.completeToolResult.mockReturnValue({ name: DATASOURCE_TOOL, args: {} }); + const handler = new SessionEventHandler(host, notifier as unknown as PluginUpdateNotifier); + + handler.handleEvent(toolCallStarted(DATASOURCE_TOOL), sendQueued); + handler.handleEvent(toolResult(), sendQueued); + handler.handleEvent(turnEnded('cancelled'), sendQueued); + expect(notifier.handleMcpToolCompleted).not.toHaveBeenCalled(); + + // A later completed turn must not replay the cancelled turn's usage. + handler.handleEvent(turnEnded('completed', 3), sendQueued); + expect(notifier.handleMcpToolCompleted).not.toHaveBeenCalled(); + }); + + it('ignores non-plugin tools', () => { + const { host, streamingUI } = makeHost(); + const notifier = makeNotifier(); + streamingUI.completeToolResult.mockReturnValue({ name: 'Bash', args: {} }); + const handler = new SessionEventHandler(host, notifier as unknown as PluginUpdateNotifier); + + handler.handleEvent(toolCallStarted('Bash'), sendQueued); + handler.handleEvent(toolResult(), sendQueued); + handler.handleEvent(turnEnded('completed'), sendQueued); + expect(notifier.handleMcpToolCompleted).not.toHaveBeenCalled(); + }); + + it('reports a finished plugin command turn', () => { + const { host } = makeHost(); + const notifier = makeNotifier(); + const handler = new SessionEventHandler(host, notifier as unknown as PluginUpdateNotifier); + + handler.handleEvent(pluginCommandTurnStarted(), sendQueued); + handler.handleEvent(turnEnded('completed', 2), sendQueued); + expect(notifier.handlePluginCommandCompleted).toHaveBeenCalledTimes(1); + expect(notifier.handlePluginCommandCompleted).toHaveBeenCalledWith('kimi-datasource'); + }); + + it('skips a cancelled plugin command turn', () => { + const { host } = makeHost(); + const notifier = makeNotifier(); + const handler = new SessionEventHandler(host, notifier as unknown as PluginUpdateNotifier); + + handler.handleEvent(pluginCommandTurnStarted(), sendQueued); + handler.handleEvent(turnEnded('cancelled', 2), sendQueued); + expect(notifier.handlePluginCommandCompleted).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-step-retry.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-step-retry.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ca1e124835cbf95cf2bbb070da8c8754237c912 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-step-retry.test.ts @@ -0,0 +1,182 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import { getBuiltInPalette } from '#/tui/theme'; + +function makeHost() { + const host = { + state: { + appState: { + sessionId: 's1', + streamingPhase: 'waiting', + isCompacting: false, + model: 'kimi-model', + permissionMode: 'auto', + stepRetry: null, + }, + queuedMessages: [], + queuedMessageDispatchPending: false, + theme: { palette: getBuiltInPalette('dark') }, + toolOutputExpanded: false, + todoPanel: { getTodos: vi.fn(() => []) }, + transcriptContainer: { addChild: vi.fn() }, + ui: { requestRender: vi.fn() }, + }, + session: { id: 's1' }, + aborted: false, + sessionEventUnsubscribe: undefined, + streamingUI: { + setTurnId: vi.fn(), + setStep: vi.fn(), + flushNow: vi.fn(), + resetToolUi: vi.fn(), + clearNotifyPanel: vi.fn(), + markNotifyPanelEnded: vi.fn(), + finalizeTurn: vi.fn(), + finalizeLiveTextBuffers: vi.fn(), + completeToolResult: vi.fn(), + }, + requireSession: vi.fn(), + setAppState: vi.fn((patch: Record) => + Object.assign(host.state.appState, patch), + ), + patchLivePane: vi.fn(), + resetLivePane: vi.fn(), + showError: vi.fn(), + showStatus: vi.fn(), + showNotice: vi.fn(), + track: vi.fn(), + recordSessionActivity: vi.fn(), + noteStepUsage: vi.fn(), + noteCompactionFinished: vi.fn(), + mountEditorReplacement: vi.fn(), + restoreEditor: vi.fn(), + restoreInputText: vi.fn(), + appendTranscriptEntry: vi.fn(), + sendNormalUserInput: vi.fn(), + sendQueuedMessage: vi.fn(), + shiftQueuedMessage: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + tasksBrowserController: {}, + }; + return { host: host as any }; +} + +const retryingEvent = { + type: 'turn.step.retrying', + sessionId: 's1', + agentId: 'main', + turnId: 1, + step: 1, + failedAttempt: 1, + nextAttempt: 2, + maxAttempts: 10, + delayMs: 4000, + errorName: 'APIStatusError', + errorMessage: 'rate limited', + statusCode: 429, +} as const; + +describe('SessionEventHandler step retry state', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + afterEach(() => { + vi.useRealTimers(); + }); + + it('stores the retry snapshot when a step starts retrying', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + expect(host.state.appState.stepRetry).toEqual({ + nextAttempt: 2, + maxAttempts: 10, + delayMs: 4000, + errorName: 'APIStatusError', + errorMessage: 'rate limited', + statusCode: 429, + phase: 'backoff', + }); + }); + + it('drives the pane back to waiting so mid-stream retries render', () => { + const { host } = makeHost(); + host.state.appState.streamingPhase = 'composing'; + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + expect(host.patchLivePane).toHaveBeenCalledWith({ mode: 'waiting' }); + expect(host.state.appState.streamingPhase).toBe('waiting'); + }); + + it.each([ + [{ type: 'turn.step.completed', turnId: 1, step: 1 }, 'turn.step.completed'], + [ + { type: 'turn.step.interrupted', turnId: 1, step: 1, reason: 'error' }, + 'turn.step.interrupted', + ], + [{ type: 'turn.ended', turnId: 1, reason: 'completed' }, 'turn.ended'], + [ + { type: 'tool.result', turnId: 1, toolCallId: 'tc1', output: 'ok', isError: false }, + 'tool.result', + ], + ])('clears the retry snapshot on %s', (event, _label) => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + expect(host.state.appState.stepRetry).not.toBeNull(); + handler.handleEvent( + { sessionId: 's1', agentId: 'main', ...event } as any, + vi.fn(), + ); + expect(host.state.appState.stepRetry).toBeNull(); + }); + + it('flips to attempt phase once the backoff delay elapses', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + expect(host.state.appState.stepRetry).toMatchObject({ phase: 'backoff' }); + vi.advanceTimersByTime(4000); + expect(host.state.appState.stepRetry).toMatchObject({ nextAttempt: 2, phase: 'attempt' }); + }); + + it('cancels the phase flip when the retry is cleared during the backoff', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + handler.handleEvent( + { + type: 'turn.step.interrupted', + sessionId: 's1', + agentId: 'main', + turnId: 1, + step: 1, + reason: 'error', + } as any, + vi.fn(), + ); + vi.advanceTimersByTime(10_000); + expect(host.state.appState.stepRetry).toBeNull(); + }); + + it('keeps the retry snapshot on turn.step.started (v2 re-emits it per attempt)', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + handler.handleEvent( + { type: 'turn.step.started', sessionId: 's1', agentId: 'main', turnId: 1, step: 1 } as any, + vi.fn(), + ); + expect(host.state.appState.stepRetry).toMatchObject({ nextAttempt: 2, phase: 'backoff' }); + }); + + it('cancels the pending phase flip via clearStepRetryAttemptTimer (TUI shutdown path)', () => { + const { host } = makeHost(); + const handler = new SessionEventHandler(host); + handler.handleEvent(retryingEvent as any, vi.fn()); + handler.clearStepRetryAttemptTimer(); + vi.advanceTimersByTime(10_000); + expect(host.state.appState.stepRetry).toMatchObject({ phase: 'backoff' }); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/session-event-handler-todo.test.ts b/apps/kimi-code/test/tui/controllers/session-event-handler-todo.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..331c1bf8d05cd3e138cd4699a630921aa94c0590 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/session-event-handler-todo.test.ts @@ -0,0 +1,88 @@ +import type { Event } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import { SessionEventHandler } from '#/tui/controllers/session-event-handler'; +import type { ToolCallBlockData } from '#/tui/types'; + +function makeHarness() { + const activeCalls = new Map(); + const streamingUI = { + setTurnId: vi.fn(), + flushNow: vi.fn(), + getTurnContext: vi.fn(() => ({ turnId: 1, step: 0 })), + registerToolCall: vi.fn((call: ToolCallBlockData) => { + activeCalls.set(call.id, call); + return true; + }), + completeToolResult: vi.fn((toolCallId: string) => { + const call = activeCalls.get(toolCallId); + activeCalls.delete(toolCallId); + return call; + }), + setTodoList: vi.fn(), + }; + const host = { + state: { + appState: { availableModels: {}, workDir: '/tmp/work', stepRetry: null }, + ui: { requestRender: vi.fn() }, + transcriptContainer: { addChild: vi.fn() }, + }, + session: undefined, + streamingUI, + appendTranscriptEntry: vi.fn(), + patchLivePane: vi.fn(), + setAppState: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + surveyController: { notifyToolCallStarted: vi.fn() }, + updateActivityPane: vi.fn(), + showStatus: vi.fn(), + }; + const handler = new SessionEventHandler(host as never); + return { handler, streamingUI }; +} + +function todoCallStarted(toolCallId: string, todos: unknown): Event { + return { + sessionId: 's1', + agentId: 'main', + type: 'tool.call.started', + turnId: 1, + toolCallId, + name: 'TodoList', + args: { todos }, + } as unknown as Event; +} + +function todoResult(toolCallId: string, isError = false): Event { + return { + sessionId: 's1', + agentId: 'main', + type: 'tool.result', + turnId: 1, + toolCallId, + output: 'ok', + isError, + } as unknown as Event; +} + +describe('SessionEventHandler — todo panel feed', () => { + it('feeds the panel from TodoList call args when the tool result arrives', () => { + const { handler, streamingUI } = makeHarness(); + const todos = [{ title: '测试 Todo 项', status: 'in_progress' }]; + + handler.handleEvent(todoCallStarted('tc-1', todos), vi.fn()); + expect(streamingUI.setTodoList).not.toHaveBeenCalled(); + + handler.handleEvent(todoResult('tc-1'), vi.fn()); + expect(streamingUI.setTodoList).toHaveBeenCalledWith(todos); + }); + + it('ignores failed TodoList results', () => { + const { handler, streamingUI } = makeHarness(); + + handler.handleEvent(todoCallStarted('tc-1', [{ title: 'x', status: 'pending' }]), vi.fn()); + handler.handleEvent(todoResult('tc-1', true), vi.fn()); + + expect(streamingUI.setTodoList).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/staging-leases.test.ts b/apps/kimi-code/test/tui/controllers/staging-leases.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6463df90d67c8289c21ee1b91a64275c8cabae21 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/staging-leases.test.ts @@ -0,0 +1,359 @@ +import type { TurnEndedEvent, TurnStartedEvent } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it, vi } from 'vitest'; + +import { + StagingLeaseTracker, + type StagingLeaseEffects, + type StagingLeaseOrigin, +} from '#/tui/controllers/staging-leases'; + +function turnStarted(turnId: number | string, kind: string, promptId?: string): TurnStartedEvent { + return { type: 'turn.started', agentId: 'main', turnId, origin: { kind }, promptId } as TurnStartedEvent; +} + +function turnEnded(turnId: number | string): TurnEndedEvent { + return { type: 'turn.ended', agentId: 'main', turnId, reason: 'completed' } as TurnEndedEvent; +} + +function makeEffects(): { + effects: StagingLeaseEffects; + takeFileIds: ReturnType readonly string[]>>; + releaseRetains: ReturnType void>>; + deleteFiles: ReturnType< + typeof vi.fn<(fileIds: readonly string[], paths: readonly string[]) => Promise> + >; + warn: ReturnType void>>; + deleted: { fileIds: string[]; paths: string[] }; +} { + const deleted = { fileIds: [] as string[], paths: [] as string[] }; + const takeFileIds = vi.fn((ids: readonly number[]) => ids.map((id) => `file-${id}`)); + const releaseRetains = vi.fn((ids: readonly number[]) => void ids); + const deleteFiles = vi.fn((fileIds: readonly string[], paths: readonly string[]) => { + deleted.fileIds.push(...fileIds); + deleted.paths.push(...paths); + return Promise.resolve(); + }); + const warn = vi.fn((message: string) => void message); + return { + effects: { takeFileIds, releaseRetains, deleteFiles, warn }, + takeFileIds, + releaseRetains, + deleteFiles, + warn, + deleted, + }; +} + +function makeTracker(): ReturnType & { tracker: StagingLeaseTracker } { + const mocks = makeEffects(); + return { ...mocks, tracker: new StagingLeaseTracker(mocks.effects) }; +} + +describe('StagingLeaseTracker', () => { + describe('create', () => { + it('returns undefined when nothing is staged', () => { + const { tracker } = makeTracker(); + expect(tracker.create([], [], 'user')).toBeUndefined(); + }); + }); + + describe('turn claiming', () => { + it('claims the earliest unbound lease of the matching origin', () => { + const { tracker } = makeTracker(); + const first = tracker.create([], ['/cache/a'], 'user'); + const second = tracker.create([], ['/cache/b'], 'user'); + + tracker.handleTurnStarted(turnStarted(1, 'user')); + expect(first?.turnId).toBe('1'); + expect(second?.turnId).toBeUndefined(); + + tracker.handleTurnStarted(turnStarted(2, 'user')); + expect(second?.turnId).toBe('2'); + }); + + it('warns when several unclaimed same-origin leases make the heuristic claim ambiguous', () => { + const { tracker, warn } = makeTracker(); + tracker.create([], ['/cache/a'], 'user'); + tracker.create([], ['/cache/b'], 'user'); + + tracker.handleTurnStarted(turnStarted(1, 'user')); + + expect(warn).toHaveBeenCalledOnce(); + expect(warn.mock.calls[0]![0]).toContain("'user'"); + expect(warn.mock.calls[0]![0]).toContain('1'); + }); + + it('stays silent while at most one same-origin lease is unclaimed', () => { + const { tracker, warn } = makeTracker(); + tracker.create([], ['/cache/a'], 'user'); + + tracker.handleTurnStarted(turnStarted(1, 'user')); + tracker.handleTurnStarted(turnStarted(2, 'user')); + + expect(warn).not.toHaveBeenCalled(); + }); + + it('binds the exact lease when turn.started echoes its submission id', () => { + const { tracker, warn } = makeTracker(); + const earlier = tracker.create([], ['/cache/a'], 'user'); + const exact = tracker.create([], ['/cache/b'], 'user', 'sub-2'); + + // The exact id wins over the earlier unclaimed same-origin lease, and + // the ambiguity warning stays silent. + tracker.handleTurnStarted(turnStarted(1, 'user', 'sub-2')); + + expect(exact?.turnId).toBe('1'); + expect(earlier?.turnId).toBeUndefined(); + expect(warn).not.toHaveBeenCalled(); + }); + + it('falls back to the origin heuristic when the promptId is unknown', () => { + const { tracker, warn } = makeTracker(); + const first = tracker.create([], ['/cache/a'], 'user', 'sub-1'); + const second = tracker.create([], ['/cache/b'], 'user'); + + tracker.handleTurnStarted(turnStarted(1, 'user', 'sub-unknown')); + + expect(first?.turnId).toBe('1'); + expect(second?.turnId).toBeUndefined(); + expect(warn).toHaveBeenCalledOnce(); + }); + + it('does not exact-bind a released lease whose submission id is echoed again', () => { + const { tracker } = makeTracker(); + const released = tracker.create([], ['/cache/a'], 'user', 'sub-1'); + tracker.release(released); + const fallback = tracker.create([], ['/cache/b'], 'user'); + + tracker.handleTurnStarted(turnStarted(1, 'user', 'sub-1')); + + expect(released?.turnId).toBeUndefined(); + expect(fallback?.turnId).toBe('1'); + }); + + it('ignores turns of other or unknown origins', () => { + const { tracker } = makeTracker(); + const lease = tracker.create([], ['/cache/a'], 'skill_activation'); + + tracker.handleTurnStarted(turnStarted(1, 'user')); + tracker.handleTurnStarted(turnStarted(2, 'plugin_command')); + tracker.handleTurnStarted(turnStarted(3, 'system_trigger')); + expect(lease?.turnId).toBeUndefined(); + + tracker.handleTurnStarted(turnStarted(4, 'skill_activation')); + expect(lease?.turnId).toBe('4'); + }); + + it('does not rebind a bound or released lease', () => { + const { tracker } = makeTracker(); + const lease = tracker.create([], ['/cache/a'], 'user'); + tracker.bindToTurn(lease, '1'); + tracker.bindToTurn(lease, '2'); + expect(lease?.turnId).toBe('1'); + + tracker.release(lease); + tracker.bindToTurn(lease, '3'); + expect(lease?.turnId).toBe('1'); + }); + }); + + describe('turn-end release', () => { + it('deletes daemon uploads but retires cache copies to session lifetime', () => { + const { tracker, deleted } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], 'user'); + tracker.bindToTurn(lease, '1'); + + tracker.handleTurnEnded(turnEnded(1)); + + expect(deleted.fileIds).toEqual(['file-1']); + expect(deleted.paths).toEqual([]); + }); + + it('deletes retired cache copies at session close', () => { + const { tracker, deleted } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], 'user'); + tracker.bindToTurn(lease, '1'); + tracker.handleTurnEnded(turnEnded(1)); + expect(deleted.paths).toEqual([]); + + tracker.releaseAll(); + expect(deleted.paths).toEqual(['/cache/a']); + }); + + it('releases a bound lease exactly once across repeated turn.ended events', () => { + const { tracker, deleteFiles } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], 'user'); + tracker.bindToTurn(lease, '1'); + + tracker.handleTurnEnded(turnEnded(1)); + tracker.handleTurnEnded(turnEnded(1)); + tracker.release(lease); + + expect(deleteFiles).toHaveBeenCalledTimes(1); + }); + + it('ignores turn.ended for unknown turns', () => { + const { tracker, deleteFiles } = makeTracker(); + tracker.create([1], ['/cache/a'], 'user'); + tracker.handleTurnEnded(turnEnded(99)); + expect(deleteFiles).not.toHaveBeenCalled(); + }); + + it('consumes one retain per id occurrence at turn end', () => { + const { tracker, takeFileIds } = makeTracker(); + // Multiplicity in the lease's id list is the retain count (creation + // sites dedupe per extraction): [7, 7] means two retains, e.g. a + // batched steer of two queued messages sharing the image. + tracker.create([7, 7], [], 'user', 'sub-dup'); + tracker.handleTurnStarted(turnStarted(1, 'user', 'sub-dup')); + + tracker.handleTurnEnded(turnEnded(1)); + + expect(takeFileIds.mock.calls).toEqual([[[7]], [[7]]]); + }); + }); + + describe('abandonment', () => { + // Every abandonment entry point deletes daemon uploads and cache copies + // immediately, whether or not a turn ever consumed the lease. + it.each([ + [ + 'release', + (tracker: StagingLeaseTracker) => { + tracker.release(tracker.create([1], ['/cache/a'], 'user')); + tracker.release(tracker.create([2], ['/cache/b'], 'user')); + }, + ], + [ + 'releaseMedia and releaseQueued', + (tracker: StagingLeaseTracker) => { + tracker.releaseMedia([1], ['/cache/a', '/cache/b']); + tracker.releaseQueued([{ text: 'q', agentId: 'main', videoAttachmentIds: [2] }]); + }, + ], + [ + 'releaseAll', + (tracker: StagingLeaseTracker) => { + tracker.create([1], ['/cache/a'], 'user'); + tracker.bindToTurn(tracker.create([2], ['/cache/b'], 'user'), '1'); + tracker.releaseAll(); + }, + ], + ] as const)('%s deletes daemon uploads and cache copies immediately', (_name, abandon) => { + const { tracker, deleted } = makeTracker(); + + abandon(tracker); + + expect(deleted.fileIds).toEqual(['file-1', 'file-2']); + expect(deleted.paths).toEqual(['/cache/a', '/cache/b']); + }); + }); + + describe('queue recall', () => { + it('consumes only the retain and retires cache copies instead of deleting', () => { + const { tracker, releaseRetains, deleted } = makeTracker(); + + // A recall restores the draft into the editor — not a discard: the + // daemon upload stays staged (only the retain is consumed) and the + // rewrite channel's cache copy retires to session lifetime. + tracker.releaseRecalled([2], ['/cache/b']); + + expect(releaseRetains).toHaveBeenCalledWith([2]); + expect(deleted.fileIds).toEqual([]); + expect(deleted.paths).toEqual([]); + + tracker.releaseAll(); + expect(deleted.fileIds).toEqual([]); + expect(deleted.paths).toEqual(['/cache/b']); + }); + }); + + describe('defer', () => { + it('unbinds the lease without consuming retains or deleting files', () => { + const { tracker, takeFileIds, releaseRetains, deleted } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], 'user', 'sub-1'); + + tracker.defer(lease); + + expect(lease?.released).toBe(true); + expect(takeFileIds).not.toHaveBeenCalled(); + expect(releaseRetains).not.toHaveBeenCalled(); + expect(deleted).toEqual({ fileIds: [], paths: [] }); + + // A deferred lease is gone for good: turn events cannot claim it and + // releaseAll does not sweep its media. + tracker.handleTurnStarted(turnStarted(1, 'user', 'sub-1')); + expect(lease?.turnId).toBeUndefined(); + tracker.releaseAll(); + expect(deleted).toEqual({ fileIds: [], paths: [] }); + }); + }); + + describe('trackDispatch', () => { + const origin: StagingLeaseOrigin = 'user'; + + it('keeps the lease when the dispatch resolves', async () => { + const { tracker, deleteFiles } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], origin); + const onError = vi.fn(); + + tracker.trackDispatch(lease, Promise.resolve(), onError); + await tracker.drain(); + + expect(onError).not.toHaveBeenCalled(); + expect(deleteFiles).not.toHaveBeenCalled(); + expect(lease?.released).toBe(false); + }); + + it('releases an unclaimed lease exactly once when the dispatch rejects', async () => { + const { tracker, deleted } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], origin); + const onError = vi.fn(); + + tracker.trackDispatch(lease, Promise.reject(new Error('boom')), onError); + await tracker.drain(); + + expect(onError).toHaveBeenCalledOnce(); + expect(deleted.fileIds).toEqual(['file-1']); + expect(deleted.paths).toEqual(['/cache/a']); + // A later turn end must not delete again. + tracker.handleTurnEnded(turnEnded(1)); + tracker.releaseAll(); + expect(deleted.fileIds).toEqual(['file-1']); + }); + + it('does not release a lease a turn already claimed when the dispatch rejects', async () => { + const { tracker, deleted } = makeTracker(); + const lease = tracker.create([1], ['/cache/a'], origin); + tracker.bindToTurn(lease, '7'); + + tracker.trackDispatch(lease, Promise.reject(new Error('boom')), vi.fn()); + await tracker.drain(); + expect(deleted.fileIds).toEqual([]); + + // The owning turn still releases it at turn end (uploads deleted, copies retired). + tracker.handleTurnEnded(turnEnded(7)); + expect(deleted.fileIds).toEqual(['file-1']); + expect(deleted.paths).toEqual([]); + }); + }); + + describe('track/drain', () => { + it('drain awaits in-flight cleanups and track swallows rejections', async () => { + const { tracker } = makeTracker(); + let settled = false; + tracker.track( + new Promise((resolve) => { + setTimeout(() => { + settled = true; + resolve(); + }, 10); + }), + ); + tracker.track(Promise.reject(new Error('ignored'))); + + await tracker.drain(); + expect(settled).toBe(true); + }); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/subagent-activity-store.test.ts b/apps/kimi-code/test/tui/controllers/subagent-activity-store.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..06b90dd6941759d20b6b44bc08601a89cbaa2894 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/subagent-activity-store.test.ts @@ -0,0 +1,313 @@ +import type { Event } from '@moonshot-ai/kimi-code-sdk'; +import { describe, expect, it } from 'vitest'; + +import { + MAX_SUBAGENT_ACTIVITY_STEPS, + SUBAGENT_ARG_STRING_MAX_CHARS, + SUBAGENT_STEP_TEXT_TAIL_CHARS, + SUBAGENT_TOOL_OUTPUT_MAX_CHARS, +} from '#/tui/constant/rendering'; +import { STREAMING_ARGS_PREVIEW_MAX_CHARS } from '#/tui/constant/streaming'; +import { + SubagentActivityStore, + type SubagentActivitySpawn, +} from '#/tui/controllers/subagent-activity-store'; + +function ev(partial: Record): Event { + return { sessionId: 's1', agentId: 'agent-1', ...partial } as unknown as Event; +} + +function spawn(overrides: Partial = {}): SubagentActivitySpawn { + return { + agentId: 'agent-1', + agentName: 'explore', + description: 'find things', + parentToolCallId: 'tc-1', + model: 'K3', + effort: 'high', + ...overrides, + }; +} + +describe('SubagentActivityStore', () => { + it('folds a full step lifecycle (text + tool call + result)', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: 0 })); + store.applyEvent(ev({ type: 'assistant.delta', turnId: 1, delta: 'Hello ' })); + store.applyEvent(ev({ type: 'assistant.delta', turnId: 1, delta: 'world' })); + store.applyEvent( + ev({ type: 'tool.call.started', turnId: 1, toolCallId: 't1', name: 'Grep', args: { pattern: 'foo' } }), + ); + store.applyEvent( + ev({ type: 'tool.progress', turnId: 1, toolCallId: 't1', update: { kind: 'stdout', text: 'line1\nline2\n' } }), + ); + store.applyEvent( + ev({ type: 'tool.result', turnId: 1, toolCallId: 't1', output: 'a\nb\nc', isError: false }), + ); + + const record = store.get('agent-1'); + expect(record?.agentName).toBe('explore'); + expect(record?.steps).toHaveLength(1); + expect(record?.totalSteps).toBe(1); + expect(record?.steps[0]?.textTail).toBe('Hello world'); + const call = record?.steps[0]?.toolCalls[0]; + expect(call?.name).toBe('Grep'); + expect(call?.args).toEqual({ pattern: 'foo' }); + expect(call?.status).toBe('done'); + expect(call?.result?.output).toBe('a\nb\nc'); + expect(call?.result?.is_error).toBe(false); + expect(call?.liveOutputTail).toBeUndefined(); + expect(call?.durationMs).toBeGreaterThanOrEqual(0); + expect(record?.version).toBeGreaterThan(0); + }); + + it('shows a status progress update as the live output tail', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent( + ev({ type: 'tool.call.started', turnId: 1, toolCallId: 't1', name: 'WaitFor', args: { timeout: 600 } }), + ); + store.applyEvent( + ev({ + type: 'tool.progress', + turnId: 1, + toolCallId: 't1', + update: { kind: 'status', text: 'Waiting 10s / 600s · 1 background task still running', replace: true }, + }), + ); + + const call = store.get('agent-1')?.steps[0]?.toolCalls[0]; + expect(call?.liveOutputTail).toBe('Waiting 10s / 600s · 1 background task still running'); + }); + + it('creates a call from streaming deltas and replaces args on start', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent( + ev({ type: 'tool.call.delta', turnId: 1, toolCallId: 't1', name: 'Bash', argumentsPart: '{"command":"ls' }), + ); + store.applyEvent( + ev({ type: 'tool.call.delta', turnId: 1, toolCallId: 't1', argumentsPart: ' -la"}' }), + ); + + let record = store.get('agent-1'); + // No step event yet — a synthetic step holds the in-flight call. + expect(record?.steps).toHaveLength(1); + expect(record?.steps[0]?.toolCalls[0]?.args).toEqual({ command: 'ls -la' }); + + store.applyEvent( + ev({ + type: 'tool.call.started', + turnId: 1, + toolCallId: 't1', + name: 'Bash', + args: { command: 'ls -la', timeout: 5 }, + }), + ); + record = store.get('agent-1'); + expect(record?.steps[0]?.toolCalls[0]?.args).toEqual({ command: 'ls -la', timeout: 5 }); + }); + + it('evicts whole steps beyond the cap while totalSteps keeps counting', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + for (let i = 0; i < MAX_SUBAGENT_ACTIVITY_STEPS + 2; i++) { + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: i })); + } + const record = store.get('agent-1'); + expect(record?.steps).toHaveLength(MAX_SUBAGENT_ACTIVITY_STEPS); + expect(record?.totalSteps).toBe(MAX_SUBAGENT_ACTIVITY_STEPS + 2); + expect(record?.steps[0]?.step).toBe(2); + }); + + it('keeps only the tail of long assistant text', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: 0 })); + store.applyEvent( + ev({ + type: 'assistant.delta', + turnId: 1, + delta: 'x'.repeat(SUBAGENT_STEP_TEXT_TAIL_CHARS) + 'y'.repeat(100), + }), + ); + const step = store.get('agent-1')?.steps[0]; + expect(step?.textTail).toHaveLength(SUBAGENT_STEP_TEXT_TAIL_CHARS); + expect(step?.textTail.endsWith('y'.repeat(100))).toBe(true); + }); + + it('caps tool output and appends a truncation sentinel', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: 0 })); + store.applyEvent( + ev({ type: 'tool.call.started', turnId: 1, toolCallId: 't1', name: 'Bash', args: {} }), + ); + store.applyEvent( + ev({ + type: 'tool.result', + turnId: 1, + toolCallId: 't1', + output: 'y'.repeat(SUBAGENT_TOOL_OUTPUT_MAX_CHARS + 100), + }), + ); + const call = store.get('agent-1')?.steps[0]?.toolCalls[0]; + expect(call?.result?.output.startsWith('yyy')).toBe(true); + expect(call?.result?.output).toContain('[output truncated'); + expect(call?.result?.output.length).toBeLessThan(SUBAGENT_TOOL_OUTPUT_MAX_CHARS + 120); + }); + + it('marks the current step on retry without opening a new one', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: 0 })); + store.applyEvent( + ev({ + type: 'turn.step.retrying', + turnId: 1, + step: 0, + nextAttempt: 2, + maxAttempts: 5, + errorName: 'RateLimitError', + }), + ); + let record = store.get('agent-1'); + expect(record?.steps).toHaveLength(1); + expect(record?.steps[0]?.retrying).toContain('2/5'); + + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: 1 })); + record = store.get('agent-1'); + expect(record?.steps[1]?.retrying).toBeUndefined(); + }); + + it('implicitly creates a record for events from an unseen agent', () => { + const store = new SubagentActivityStore(); + store.applyEvent(ev({ type: 'assistant.delta', turnId: 1, delta: 'hi' })); + const record = store.get('agent-1'); + expect(record?.agentName).toBe('agent-1'); + expect(record?.steps[0]?.textTail).toBe('hi'); + }); + + it('drops results for unknown agents instead of creating records', () => { + const store = new SubagentActivityStore(); + store.applyEvent(ev({ type: 'tool.result', turnId: 1, toolCallId: 't1', output: 'x' })); + expect(store.get('agent-1')).toBeUndefined(); + }); + + it('caps the raw streaming-args buffer at the preview window', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent( + ev({ + type: 'tool.call.delta', + turnId: 1, + toolCallId: 't1', + name: 'Write', + argumentsPart: 'x'.repeat(STREAMING_ARGS_PREVIEW_MAX_CHARS + 1000), + }), + ); + const buffers = ( + store as unknown as { streamingArgs: Map } + ).streamingArgs; + expect(buffers.get('agent-1:t1')?.length).toBeLessThanOrEqual(STREAMING_ARGS_PREVIEW_MAX_CHARS); + }); + + it('tracks terminal state and resets it on respawn', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.markCompleted('agent-1', 'done summary'); + let record = store.get('agent-1'); + expect(record?.status).toBe('completed'); + expect(record?.resultSummary).toBe('done summary'); + + store.ensureRecord(spawn()); + record = store.get('agent-1'); + expect(record?.status).toBe('running'); + expect(record?.resultSummary).toBeUndefined(); + + store.markFailed('agent-1', 'boom'); + record = store.get('agent-1'); + expect(record?.status).toBe('failed'); + expect(record?.error).toBe('boom'); + }); + + it('clear() releases all records', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: 0 })); + store.clear(); + expect(store.get('agent-1')).toBeUndefined(); + }); + + it('drop() removes one record along with its streaming buffers', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.ensureRecord(spawn({ agentId: 'agent-2', agentName: 'general' })); + store.applyEvent( + ev({ type: 'tool.call.delta', turnId: 1, toolCallId: 't1', name: 'Write', argumentsPart: '{"path":"a"}' }), + ); + + store.drop('agent-1'); + + expect(store.get('agent-1')).toBeUndefined(); + expect(store.get('agent-2')).toBeDefined(); + const buffers = ( + store as unknown as { streamingArgs: Map } + ).streamingArgs; + expect([...buffers.keys()].every((key) => !key.startsWith('agent-1:'))).toBe(true); + }); + + it('caps long string argument values retained in a record', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent( + ev({ + type: 'tool.call.started', + turnId: 1, + toolCallId: 't1', + name: 'Write', + args: { path: 'a.ts', content: 'c'.repeat(SUBAGENT_ARG_STRING_MAX_CHARS + 500) }, + }), + ); + const call = store.get('agent-1')?.steps[0]?.toolCalls[0]; + expect(typeof call?.args['content']).toBe('string'); + expect((call?.args['content'] as string).length).toBeLessThanOrEqual( + SUBAGENT_ARG_STRING_MAX_CHARS + 1, + ); + expect(call?.args['path']).toBe('a.ts'); + }); + + it('drops delta-only arg buffers when their step is evicted', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + // A call truncated before started/result only ever produced deltas. + store.applyEvent( + ev({ type: 'tool.call.delta', turnId: 1, toolCallId: 't-trunc', name: 'Write', argumentsPart: '{"path":"a"' }), + ); + const buffers = ( + store as unknown as { streamingArgs: Map } + ).streamingArgs; + expect(buffers.has('agent-1:t-trunc')).toBe(true); + + for (let i = 0; i < MAX_SUBAGENT_ACTIVITY_STEPS; i++) { + store.applyEvent(ev({ type: 'turn.step.started', turnId: 1, step: i })); + } + expect(buffers.has('agent-1:t-trunc')).toBe(false); + }); + + it('drops leftover arg buffers when the record turns terminal', () => { + const store = new SubagentActivityStore(); + store.ensureRecord(spawn()); + store.applyEvent( + ev({ type: 'tool.call.delta', turnId: 1, toolCallId: 't-trunc', name: 'Write', argumentsPart: '{"path":"a"' }), + ); + const buffers = ( + store as unknown as { streamingArgs: Map } + ).streamingArgs; + expect(buffers.has('agent-1:t-trunc')).toBe(true); + + store.markCompleted('agent-1', 'done'); + expect(buffers.has('agent-1:t-trunc')).toBe(false); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/subagent-event-handler.test.ts b/apps/kimi-code/test/tui/controllers/subagent-event-handler.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..84852d92e458f6d22f6a4c0e398638e0ea2ae1cb --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/subagent-event-handler.test.ts @@ -0,0 +1,183 @@ +import type { Event } from '@moonshot-ai/kimi-code-sdk'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import type { AgentSwarmProgressComponent } from '#/tui/components/messages/agent-swarm-progress'; +import { + SubAgentEventHandler, + type SubagentLifecycleEvent, +} from '#/tui/controllers/subagent-event-handler'; + +function makeSwarmHandler() { + const requestRender = vi.fn(); + const transcriptContainer = { addChild: vi.fn() }; + const dockChild = { render: vi.fn(() => ['dock line']) }; + const host = { + state: { + appState: { availableModels: {} }, + ui: { + requestRender, + terminal: { rows: 40, columns: 120 }, + children: [transcriptContainer, dockChild], + }, + transcriptContainer, + dockContainer: undefined, + }, + streamingUI: { + getToolComponent: vi.fn(() => undefined), + getActiveToolCall: vi.fn(() => undefined), + onToolCallStart: vi.fn(), + getTurnContext: vi.fn(() => ({ turnId: 1, step: 0 })), + removeToolComponentIfInactive: vi.fn(), + finalizeLiveTextBuffers: vi.fn(), + }, + appendTranscriptEntry: vi.fn(), + btwPanelController: { routeEvent: vi.fn(() => false) }, + updateActivityPane: vi.fn(), + }; + const handler = new SubAgentEventHandler(host as never, { + backgroundTasks: new Map(), + backgroundTaskTranscriptedTerminal: new Set(), + syncBackgroundAgentBadge: vi.fn(), + }); + return { handler, host, requestRender, transcriptContainer, dockChild }; +} + +function swarmComponentOf(transcriptContainer: { addChild: ReturnType }) { + return transcriptContainer.addChild.mock.calls[0]?.[0] as AgentSwarmProgressComponent; +} + +function lifecycleEvent( + type: 'subagent.spawned' | 'subagent.started' | 'subagent.completed' | 'subagent.cancelled', + subagentId: string, + parentToolCallId: string, +): SubagentLifecycleEvent { + return { + sessionId: 's1', + agentId: 'main', + type, + subagentId, + subagentName: 'explore', + parentToolCallId, + description: `task ${subagentId}`, + runInBackground: false, + resultSummary: type === 'subagent.completed' ? 'done' : undefined, + } as unknown as SubagentLifecycleEvent; +} + +function childEvent(type: 'assistant.delta' | 'tool.call.started', subagentId: string): Event { + return { + sessionId: 's1', + agentId: subagentId, + type, + delta: type === 'assistant.delta' ? 'hello' : undefined, + toolCallId: type === 'tool.call.started' ? 'tool-1' : undefined, + name: type === 'tool.call.started' ? 'Read' : undefined, + args: {}, + } as unknown as Event; +} + +function startSwarmWithChild(handler: SubAgentEventHandler): void { + handler.handleAgentSwarmToolCallStarted('tc-1', { + description: 'Review changed files', + items: ['src/a.ts'], + }); + handler.handleLifecycleEvent(lifecycleEvent('subagent.spawned', 'child-1', 'tc-1')); + handler.handleLifecycleEvent(lifecycleEvent('subagent.started', 'child-1', 'tc-1')); +} + +afterEach(() => { + vi.useRealTimers(); +}); + +describe('SubAgentEventHandler — swarm render batching', () => { + it('does not request a render for each child delta routed to a swarm', () => { + vi.useFakeTimers(); + const { handler, requestRender } = makeSwarmHandler(); + startSwarmWithChild(handler); + requestRender.mockClear(); + + handler.routeChildAgentEvent(childEvent('assistant.delta', 'child-1')); + handler.routeChildAgentEvent(childEvent('assistant.delta', 'child-1')); + handler.routeChildAgentEvent(childEvent('tool.call.started', 'child-1')); + + expect(requestRender).not.toHaveBeenCalled(); + }); + + it('still requests a render for swarm lifecycle transitions', () => { + vi.useFakeTimers(); + const { handler, requestRender } = makeSwarmHandler(); + handler.handleAgentSwarmToolCallStarted('tc-1', { + description: 'Review changed files', + items: ['src/a.ts'], + }); + handler.handleLifecycleEvent(lifecycleEvent('subagent.spawned', 'child-1', 'tc-1')); + requestRender.mockClear(); + + handler.handleLifecycleEvent(lifecycleEvent('subagent.started', 'child-1', 'tc-1')); + handler.handleLifecycleEvent(lifecycleEvent('subagent.completed', 'child-1', 'tc-1')); + + expect(requestRender).toHaveBeenCalled(); + }); + + it('drives swarm re-renders from the frame timer after deltas', () => { + vi.useFakeTimers(); + const { handler, requestRender } = makeSwarmHandler(); + startSwarmWithChild(handler); + requestRender.mockClear(); + + handler.routeChildAgentEvent(childEvent('assistant.delta', 'child-1')); + expect(requestRender).not.toHaveBeenCalled(); + + vi.advanceTimersByTime(80); + expect(requestRender).toHaveBeenCalledTimes(1); + }); +}); + +describe('SubAgentEventHandler — subagent.cancelled', () => { + it('marks a running swarm member cancelled instead of leaving it running', () => { + const { handler, transcriptContainer } = makeSwarmHandler(); + startSwarmWithChild(handler); + const component = swarmComponentOf(transcriptContainer); + + handler.handleLifecycleEvent(lifecycleEvent('subagent.cancelled', 'child-1', 'tc-1')); + + const output = component.render(120).join('\n'); + expect(output).toContain('⊘'); + }); + + it('keeps the batch-level cancelled label when a member cancel event follows', () => { + const { handler, transcriptContainer } = makeSwarmHandler(); + startSwarmWithChild(handler); + handler.routeChildAgentEvent(childEvent('assistant.delta', 'child-1')); + + handler.handleAgentSwarmToolResult( + 'tc-1', + { output: 'The user manually interrupted this subagent batch.' } as never, + true, + ); + handler.handleLifecycleEvent(lifecycleEvent('subagent.cancelled', 'child-1', 'tc-1')); + + const component = swarmComponentOf(transcriptContainer); + const output = component.render(120).join('\n'); + expect(output).toContain('⊘'); + expect(output).toContain('hello'); + }); +}); + +describe('SubAgentEventHandler — swarm grid height measurement', () => { + it('measures the rows after the transcript once per render pass', async () => { + const { handler, transcriptContainer, dockChild } = makeSwarmHandler(); + startSwarmWithChild(handler); + const component = swarmComponentOf(transcriptContainer); + + component.render(120); + component.render(120); + expect(dockChild.render).toHaveBeenCalledTimes(1); + + await Promise.resolve(); + component.render(120); + expect(dockChild.render).toHaveBeenCalledTimes(2); + + handler.clearAgentSwarmProgress(); + }); +}); diff --git a/apps/kimi-code/test/tui/controllers/survey-controller.test.ts b/apps/kimi-code/test/tui/controllers/survey-controller.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0356439c2b1f9dfb58c4941fbc0c9e9dea6f279 --- /dev/null +++ b/apps/kimi-code/test/tui/controllers/survey-controller.test.ts @@ -0,0 +1,2089 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { GutterContainer } from '#/tui/components/chrome/gutter-container'; +import { + SurveyController, + type SurveyControllerDeps, + type SurveyHost, +} from '#/tui/controllers/survey-controller'; +import type { TranscriptEntry } from '#/tui/types'; +import { DEFAULT_SURVEY_POPUP_CONFIG } from '#/utils/survey-popup-config'; + +const mocks = vi.hoisted(() => ({ + getSurveyPopupConfig: vi.fn(() => Promise.resolve(undefined)), +})); + +vi.mock('#/utils/survey-popup-config', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + getSurveyPopupConfig: mocks.getSurveyPopupConfig, + }; +}); + +const ESC = '\u001B'; +const CSI_LEFT = '\u001B[D'; +const CSI_RIGHT = '\u001B[C'; +const CSI_UP = '\u001B[A'; + +interface TimerDriver { + readonly setTimer: (fn: () => void, ms: number) => unknown; + readonly clearTimer: (handle: unknown) => void; + fire(ms: number): void; + pending(): number[]; +} + +function createTimerDriver(): TimerDriver { + interface Entry { + readonly id: number; + readonly fn: () => void; + readonly ms: number; + cleared: boolean; + } + const entries: Entry[] = []; + let nextId = 0; + return { + setTimer: (fn, ms) => { + nextId += 1; + entries.push({ id: nextId, fn, ms, cleared: false }); + return nextId; + }, + clearTimer: (handle) => { + const entry = entries.find((candidate) => candidate.id === handle); + if (entry !== undefined) entry.cleared = true; + }, + fire: (ms) => { + for (const entry of entries.splice(0)) { + if (!entry.cleared && entry.ms === ms) entry.fn(); + } + }, + pending: () => entries.filter((entry) => !entry.cleared).map((entry) => entry.ms), + }; +} + +interface Harness { + readonly controller: SurveyController; + readonly host: SurveyHost; + readonly container: GutterContainer; + readonly timers: TimerDriver; + readonly clock: { mono: number; wall: number }; + elapse(ms: number): void; + readonly track: ReturnType; + readonly editor: { + inputMode: 'prompt' | 'bash'; + autocompleteActive: boolean; + getText(): string; + setText(text: string): void; + }; + typeDigit(digit: string): void; + readonly state: SurveyHost['state']; + readonly writes: number[]; + readonly randomCalls: () => number; + flush(): Promise; + runTurns(count: number): void; + appear(): void; + renderSurvey(): string; +} + +function createHarness(deps: Partial = {}): Harness { + const clock = { mono: 0, wall: 1_700_000_000_000 }; + const timers = createTimerDriver(); + const track = vi.fn(); + const writes: number[] = []; + const container = new GutterContainer(1, 1); + let editorText = ''; + const editor = { + inputMode: 'prompt' as 'prompt' | 'bash', + autocompleteActive: false, + getText: () => editorText, + setText: (text: string) => { + editorText = text; + }, + hasAutocompleteActivity: () => editor.autocompleteActive, + }; + const state = { + surveyContainer: container, + transcriptEntries: [] as TranscriptEntry[], + editorReplacementMounted: false, + activeDialog: null, + livePane: { mode: 'idle', pendingApproval: null, pendingQuestion: null }, + externalEditorRunning: false, + tasksBrowser: undefined, + editor, + appState: { + model: 'k2', + streamingPhase: 'idle', + isCompacting: false, + contextTokens: 640, + cumulativeTokens: 1234, + permissionMode: 'manual', + thinkingEffort: 'high', + disableFeedbackSurvey: false, + availableModels: {}, + availableProviders: {}, + }, + ui: { requestRender: vi.fn() }, + }; + let randomCallCount = 0; + let appearanceCounter = 0; + const { random: randomOverride, ...restDeps } = deps; + const host = { + state, + btwPanelController: { isActive: () => false }, + track, + } as unknown as SurveyHost; + const controller = new SurveyController(host, { + monotonicNow: () => clock.mono, + wallNow: () => clock.wall, + random: () => { + randomCallCount += 1; + return (randomOverride ?? (() => 0))(); + }, + appearanceId: () => { + appearanceCounter += 1; + return `appearance-${String(appearanceCounter)}`; + }, + setTimer: timers.setTimer, + clearTimer: timers.clearTimer, + terminalWidth: () => 120, + terminalHeight: () => 24, + configFresh: () => true, + readGlobalLastShown: async () => undefined, + writeGlobalLastShown: (wallTime) => { + writes.push(wallTime); + }, + ...restDeps, + }); + + const harness: Harness = { + controller, + host, + container, + timers, + clock, + track, + editor, + state: state as unknown as SurveyHost['state'], + writes, + randomCalls: () => randomCallCount, + elapse: (ms) => { + clock.mono += ms; + timers.fire(ms); + }, + flush: async () => { + await new Promise((resolve) => { + setImmediate(resolve); + }); + }, + runTurns: (count) => { + for (let turn = 1; turn <= count; turn++) { + controller.notifyTurnStarted(true); + controller.notifyTurnEnded(); + } + }, + appear: () => { + clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + clock.mono += 600; + }, + typeDigit: (digit: string) => { + controller.handlePreInput(digit); + controller.handleEditorChange(digit); + }, + renderSurvey: () => + container + .render(120) + .join('\n') + .replaceAll(/\u001B\[[0-9;]*m/g, ''), + }; + return harness; +} + +function userEntry(content: string): TranscriptEntry { + return { id: content, kind: 'user', turnId: undefined, renderMode: 'plain', content }; +} + +const HARNESS_ENVIRONMENT = { + current_model: 'k2', + user_turn_count: 5, + cumulative_tokens: 1234, + virtual_context_tokens: 640, + tool_call_count: 0, + compaction_count: 0, + permission_mode: 'manual', + thinking_effort: 'high', +}; + +const DEFAULT_SNAPSHOT = { + config_probability: 0.005, + config_on_for_models: '*', + config_min_time_before_feedback_ms: 600_000, + config_min_user_turns_before_feedback: 5, + config_min_time_between_feedback_ms: 3_600_000, + config_min_user_turns_between_feedback: 10, + config_min_time_between_global_feedback_ms: 100_000_000, + config_long_context_survey_threshold: 200_000, + config_long_context_probability: 0.2, + config_long_context_trigger_mode: 'virtual_context', +}; + +describe('SurveyController gating', () => { + it('appears once the session clears warmup and reports appeared', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + + expect(harness.renderSurvey()).toContain('How is Kimi doing this session? (optional)'); + expect(harness.renderSurvey()).toContain('1: Bad'); + expect(harness.track).toHaveBeenCalledTimes(1); + expect(harness.track).toHaveBeenCalledWith('feedback_survey', { + event_type: 'appeared', + appearance_id: 'appearance-1', + appearance_index: 1, + response: undefined, + ...HARNESS_ENVIRONMENT, + ...DEFAULT_SNAPSHOT, + }); + expect(harness.writes).toEqual([1_700_000_000_000]); + }); + + it('stays hidden during warmup and appears once it completes', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 597_999; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('stays hidden without enough user turns', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden when sampled out', async () => { + const harness = createHarness({ random: () => 0.9 }); + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('stays hidden when telemetry is disabled', async () => { + const harness = createHarness({ telemetryDisabled: () => true }); + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden when the user disabled the survey', async () => { + const harness = createHarness({ feedbackSurveyDisabled: () => true }); + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden inside the persisted global cooldown', async () => { + const harness = createHarness({ + readGlobalLastShown: async () => 1_700_000_000_000 - 1000, + }); + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden while the latest user message opens an ordered list', async () => { + const harness = createHarness(); + await harness.flush(); + harness.state.transcriptEntries.push(userEntry('1. first item')); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden while a btw panel is active', async () => { + const harness = createHarness(); + (harness.host.btwPanelController as { isActive: () => boolean }).isActive = () => true; + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden while an editor replacement is mounted', async () => { + const harness = createHarness(); + harness.state.editorReplacementMounted = true; + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); + + it('cancels a pending evaluation when a new turn starts', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.controller.notifyTurnStarted(true); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + }); + + it('does not arm the idle evaluation when a cron turn ends on its own', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.controller.notifyTurnStarted(false); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + }); + + it('re-arms the pending evaluation after non-user continuation turns end', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + + harness.controller.notifyTurnStarted(false); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('keeps one sample per user turn across evaluations', async () => { + const harness = createHarness({ random: () => 0.9 }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + harness.controller.notifyTurnStarted(false); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.randomCalls()).toBe(1); + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.randomCalls()).toBe(2); + }); + + it('paces the second appearance by time and turns, and bumps appearance_index', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.controller.handlePreInput(ESC); + expect(harness.container.children).toHaveLength(0); + + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + harness.clock.mono += 3_600_000; + harness.clock.wall += 100_000_000; + harness.runTurns(10); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenLastCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', appearance_index: 2 }), + ); + }); +}); + +describe('SurveyController long-context arm', () => { + it('shows the long-context survey over the context-window threshold without any warmup', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.renderSurvey()).toContain('How is Kimi doing this session? (optional)'); + expect(harness.track).toHaveBeenCalledTimes(1); + expect(harness.track).toHaveBeenCalledWith('long_context_survey', { + event_type: 'appeared', + appearance_id: 'appearance-1', + appearance_index: 1, + response: undefined, + current_model: 'k2', + user_turn_count: 1, + cumulative_tokens: 1234, + virtual_context_tokens: 250_000, + tool_call_count: 0, + compaction_count: 0, + permission_mode: 'manual', + thinking_effort: 'high', + ...DEFAULT_SNAPSHOT, + }); + expect(harness.writes).toEqual([]); + }); + + it('reports the responded and abandoned states under the long_context_survey name', async () => { + const responded = createHarness(); + responded.state.appState.contextTokens = 250_000; + await responded.flush(); + responded.controller.notifyTurnStarted(true); + responded.controller.notifyTurnEnded(); + responded.elapse(2000); + responded.clock.mono += 600; + + responded.typeDigit('2'); + responded.elapse(400); + responded.elapse(3000); + expect(responded.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ + event_type: 'responded', + response: 'fine', + appearance_id: 'appearance-1', + }), + ); + + const abandoned = createHarness(); + abandoned.state.appState.contextTokens = 250_000; + await abandoned.flush(); + abandoned.controller.notifyTurnStarted(true); + abandoned.controller.notifyTurnEnded(); + abandoned.elapse(2000); + abandoned.clock.mono += 600; + + abandoned.controller.handleEditorChange('hello'); + expect(abandoned.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'abandoned', appearance_id: 'appearance-1' }), + ); + }); + + it('prefers the long-context survey when the session arm is also eligible', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.appear(); + + expect(harness.track).toHaveBeenCalledTimes(1); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared', appearance_index: 1 }), + ); + }); + + it('ignores the cumulative counter by default, however large it grows', async () => { + const harness = createHarness(); + harness.state.appState.cumulativeTokens = 500_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('triggers on the current window by default even when the cumulative counter is tiny', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + harness.state.appState.cumulativeTokens = 100; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ + event_type: 'appeared', + cumulative_tokens: 100, + virtual_context_tokens: 250_000, + config_long_context_trigger_mode: 'virtual_context', + }), + ); + }); + + it('compares the cumulative counter when the trigger mode is cumulative', async () => { + const harness = createHarness({ + config: () => ({ + ...DEFAULT_SURVEY_POPUP_CONFIG, + long_context_trigger_mode: 'cumulative', + }), + }); + harness.state.appState.cumulativeTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ + event_type: 'appeared', + cumulative_tokens: 250_000, + virtual_context_tokens: 640, + config_long_context_trigger_mode: 'cumulative', + }), + ); + }); + + it('closes the arm on a non-positive effective threshold and produces no events', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, long_context_survey_threshold: 0 }), + }); + harness.state.appState.contextTokens = 500_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('leaves the session arm running when the threshold closes the long-context arm', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, long_context_survey_threshold: 0 }), + }); + harness.state.appState.contextTokens = 500_000; + await harness.flush(); + + harness.appear(); + + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', config_long_context_survey_threshold: 0 }), + ); + }); + + it('stays hidden when the long-context roll misses, and never rolls again this mount', async () => { + const harness = createHarness({ random: () => 0.9 }); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.randomCalls()).toBe(2); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.randomCalls()).toBe(3); + }); + + it('shows at most once per mount even after the first appearance closes', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + + harness.clock.mono += 600; + harness.controller.handlePreInput(ESC); + expect(harness.container.children).toHaveLength(0); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + const appeared = harness.track.mock.calls.filter( + (call) => (call[1] as { event_type?: string }).event_type === 'appeared', + ); + expect(appeared).toHaveLength(1); + }); + + it('regains its one chance after a session reset', async () => { + let roll = 0.9; + const harness = createHarness({ random: () => roll }); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + roll = 0.1; + harness.controller.reset(); + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared', appearance_index: 1 }), + ); + expect(harness.writes).toEqual([]); + }); + + it('does not spend the roll while an active prompt suppresses the evaluation', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + (harness.host.btwPanelController as { isActive: () => boolean }).isActive = () => true; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.randomCalls()).toBe(1); + + (harness.host.btwPanelController as { isActive: () => boolean }).isActive = () => false; + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + }); + + it('evaluates only after the mount produced a user turn, even with tokens past the threshold', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + harness.controller.notifyTurnStarted(false); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + }); + + it('ignores the persisted global cooldown that gates the session arm', async () => { + const harness = createHarness({ + readGlobalLastShown: async () => 1_700_000_000_000 - 1000, + }); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + expect(harness.writes).toEqual([]); + }); + + it('does not suppress the session arm through the persisted cooldown after a long-context appearance', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + harness.clock.mono += 600; + harness.controller.handlePreInput(ESC); + expect(harness.writes).toEqual([]); + + harness.clock.mono += 3_600_000; + harness.runTurns(10); + harness.elapse(2000); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + expect(harness.writes).toEqual([1_700_000_000_000]); + }); +}); + +describe('SurveyController kfc model gate', () => { + const MANAGED_BASE_URL = 'https://api.kimi.com/coding/v1'; + const GATEWAY_BASE_URL = 'https://gateway.example.com/coding/v1'; + const savedBaseUrl = process.env['KIMI_CODE_BASE_URL']; + + beforeEach(() => { + delete process.env['KIMI_CODE_BASE_URL']; + }); + + afterEach(() => { + if (savedBaseUrl === undefined) { + delete process.env['KIMI_CODE_BASE_URL']; + } else { + process.env['KIMI_CODE_BASE_URL'] = savedBaseUrl; + } + }); + + function useModel( + harness: Harness, + options: { entryBaseUrl?: string; providerBaseUrl?: string } = {}, + ): void { + harness.state.appState.model = 'main'; + harness.state.appState.availableModels = { + main: { + provider: 'managed:kimi-code', + model: 'k3', + maxContextSize: 256_000, + baseUrl: options.entryBaseUrl, + }, + }; + harness.state.appState.availableProviders = { + 'managed:kimi-code': { type: 'kimi', baseUrl: options.providerBaseUrl ?? MANAGED_BASE_URL }, + }; + } + + function trackedKfcModelId(harness: Harness): unknown { + const call = harness.track.mock.calls[0]; + return call === undefined ? undefined : (call[1] as Record)['kfc_model_id']; + } + + it('opens on "*" for a kfc user and reports the real model id alongside the alias', async () => { + const harness = createHarness(); + useModel(harness); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ + event_type: 'appeared', + current_model: 'main', + kfc_model_id: 'k3', + }), + ); + }); + + it('opens for a kfc user when the real id is listed', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['k2', 'k3'] }), + }); + useModel(harness); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', kfc_model_id: 'k3' }), + ); + }); + + it('stays closed for a kfc user whose real id is not listed', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['k3-256k'] }), + }); + useModel(harness); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('opens on "*" for a self-hosted user but omits the kfc model id', async () => { + const harness = createHarness(); + useModel(harness, { providerBaseUrl: GATEWAY_BASE_URL }); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', current_model: 'main' }), + ); + expect(trackedKfcModelId(harness)).toBeUndefined(); + }); + + it('stays closed for a self-hosted model that happens to share the listed id', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['k3'] }), + }); + useModel(harness, { providerBaseUrl: GATEWAY_BASE_URL }); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('opens on "*" with a dangling alias and omits the kfc model id', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', current_model: 'k2' }), + ); + expect(trackedKfcModelId(harness)).toBeUndefined(); + }); + + it('stays closed on a concrete list when the alias cannot be resolved', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['k2'] }), + }); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('reports the kfc model id on long-context events as well', async () => { + const harness = createHarness(); + useModel(harness); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + + harness.controller.notifyTurnStarted(true); + harness.controller.notifyTurnEnded(); + harness.elapse(2000); + + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ + event_type: 'appeared', + current_model: 'main', + kfc_model_id: 'k3', + }), + ); + }); + + it('prefers the entry baseUrl over the provider baseUrl when the entry is managed', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['k3'] }), + }); + useModel(harness, { entryBaseUrl: MANAGED_BASE_URL, providerBaseUrl: GATEWAY_BASE_URL }); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', kfc_model_id: 'k3' }), + ); + }); + + it('prefers the entry baseUrl over the provider baseUrl when the entry is self-hosted', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['k3'] }), + }); + useModel(harness, { entryBaseUrl: GATEWAY_BASE_URL, providerBaseUrl: MANAGED_BASE_URL }); + await harness.flush(); + harness.appear(); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); +}); + +describe('SurveyController interaction', () => { + it('selects a rating after the digit debounce and walks pending → thanks → closed', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + harness.editor.setText('2'); + harness.typeDigit('2'); + harness.typeDigit('2'); + harness.elapse(400); + + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.editor.getText()).toBe(''); + expect(harness.renderSurvey()).toContain('Feedback: Fine · [escape: undo]'); + + harness.elapse(3000); + expect(harness.track).toHaveBeenCalledWith('feedback_survey', { + event_type: 'responded', + appearance_id: 'appearance-1', + appearance_index: 1, + response: 'fine', + ...HARNESS_ENVIRONMENT, + ...DEFAULT_SNAPSHOT, + }); + expect(harness.renderSurvey()).toContain('Thanks for your feedback!'); + + harness.elapse(5000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledTimes(1); + }); + + it('cancels a pending digit selection when the edit continues', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.typeDigit('1'); + harness.controller.handleEditorChange(''); + harness.elapse(400); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledTimes(1); + }); + + it('undo cancels the pending report, and a re-choice reports only the final rating', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + harness.typeDigit('1'); + harness.elapse(400); + expect(harness.controller.handlePreInput(ESC)).toBe(true); + expect(harness.renderSurvey()).toContain('How is Kimi doing this session? (optional)'); + harness.elapse(3000); + expect(harness.track).not.toHaveBeenCalled(); + + harness.typeDigit('3'); + harness.elapse(400); + harness.elapse(3000); + + const responses = harness.track.mock.calls.map( + (call) => (call[1] as { response?: string }).response, + ); + expect(responses).toEqual(['good']); + expect(harness.track.mock.calls[0]![1]).toMatchObject({ appearance_id: 'appearance-1' }); + }); + + it('Esc dismisses without thanks', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput(ESC)).toBe(true); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledTimes(1); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'dismissed' }), + ); + expect(harness.timers.pending()).toHaveLength(0); + }); + + it('digit 0 dismisses without thanks and clears the editor', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.setText('0'); + harness.typeDigit('0'); + harness.elapse(400); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'dismissed' }), + ); + expect(harness.editor.getText()).toBe(''); + expect(harness.container.children).toHaveLength(0); + }); + + it('abandons on non-option input', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + harness.controller.handleEditorChange('hello'); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('preserves the pre-existing draft snapshot through the editor pre-submit clear', async () => { + const harness = createHarness(); + await harness.flush(); + harness.editor.setText('2'); + harness.appear(); + harness.track.mockClear(); + + harness.controller.handleEditorChange(''); + expect(harness.controller.handleSubmit('2')).toBe(false); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('treats a digit retyped after deleting the snapshot draft as fresh input', async () => { + const harness = createHarness(); + await harness.flush(); + harness.editor.setText('2'); + harness.appear(); + + harness.controller.handleEditorChange(''); + harness.controller.handlePreInput('2'); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + expect(harness.timers.pending()).toHaveLength(1); + }); + + it('lets a pre-existing digit draft submit instead of treating it as a rating', async () => { + const harness = createHarness(); + await harness.flush(); + harness.editor.setText('2'); + harness.appear(); + harness.track.mockClear(); + + harness.controller.handleEditorChange('2'); + harness.elapse(400); + expect(harness.track).not.toHaveBeenCalled(); + + expect(harness.controller.handleSubmit('2')).toBe(false); + expect(harness.editor.getText()).toBe('2'); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('intercepts a lone digit submit as a selection instead of sending', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.setText('1'); + + expect(harness.controller.handleSubmit('1')).toBe(true); + harness.elapse(3000); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'bad' }), + ); + expect(harness.editor.getText()).toBe(''); + }); + + it('lets other submissions through and abandons the survey', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + + expect(harness.controller.handleSubmit('hello')).toBe(false); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('ignores all input during the mount protection window', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + + expect(harness.controller.handlePreInput('1')).toBe(false); + harness.editor.setText('1'); + harness.controller.handleEditorChange('1'); + expect(harness.timers.pending()).toHaveLength(0); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.controller.handlePreInput(ESC)).toBe(false); + expect(harness.controller.handleSubmit('1')).toBe(false); + + harness.clock.mono += 600; + harness.typeDigit('1'); + harness.elapse(400); + harness.elapse(3000); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'bad' }), + ); + }); + + it('abandons when a yank injects a lone digit during the mount window', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput('\u0019')).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('abandons when history recall injects a digit during the mount window', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput(CSI_UP)).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('moves the hover with arrow keys and confirms with Enter', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + + expect(harness.controller.handlePreInput(CSI_RIGHT)).toBe(true); + expect(harness.controller.handlePreInput(CSI_RIGHT)).toBe(true); + expect(harness.controller.handleSubmit('')).toBe(true); + harness.elapse(3000); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'fine' }), + ); + }); + + it('wraps the hover backwards from nothing to Dismiss', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + + expect(harness.controller.handlePreInput(CSI_LEFT)).toBe(true); + expect(harness.controller.handleSubmit('')).toBe(true); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'dismissed' }), + ); + }); + + it('abandons instead of rating when history recall replaces a draft at column zero', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.setText('draft'); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput(CSI_UP)).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('debounces a digit that arrives as a CSI-u sequence', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + + expect(harness.controller.handlePreInput('\u001B[49u')).toBe(false); + harness.editor.setText('1'); + harness.controller.handleEditorChange('1'); + expect(harness.timers.pending()).toHaveLength(1); + harness.elapse(400); + harness.elapse(3000); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'bad' }), + ); + }); + + it('debounces a typed digit even right after an Up cursor move', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.setText('draft'); + + expect(harness.controller.handlePreInput(CSI_UP)).toBe(false); + expect(harness.controller.handlePreInput('2')).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + expect(harness.timers.pending()).toHaveLength(1); + harness.elapse(400); + harness.elapse(3000); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'fine' }), + ); + }); + + it('abandons instead of rating when history recall injects a lone digit', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput(CSI_UP)).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + harness.elapse(400); + expect(harness.track).toHaveBeenCalledTimes(1); + }); + + it('abandons instead of rating when a kill-ring yank injects a lone digit', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput('\u0019')).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('abandons instead of rating when a paste injects a lone digit', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + expect(harness.controller.handlePreInput('\u001B[200~2\u001B[201~')).toBe(false); + harness.editor.setText('2'); + harness.controller.handleEditorChange('2'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + harness.elapse(400); + expect(harness.track).toHaveBeenCalledTimes(1); + }); + + it('lets arrow keys through to the editor when a draft exists', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.setText('draft'); + + expect(harness.controller.handlePreInput(CSI_RIGHT)).toBe(false); + expect(harness.controller.handlePreInput(CSI_LEFT)).toBe(false); + expect(harness.controller.handleSubmit('')).toBe(false); + expect(harness.track).toHaveBeenCalledTimes(1); + }); + + it('clears the hover when the survey closes so a later appearance starts clean', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + expect(harness.controller.handlePreInput(CSI_RIGHT)).toBe(true); + harness.controller.handlePreInput(ESC); + expect(harness.container.children).toHaveLength(0); + + harness.clock.mono += 3_600_000; + harness.clock.wall += 100_000_000; + harness.runTurns(10); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + + harness.track.mockClear(); + expect(harness.controller.handleSubmit('')).toBe(false); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('reports the settled rating with the turn count of the turn it was made in', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.typeDigit('1'); + harness.elapse(400); + harness.track.mockClear(); + + harness.controller.notifyTurnStarted(true); + + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', user_turn_count: 5 }), + ); + }); + + it('settles the pending rating when a turn starts inside the undo window', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.typeDigit('1'); + harness.elapse(400); + harness.track.mockClear(); + + harness.controller.notifyTurnStarted(true); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'bad' }), + ); + expect(harness.timers.pending()).toHaveLength(0); + }); + + it('closes silently when a turn starts while open', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + harness.controller.notifyTurnStarted(true); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('closes silently on a gate flip (editor replacement) without reporting', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + harness.controller.closeSilently(); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('treats bash-mode input as non-option input', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.inputMode = 'bash'; + + harness.typeDigit('1'); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + }); + + it('sweeps the survey away as abandoned when the editor enters bash mode', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + harness.editor.inputMode = 'bash'; + harness.controller.notifyInputModeChanged('bash'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'abandoned' }), + ); + expect(harness.controller.handlePreInput(ESC)).toBe(false); + }); + + it('does not open while the external editor is running, on either arm', async () => { + const harness = createHarness(); + harness.state.appState.contextTokens = 250_000; + await harness.flush(); + harness.clock.mono += 600_000; + harness.state.externalEditorRunning = true; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.state.externalEditorRunning = false; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'long_context_survey', + expect.objectContaining({ event_type: 'appeared' }), + ); + }); + + it('does not open while the tasks browser takeover is active', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.state.tasksBrowser = {} as never; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.state.tasksBrowser = undefined; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('does not select a hovered option with Enter after the terminal narrows', async () => { + let width = 120; + const harness = createHarness({ terminalWidth: () => width }); + await harness.flush(); + harness.appear(); + expect(harness.controller.handlePreInput(CSI_RIGHT)).toBe(true); + harness.track.mockClear(); + + width = 8; + expect(harness.controller.handleSubmit('')).toBe(false); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('does not fire a pending digit selection after the terminal narrows', async () => { + let width = 120; + const harness = createHarness({ terminalWidth: () => width }); + await harness.flush(); + harness.appear(); + harness.editor.setText('2'); + harness.typeDigit('2'); + harness.track.mockClear(); + + width = 8; + harness.elapse(400); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.editor.getText()).toBe('2'); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('lets Escape undo a pending rating even after the terminal narrows', async () => { + let width = 120; + const harness = createHarness({ terminalWidth: () => width }); + await harness.flush(); + harness.appear(); + harness.typeDigit('2'); + harness.elapse(400); + harness.track.mockClear(); + + width = 8; + expect(harness.controller.handlePreInput(ESC)).toBe(true); + harness.elapse(3000); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.renderSurvey()).toContain('How is Kimi doing this session? (optional)'); + }); + + it('does not open when the terminal is shorter than the survey needs', async () => { + let height = 24; + const harness = createHarness({ terminalHeight: () => height }); + await harness.flush(); + harness.clock.mono += 600_000; + height = 7; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + height = 8; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('requires more height when a narrow terminal wraps the survey title', async () => { + let height = 24; + const harness = createHarness({ terminalWidth: () => 14, terminalHeight: () => height }); + await harness.flush(); + harness.clock.mono += 600_000; + height = 14; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + height = 15; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('counts word-wrapped title rows instead of dividing characters', async () => { + let height = 24; + const harness = createHarness({ terminalWidth: () => 18, terminalHeight: () => height }); + await harness.flush(); + harness.clock.mono += 600_000; + height = 13; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + height = 14; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('passes keys through when the terminal shrinks in height while open', async () => { + let height = 24; + const harness = createHarness({ terminalHeight: () => height }); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + height = 6; + expect(harness.controller.handlePreInput(ESC)).toBe(false); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('does not open when the terminal is narrower than the option legend', async () => { + let width = 120; + const harness = createHarness({ terminalWidth: () => width }); + await harness.flush(); + harness.clock.mono += 600_000; + width = 13; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + width = 14; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('passes keys through when the terminal is narrowed below the legend width while open', async () => { + let width = 120; + const harness = createHarness({ terminalWidth: () => width }); + await harness.flush(); + harness.appear(); + harness.track.mockClear(); + + width = 8; + expect(harness.controller.handlePreInput(ESC)).toBe(false); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('does not open while autocomplete is active, and Esc passes through to it', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.editor.autocompleteActive = true; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.editor.autocompleteActive = false; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + + harness.editor.autocompleteActive = true; + harness.track.mockClear(); + expect(harness.controller.handlePreInput(ESC)).toBe(false); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('does not open while the editor is in bash mode', async () => { + const harness = createHarness(); + await harness.flush(); + harness.clock.mono += 600_000; + harness.editor.inputMode = 'bash'; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.editor.inputMode = 'prompt'; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('settles and closes a pending rating when the editor enters bash mode', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.typeDigit('2'); + harness.elapse(400); + harness.track.mockClear(); + + harness.editor.inputMode = 'bash'; + harness.controller.notifyInputModeChanged('bash'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', response: 'fine' }), + ); + expect(harness.controller.handlePreInput(ESC)).toBe(false); + }); + + it('closes the thanks state silently when the editor enters bash mode', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.typeDigit('2'); + harness.elapse(400); + harness.elapse(3000); + expect(harness.renderSurvey()).toContain('Thanks for your feedback!'); + harness.track.mockClear(); + + harness.editor.inputMode = 'bash'; + harness.controller.notifyInputModeChanged('bash'); + + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + expect(harness.controller.handlePreInput(ESC)).toBe(false); + }); + + it('defers evaluation until the persisted cooldown read settles, then honors it', async () => { + let settleRead!: () => void; + const harness = createHarness({ + readGlobalLastShown: () => + new Promise((resolve) => { + settleRead = () => { + resolve(1_700_000_000_000); + }; + }), + }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + settleRead(); + await harness.flush(); + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('keeps the just-written global cooldown across a reset', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + expect(harness.writes).toEqual([1_700_000_000_000]); + harness.track.mockClear(); + + harness.controller.reset(); + await harness.flush(); + + harness.clock.wall += 1; + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('takes the newer of the in-memory and reloaded cooldown timestamps', async () => { + let diskValue: number | undefined = 1_600_000_000_000; + const harness = createHarness({ readGlobalLastShown: async () => diskValue }); + await harness.flush(); + harness.appear(); + expect(harness.writes).toEqual([1_700_000_000_000]); + harness.track.mockClear(); + + diskValue = 1_650_000_000_000; + harness.controller.reset(); + await harness.flush(); + + harness.clock.wall += 1; + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('resets in-session pacing on session reset', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.controller.reset(); + await harness.flush(); + + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + }); + + it('stays hidden when the appState mirror disables the survey', async () => { + const harness = createHarness(); + harness.state.appState.disableFeedbackSurvey = true; + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); +}); + +describe('SurveyController event payload', () => { + it('reports the live session statistics and the current model', async () => { + const harness = createHarness(); + await harness.flush(); + harness.state.appState.model = 'k3'; + harness.clock.mono += 600_000; + for (let turn = 1; turn <= 5; turn++) { + harness.controller.notifyTurnStarted(true); + harness.controller.notifyToolCallStarted(); + harness.controller.notifyToolCallStarted(); + harness.controller.notifyTurnEnded(); + } + harness.controller.notifyToolCallStarted(); + harness.elapse(2000); + + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ + current_model: 'k3', + user_turn_count: 5, + cumulative_tokens: 1234, + virtual_context_tokens: 640, + tool_call_count: 11, + permission_mode: 'manual', + }), + ); + }); + + it('counts finished compactions since mount and resets on remount', async () => { + const harness = createHarness(); + await harness.flush(); + harness.controller.notifyCompactionFinished(); + harness.controller.notifyCompactionFinished(); + harness.appear(); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ compaction_count: 2, thinking_effort: 'high' }), + ); + + harness.controller.reset(); + await harness.flush(); + harness.clock.wall += 100_000_000; + harness.appear(); + expect(harness.track).toHaveBeenLastCalledWith( + 'feedback_survey', + expect.objectContaining({ compaction_count: 0 }), + ); + }); + + it('snapshots the config that produced the appearance, not a later refresh', async () => { + let cloudConfig = { ...DEFAULT_SURVEY_POPUP_CONFIG, probability: 0.5 }; + const harness = createHarness({ config: () => cloudConfig }); + await harness.flush(); + harness.appear(); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', config_probability: 0.5 }), + ); + + cloudConfig = { ...cloudConfig, probability: 0.9 }; + harness.typeDigit('1'); + harness.elapse(400); + harness.elapse(3000); + expect(harness.track).toHaveBeenLastCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'responded', config_probability: 0.5 }), + ); + }); + + it('cancels the pending digit selection when a cursor key passes through to the draft', async () => { + const harness = createHarness(); + await harness.flush(); + harness.appear(); + harness.editor.setText('2'); + harness.typeDigit('2'); + + expect(harness.controller.handlePreInput(CSI_LEFT)).toBe(false); + harness.elapse(400); + expect(harness.track).toHaveBeenCalledTimes(1); + expect(harness.editor.getText()).toBe('2'); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('keeps deferring while a region-change refresh is still in flight', async () => { + let region = 'region-a'; + let settle!: () => void; + let first = true; + const harness = createHarness({ + configRegion: () => region, + refreshConfig: () => { + if (first) { + first = false; + return undefined; + } + return new Promise((resolve) => { + settle = resolve; + }); + }, + }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + + region = 'region-b'; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + settle(); + await harness.flush(); + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('defers evaluation until the startup refresh settles', async () => { + let settle!: () => void; + const harness = createHarness({ + refreshConfig: () => + new Promise((resolve) => { + settle = resolve; + }), + }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(5); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + settle(); + await harness.flush(); + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('refreshes and defers when the config cache has gone stale', async () => { + let fresh = true; + const refreshConfig = vi.fn(() => { + fresh = true; + }); + const harness = createHarness({ configFresh: () => fresh, refreshConfig }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + expect(harness.container.children).toHaveLength(0); + + fresh = false; + harness.clock.mono += 3_600_000; + harness.runTurns(1); + harness.elapse(2000); + expect(refreshConfig).toHaveBeenCalledTimes(2); + expect(harness.container.children).toHaveLength(0); + + await harness.flush(); + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + }); + + it('defers the evaluation that triggers a refresh so a stale policy cannot open the survey', async () => { + let region = 'region-a'; + let config = { ...DEFAULT_SURVEY_POPUP_CONFIG, probability: 1 }; + const refreshConfig = vi.fn(() => { + config = { ...config, probability: 0 }; + }); + const harness = createHarness({ + configRegion: () => region, + config: () => config, + refreshConfig, + random: () => 0.9, + }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + + region = 'region-b'; + harness.runTurns(1); + harness.elapse(2000); + expect(refreshConfig).toHaveBeenCalledTimes(2); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + expect(harness.track).not.toHaveBeenCalled(); + }); + + it('evaluates with the refreshed policy on the next turn after the deferred evaluation', async () => { + let region = 'region-a'; + let config = { ...DEFAULT_SURVEY_POPUP_CONFIG, probability: 1, on_for_models: ['other-model'] }; + const refreshConfig = vi.fn(() => { + config = { ...config, on_for_models: ['*'] }; + }); + const harness = createHarness({ + configRegion: () => region, + config: () => config, + refreshConfig, + }); + await harness.flush(); + harness.clock.mono += 600_000; + harness.runTurns(4); + + region = 'region-b'; + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).toHaveLength(0); + + await harness.flush(); + harness.runTurns(1); + harness.elapse(2000); + expect(harness.container.children).not.toHaveLength(0); + expect(harness.track).toHaveBeenCalledWith( + 'feedback_survey', + expect.objectContaining({ event_type: 'appeared', config_on_for_models: '*' }), + ); + }); + + it('re-refreshes the cloud config when the region changes', async () => { + let region = 'region-a'; + const refreshConfig = vi.fn(); + const harness = createHarness({ refreshConfig, configRegion: () => region }); + await harness.flush(); + expect(refreshConfig).toHaveBeenCalledTimes(1); + + region = 'region-b'; + harness.runTurns(1); + harness.elapse(2000); + expect(refreshConfig).toHaveBeenCalledTimes(2); + }); + + it('re-refreshes the cloud config once the previous refresh is over an hour old', async () => { + const refreshConfig = vi.fn(); + const harness = createHarness({ refreshConfig }); + await harness.flush(); + expect(refreshConfig).toHaveBeenCalledTimes(1); + + harness.clock.mono += 3_597_000; + harness.runTurns(1); + harness.elapse(2000); + expect(refreshConfig).toHaveBeenCalledTimes(1); + + harness.clock.mono += 2_000; + harness.runTurns(1); + harness.elapse(2000); + expect(refreshConfig).toHaveBeenCalledTimes(2); + }); + + it('applies the cloud model gate at evaluation time', async () => { + const harness = createHarness({ + config: () => ({ ...DEFAULT_SURVEY_POPUP_CONFIG, on_for_models: ['other-model'] }), + }); + await harness.flush(); + harness.appear(); + expect(harness.container.children).toHaveLength(0); + }); +}); + +describe('SurveyController cloud config refresh', () => { + it('fires the injected refresh once at mount and not on session reset', async () => { + const refreshConfig = vi.fn(); + const harness = createHarness({ refreshConfig }); + await harness.flush(); + expect(refreshConfig).toHaveBeenCalledTimes(1); + + harness.controller.reset(); + expect(refreshConfig).toHaveBeenCalledTimes(1); + }); + + it('resolves the access token before refreshing the named config', async () => { + mocks.getSurveyPopupConfig.mockClear(); + const harness = createHarness({ accessToken: async () => 'tok' }); + await harness.flush(); + expect(mocks.getSurveyPopupConfig).toHaveBeenCalledWith({ + accessToken: 'tok', + }); + }); + + it('refreshes anonymously when no token is cached', async () => { + mocks.getSurveyPopupConfig.mockClear(); + const harness = createHarness({ accessToken: async () => undefined }); + await harness.flush(); + expect(mocks.getSurveyPopupConfig).toHaveBeenCalledWith({ + accessToken: undefined, + }); + }); + + it.each([ + [ + 'rejects', + async (): Promise => { + throw new Error('no facade'); + }, + ], + [ + 'throws synchronously', + () => { + throw new Error('no facade'); + }, + ], + ])('skips the fetch when the token provider %s', async (_kind, accessToken) => { + mocks.getSurveyPopupConfig.mockClear(); + const harness = createHarness({ + accessToken: accessToken as () => Promise, + }); + await harness.flush(); + expect(mocks.getSurveyPopupConfig).not.toHaveBeenCalled(); + }); + + it('does not fetch without a token provider', async () => { + mocks.getSurveyPopupConfig.mockClear(); + const harness = createHarness(); + await harness.flush(); + expect(mocks.getSurveyPopupConfig).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/kimi-code/test/tui/create-tui-state.test.ts b/apps/kimi-code/test/tui/create-tui-state.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ea9f6c3d3352ab8cb22da10808999c3dca4ab5a --- /dev/null +++ b/apps/kimi-code/test/tui/create-tui-state.test.ts @@ -0,0 +1,153 @@ + +import { describe, it, expect, vi } from 'vitest'; + +import { TuiAltScreen, TuiMainScreen } from '@moonshot-ai/pi-tui'; + +import { createTUIState, type KimiTUIOptions } from '#/tui/kimi-tui'; +import type { AppState } from '#/tui/types'; + +function fakeInitialAppState(): AppState { + return { + model: 'test-model', + workDir: '/tmp/kimi-test', + additionalDirs: [], + sessionId: 'sess-1', + permissionMode: 'manual', + planMode: false, + inputMode: 'prompt', + swarmMode: false, + towerMode: false, + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + stepRetry: null, + theme: 'dark', + version: '0.0.0-test', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + availableModels: {}, + availableProviders: {}, + sessionTitle: null, + mcpServersSummary: null, + }; +} + +describe('createTUIState', () => { + it('initializes all fields with sensible defaults', () => { + const opts: KimiTUIOptions = { + initialAppState: fakeInitialAppState(), + startup: { + continueLast: false, + yolo: false, + auto: false, + plan: false, + }, + }; + const state = createTUIState(opts); + + // UI objects are created. + expect(state.ui).toBeDefined(); + expect(state.terminal).toBeDefined(); + expect(state.transcriptContainer).toBeDefined(); + expect(state.activityContainer).toBeDefined(); + expect(state.todoPanelContainer).toBeDefined(); + expect(state.queueContainer).toBeDefined(); + expect(state.surveyContainer).toBeDefined(); + expect(state.editorContainer).toBeDefined(); + expect(state.editor).toBeDefined(); + expect(state.footer).toBeDefined(); + expect(state.todoPanel).toBeDefined(); + expect(state.notifyPanelContainer).toBeDefined(); + expect(state.notifyPanel).toBeDefined(); + expect(state.theme.palette).toBeDefined(); + + // App state is cloned from initialAppState, not reused by reference. + expect(state.appState).not.toBe(opts.initialAppState); + expect(state.appState.model).toBe('test-model'); + expect(state.appState.additionalDirs).toEqual([]); + expect(state.appState.sessionId).toBe('sess-1'); + expect(state.startupState).toBe('pending'); + + // LivePane defaults. + expect(state.livePane.mode).toBe('idle'); + expect(state.livePane.pendingApproval).toBeNull(); + expect(state.livePane.pendingQuestion).toBeNull(); + + // Empty collections. + expect(state.transcriptEntries).toHaveLength(0); + expect(state.queuedMessages).toHaveLength(0); + + // Boolean, counter, and optional-field defaults. + expect(state.toolOutputExpanded).toBe(false); + expect(state.activeDialog).toBeNull(); + expect(state.externalEditorRunning).toBe(false); + expect(state.loadingSessions).toBe(false); + expect(state.sessionsScope).toBe('cwd'); + expect(state.activitySpinner).toBeNull(); + }); + + it('uses the main-screen renderer by default', () => { + const state = createTUIState({ + initialAppState: fakeInitialAppState(), + startup: { + continueLast: false, + yolo: false, + auto: false, + plan: false, + }, + }); + + expect(state.ui).toBeInstanceOf(TuiMainScreen); + expect(state.ui.mode).toBe('regular'); + expect(state.dockContainer).toBeUndefined(); + }); + + it('builds an alternate-screen renderer with a docked layout in fullscreen mode', () => { + vi.stubEnv('KIMI_CODE_TUI_FULL_SCREEN', '1'); + const state = createTUIState({ + initialAppState: fakeInitialAppState(), + startup: { + continueLast: false, + yolo: false, + auto: false, + plan: false, + }, + }); + vi.unstubAllEnvs(); + + expect(state.ui).toBeInstanceOf(TuiAltScreen); + expect(state.ui.mode).toBe('fullscreen'); + + // The chrome docks below the transcript ScrollView, in z-order. + const dock = state.dockContainer; + expect(dock).toBeDefined(); + expect(dock?.children).toEqual([ + state.activityContainer, + state.todoPanelContainer, + state.notifyPanelContainer, + state.queueContainer, + state.btwPanelContainer, + state.surveyContainer, + state.editorContainer, + ]); + + // The layout root is mounted and the root children list stays empty. + expect((state.ui as TuiAltScreen).getLayoutRoot()).toBeDefined(); + expect(state.ui.children).toHaveLength(0); + + // Mouse capture replaces native terminal link activation / right-click + // paste, so both must be routed through renderer callbacks. + const internals = state.ui as unknown as { + openUrl?: (url: string) => void; + onRightClickPaste?: () => void; + }; + expect(typeof internals.openUrl).toBe('function'); + expect(typeof internals.onRightClickPaste).toBe('function'); + }); +}); diff --git a/apps/kimi-code/test/tui/easter-eggs/dance.test.ts b/apps/kimi-code/test/tui/easter-eggs/dance.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5406a299802e091f8f90be6f3b0b92bcbbb99d6f --- /dev/null +++ b/apps/kimi-code/test/tui/easter-eggs/dance.test.ts @@ -0,0 +1,264 @@ +import chalk from 'chalk'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + DANCE_FLOW_MS, + DANCE_FRAME_MS, + getRainbowDanceView, + installRainbowDance, + RainbowDance, + rainbowText, + setRainbowDance, + tryHandleDanceCommand, +} from '#/tui/easter-eggs/dance'; +import type { SlashCommandHost } from '#/tui/commands/dispatch'; +import { darkColors } from '#/tui/theme/colors'; + +const TRUECOLOR_PATTERN = /\[38;2;(\d+);(\d+);(\d+)m/g; + +/** Ordered list of "r,g,b" truecolor codes in the order they appear. */ +function truecolorCodes(text: string): string[] { + return [...text.matchAll(TRUECOLOR_PATTERN)].map((m) => `${m[1]},${m[2]},${m[3]}`); +} + +describe('RainbowDance', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + it('starts uncolored — the banner keeps its default look', () => { + const dance = new RainbowDance(vi.fn()); + + expect(dance.colored).toBe(false); + expect(dance.phase).toBe(0); + }); + + it('flows while dancing and requests renders', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const dance = new RainbowDance(requestRender); + + dance.start({ hold: false }); + expect(dance.colored).toBe(true); + + const before = dance.phase; + vi.advanceTimersByTime(DANCE_FRAME_MS); + expect(dance.phase).not.toBe(before); + expect(requestRender).toHaveBeenCalled(); + }); + + it('fades back to default after the flow when not holding', () => { + vi.useFakeTimers(); + const dance = new RainbowDance(vi.fn()); + + dance.start({ hold: false }); + vi.advanceTimersByTime(DANCE_FLOW_MS + DANCE_FRAME_MS); + + expect(dance.colored).toBe(false); + expect(dance.phase).toBe(0); + }); + + it('freezes into a static rainbow after the flow when holding', () => { + vi.useFakeTimers(); + const dance = new RainbowDance(vi.fn()); + + dance.start({ hold: true }); + vi.advanceTimersByTime(DANCE_FLOW_MS + DANCE_FRAME_MS); + + expect(dance.colored).toBe(true); + const frozen = dance.phase; + vi.advanceTimersByTime(DANCE_FRAME_MS * 10); + expect(dance.phase).toBe(frozen); + }); + + it('stops on demand back to the default colors and clears its timers', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const dance = new RainbowDance(requestRender); + + dance.start({ hold: true }); + vi.advanceTimersByTime(DANCE_FRAME_MS * 3); + expect(dance.phase).toBeGreaterThan(0); + + requestRender.mockClear(); + dance.stop(); + expect(dance.colored).toBe(false); + expect(dance.phase).toBe(0); + expect(requestRender).toHaveBeenCalled(); + + requestRender.mockClear(); + vi.advanceTimersByTime(DANCE_FRAME_MS * 5); + expect(requestRender).not.toHaveBeenCalled(); + }); + + it('dispose clears timers silently, without a final render', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const dance = new RainbowDance(requestRender); + + dance.start({ hold: false }); + vi.advanceTimersByTime(DANCE_FRAME_MS * 2); + requestRender.mockClear(); + + dance.dispose(); + expect(requestRender).not.toHaveBeenCalled(); + + vi.advanceTimersByTime(DANCE_FLOW_MS + DANCE_FRAME_MS * 10); + expect(requestRender).not.toHaveBeenCalled(); + }); + + it('advances the phase by one per frame while flowing', () => { + vi.useFakeTimers(); + const dance = new RainbowDance(vi.fn()); + + dance.start({ hold: true }); + vi.advanceTimersByTime(DANCE_FRAME_MS * 5); + expect(dance.phase).toBe(5); + + // Monotonic — the dance state itself has no palette-length cycle. + vi.advanceTimersByTime(DANCE_FRAME_MS * 5); + expect(dance.phase).toBe(10); + }); +}); + +describe('rainbowText', () => { + const previousChalkLevel = chalk.level; + + beforeEach(() => { + chalk.level = 3; + }); + + afterEach(() => { + chalk.level = previousChalkLevel; + }); + + it('assigns each visible character the next palette color', () => { + const out = rainbowText('abcd', ['#111111', '#226622', '#aa33cc', '#44ddee'], 0); + + expect(truecolorCodes(out)).toEqual([ + '17,17,17', + '34,102,34', + '170,51,204', + '68,221,238', + ]); + }); + + it('does not consume a palette slot for spaces', () => { + const out = rainbowText('a b', ['#111111', '#226622'], 0); + + expect(truecolorCodes(out)).toEqual(['17,17,17', '34,102,34']); + }); + + it('starts from the given offset', () => { + const out = rainbowText('a', ['#111111', '#226622'], 1); + + expect(truecolorCodes(out)).toEqual(['34,102,34']); + }); +}); + +describe('installRainbowDance', () => { + afterEach(() => { + setRainbowDance(undefined); + vi.useRealTimers(); + }); + + it('returns a disposer that clears timers and uninstalls the controller', () => { + vi.useFakeTimers(); + const requestRender = vi.fn(); + const dispose = installRainbowDance(requestRender); + const host = { + showStatus: vi.fn(), + state: { theme: { palette: darkColors } }, + } as unknown as SlashCommandHost; + + tryHandleDanceCommand(host, { name: 'dance', args: 'on' }); + vi.advanceTimersByTime(DANCE_FRAME_MS * 2); + expect(requestRender).toHaveBeenCalled(); + + requestRender.mockClear(); + dispose(); + + expect(getRainbowDanceView()).toBeUndefined(); + vi.advanceTimersByTime(DANCE_FLOW_MS + DANCE_FRAME_MS * 10); + expect(requestRender).not.toHaveBeenCalled(); + }); +}); + +interface DanceCall { + fn: 'start' | 'stop'; + hold?: boolean; +} + +function makeHost(): { host: SlashCommandHost; calls: DanceCall[]; status: string[] } { + const calls: DanceCall[] = []; + const status: string[] = []; + const rainbowDance = { + colored: false, + phase: 0, + start: (opts: { hold: boolean }) => calls.push({ fn: 'start', hold: opts.hold }), + stop: () => calls.push({ fn: 'stop' }), + dispose: () => {}, + }; + setRainbowDance(rainbowDance); + const host = { + showStatus: (msg: string) => status.push(msg), + state: { theme: { palette: darkColors } }, + } as unknown as SlashCommandHost; + return { host, calls, status }; +} + +describe('tryHandleDanceCommand', () => { + let host: SlashCommandHost; + let calls: DanceCall[]; + let status: string[]; + + beforeEach(() => { + ({ host, calls, status } = makeHost()); + }); + + afterEach(() => { + setRainbowDance(undefined); + }); + + it('claims /dance, flowing then fading, and hints at /dance on', () => { + const handled = tryHandleDanceCommand(host, { name: 'dance', args: '' }); + + expect(handled).toBe(true); + expect(calls).toEqual([{ fn: 'start', hold: false }]); + expect(status.join(' ')).toContain('/dance on'); + }); + + it('holds the rainbow for /dance on and hints at /dance off', () => { + const handled = tryHandleDanceCommand(host, { name: 'dance', args: 'on' }); + + expect(handled).toBe(true); + expect(calls).toEqual([{ fn: 'start', hold: true }]); + expect(status.join(' ')).toContain('/dance off'); + }); + + it('turns the rainbow off for /dance off', () => { + const handled = tryHandleDanceCommand(host, { name: 'dance', args: 'off' }); + + expect(handled).toBe(true); + expect(calls).toEqual([{ fn: 'stop' }]); + }); + + it('ignores case and surrounding whitespace in the sub-command', () => { + tryHandleDanceCommand(host, { name: 'dance', args: ' ON ' }); + + expect(calls).toEqual([{ fn: 'start', hold: true }]); + }); + + it('treats an unknown sub-command as a one-off dance', () => { + tryHandleDanceCommand(host, { name: 'dance', args: 'wiggle' }); + + expect(calls).toEqual([{ fn: 'start', hold: false }]); + }); + + it('does not claim other commands, so they fall through normally', () => { + const handled = tryHandleDanceCommand(host, { name: 'help', args: '' }); + + expect(handled).toBe(false); + expect(calls).toEqual([]); + }); +}); diff --git a/apps/kimi-code/test/tui/export-markdown.test.ts b/apps/kimi-code/test/tui/export-markdown.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e65577332b016890eac784d4f7a2b0efe295d0d --- /dev/null +++ b/apps/kimi-code/test/tui/export-markdown.test.ts @@ -0,0 +1,446 @@ +import { describe, expect, it } from 'vitest'; +import type { ContentPart, ToolCall } from '@moonshot-ai/kimi-code-sdk'; +import type { ContextMessage, PromptOrigin } from '@moonshot-ai/kimi-code-sdk'; + +import { + buildExportMarkdown, + extractToolCallHint, + formatContentPartMd, + formatToolCallMd, + groupIntoTurns, + isInternalMessage, +} from '../../src/tui/utils/export-markdown'; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function userMsg(text: string, origin?: PromptOrigin): ContextMessage { + return { + role: 'user', + content: [{ type: 'text', text }], + toolCalls: [], + origin, + }; +} + +function assistantMsg( + text: string, + toolCalls: ToolCall[] = [], + thinkText?: string, +): ContextMessage { + const content: ContentPart[] = []; + if (thinkText !== undefined) { + content.push({ type: 'think', think: thinkText }); + } + content.push({ type: 'text', text }); + return { + role: 'assistant', + content, + toolCalls, + }; +} + +function toolMsg(callId: string, text: string): ContextMessage { + return { + role: 'tool', + content: [{ type: 'text', text }], + toolCalls: [], + toolCallId: callId, + }; +} + +function makeToolCall(id: string, name: string, args: Record): ToolCall { + return { + type: 'function', + id, + name, + arguments: JSON.stringify(args), + }; +} + +// --------------------------------------------------------------------------- +// extractToolCallHint +// --------------------------------------------------------------------------- + +describe('extractToolCallHint', () => { + it('extracts path from arguments', () => { + expect(extractToolCallHint(JSON.stringify({ path: '/foo/bar.ts' }))).toBe('/foo/bar.ts'); + }); + + it('extracts command from arguments', () => { + expect(extractToolCallHint(JSON.stringify({ command: 'ls -la' }))).toBe('ls -la'); + }); + + it('prefers path over command', () => { + expect(extractToolCallHint(JSON.stringify({ command: 'ls', path: '/a.ts' }))).toBe('/a.ts'); + }); + + it('falls back to first short string value', () => { + expect(extractToolCallHint(JSON.stringify({ foo: 'hello world' }))).toBe('hello world'); + }); + + it('returns empty string for invalid JSON', () => { + expect(extractToolCallHint('not json')).toBe(''); + }); + + it('returns empty string for non-object JSON', () => { + expect(extractToolCallHint('"just a string"')).toBe(''); + }); + + it('truncates long values', () => { + const long = 'a'.repeat(100); + const hint = extractToolCallHint(JSON.stringify({ path: long })); + expect(hint.length).toBeLessThanOrEqual(63); // 60 + "…" + }); +}); + +// --------------------------------------------------------------------------- +// formatContentPartMd +// --------------------------------------------------------------------------- + +describe('formatContentPartMd', () => { + it('renders text part', () => { + expect(formatContentPartMd({ type: 'text', text: 'hello' })).toBe('hello'); + }); + + it('renders think part as collapsible', () => { + const result = formatContentPartMd({ type: 'think', think: 'reasoning here' }); + expect(result).toContain('
'); + expect(result).toContain('Thinking'); + expect(result).toContain('reasoning here'); + }); + + it('returns empty for blank think', () => { + expect(formatContentPartMd({ type: 'think', think: ' ' })).toBe(''); + }); + + it('renders image placeholder', () => { + expect( + formatContentPartMd({ type: 'image_url', imageUrl: { url: 'http://x' } }), + ).toBe('[image]'); + }); + + it('renders audio placeholder', () => { + expect( + formatContentPartMd({ type: 'audio_url', audioUrl: { url: 'http://x' } }), + ).toBe('[audio]'); + }); + + it('renders video placeholder', () => { + expect( + formatContentPartMd({ type: 'video_url', videoUrl: { url: 'http://x' } }), + ).toBe('[video]'); + }); +}); + +// --------------------------------------------------------------------------- +// formatToolCallMd +// --------------------------------------------------------------------------- + +describe('formatToolCallMd', () => { + it('renders tool call with hint', () => { + const tc = makeToolCall('c1', 'Bash', { command: 'ls' }); + const md = formatToolCallMd(tc); + expect(md).toContain('#### Tool Call: Bash'); + expect(md).toContain('`ls`'); + expect(md).toContain('```json'); + expect(md).toContain('"command": "ls"'); + }); + + it('renders tool call without hint', () => { + const tc = makeToolCall('c1', 'CustomTool', {}); + const md = formatToolCallMd(tc); + expect(md).toContain('#### Tool Call: CustomTool'); + expect(md).not.toContain('(`'); + }); +}); + +// --------------------------------------------------------------------------- +// isInternalMessage +// --------------------------------------------------------------------------- + +describe('isInternalMessage', () => { + it('marks injection origin as internal', () => { + expect(isInternalMessage(userMsg('x', { kind: 'injection', variant: 'test' }))).toBe(true); + }); + + it('marks system_trigger origin as internal', () => { + expect( + isInternalMessage(userMsg('x', { kind: 'system_trigger', name: 'test' })), + ).toBe(true); + }); + + it('marks compaction_summary origin as internal', () => { + expect(isInternalMessage(userMsg('x', { kind: 'compaction_summary' }))).toBe(true); + }); + + it('marks hook_result origin as internal', () => { + expect( + isInternalMessage(userMsg('x', { kind: 'hook_result', event: 'test' })), + ).toBe(true); + }); + + it('marks cron_job origin as internal', () => { + expect( + isInternalMessage( + userMsg('x', { + kind: 'cron_job', + jobId: 'a1b2c3d4', + cron: '0 9 * * *', + recurring: true, + coalescedCount: 1, + stale: false, + }), + ), + ).toBe(true); + }); + + it('marks cron_missed origin as internal', () => { + expect( + isInternalMessage(userMsg('x', { kind: 'cron_missed', count: 2 })), + ).toBe(true); + }); + + it('keeps real user messages', () => { + expect(isInternalMessage(userMsg('hello', { kind: 'user' }))).toBe(false); + }); + + it('keeps assistant messages', () => { + expect(isInternalMessage(assistantMsg('hi'))).toBe(false); + }); + + it('keeps tool messages', () => { + expect(isInternalMessage(toolMsg('c1', 'output'))).toBe(false); + }); + + it('keeps user messages without origin', () => { + expect(isInternalMessage(userMsg('hello'))).toBe(false); + }); +}); + +// --------------------------------------------------------------------------- +// groupIntoTurns +// --------------------------------------------------------------------------- + +describe('groupIntoTurns', () => { + it('groups messages into turns starting at user messages', () => { + const msgs: ContextMessage[] = [ + userMsg('q1', { kind: 'user' }), + assistantMsg('a1'), + userMsg('q2', { kind: 'user' }), + assistantMsg('a2'), + ]; + const turns = groupIntoTurns(msgs); + expect(turns).toHaveLength(2); + expect(turns[0]).toHaveLength(2); + expect(turns[1]).toHaveLength(2); + }); + + it('skips internal messages', () => { + const msgs: ContextMessage[] = [ + userMsg('q1', { kind: 'user' }), + userMsg('injected', { kind: 'injection', variant: 'test' }), + assistantMsg('a1'), + ]; + const turns = groupIntoTurns(msgs); + expect(turns).toHaveLength(1); + expect(turns[0]).toHaveLength(2); + }); + + it('returns empty for empty input', () => { + expect(groupIntoTurns([])).toHaveLength(0); + }); + + it('handles tool messages within a turn', () => { + const tc = makeToolCall('c1', 'Bash', { command: 'ls' }); + const msgs: ContextMessage[] = [ + userMsg('do it', { kind: 'user' }), + assistantMsg('ok', [tc]), + toolMsg('c1', 'file1.txt'), + assistantMsg('done'), + ]; + const turns = groupIntoTurns(msgs); + expect(turns).toHaveLength(1); + expect(turns[0]).toHaveLength(4); + }); +}); + +// --------------------------------------------------------------------------- +// buildExportMarkdown +// --------------------------------------------------------------------------- + +describe('buildExportMarkdown', () => { + const now = new Date('2026-05-27T10:00:00+08:00'); + + it('builds complete markdown with frontmatter and overview', () => { + const msgs: ContextMessage[] = [ + userMsg('Hello world', { kind: 'user' }), + assistantMsg('Hi there'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_abc12345xyz', + workDir: '/home/user/project', + history: msgs, + tokenCount: 1234, + now, + }); + + expect(md).toContain('---'); + expect(md).toContain('session_id: ses_abc12345xyz'); + expect(md).toContain('work_dir: /home/user/project'); + expect(md).toContain('message_count: 2'); + expect(md).toContain('token_count: 1234'); + expect(md).toContain('# Kimi Session Export'); + expect(md).toContain('## Overview'); + expect(md).toContain('Hello world'); + expect(md).toContain('## Turn 1'); + expect(md).toContain('### User'); + expect(md).toContain('### Assistant'); + expect(md).toContain('Hi there'); + }); + + it('includes thinking in collapsible details', () => { + const msgs: ContextMessage[] = [ + userMsg('question', { kind: 'user' }), + assistantMsg('answer', [], 'deep thought'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 0, + now, + }); + expect(md).toContain('
Thinking'); + expect(md).toContain('deep thought'); + }); + + it('renders an uploaded image daemon ref as [image] in the exported user message', () => { + // An uploaded image persists as a self-contained `kimi-file://` part — + // the export keeps the real text and `[image]`, never the materialization + // path or the internal url. + const msgs: ContextMessage[] = [ + { + role: 'user', + content: [ + { type: 'text', text: 'what is this? ' }, + { + type: 'image_url', + imageUrl: { url: 'kimi-file://f_1?path=%2FUsers%2Falice%2Fmedia%2Ff_1.png' }, + }, + ], + toolCalls: [], + origin: { kind: 'user' }, + }, + assistantMsg('a screenshot'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 0, + now, + }); + expect(md).toContain('what is this?'); + expect(md).toContain('[image]'); + expect(md).not.toContain('/Users/alice'); + expect(md).not.toContain('kimi-file'); + expect(md).not.toContain(' tag as user text in the export', () => { + const msgs: ContextMessage[] = [ + userMsg('', { kind: 'user' }), + assistantMsg('ok'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 0, + now, + }); + expect(md).toContain(''); + }); + + it('renders tool calls and results', () => { + const tc = makeToolCall('c1', 'Read', { file_path: '/foo.ts' }); + const msgs: ContextMessage[] = [ + userMsg('read file', { kind: 'user' }), + assistantMsg('let me read', [tc]), + toolMsg('c1', 'file contents here'), + assistantMsg('the file contains...'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 0, + now, + }); + expect(md).toContain('#### Tool Call: Read'); + expect(md).toContain('`/foo.ts`'); + expect(md).toContain('Tool Result: Read'); + expect(md).toContain('file contents here'); + }); + + it('filters out internal messages', () => { + const msgs: ContextMessage[] = [ + userMsg('hello', { kind: 'user' }), + userMsg('injected stuff', { kind: 'injection', variant: 'system-reminder' }), + assistantMsg('response'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 0, + now, + }); + expect(md).not.toContain('injected stuff'); + expect(md).toContain('hello'); + expect(md).toContain('response'); + }); + + it('counts turns correctly in overview', () => { + const msgs: ContextMessage[] = [ + userMsg('q1', { kind: 'user' }), + assistantMsg('a1'), + userMsg('q2', { kind: 'user' }), + assistantMsg('a2'), + userMsg('q3', { kind: 'user' }), + assistantMsg('a3'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 500, + now, + }); + expect(md).toContain('3 turns'); + expect(md).toContain('## Turn 1'); + expect(md).toContain('## Turn 2'); + expect(md).toContain('## Turn 3'); + }); + + it('counts tool calls in overview', () => { + const tc1 = makeToolCall('c1', 'Bash', { command: 'ls' }); + const tc2 = makeToolCall('c2', 'Read', { file_path: '/a.ts' }); + const msgs: ContextMessage[] = [ + userMsg('do things', { kind: 'user' }), + assistantMsg('ok', [tc1, tc2]), + toolMsg('c1', 'out1'), + toolMsg('c2', 'out2'), + ]; + const md = buildExportMarkdown({ + sessionId: 'ses_test', + workDir: '/tmp', + history: msgs, + tokenCount: 0, + now, + }); + expect(md).toContain('2 tool calls'); + }); +}); diff --git a/apps/kimi-code/test/tui/fullscreen-layout.test.ts b/apps/kimi-code/test/tui/fullscreen-layout.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd847d05f577bb537296f8685f60d96e98f9790d --- /dev/null +++ b/apps/kimi-code/test/tui/fullscreen-layout.test.ts @@ -0,0 +1,171 @@ +/** + * Fullscreen layout contract tests: the docked chrome must keep the editor's + * full height (top border / input / bottom border) even when the transcript + * far exceeds the screen. Regression: the dock used to participate in VStack + * shrink distribution with no minSize, so a tall transcript crushed it and + * the editor's bottom border row was clipped off screen. + */ +import { describe, expect, it, vi } from 'vitest'; + +import { Spacer, type Terminal, TuiAltScreen } from '@moonshot-ai/pi-tui'; +import { VirtualTerminal } from '../../../../packages/pi-tui/test/virtual-terminal'; + +import { GutterContainer } from '#/tui/components/chrome/gutter-container'; +import { MoonLoader } from '#/tui/components/chrome/moon-loader'; +import { AssistantMessageComponent } from '#/tui/components/messages/assistant-message'; +import { StatusMessageComponent } from '#/tui/components/messages/status-message'; +import { UserMessageComponent } from '#/tui/components/messages/user-message'; +import { ActivityPaneComponent } from '#/tui/components/panes/activity-pane'; +import { CHROME_GUTTER } from '#/tui/constant/rendering'; +import { createTUIState, type KimiTUIOptions } from '#/tui/kimi-tui'; +import type { AppState } from '#/tui/types'; + +const WIDTH = 120; +const HEIGHT = 30; + +function fakeInitialAppState(): AppState { + return { + model: 'test-model', + workDir: '/tmp/kimi-test', + additionalDirs: [], + sessionId: 'sess-1', + permissionMode: 'manual', + planMode: false, + inputMode: 'prompt', + swarmMode: false, + towerMode: false, + thinkingEffort: 'off', + contextUsage: 0, + contextTokens: 0, + maxContextTokens: 0, + isCompacting: false, + isReplaying: false, + streamingPhase: 'idle', + streamingStartTime: 0, + stepRetry: null, + theme: 'dark', + version: '0.0.0-test', + editorCommand: null, + notifications: { enabled: true, condition: 'unfocused' }, + upgrade: { autoInstall: true }, + availableModels: {}, + availableProviders: {}, + sessionTitle: null, + mcpServersSummary: null, + }; +} + +function stripAnsi(s: string): string { + // eslint-disable-next-line no-control-regex + return s.replace(/\x1b\[[0-9;?]*[a-zA-Z]|\x1b\][^\x07]*\x07/g, ''); +} + +const LONG_MARKDOWN = Array.from( + { length: 40 }, + (_, i) => `### Section ${i + 1}\n\nSome **bold** and \`code\` content in paragraph ${i + 1}.\n`, +).join('\n'); + +async function mountFullscreen(): Promise<{ + state: ReturnType; + vt: VirtualTerminal; +}> { + const opts: KimiTUIOptions = { + initialAppState: fakeInitialAppState(), + startup: { continueLast: false, yolo: false, auto: false, plan: false }, + }; + vi.stubEnv('KIMI_CODE_TUI_FULL_SCREEN', '1'); + const state = createTUIState(opts); + vi.unstubAllEnvs(); + const vt = new VirtualTerminal(WIDTH, HEIGHT); + (state.ui as { terminal: Terminal }).terminal = vt; + + // Footer is mounted into the dock after init (mirrors mountFooter()). + const footerWrap = new GutterContainer(CHROME_GUTTER, CHROME_GUTTER); + footerWrap.addChild(state.footer); + state.dockContainer?.addChild(footerWrap, { shrink: 1, minSize: 1 }); + state.editorContainer.addChild(state.editor); + state.ui.setFocus(state.editor); + state.ui.start(); + await vt.waitForRender(); + return { state, vt }; +} + +describe('fullscreen layout', () => { + it('keeps the editor bottom border visible after a streaming grow/shrink cycle', async () => { + const { state, vt } = await mountFullscreen(); + expect(state.ui).toBeInstanceOf(TuiAltScreen); + + const screenRows = (): string[] => { + const rows: string[] = []; + for (let i = 0; i < HEIGHT; i++) rows.push(stripAnsi(vt.getViewport()[i] ?? '').trimEnd()); + return rows; + }; + + // User message, then a streaming assistant message with the activity pane up. + state.transcriptContainer.addChild(new UserMessageComponent('分析下这个项目')); + const spinner = new MoonLoader(state.ui); + state.activityContainer.addChild( + new ActivityPaneComponent({ mode: 'tool', spinner, tip: 'streaming' }), + ); + const assistant = new AssistantMessageComponent(); + state.transcriptContainer.addChild(assistant); + assistant.updateContent(LONG_MARKDOWN, { transient: true }); + state.ui.requestRender(true); + await vt.waitForRender(); + + // Streaming ends: final highlight, spinner -> one-row placeholder, debug line. + assistant.updateContent(LONG_MARKDOWN, { transient: false }); + state.activityContainer.clear(); + state.activityContainer.addChild(new Spacer(1)); + state.transcriptContainer.addChild( + new StatusMessageComponent('[Debug] TTFT: 4.3s | TPS: 203 tok/s'), + ); + state.ui.requestRender(true); + await vt.waitForRender(); + + const rows = screenRows(); + const promptRow = rows.findIndex((line) => /│\s*>/.test(line)); + expect(promptRow).toBeGreaterThan(0); + expect(rows[promptRow + 1]).toContain('╰'); + + state.ui.stop(); + }); + + it('jumps between prompts with Ctrl-Shift-Up/Down (OSC 133 zones survive the chain)', async () => { + const { state, vt } = await mountFullscreen(); + + state.transcriptContainer.addChild(new UserMessageComponent('第一轮提问')); + const first = new AssistantMessageComponent(); + state.transcriptContainer.addChild(first); + first.updateContent(`回答一\n\n${LONG_MARKDOWN}`); + state.transcriptContainer.addChild(new UserMessageComponent('第二轮提问')); + const second = new AssistantMessageComponent(); + state.transcriptContainer.addChild(second); + second.updateContent(`回答二\n\n${LONG_MARKDOWN}`); + state.ui.requestRender(true); + await vt.waitForRender(); + + const alt = state.ui as TuiAltScreen; + expect(alt.isFollowingOutput).toBe(true); + + const topRows = (): string[] => + Array.from({ length: 6 }, (_, i) => stripAnsi(vt.getViewport()[i] ?? '').trimEnd()); + + // Zones anchor every user/assistant message, so the nearest previous zone + // below the fold is the current turn's assistant message, then the user + // message that started the turn. + vt.sendInput('\x1b[1;6A'); // ctrl+shift+up = previous prompt + await vt.waitForRender(); + expect(topRows()[1]).toContain('回答二'); + + vt.sendInput('\x1b[1;6A'); + await vt.waitForRender(); + expect(topRows()[1]).toContain('第二轮提问'); + + vt.sendInput('\x1b[1;6B'); // ctrl+shift+down = next prompt + await vt.waitForRender(); + expect(topRows()[1]).toContain('回答二'); + + state.ui.stop(); + }); +}); diff --git a/apps/kimi-code/test/tui/goal-queue-store.test.ts b/apps/kimi-code/test/tui/goal-queue-store.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1efba07b332f8f51d33d60919c06b51cbb6e3d1 --- /dev/null +++ b/apps/kimi-code/test/tui/goal-queue-store.test.ts @@ -0,0 +1,171 @@ +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { ErrorCodes, KimiError } from '@moonshot-ai/kimi-code-sdk'; + +import { + appendGoalQueueItem, + moveGoalQueueItem, + readGoalQueue, + removeGoalQueueItem, + restoreGoalQueueItem, + updateGoalQueueItem, +} from '#/tui/goal-queue-store'; + +const QUEUE_FILE = 'upcoming-goals.json'; + +let dir: string; + +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), 'kimi-goal-queue-')); +}); + +afterEach(async () => { + await rm(dir, { recursive: true, force: true }); +}); + +function session(sessionDir = dir) { + return { + id: 'session_test', + summary: { + sessionDir, + }, + }; +} + +async function readQueueFile() { + return JSON.parse(await readFile(join(dir, QUEUE_FILE), 'utf-8')) as unknown; +} + +describe('goal queue store', () => { + it('reads an empty queue when the file is missing', async () => { + await expect(readGoalQueue(session())).resolves.toEqual({ goals: [] }); + }); + + it('appends a trimmed upcoming goal and writes the session file', async () => { + const snapshot = await appendGoalQueueItem(session(), { objective: ' Ship release notes ' }); + + expect(snapshot.goals).toHaveLength(1); + expect(snapshot.goals[0]).toMatchObject({ objective: 'Ship release notes' }); + expect(snapshot.goals[0]?.id).toEqual(expect.any(String)); + expect(snapshot.goals[0]?.createdAt).toEqual(expect.any(String)); + expect(await readQueueFile()).toMatchObject({ + version: 1, + goals: [{ objective: 'Ship release notes' }], + }); + }); + + it('preserves concurrent appends to the same session queue', async () => { + await Promise.all( + Array.from({ length: 10 }, (_, index) => + appendGoalQueueItem(session(), { objective: `Queued goal ${index + 1}` }), + ), + ); + + const snapshot = await readGoalQueue(session()); + + expect(snapshot.goals.map((goal) => goal.objective).toSorted()).toEqual( + Array.from({ length: 10 }, (_, index) => `Queued goal ${index + 1}`).toSorted(), + ); + }); + + it('updates an upcoming goal objective', async () => { + const first = await appendGoalQueueItem(session(), { objective: 'Draft docs' }); + const goal = first.goals[0]!; + + const updated = await updateGoalQueueItem(session(), { + goalId: goal.id, + objective: ' Publish docs ', + }); + + expect(updated.goals).toHaveLength(1); + expect(updated.goals[0]).toMatchObject({ + id: goal.id, + objective: 'Publish docs', + createdAt: goal.createdAt, + }); + expect(updated.goals[0]?.updatedAt).not.toBe(goal.updatedAt); + }); + + it('removes an upcoming goal by id', async () => { + const first = await appendGoalQueueItem(session(), { objective: 'First' }); + const second = await appendGoalQueueItem(session(), { objective: 'Second' }); + + const snapshot = await removeGoalQueueItem(session(), { goalId: first.goals[0]!.id }); + + expect(snapshot.goals).toEqual([second.goals[1]]); + }); + + it('restores a removed upcoming goal at the front without duplicating it', async () => { + const first = await appendGoalQueueItem(session(), { objective: 'First' }); + await appendGoalQueueItem(session(), { objective: 'Second' }); + const removed = first.goals[0]!; + await removeGoalQueueItem(session(), { goalId: removed.id }); + + const restored = await restoreGoalQueueItem(session(), removed); + expect(restored.goals.map((goal) => goal.objective)).toEqual(['First', 'Second']); + + const deduped = await restoreGoalQueueItem(session(), removed); + expect(deduped.goals.map((goal) => goal.objective)).toEqual(['First', 'Second']); + }); + + it('moves an upcoming goal up and down', async () => { + const first = await appendGoalQueueItem(session(), { objective: 'First' }); + await appendGoalQueueItem(session(), { objective: 'Second' }); + const third = await appendGoalQueueItem(session(), { objective: 'Third' }); + + const movedUp = await moveGoalQueueItem(session(), { + goalId: third.goals[2]!.id, + direction: 'up', + }); + expect(movedUp.goals.map((goal) => goal.objective)).toEqual(['First', 'Third', 'Second']); + + const movedDown = await moveGoalQueueItem(session(), { + goalId: first.goals[0]!.id, + direction: 'down', + }); + expect(movedDown.goals.map((goal) => goal.objective)).toEqual(['Third', 'First', 'Second']); + }); + + it('rejects empty and over-long objectives', async () => { + await expect(appendGoalQueueItem(session(), { objective: ' ' })).rejects.toMatchObject({ + code: ErrorCodes.GOAL_OBJECTIVE_EMPTY, + }); + await expect(appendGoalQueueItem(session(), { objective: 'x'.repeat(4001) })).rejects.toMatchObject({ + code: ErrorCodes.GOAL_OBJECTIVE_TOO_LONG, + }); + }); + + it('normalizes malformed queue files to an empty queue', async () => { + await mkdir(dir, { recursive: true }); + await writeFile(join(dir, QUEUE_FILE), JSON.stringify({ version: 1, goals: [{ bad: true }] }), 'utf-8'); + + await expect(readGoalQueue(session())).resolves.toEqual({ goals: [] }); + await expect(readQueueFile()).resolves.toEqual({ version: 1, goals: [] }); + }); + + it('does not clear the queue file when JSON cannot be parsed', async () => { + const partial = '{"version":1,"goals":['; + await mkdir(dir, { recursive: true }); + await writeFile(join(dir, QUEUE_FILE), partial, 'utf-8'); + + await expect(readGoalQueue(session())).rejects.toThrow('Invalid JSON in goal queue'); + await expect(readFile(join(dir, QUEUE_FILE), 'utf-8')).resolves.toBe(partial); + }); + + it('throws when the session summary does not expose a session directory', async () => { + await expect(readGoalQueue({ id: 'missing', summary: undefined })).rejects.toThrow( + 'Session missing does not expose a session directory', + ); + }); + + it('throws a goal-not-found error when the target item is missing', async () => { + await expect(removeGoalQueueItem(session(), { goalId: 'missing' })).rejects.toBeInstanceOf( + KimiError, + ); + await expect(removeGoalQueueItem(session(), { goalId: 'missing' })).rejects.toMatchObject({ + code: ErrorCodes.GOAL_NOT_FOUND, + }); + }); +}); diff --git a/apps/kimi-code/test/tui/input/image-attachment-store.test.ts b/apps/kimi-code/test/tui/input/image-attachment-store.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6cf3fb45d49d61a3cefff92ec5bf51ca05e2847a --- /dev/null +++ b/apps/kimi-code/test/tui/input/image-attachment-store.test.ts @@ -0,0 +1,228 @@ +import { describe, it, expect } from 'vitest'; + +import { + ImageAttachmentStore, + formatPlaceholder, + formatVideoPlaceholder, +} from '#/tui/utils/image-attachment-store'; + +describe('ImageAttachmentStore', () => { + it('assigns monotonically increasing ids starting at 1', () => { + const s = new ImageAttachmentStore(); + const a = s.addImage(new Uint8Array([1]), 'image/png', 10, 20); + const b = s.addVideo('video/quicktime', '/tmp/sample.mov'); + expect(a.id).toBe(1); + expect(b.id).toBe(2); + }); + + it('builds the canonical placeholder string', () => { + expect(formatPlaceholder(1, 640, 480)).toBe('[image #1 (640×480)]'); + expect(formatPlaceholder(42, 3840, 2160)).toBe('[image #42 (3840×2160)]'); + }); + + it('builds video placeholders with sanitized labels', () => { + expect(formatVideoPlaceholder(1, 'sample.mov')).toBe('[video #1 sample.mov]'); + expect(formatVideoPlaceholder(2, 'bad[name]\u0000.mov')).toBe('[video #2 bad_name__.mov]'); + }); + + it('uses the video filename basename as the placeholder label', () => { + const s = new ImageAttachmentStore(); + const att = s.addVideo('video/mp4', '/tmp/clips/sample.mp4'); + expect(att.filename).toBe('sample.mp4'); + expect(att.sourcePath).toBe('/tmp/clips/sample.mp4'); + expect(att.placeholder).toBe('[video #1 sample.mp4]'); + }); + + it('get() returns stored attachment', () => { + const s = new ImageAttachmentStore(); + const bytes = new Uint8Array([9, 8, 7]); + const att = s.addImage(bytes, 'image/jpeg', 100, 200); + expect(s.get(att.id)).toBe(att); + expect(s.get(99)).toBeUndefined(); + }); + + it('keeps pasted image bytes in memory', () => { + const s = new ImageAttachmentStore(); + const bytes = new Uint8Array([9, 8, 7]); + const att = s.addImage(bytes, 'image/jpeg', 100, 200); + expect(att.bytes).toBe(bytes); + expect(att.mime).toBe('image/jpeg'); + }); + + it('completes a pending image without changing its attachment id', () => { + const s = new ImageAttachmentStore(); + const att = s.addImage(new Uint8Array([1]), 'image/png', 10, 20); + + const completed = s.completeImage(att, { + bytes: new Uint8Array([2, 3]), + mime: 'image/jpeg', + width: 30, + height: 40, + fileId: 'file-2', + }); + + expect(completed).toBe(att); + expect(att.id).toBe(1); + expect(att.bytes).toEqual(new Uint8Array([2, 3])); + expect(att.mime).toBe('image/jpeg'); + expect(att.placeholder).toBe('[image #1 (30×40)]'); + const stale = att; + s.clear(); + const fresh = s.addImage(new Uint8Array([9]), 'image/png', 2, 2); + expect(s.completeImage(stale, { + bytes: new Uint8Array([8]), + mime: 'image/png', + width: 3, + height: 3, + })).toBeUndefined(); + expect(fresh.bytes).toEqual(new Uint8Array([9])); + }); + + it('records the daemon file-store id when the paste was uploaded (v2)', () => { + const s = new ImageAttachmentStore(); + const att = s.addImage(new Uint8Array([1]), 'image/png', 10, 20, undefined, 'file-abc'); + expect(att.fileId).toBe('file-abc'); + }); + + it('leaves fileId undefined for attachments that were not uploaded', () => { + const s = new ImageAttachmentStore(); + const att = s.addImage(new Uint8Array([1]), 'image/png', 10, 20); + expect(att.fileId).toBeUndefined(); + }); + + it('clear() resets ids and empties storage', () => { + const s = new ImageAttachmentStore(); + s.addImage(new Uint8Array(), 'image/png', 10, 10, undefined, 'file-1'); + s.addImage(new Uint8Array(), 'image/png', 10, 10); + expect(s.size()).toBe(2); + expect(s.clear()).toEqual(['file-1']); + expect(s.size()).toBe(0); + const next = s.addImage(new Uint8Array(), 'image/png', 10, 10); + expect(next.id).toBe(1); + }); + + it('remove() drops a single attachment without resetting ids', () => { + const s = new ImageAttachmentStore(); + const a = s.addImage(new Uint8Array([1]), 'image/png', 10, 10); + const b = s.addImage(new Uint8Array([2]), 'image/png', 10, 10); + expect(s.size()).toBe(2); + s.remove(a.id); + expect(s.size()).toBe(1); + expect(s.get(a.id)).toBeUndefined(); + expect(s.get(b.id)).toBe(b); + // Unlike clear(), remove() must not reset the id counter. + const next = s.addImage(new Uint8Array([3]), 'image/png', 10, 10); + expect(next.id).toBe(3); + }); + + it('removeMany() drops many attachments at once', () => { + const s = new ImageAttachmentStore(); + const a = s.addImage(new Uint8Array([1]), 'image/png', 10, 10); + const b = s.addImage(new Uint8Array([2]), 'image/png', 10, 10); + const c = s.addImage(new Uint8Array([3]), 'image/png', 10, 10); + s.removeMany([a.id, c.id]); + expect(s.size()).toBe(1); + expect(s.get(b.id)).toBe(b); + expect(s.get(a.id)).toBeUndefined(); + expect(s.get(c.id)).toBeUndefined(); + }); + + it('transfers staging file ownership without dropping thumbnail bytes', () => { + const s = new ImageAttachmentStore(); + const bytes = new Uint8Array([1, 2, 3]); + const att = s.addImage(bytes, 'image/png', 10, 10, undefined, 'file-1'); + + expect(s.takeFileIds([att.id])).toEqual(['file-1']); + expect(att.fileId).toBeUndefined(); + expect(att.bytes).toBe(bytes); + expect(s.takeFileIds([att.id])).toEqual([]); + }); + + it('keeps a daemon upload until every extracted message releases it', () => { + const s = new ImageAttachmentStore(); + const att = s.addImage(new Uint8Array([1]), 'image/png', 10, 10, undefined, 'file-1'); + + s.retainFileIds([att.id]); + s.retainFileIds([att.id]); + expect(s.takeFileIds([att.id])).toEqual([]); + expect(att.fileId).toBe('file-1'); + expect(s.takeFileIds([att.id])).toEqual(['file-1']); + expect(att.fileId).toBeUndefined(); + }); + + it('releaseRetains consumes the retain but keeps the staged upload on the attachment', () => { + const s = new ImageAttachmentStore(); + const att = s.addImage(new Uint8Array([1]), 'image/png', 10, 10, undefined, 'file-1'); + + s.retainFileIds([att.id]); + s.releaseRetains([att.id]); + expect(att.fileId).toBe('file-1'); + // The retain is gone: a later take consumes the upload immediately. + expect(s.takeFileIds([att.id])).toEqual(['file-1']); + expect(att.fileId).toBeUndefined(); + }); + + it('releaseRetains leaves retains held by other submissions untouched', () => { + const s = new ImageAttachmentStore(); + const att = s.addImage(new Uint8Array([1]), 'image/png', 10, 10, undefined, 'file-1'); + + s.retainFileIds([att.id]); // submission A queues + s.retainFileIds([att.id]); // submission B queues + s.releaseRetains([att.id]); // A is recalled into the editor + s.retainFileIds([att.id]); // A's restored draft resubmits + // A's consuming turn ends: one retain (B's) is still outstanding, so the + // upload survives. + expect(s.takeFileIds([att.id])).toEqual([]); + expect(att.fileId).toBe('file-1'); + // B's turn ends: the last retain is gone, the upload is taken. + expect(s.takeFileIds([att.id])).toEqual(['file-1']); + expect(att.fileId).toBeUndefined(); + }); + + it('completeVideo lands the daemon upload id and clears the pending marker', () => { + const s = new ImageAttachmentStore(); + const att = s.addVideo('video/mp4', '/tmp/original.mp4'); + att.pending = Promise.resolve(); + + const completed = s.completeVideo(att, { fileId: 'file-v1', fileExpiresAt: 123_000 }); + + expect(completed).toBe(att); + expect(att.fileId).toBe('file-v1'); + expect(att.fileExpiresAt).toBe(123_000); + expect(att.pending).toBeUndefined(); + + // A cleared attachment is not completed — the caller deletes the upload. + s.clear(); + const stale = att; + const fresh = s.addVideo('video/mp4', '/tmp/other.mp4'); + expect(s.completeVideo(stale, { fileId: 'file-v2' })).toBeUndefined(); + expect(fresh.fileId).toBeUndefined(); + }); + + it('clear() keeps staged uploads that still have an outstanding retain', () => { + const s = new ImageAttachmentStore(); + const img = s.addImage(new Uint8Array(), 'image/png', 10, 10, undefined, 'file-1'); + const vid = s.addVideo('video/mp4', '/tmp/a.mp4'); + s.completeVideo(vid, { fileId: 'file-2' }); + + // The video's upload is still referenced by a stashed/queued draft; the + // image's is not, so only the latter comes back for deletion. + s.retainFileIds([vid.id]); + expect(s.clear()).toEqual(['file-1']); + expect(s.size()).toBe(0); + expect(img.fileId).toBe('file-1'); + }); + + it('takes a video upload through the same retain/take lifecycle as an image', () => { + const s = new ImageAttachmentStore(); + const vid = s.addVideo('video/mp4', '/tmp/a.mp4'); + s.completeVideo(vid, { fileId: 'file-v1' }); + + s.retainFileIds([vid.id]); + s.retainFileIds([vid.id]); + expect(s.takeFileIds([vid.id])).toEqual([]); + expect(vid.fileId).toBe('file-v1'); + expect(s.takeFileIds([vid.id])).toEqual(['file-v1']); + expect(vid.fileId).toBeUndefined(); + }); +}); diff --git a/apps/kimi-code/test/tui/input/image-placeholder.test.ts b/apps/kimi-code/test/tui/input/image-placeholder.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..67f5939bd2645cc5d20584444664234a671859b6 --- /dev/null +++ b/apps/kimi-code/test/tui/input/image-placeholder.test.ts @@ -0,0 +1,869 @@ +/** + * Media placeholder expansion and rewrite contracts, including dispatch-time + * fallback from expiring daemon uploads to bytes retained by the TUI. + */ + +import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync, utimesSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +import { describe, it, expect } from 'vitest'; + +import { parseDaemonFileUrl } from '@moonshot-ai/kimi-code-sdk'; + +import { KIMI_CODE_HOME_ENV } from '#/constant/app'; +import { ImageAttachmentStore } from '#/tui/utils/image-attachment-store'; +import { + extractMediaAttachments, + makeExtractionResendable, + pendingMediaIngestions, + persistOriginalImageSync, + refreshExpiringImageFileRefs, + resolveOriginalCaptions, + rewriteMediaPlaceholders, +} from '#/tui/utils/image-placeholder'; +import { getCacheDir } from '#/utils/paths'; + +function storeWith( + bytes: Uint8Array, + width = 640, + height = 480, +): { store: ImageAttachmentStore; placeholder: string } { + const store = new ImageAttachmentStore(); + const att = store.addImage(bytes, 'image/png', width, height); + return { store, placeholder: att.placeholder }; +} + +/** Point `getCacheDir()` at a fresh temp home for the duration of a test. */ +function setupTempCache(): { cleanup: () => void } { + const home = mkdtempSync(join(tmpdir(), 'kimi-home-')); + const prev = process.env[KIMI_CODE_HOME_ENV]; + process.env[KIMI_CODE_HOME_ENV] = home; + return { + cleanup: () => { + if (prev === undefined) delete process.env[KIMI_CODE_HOME_ENV]; + else process.env[KIMI_CODE_HOME_ENV] = prev; + rmSync(home, { recursive: true, force: true }); + }, + }; +} + +function makeTempDir(): string { + return mkdtempSync(join(tmpdir(), 'kimi-src-')); +} + +type VideoUrlPart = { type: 'video_url'; videoUrl: { url: string } }; + +// Prompt-attached videos are emitted as a `video_url` part whose url is a +// bare `kimi-file://` daemon reference (the paste was uploaded at paste +// time); pull the url out for assertions. +function videoUrlFromParts(parts: unknown[]): string { + const part = parts.find( + (p): p is VideoUrlPart => (p as VideoUrlPart).type === 'video_url', + ); + if (!part) throw new Error(`no video_url part found in: ${JSON.stringify(parts)}`); + return part.videoUrl.url; +} + +describe('extractMediaAttachments', () => { + it('returns no parts and hasMedia=false for plain text', () => { + const store = new ImageAttachmentStore(); + const r = extractMediaAttachments('hello world', store); + expect(r.hasMedia).toBe(false); + expect(r.parts).toEqual([]); + expect(r.imageAttachmentIds).toEqual([]); + expect(r.videoAttachmentIds).toEqual([]); + }); + + it('extracts a single matching placeholder into an image content part', () => { + const { store, placeholder } = storeWith(new Uint8Array([0xaa, 0xbb])); + const r = extractMediaAttachments(`describe ${placeholder} please`, store); + expect(r.hasMedia).toBe(true); + expect(r.imageAttachmentIds).toEqual([1]); + expect(r.parts).toEqual([ + { type: 'text', text: 'describe ' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,qrs=' } }, + { type: 'text', text: ' please' }, + ]); + }); + + it('keeps matched-placeholder order with multiple images', () => { + const store = new ImageAttachmentStore(); + const a = store.addImage(new Uint8Array([1]), 'image/png', 10, 10); + const b = store.addImage(new Uint8Array([2]), 'image/png', 20, 20); + const text = `first ${a.placeholder} then ${b.placeholder} end`; + const r = extractMediaAttachments(text, store); + expect(r.imageAttachmentIds).toEqual([1, 2]); + expect(r.parts).toEqual([ + { type: 'text', text: 'first ' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,AQ==' } }, + { type: 'text', text: ' then ' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,Ag==' } }, + { type: 'text', text: ' end' }, + ]); + }); + + it('keeps matched-placeholder order with mixed image and video attachments', () => { + const store = new ImageAttachmentStore(); + const img = store.addImage(new Uint8Array([1]), 'image/png', 10, 10); + const vid = store.addVideo('video/quicktime', '/tmp/clip.mov'); + store.completeVideo(vid, { fileId: 'file-v1' }); + const text = `first ${img.placeholder} then ${vid.placeholder} end`; + const r = extractMediaAttachments(text, store); + expect(r.imageAttachmentIds).toEqual([1]); + expect(r.videoAttachmentIds).toEqual([2]); + expect(r.parts).toEqual([ + { type: 'text', text: 'first ' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,AQ==' } }, + { type: 'text', text: ' then ' }, + { type: 'video_url', videoUrl: { url: 'kimi-file://file-v1' } }, + { type: 'text', text: ' end' }, + ]); + }); + + it('leaves unresolved (typed by hand) placeholders as literal text', () => { + const store = new ImageAttachmentStore(); + const r = extractMediaAttachments('try [image #999 (1×1)] and [video #42 clip.mov] now', store); + expect(r.hasMedia).toBe(false); + expect(r.parts).toEqual([]); + }); + + it('uses pasted image bytes in data URLs', () => { + const bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47]); + const { store, placeholder } = storeWith(bytes); + const r = extractMediaAttachments(placeholder, store); + expect(r.parts).toHaveLength(1); + expect(r.parts[0]).toEqual({ + type: 'image_url', + imageUrl: { url: 'data:image/png;base64,iVBORw==' }, + }); + }); + + it('emits a bare kimi-file video_url part for an uploaded video', () => { + const { cleanup } = setupTempCache(); + try { + const store = new ImageAttachmentStore(); + const att = store.addVideo('video/mp4', '/tmp/sample.mp4'); + store.completeVideo(att, { fileId: 'file-v1' }); + const r = extractMediaAttachments(att.placeholder, store); + expect(r.hasMedia).toBe(true); + expect(r.videoAttachmentIds).toEqual([1]); + expect(r.parts).toHaveLength(1); + const part = r.parts[0] as VideoUrlPart; + expect(part.type).toBe('video_url'); + // No cache copy and no `?path=`: the engine's prompt intake + // materializes the session copy and rewrites the reference — the part + // is self-contained. + expect(parseDaemonFileUrl(part.videoUrl.url)).toEqual({ fileId: 'file-v1' }); + expect(existsSync(getCacheDir())).toBe(false); + } finally { + cleanup(); + } + }); + + it('refuses a video whose upload is still in flight', () => { + const store = new ImageAttachmentStore(); + const att = store.addVideo('video/mp4', '/tmp/sample.mp4'); + att.pending = new Promise(() => undefined); // never settles + expect(() => extractMediaAttachments(att.placeholder, store)).toThrow( + /still uploading/, + ); + }); + + it('refuses a video whose upload failed or is missing', () => { + const store = new ImageAttachmentStore(); + const att = store.addVideo('video/mp4', '/tmp/sample.mp4'); + expect(() => extractMediaAttachments(att.placeholder, store)).toThrow( + /could not be uploaded/, + ); + }); + + it('refuses a video whose staged upload is too close to expiry', () => { + const store = new ImageAttachmentStore(); + const att = store.addVideo('video/mp4', '/tmp/sample.mp4'); + store.completeVideo(att, { + fileId: 'file-v1', + fileExpiresAt: Date.now() + 1_000, + }); + expect(() => extractMediaAttachments(att.placeholder, store)).toThrow(/expired/); + }); + + it('expands a compressed paste without a caption — captions are authored at dispatch', () => { + const store = new ImageAttachmentStore(); + const att = store.addImage(new Uint8Array([1, 2, 3]), 'image/png', 2000, 2000, { + bytes: new Uint8Array([9, 8, 7]), + width: 2600, + height: 2600, + byteLength: 3, + mime: 'image/png', + }); + + const r = extractMediaAttachments(`look ${att.placeholder}`, store); + + // Extraction stays persistence-free: no caption part, no original path. + expect(r.parts).toEqual([ + { type: 'text', text: 'look ' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,AQID' } }, + ]); + expect(att.original?.path).toBeUndefined(); + }); + + it('adds no caption for an uncompressed image attachment', () => { + const { store, placeholder } = storeWith(new Uint8Array([0xaa])); + const r = extractMediaAttachments(placeholder, store); + expect(r.parts).toHaveLength(1); + expect(r.parts[0]?.type).toBe('image_url'); + }); + + it('expands an uploaded (fileId) image into a bare kimi-file reference', () => { + const { cleanup } = setupTempCache(); + try { + const store = new ImageAttachmentStore(); + const att = store.addImage(new Uint8Array([0x89, 0x50, 0x4e, 0x47]), 'image/png', 640, 480, undefined, 'file-1'); + const r = extractMediaAttachments(`describe ${att.placeholder} please`, store); + expect(r.hasMedia).toBe(true); + expect(r.imageAttachmentIds).toEqual([1]); + // No tag text part and no `?path=`: the engine's prompt intake + // materializes the session copy and rewrites the reference with its + // path — the part is self-contained, no paired tag is authored. + expect(r.parts).toEqual([ + { type: 'text', text: 'describe ' }, + { type: 'image_url', imageUrl: { url: 'kimi-file://file-1' } }, + { type: 'text', text: ' please' }, + ]); + expect(parseDaemonFileUrl('kimi-file://file-1')).toEqual({ fileId: 'file-1' }); + // The edge stages no local copy for an uploaded image — the cache dir + // is never even created. + expect(existsSync(getCacheDir())).toBe(false); + } finally { + cleanup(); + } + }); + + it('falls back to retained bytes when an uploaded image is too close to expiry', () => { + const store = new ImageAttachmentStore(); + const att = store.addImage( + new Uint8Array([0x89, 0x50, 0x4e, 0x47]), + 'image/png', + 640, + 480, + undefined, + 'file-1', + 1_060_000, + ); + + const parts = refreshExpiringImageFileRefs( + [{ type: 'image_url', imageUrl: { url: 'kimi-file://file-1' } }], + [att.id], + store, + 1_000_000, + ); + + expect(parts).toEqual([ + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,iVBORw==' } }, + ]); + expect(att.fileId).toBeUndefined(); + expect(att.fileExpiresAt).toBeUndefined(); + }); + + it('rebuilds an uploaded image as inline bytes for a new-session resend', () => { + const { cleanup } = setupTempCache(); + try { + const bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47]); + const store = new ImageAttachmentStore(); + const att = store.addImage(bytes, 'image/png', 640, 480, undefined, 'file-1'); + const extraction = extractMediaAttachments(att.placeholder, store); + + const resend = makeExtractionResendable(extraction); + + expect(resend.imageAttachmentIds).toEqual([]); + expect(resend.parts).toContainEqual({ + type: 'image_url', + imageUrl: { url: 'data:image/png;base64,iVBORw==' }, + }); + } finally { + cleanup(); + } + }); + + it('rebuilds a compressed paste with its caption and original for a new-session resend', () => { + const dir = makeTempDir(); + try { + const store = new ImageAttachmentStore(); + const att = store.addImage( + new Uint8Array([1, 2, 3]), + 'image/png', + 2000, + 1000, + { + bytes: new Uint8Array([9, 8, 7, 6]), + width: 2600, + height: 2600, + byteLength: 4, + mime: 'image/png', + }, + 'file-1', + ); + // The session reset clears the store, so the snapshot is the only place + // the original survives — the resend must persist it into the NEW + // session's originals dir and author the caption itself. + const extraction = extractMediaAttachments(att.placeholder, store); + + const resend = makeExtractionResendable(extraction, dir); + + expect(resend.imageAttachmentIds).toEqual([]); + expect(resend.parts).toHaveLength(2); + const caption = resend.parts[0]; + if (caption?.type !== 'text') throw new Error('expected caption text part'); + expect(caption.text).toContain('Image compressed'); + expect(caption.text).toContain('2600x2600'); + const files = readdirSync(dir); + expect(files).toHaveLength(1); + expect(caption.text).toContain(join(dir, files[0]!)); + expect(resend.parts[1]).toEqual({ + type: 'image_url', + imageUrl: { url: 'data:image/png;base64,AQID' }, + }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('keeps expanding an uploaded image as a bare reference when the cache dir is broken', () => { + const { cleanup } = setupTempCache(); + try { + // A file at the cache dir path breaks local cache copies, but neither + // form stages one: an uploaded image expands to a bare reference and + // the inline (no fileId) form embeds its bytes. + writeFileSync(getCacheDir(), 'occupied'); + const store = new ImageAttachmentStore(); + const uploaded = store.addImage(new Uint8Array([1]), 'image/png', 10, 10, undefined, 'file-1'); + const plain = store.addImage(new Uint8Array([2]), 'image/png', 20, 20); + const r = extractMediaAttachments(`${uploaded.placeholder} and ${plain.placeholder}`, store); + expect(r.imageAttachmentIds).toEqual([1, 2]); + expect(r.parts).toEqual([ + { type: 'image_url', imageUrl: { url: 'kimi-file://file-1' } }, + { type: 'text', text: ' and ' }, + { type: 'image_url', imageUrl: { url: 'data:image/png;base64,Ag==' } }, + ]); + } finally { + cleanup(); + } + }); + + it('stages nothing when a later video refuses the submission', () => { + const { cleanup } = setupTempCache(); + try { + const store = new ImageAttachmentStore(); + const first = store.addVideo('video/mp4', '/tmp/first.mp4'); + store.completeVideo(first, { fileId: 'file-v1' }); + const missing = store.addVideo('video/mp4', '/tmp/missing.mp4'); + + expect(() => + extractMediaAttachments(`${first.placeholder} ${missing.placeholder}`, store), + ).toThrow(/could not be uploaded/); + // The prompt path stages no cache copies at all, so the throw leaves + // no local cleanup behind — the first video's daemon upload is owned + // by its retain, not by a staging path. + expect(existsSync(getCacheDir())).toBe(false); + } finally { + cleanup(); + } + }); +}); + +describe('resolveOriginalCaptions', () => { + function storeWithOriginal( + original?: { + bytes: Uint8Array; + width: number; + height: number; + byteLength: number; + mime: string; + path?: string; + }, + fileId?: string, + ) { + const store = new ImageAttachmentStore(); + const att = store.addImage( + new Uint8Array([1, 2, 3]), + 'image/png', + 2000, + 1000, + original, + fileId, + ); + return { store, att }; + } + + it('persists the original into the given dir and inserts the caption before the image', () => { + const dir = makeTempDir(); + try { + const originalBytes = new Uint8Array([9, 8, 7, 6]); + const { store, att } = storeWithOriginal({ + bytes: originalBytes, + width: 2600, + height: 2600, + byteLength: originalBytes.length, + mime: 'image/png', + }); + const r = extractMediaAttachments(`look ${att.placeholder}`, store); + + const resolved = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + expect(att.original?.path?.startsWith(dir)).toBe(true); + expect(readFileSync(att.original!.path!)).toEqual(Buffer.from(originalBytes)); + expect(resolved).toHaveLength(3); + const caption = resolved[1]; + if (caption?.type !== 'text') throw new Error('expected caption text part'); + expect(caption.text).toContain('Image compressed'); + expect(caption.text).toContain('2600x2600'); + expect(caption.text).toContain(att.original!.path!); + expect(resolved[2]).toEqual({ + type: 'image_url', + imageUrl: { url: 'data:image/png;base64,AQID' }, + }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('releases the in-memory original bytes once persistence succeeds', () => { + const dir = makeTempDir(); + try { + const originalBytes = new Uint8Array([9, 8, 7, 6]); + const { store, att } = storeWithOriginal({ + bytes: originalBytes, + width: 2600, + height: 2600, + byteLength: originalBytes.length, + mime: 'image/png', + }); + const r = extractMediaAttachments(att.placeholder, store); + resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + // The on-disk copy is the original from here on; the caption still + // renders the original size from the retained metadata. + expect(att.original?.bytes).toBeUndefined(); + const again = resolveOriginalCaptions( + r.parts, + r.imageAttachmentIds, + store, + dir, + ); + const caption = again[0]; + if (caption?.type !== 'text') throw new Error('expected caption text part'); + expect(caption.text).toContain('2600x2600'); + expect(caption.text).toContain('4 B'); + expect(caption.text).toContain(att.original!.path!); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('authors the caption before the bare kimi-file reference', () => { + const dir = makeTempDir(); + try { + const { store, att } = storeWithOriginal( + { bytes: new Uint8Array([9, 9]), width: 2600, height: 2600, byteLength: 2, mime: 'image/png' }, + 'file-2', + ); + const r = extractMediaAttachments(att.placeholder, store); + + const resolved = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + expect(resolved).toHaveLength(2); + const caption = resolved[0]; + if (caption?.type !== 'text') throw new Error('expected caption text part'); + expect(caption.text).toContain('Image compressed'); + expect(caption.text).toContain(att.original!.path!); + expect(resolved[1]).toEqual({ + type: 'image_url', + imageUrl: { url: 'kimi-file://file-2' }, + }); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('refreshes an already-authored caption in place instead of duplicating it', () => { + const dir = makeTempDir(); + try { + const { store, att } = storeWithOriginal({ + bytes: new Uint8Array([9]), + width: 2600, + height: 2600, + byteLength: 1, + mime: 'image/png', + }); + const r = extractMediaAttachments(att.placeholder, store); + const once = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + const twice = resolveOriginalCaptions(once, r.imageAttachmentIds, store, dir); + + expect(twice).toHaveLength(2); + expect(twice[0]?.type).toBe('text'); + expect(twice[1]?.type).toBe('image_url'); + // The content-addressed original was persisted exactly once. + expect(att.original?.path?.startsWith(dir)).toBe(true); + expect(readdirSync(dir)).toHaveLength(1); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('reuses an already-persisted original path without rewriting the file', () => { + const dir = makeTempDir(); + try { + const existing = join(dir, 'already.png'); + writeFileSync(existing, 'orig'); + const { store, att } = storeWithOriginal({ + bytes: new Uint8Array([7, 7, 7]), + width: 2600, + height: 2600, + byteLength: 3, + mime: 'image/png', + path: existing, + }); + const r = extractMediaAttachments(att.placeholder, store); + + const resolved = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + const caption = resolved[0]; + if (caption?.type !== 'text') throw new Error('expected caption text part'); + expect(caption.text).toContain(existing); + expect(readFileSync(existing, 'utf8')).toBe('orig'); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('notes an unpreserved original when persistence fails, then retries at a later dispatch', () => { + const dir = makeTempDir(); + try { + // A file where the target directory must be created breaks persistence. + const occupied = join(dir, 'occupied'); + writeFileSync(occupied, 'x'); + const { store, att } = storeWithOriginal({ + bytes: new Uint8Array([5, 5]), + width: 2600, + height: 2600, + byteLength: 2, + mime: 'image/png', + }); + const r = extractMediaAttachments(att.placeholder, store); + + const failed = resolveOriginalCaptions( + r.parts, + r.imageAttachmentIds, + store, + join(occupied, 'sub'), + ); + + const caption = failed[0]; + if (caption?.type !== 'text') throw new Error('expected caption text part'); + expect(caption.text).toMatch(/not preserved/i); + // The failure is not terminal: the path stays unset and the bytes are + // retained, so a later dispatch retries the write. + expect(att.original?.path).toBeUndefined(); + expect(att.original?.bytes).toBeDefined(); + + const retried = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + expect(att.original?.path?.startsWith(dir)).toBe(true); + const retryCaption = retried[0]; + if (retryCaption?.type !== 'text') throw new Error('expected caption text part'); + expect(retryCaption.text).toContain(att.original!.path!); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('skips the caption when ingestion landed after extraction (stale inline part)', () => { + const dir = makeTempDir(); + try { + const store = new ImageAttachmentStore(); + const rawBytes = new Uint8Array([1, 2, 3, 4]); + // Extraction raced the background ingestion: the part encodes the raw + // paste bytes… + const att = store.addImage(rawBytes, 'image/png', 2600, 2600); + const r = extractMediaAttachments(att.placeholder, store); + // …then ingestion completed, recording the compressed form. Captioning + // now would describe an image the model did not receive. + store.completeImage(att, { + bytes: new Uint8Array([1, 2, 3]), + mime: 'image/png', + width: 2000, + height: 2000, + original: { bytes: rawBytes, width: 2600, height: 2600, byteLength: 4, mime: 'image/png' }, + }); + + const resolved = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, dir); + + expect(resolved).toHaveLength(1); + expect(resolved[0]?.type).toBe('image_url'); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); + + it('leaves images without an original untouched', () => { + const { store, placeholder } = storeWith(new Uint8Array([0xaa])); + const r = extractMediaAttachments(placeholder, store); + const resolved = resolveOriginalCaptions(r.parts, r.imageAttachmentIds, store, undefined); + expect(resolved).toHaveLength(1); + expect(resolved[0]?.type).toBe('image_url'); + }); +}); + +describe('persistOriginalImageSync', () => { + it('evicts the oldest originals once the store exceeds the size cap', () => { + const dir = makeTempDir(); + try { + const first = persistOriginalImageSync(new Uint8Array(6).fill(1), 'image/png', dir); + expect(first).not.toBeNull(); + // Pin the first file far into the past so eviction order is deterministic. + const old = new Date(Date.now() - 60_000); + utimesSync(first!, old, old); + + const second = persistOriginalImageSync(new Uint8Array(6).fill(2), 'image/png', dir, 10); + + expect(second).not.toBeNull(); + expect(existsSync(first!)).toBe(false); + expect(existsSync(second!)).toBe(true); + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +}); + +describe('rewriteMediaPlaceholders', () => { + it('returns plain text untouched with hasMedia=false', () => { + const store = new ImageAttachmentStore(); + const r = rewriteMediaPlaceholders('just some args', store); + expect(r.text).toBe('just some args'); + expect(r.hasMedia).toBe(false); + expect(r.imageAttachmentIds).toEqual([]); + expect(r.videoAttachmentIds).toEqual([]); + }); + + it('rewrites an image placeholder into a cache-path image tag', () => { + const { cleanup } = setupTempCache(); + try { + const bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47]); + const { store, placeholder } = storeWith(bytes); + const r = rewriteMediaPlaceholders(`look at ${placeholder} please`, store); + expect(r.hasMedia).toBe(true); + expect(r.imageAttachmentIds).toEqual([1]); + const m = /^look at <\/image> please$/.exec(r.text); + if (!m) throw new Error(`no image tag found in: ${r.text}`); + expect(m[1]!.startsWith(getCacheDir())).toBe(true); + expect(m[1]!.endsWith('.png')).toBe(true); + expect(new Uint8Array(readFileSync(m[1]!))).toEqual(bytes); + } finally { + cleanup(); + } + }); + + it('rewrites a video placeholder into a cache-path video tag', () => { + const { cleanup } = setupTempCache(); + const srcDir = makeTempDir(); + try { + const srcVideo = join(srcDir, 'clip.mov'); + writeFileSync(srcVideo, 'video-bytes'); + const store = new ImageAttachmentStore(); + const att = store.addVideo('video/quicktime', srcVideo); + const r = rewriteMediaPlaceholders(att.placeholder, store); + expect(r.hasMedia).toBe(true); + expect(r.videoAttachmentIds).toEqual([1]); + const m = /.ro-scratch/-*`, dropped on close) and adopts the disk base there instead of aggregating a full in-RAM base. Async base reads are commit-safe via a base-swap epoch (`TextIndex.baseEpoch`): a read straddling a base commit re-reads from the fresh base and never caches a stale list. + +A healthy writer also keeps a valid generation around at runtime — the per-write WAL-growth trigger (`MiniDb.maybeAutoGenerationBuild`, 4 MiB staleness rule, throttled with failure backoff) covers the started-from-empty window the open-time kick cannot, and `close()` publishes a missing/stale generation best-effort (`buildGeneration('close')`). Load-time integrity is per-file crc32 + definition hashes — a corrupt or definition-mismatched image rebuilds only the affected index from the loaded store. The whole open path is cooperative (phase 3, main-thread relief): payload verification is chunked with yields (`readGenerationFileCheckedAsync`, `verifyFileIntegrityAsync` — same error semantics as the sync originals), the store/image map construction is sliced (`Store.bulkLoadRefsAsync` — with the active-expire timer paused for the load's duration, so a mid-load reap can never diverge the map from the not-yet-rebuilt ordered index — the async image parsers, the secondary/compound `loadImageAsync`, `TextIndex.attachImageAsync`), and the WAL-delta apply yields on primitive-op + wall-clock budgets (`walApplySlicer` — a batch frame unrolls into thousands of ops, so frame-granular yielding could never bound a slice). + +Open-time lifecycle telemetry — the `no-generation` / `generation-load` / `wal-catch-up` / `full-rebuild` / `ready` / `degraded` state machine plus per-phase wall-clock timings (image loads, postings crc, WAL scan/apply, full recovery, text rebuilds incl. their hosting mode) — lives in the `LifecycleTracker` (`src/lifecycle-status.ts`), fed by `lifecycle.ts` / `generation-loader.ts` / `recovery.ts` and read through `MiniDb.lifecycleStatus()`; `bench/open-lifecycle.ts` (`pnpm bench:open`) is the repeatable event-loop-delay / input-latency baseline over the four open paths (small corpus, large WAL delta, large full-text generation, corrupt generation). + +## Maintenance and worker builds + +Heavy maintenance runs through the unified **maintenance scheduler** (`src/maintenance.ts` — one heavy task per database at a time, queue backpressure, disk free-space preflight, deadline/cancellation, shutdown drain-or-cancel, `MiniDb.maintenanceStatus()` read model; nested submissions from inside a task run inline via AsyncLocalStorage to avoid self-deadlock). + +Full-text generation artifacts (tokenization → bounded-memory aggregation → segmented external merge → postings/dictionary/base-docs) are produced **off the main thread** by a worker build (`src/worker/text-build-core.ts`, hosted by `src/worker/text-build.ts` + `src/worker/text-build-worker.ts` — Node-native type-stripping with `execArgv: ['--experimental-transform-types']`, explicit `.ts` import specifiers in the whole worker closure; worker writes only inside the tmp generation dir, the main thread verifies (sanity + streaming crc) and swaps the live base via `TextIndex.commitRebase` after `beginRebase`; `OpenOptions.textBuildWorker: false` is the rollback switch; a missing worker file hosts the SAME bounded core inline on the main thread, while worker-slot pressure first QUEUES for a process-wide slot (`WorkerSlots.acquireBounded`, bounded by `MiniDb.textBuildSlotWaitMs`, default 30 s, abort-aware) and only a persisted drought hosts the inline core as the explicit last resort — the in-thread staged aggregation is kept only for small corpora (< 4096 docs), custom function tokenizers, and the explicit rollback). The same bounded engine (worker-or-inline + rebase, `MiniDb.boundedTextBuild`) also backs the two full-corpus initial-build entries — `createTextIndex` and the open-time loader rebuild of a corrupt/definition-mismatched image — so first-time indexing of a large existing store no longer aggregates the whole term->postings map in RAM. + +## Async read surface + +The async read surface is additive: `getAsync` / `searchAsync` / `searchBoundedAsync` / `queryAsync` (`ValueReader.readAsync`, `PostingsFile.readAsync`, byte-bounded decoded-postings cache via `TextIndexOptions.cacheBytes`); recovery scans use the async sequential scanner (`scanFrameRefsFdAsync` — windowed reads, sliced CRC, periodic yields, AbortSignal, bounded corruption-resync candidate budget shared with the sync scanner); compaction's disk-mode snapshot groups live refs by (file, offset) and reads them with bounded-concurrency async positioned reads (`src/snapshot.ts`). Read-replica catch-up (`MiniDb.catchUpFromWal`) is cooperative too: the delta scan rides the same async scanner and the apply yields on primitive-op + wall-clock budgets (`walApplySlicer`), with calls serialized per instance so overlapping catch-ups never interleave mid-apply — a replica that fell far behind no longer stalls the host loop in one synchronous scan+apply. diff --git a/packages/minidb/CHANGELOG.md b/packages/minidb/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..f46ba96d5d82074ff55a4f7bf68144fc50034c17 --- /dev/null +++ b/packages/minidb/CHANGELOG.md @@ -0,0 +1,15 @@ +# @moonshot-ai/minidb + +## 0.2.0 + +### Minor Changes + +- [#1816](https://github.com/MoonshotAI/kimi-code/pull/1816) [`44f3341`](https://github.com/MoonshotAI/kimi-code/commit/44f334191989183d21920f6867c405581347c748) Thanks [@sailist](https://github.com/sailist)! - Cluster readers of the embedded key-value engine now catch up incrementally by replaying only newly appended WAL frames after another process writes, instead of fully reopening the shard on every read; cross-process read latency drops by orders of magnitude at larger shard sizes, and readers still fall back to a full reopen after WAL rotation or truncation. + +### Patch Changes + +- [#1816](https://github.com/MoonshotAI/kimi-code/pull/1816) [`44f3341`](https://github.com/MoonshotAI/kimi-code/commit/44f334191989183d21920f6867c405581347c748) Thanks [@sailist](https://github.com/sailist)! - Harden the embedded key-value engine's durability: WAL compaction now always terminates under sustained write storms instead of chasing the tail forever, a committed write can no longer slip through a compaction rotation undetected, torn WAL tails no longer misplace later disk-mode value pointers, read-only opens never create or modify database files or compact under a live writer, corrupt index-definition files no longer force a full rebuild, stale compaction temp files are cleaned on open, and the process lock can no longer be taken over by several processes at once. + +- [#1816](https://github.com/MoonshotAI/kimi-code/pull/1816) [`44f3341`](https://github.com/MoonshotAI/kimi-code/commit/44f334191989183d21920f6867c405581347c748) Thanks [@sailist](https://github.com/sailist)! - Speed up the embedded key-value engine under stress: queries with skip/limit now stream candidates instead of decoding every match first, LRU eviction picks victims in O(1) instead of scanning every key, bursts of simultaneously expired TTL keys are drained within seconds, existence checks and size counting no longer read values when they only need metadata, and one oversized token can no longer poison the full-text index. + +- [#1816](https://github.com/MoonshotAI/kimi-code/pull/1816) [`44f3341`](https://github.com/MoonshotAI/kimi-code/commit/44f334191989183d21920f6867c405581347c748) Thanks [@sailist](https://github.com/sailist)! - Keep the embedded key-value engine writable when a WAL compaction rotation fails mid-way instead of wedging it until reopen, stop a rolled-back write from erasing a concurrently committed value for the same key, let the RESP server survive aborted connections, recover after oversized requests, and answer each pipelined command independently, and keep the previous full-text index intact when a postings rebuild fails. diff --git a/packages/minidb/DESIGN_NOTES.md b/packages/minidb/DESIGN_NOTES.md new file mode 100644 index 0000000000000000000000000000000000000000..41d18bba71937e928af6c5f0135769267ed7098c --- /dev/null +++ b/packages/minidb/DESIGN_NOTES.md @@ -0,0 +1,301 @@ +# minidb — Design Notes + +A pure-Node.js (no native addons) embedded key-value database that mixes +**Redis** (in-memory KV speed, data structures, AOF/RDB persistence) with +**SQLite** (durable single-file persistence, WAL, indexed queries). + +This document distills what we learned by reading real database source code, and +records the concrete decisions for our implementation. + +## Sources studied + +| Source | Why we read it | Key takeaways | +|---|---|---| +| **Redis** (`references/redis`) | Gold standard for in-memory KV + AOF/RDB + data structures | dict incremental rehashing, skiplist with `span`, lazy+sampled expiration, RDB framing, AOF rewrite, RESP | +| **SQLite** WAL doc (`sqlite.org/wal.html`) | WAL semantics done right | append-only changes + commit record, checkpoint, single writer / multi reader, read-degradation vs WAL size, `synchronous` FULL/NORMAL | +| **NeDB** (`references/nedb`) | Pure-JS embedded DB — closest to our stack | append-only log + tombstones + last-writer-wins replay, in-memory AVL secondary indexes, temp+rename compaction, single-concurrency executor, torn-tail tolerance | +| **Bitcask** (`references/bitcask`) | Log-structured hash KV — our storage model | entry format, in-memory keydir (key→offset), append+rotate, merge/compaction, hint-file recovery | +| **cstack/db_tutorial** (`references/db_tutorial`) | Tiny SQLite clone (paged B-tree) | page cache, B-tree node split/merge, cursor; also clarifies what a paged engine costs vs a log | + +--- + +## 1. Constraints + +- **Pure Node.js**, zero native addons. Only built-ins: `node:fs`, + `node:worker_threads`, `node:buffer`, `node:net`, etc. +- **Single-writer, many-reader** within one process (like SQLite WAL). No + multi-process locking in v1. +- Embedded library first; optional TCP server later. + +## 2. Storage model: log-structured, in-memory index + +We deliberately choose a **log-structured** engine (Bitcask/Redis-AOF style) +over a **paged B-tree** (SQLite style): + +- The db_tutorial clone shows the real cost of a paged engine: fixed page + frames + cache, in-place overwrite, node split/merge, parent pointers, + separator keys, root special-casing — and that toy *still* has no WAL, fsync + or crash recovery. That is a lot of complexity for our target. +- A log-structured store gives **sequential writes** (the fastest disk access), + trivial **recovery by replay**, and simple crash safety — at the cost of + needing an in-memory index and a compaction strategy, and range scans being + harder (we solve those with secondary indexes + a skiplist). + +So: **writes append to a log; compaction rewrites.** Reads can then be served +in one of two modes. + +We borrow Bitcask's record format, rotation, copy-out merge, and truncate-tail +recovery. In the default `valueMode: 'memory'`, we keep **values in memory** +like Redis (dataset must fit in RAM), which makes reads O(1) with zero disk +I/O. In `valueMode: 'disk'`, we follow Bitcask more closely: the store keeps +only keys/metadata plus a `(file, offset, len)` pointer, and reads value bulk +from the snapshot/WAL with synchronous positioned reads so datasets can exceed +RAM without changing the synchronous public API. `valueMode: 'auto'` chooses +between the two at startup by comparing the current snapshot/WAL size against +`maxMemoryBytes` (falling back to `memory` when no budget is set). + +## 3. On-disk record format (WAL + snapshot) + +Borrowed from Bitcask's entry layout and Redis RDB's typed, length-prefixed +encoding. Every record is a self-contained frame: + +``` + off size field + 0 2 magic = "MD" (0x4D 0x44) + 2 1 type 1=SET, 2=DEL(tombstone) + 3 1 flags reserved + 4 2 keyLen uint16 + 6 4 valLen uint32 (0 for DEL) + 10 4 metaLen uint32 (0 if none) + 14 8 expireAt int64 ms since epoch, 0 = none + 22 keyLen key + 22+k valLen value + 22+k+v metaLen meta optional metadata blob (dt columns, …) + 22+k+v+m 4 crc32 CRC-32 trailer over [type..meta] +``` + +- **Fixed 22-byte header + 4-byte CRC trailer** → a reader computes the full + frame length (`22 + keyLen + valLen + metaLen + 4`) before reading the + payload (mirrors RDB's length-prefixed idea). The layout matches Bitcask's + `[klen][vlen][key][val][crc32]` records, extended with an optional `meta` + blob for top-level datetime columns; CRC-as-trailer verifies a frame in a + single pass. +- **CRC-32** per frame → recovery detects a torn/corrupt tail and stops cleanly. + (NeDB tolerates a torn last line by ignoring it; we enforce integrity with CRC + and truncate at the first bad frame.) +- **Big-endian vs little-endian**: little-endian (matches Node/x86). + +See `src/codec.ts`. + +## 4. WAL + group commit + fsync policies + +Borrowed from Redis AOF and SQLite WAL: + +- Writes are appended to the active WAL **through a buffer**; frames accumulate + and are flushed in batches (**group commit**) → one `write` syscall covers many + ops. This is the single biggest throughput win in pure Node. +- **fsync policy** (configurable, exactly Redis's three modes): + - `always` — `fsync` after every write (safest, slowest). + - `everysec` — flush + `fsync` on a 1s timer (good default; ≤1s loss window). + - `no` — let the OS flush (fastest, may lose seconds on power loss). +- Single-writer: Node's event loop already serializes JS execution, so in-memory + index updates and WAL appends are naturally ordered. We additionally serialize + the async flush so frames never reach disk out of order (NeDB's + concurrency-1 executor is the same idea; we get it for free from the event + loop plus an explicit flush gate). + +See `src/wal.ts`. + +## 5. Snapshot + compaction + +Borrowed from Redis RDB/`BGREWRITEAOF` and Bitcask's merge. Compaction is +**non-blocking for writes**: the live WAL doubles as a Redis-style rewrite +buffer (`aof_rewrite_buf`), so the (slow) snapshot is written while writers +keep appending, and they pause only for the final rotation — bounded, but the +pause scales with the remaining tail when a write storm outruns the pre-copy. + +- When the WAL exceeds a size threshold, compact (rewrite state): + 1. **Fence.** Flush the WAL and record `baseOffset = wal.size`. Every write + durable at/before `baseOffset` is already reflected in the store + (`applyOp` runs synchronously in the same tick as `wal.append`, before the + op awaits the WAL write). + 2. **Snapshot.** Write the live store to `db.snapshot.tmp` as a sequence of + SET frames (tombstones dropped), then `fsync`. This phase is + **non-blocking**: writers keep appending to the live WAL and mutating the + store while we iterate. The snapshot need not be point-in-time — the WAL + tail below repairs any fuzziness on replay. + 3. **Pre-copy the tail.** Stream `WAL[baseOffset .. head]` into `db.wal.tmp`, + while the copy is CONVERGING: each pass must shrink the remaining delta + meaningfully, bounded by a small pass cap. Also non-blocking: post-fence + writes accumulate in the live WAL instead of a separate in-memory buffer. + Under sustained writes whose append rate approaches the copy rate the gap + stops shrinking, and looping until it was small enough would never + terminate — observed in stress testing as compactions stalling for as long + as a write storm lasted (WAL unbounded, disk amplification ~20x). Giving + up to the rotation phase is what keeps compaction live in that regime. + 4. **Rotate** (the only blocking phase): set `_rotateLock` so new writers + park, then **seal** the old WAL — post-seal appends fail fast with a + retryable error and the op re-runs against the new WAL — flush, and copy + the remaining tail in a drain loop. With the WAL sealed the head no + longer moves, so the loop provably terminates; the pause scales with the + tail the pre-copy could not drain (the same bounded end-of-rewrite pause + Redis accepts for its AOF diff flush). Finish by `rename`ing the snapshot + into place, `rename`ing the new WAL into place, and reopening it. The two + renames are ordered **snapshot-first** so a crash between them pairs the + new snapshot with the old full WAL — replaying the whole old WAL on top + of the new snapshot is idempotent for pre-fence frames and correct for + post-fence frames, so the state stays consistent. Reversing the order + would pair an old snapshot with a truncated new WAL and lose pre-fence + data. +- Reads are unaffected throughout. Writes pause only for the rotation critical + section (one flush, the remaining tail copy, two renames + two `fsyncDir`s); + the bulk snapshot + tail copy happen concurrently with writes. Recovery is + always `load snapshot + replay WAL`, last-writer-wins, which is exactly what + makes the non-point-in-time snapshot converge to the correct latest state. +- The rotation cannot slip a committed write: a writer's gate check + (`if (_rotateLock) await _rotateLock`) and its `wal.append()` are NOT in the + same synchronous segment (memory-budget checks yield microtasks in between), + so an in-flight op could previously append between the final flush and the + close and lose a resolved write into the abandoned old file. Sealing the old + WAL before the final flush closes that hole: such an op fails fast against + the sealed WAL and transparently retries against the new one. +- The snapshot encoder runs on the main thread but **yields to the event loop + every N entries** (chunked), so large snapshots stay responsive without a + Worker. Offloading the encode to a `worker_thread` is the planned + optimization; the snapshot is already consistent without it. + +See `src/snapshot.ts`. + +## 6. Recovery + +1. Load the latest `db.snapshot` if present (CRC-checked frames) → rebuild map. +2. Replay the WAL from the snapshot point → apply SET/DEL, last-writer-wins. +3. **Corruption handling** (`recovery` option): + - `resync` (default): a frame that fails CRC is **skipped** and the parser + resynchronizes to the next valid frame (scan for the `MD` magic, re-validate + with CRC). Only the corrupted bytes are lost; everything after the next + valid frame is recovered. Each lost byte range is reported in + `recoveryInfo.corruptRanges`. A torn tail (corruption reaching EOF) is + **truncated**. A random byte sequence passing magic + length + CRC-32 is + ~1/2³², so a revalidated frame is genuine. + - `strict`: stop at the first bad frame and treat the entire tail as lost (the + classic truncate-at-first-error behavior). + +Either way the database opens in a consistent state; at most the last +un-`fsync`'d records or the individually corrupt frames are lost. + +See `src/recovery.ts`. + +## 7. In-memory primary index + +- `Map`. V8's `Map` already gives us, for + free, the equivalent of Redis's **incrementally-rehashed, power-of-two, + load-factor-managed hash table** (ht_table[2] + rehashidx + SipHash). We do + not reimplement it — that is the big win of targeting Node. +- Values are stored as `Buffer` to keep the hot path allocation-light; a higher + layer handles JS-value encoding. + +## 8. Expiration (TTL) + +Directly ported from Redis: + +- **Lazy**: every `get` checks `expireAt` and deletes if past. +- **Active**: a periodic timer samples a bounded number of keys (Redis samples + ~20 per cycle under a CPU time limit) and deletes expired ones — incremental, + non-blocking, friendly to the event loop. +- A small **min-heap** of expirations lets us short-circuit when nothing is due. + +## 9. Secondary indexes + range queries + +- Equality index: `Map>` (NeDB indexes field values, + including per-element for arrays — we support the same). +- Range / order index: a **skip list** per indexed field, copied from Redis's + `zskiplist`: node `{ key, backward, level[]{forward, span} }`, max level 32, + P=0.25. The `span` field gives **O(log N) rank access** and efficient ordered + range scans (`range`, `order by`, `limit`) without a full scan. +- Unique/sparse indexes with rollback on violation (NeDB pattern). + +## 9b. Document model & query layer (MongoDB-like subset) + +Records are `{ key, value, dt1..dtN }`: + +- **key** — string ≤ 128. Kept in a hash `Map` (O(1) point) **and** a + string-ordered skip list (O(log N) range / prefix / ordered scan). +- **value** — any JSON. Queried by a zero-dep path/filter/projection engine + (`getPath`/`match`/`project`) supporting Mongo-like operators + (`$gt $in $regex $contains $and $or …`) and dot/bracket paths. +- **dt columns** — top-level datetime columns (`dt1..dtN`), each a numeric + (epoch-ms) skip list for O(log N) range. Stored in the frame's optional + `meta` blob (`{ dt }`), separate from `value`. + +Plus a **full-text inverted index** with a Latin + CJK unigram/bigram tokenizer +and TF-IDF ranking. The inverted index is **larger-than-RAM**: the bulk (every +`(doc, term)` posting) lives in an on-disk postings file (`db.text-.postings`, +delta+varint compressed, CRC-framed), while only the small term dictionary +(`Map`), per-doc lengths, and `key↔docID` maps stay in +RAM. Writes go to an in-memory `delta` and deletes set a tombstone; `search` +reads each query term's postings from disk (or a small LRU cache), merges the +delta, drops tombstones, and scores — synchronously, so `db.search()` / +`db.query()` keep their sync API. See `src/text-index.ts` and +`src/text-postings.ts`. + +`db.query(q)` composes all four: it intersects candidate key sets from the key +range, dt range, and text search, then applies the value filter, sort, skip, +limit, and projection. Indexed dimensions are fast; an unindexed value filter +degrades to a full scan (same as Mongo without an index). + +Indexes are pure derived state, rebuilt from the store on startup (definitions +persisted in `db.indexes.json` / `db.textindexes.json`). The equality/range/dt/ +compound indexes are in-memory; the full-text index keeps only its small +dictionary + metadata in memory and stores its postings on disk (rewritten from +the store on open and on compaction), so a crash never loses it — it is simply +rebuilt. + +## 10. Concurrency model + +- **Main thread**: all GET/SET/DEL and index maintenance — lock-free by virtue + of the single-threaded event loop. Snapshot encoding is chunked + yielding so + it does not starve other work. +- **Single writer** at process scope, like SQLite WAL. No multi-process locking + in v1. +- A future `worker_thread` can offload snapshot encoding / compression / heavy + CRC if needed (Node's analog of Redis's `fork()`/COW). + +## 11. Optional server + +A small **RESP-like** TCP server (length-prefixed, CRLF-framed, binary-safe — +trivial per Redis's `rio.c`) so existing Redis clients can talk to minidb. + +## 12. Module map + +``` +src/ + index.ts public API barrel; MiniDb in mini-db.ts, facets: types / + value-codec / memory-guard / backup / query-engine / + text-registry / wal-group / generation-builder(+loader) / + write-path / read-path / index-admin / lifecycle / stats + codec.ts frame encode/decode + CRC streaming parser [done] + crc32.ts table-based CRC-32 [done] + wal.ts buffered append + group commit + fsync policy + store.ts in-memory primary index + TTL (lazy + active) + snapshot.ts chunked snapshot writer (yields to event loop) + recovery.ts load snapshot + replay WAL + truncate torn tail + compaction.ts threshold checks + rewrite/rotate trigger + skiplist.ts comparator-driven skip list (string + numeric) with span + index-manager.ts value-field secondary indexes (equality + range) + compound-index.ts compound indexes (groupBy + orderBy, multiple dt columns) + dt-index.ts datetime-column range indexes (per-column skip list) + query.ts value path / Mongo-like filter / projection / sort + text-index/ full-text index (CJK n-gram + TF-IDF): in-RAM dictionary + delta + tombstones + text-postings.ts on-disk postings file (delta+varint + CRC) for the text index + lockfile.ts exclusive file lock + stale-lock recovery + read-only + server.ts optional RESP TCP server (redis-cli compatible) +``` + +## 13. Roadmap + +1. **MVP**: Map index + get/set/del + WAL (`everysec`) + recovery replay. +2. **Durability**: snapshot + WAL rewrite/compaction (Worker). +3. **Queries**: secondary indexes + skiplist range. +4. **Server**: RESP-like protocol. +5. **Extras**: eviction (LRU/LFU), compression, sharding. diff --git a/packages/minidb/README.md b/packages/minidb/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9539dda142d0f94f56bb1388c699986439d53453 --- /dev/null +++ b/packages/minidb/README.md @@ -0,0 +1,544 @@ +# minidb + +A **pure-Node.js** (zero native addons) embedded key-value database that mixes +ideas from **Redis** (in-memory KV speed, data structures, AOF-style rewrite) +and **SQLite** (durable single-file persistence, WAL, indexed queries). +Written in **TypeScript**, with strict types and zero runtime dependencies. + +> Built by studying the real source code of Redis, SQLite, NeDB, Bitcask, and a +> tiny SQLite clone — see [`DESIGN_NOTES.md`](./DESIGN_NOTES.md) for what each +> one taught us. + +## Features + +- **O(1) GET/SET** from an in-memory index (`Map`), values as bytes. +- **Optional larger-than-RAM values**: `valueMode: 'disk'` keeps only value + pointers in RAM and reads value bulk from the snapshot/WAL with synchronous + positioned reads. +- **Durable**: append-only **WAL** with group commit + three fsync policies + (`always` / `everysec` / `no`), exactly like Redis AOF. +- **Crash-safe recovery**: CRC-framed records; a torn tail from a crash is + detected and truncated automatically. +- **Snapshots + compaction** (WAL rewrite) bound disk growth and speed up + restart. +- **TTL**: lazy + active expiration (Redis-style, heap-backed). +- **Secondary indexes**: equality and **range** indexes over JSON documents, + backed by a Redis-style **skip list** with O(log N) rank/range; unique and + sparse supported; array fields indexed per element. +- **RESP server** (optional): talk to it with `redis-cli` / `ioredis`. +- **ClusterDb** (optional sharding layer): multi-process concurrent read/write + over N sharded MiniDb directories, scaling write throughput with shard count. +- **Value codecs**: `buffer`, `string`, or `json`. +- **Zero dependencies**, pure `node:*` built-ins. + +## Install / layout + +Written in **TypeScript**, zero runtime dependencies. Source is in `src/`; build +output goes to `dist/` (generated by `npm run build`). + +``` +src/ + index.ts public API barrel (re-exports; no logic) + mini-db.ts the MiniDb class (open/close, KV reads, index admin, delegates) + types.ts public option/record types (+ the internal PreparedOp) + value-codec.ts value codecs + key byte-string / atomic sidecar helpers + memory-guard.ts maxMemory facet (LRU access set, evict/reject enforce) + backup.ts online backup (write-gate fence + atomic copy) + query-engine.ts unified query facet (candidate collection, dt fast path) + text-registry.ts text-index registry facet (defs, create/drop, search) + wal-group.ts WAL group-commit + in-place recovery gating facet + generation-builder.ts persistent index generation build facet + generation-loader.ts generation load facet (image loads + WAL delta replay) + write-path.ts write path facet (set/del/batch/expire commit machinery) + read-path.ts read path facet (KV reads, scans, live-record feeds) + index-admin.ts secondary/compound index admin facet (+ open-time rebuild) + lifecycle.ts open/close/openOrRebuild/renewLock flows + stats.ts the stats object factory + codec.ts binary frame encode/decode + CRC parser + resync + crc32.ts table-based CRC-32 + wal.ts buffered append + group commit + fsync policies + store.ts in-memory index + TTL (lazy + active) + value refs + value-reader.ts synchronous positioned reads for disk-backed values + snapshot.ts chunked snapshot writer + recovery.ts load snapshot + replay WAL + resync/truncate + compaction.ts WAL rewrite / rotation + skiplist.ts comparator-driven skip list with span + index-manager.ts secondary indexes (equality + range) + dt-index.ts datetime-column indexes + query.ts jq-like value query engine + text-index/ full-text index (in-RAM dictionary + on-disk postings) + text-postings.ts on-disk postings file for the full-text index + lockfile.ts exclusive file lock + read-only + server.ts optional RESP TCP server +``` + +```bash +npm run build # compile src/ -> dist/ (JS + .d.ts) +npm run typecheck # tsc --noEmit (strict) +``` + +## Quick start (embedded) + +```ts +import { MiniDb } from 'minidb'; + +const db = await MiniDb.open({ + dir: './data', + valueCodec: 'string', // 'buffer' | 'string' | 'json' + fsyncPolicy: 'everysec', // 'always' | 'everysec' | 'no' +}); + +await db.set('hello', 'world'); +db.get('hello'); // 'world' + +await db.set('temp', 'x', { ttl: 5000 }); // expires in 5s +db.ttl('temp'); // remaining ms (-1 none, -2 missing) + +await db.del('hello'); +await db.close(); // flush + fsync + close +``` + +> Within this repo, import from `./src/index.ts` (run with `tsx`). As an installed +> package, import from `'minidb'` (the built `dist/` output). + +Re-open the same `dir` and your data is recovered from the snapshot + WAL. + +### Typed usage + +`MiniDb` is generic over the value type: + +```ts +interface User { name: string; age: number; city: string } +const db = await MiniDb.open({ dir: './data', valueCodec: 'json' }); +await db.set('u1', { name: 'Ann', age: 30, city: 'Paris' }); +const u = db.get('u1'); // User | undefined +``` + +### JSON + secondary indexes + +```js +const db = await MiniDb.open({ dir: './data', valueCodec: 'json' }); + +await db.createIndex('byCity', { field: 'city' }); // equality +await db.createIndex('byAge', { field: 'age', type: 'range' }); // range (skip list) +await db.createIndex('byMail', { field: 'email', unique: true }); // unique + +await db.set('u1', { name: 'Ann', city: 'Paris', age: 30, email: 'ann@example.com' }); +await db.set('u2', { name: 'Bob', city: 'Paris', age: 41, email: 'bob@example.com' }); + +db.findEq('byCity', 'Paris'); // [{ key:'u1', value:{...} }, { key:'u2', ... }] +db.findRange('byAge', { min: 30, max: 40, count: 10 }); +``` + +Index definitions are persisted and rebuilt from the store on startup. + +## Document model & querying (MongoDB-like subset) + +A record is: + +```js +{ key: 'user:1234', value: { ...any JSON... }, dt1..dtN: } +``` + +- **key** — string ≤ 128 chars, unique, **ordered** (range / prefix / ordered scan). +- **value** — any JSON object (jq-like filter + projection + full-text). +- **dt1..dtN** — any number of top-level **datetime columns**, each indexed for + O(log N) range queries. Pass them as `{ dt: { created: Date.now() } }` (ISO + strings or epoch ms). + +### Key scans (ordered) + +```js +db.scan({ gte: 'user:1', lte: 'user:9', limit: 100 }); // range in key order +db.prefix('user:'); // prefix scan +``` + +### Datetime column queries + +```js +await db.set('a', { n: 1 }, { dt: { created: '2024-01-01' } }); +db.dtColumns(); // ['created'] +db.dtRange('created', { gte: t0, lte: t1 }); // O(log N), [{ key, value, dt, dtValue }] +``` + +### Unified query + +`db.query(q)` composes key range, dt range, full-text, and a value filter: + +```js +db.query({ + key: { prefix: 'post:' }, + dt: { created: { gte: t0, lte: t1 } }, + text: { index: 'body', q: '北京', op: 'AND' }, + filter: { age: { $gte: 18 }, $or: [{ city: 'Paris' }, { city: 'London' }] }, + sort: { age: -1 }, + project: ['name', 'age'], + skip: 0, limit: 20, +}); +``` + +Filter operators: `$eq $ne $gt $gte $lt $lte $in $nin $regex $exists $contains +$type`, plus `$and $or $nor $not`. Paths use dot/bracket notation +(`"address.city"`, `"tags[0]"`). + +> Indexed dimensions (key / dt / text / a `createIndex`'d field) are fast; +> `db.query()` automatically uses matching equality/range value indexes for simple +> top-level predicates (including `$and`), while a value `filter` with no matching +> index falls back to a full collection scan, exactly like MongoDB without an index. + +### Full-text search + +```js +await db.createTextIndex('body', { fields: ['bio'] }); // fields optional (default: all strings) +db.search('body', 'hello 世界', { op: 'AND' }); // [{ key, value, score }] +``` + +Latin words + CJK unigram/bigram tokenization (no dictionary, zero deps), with +TF-IDF ranking. + +## API + +| Method | Description | +|---|---| +| `MiniDb.open({ dir, valueCodec?, valueMode?, fsyncPolicy?, compactThresholdBytes?, autoCompact?, activeExpireIntervalMs?, recovery?, readOnly?, onLockFail?, maxMemoryBytes?, maxMemoryPolicy? })` | Open / create a database | +| `MiniDb.restore(srcDir, destDir, opts?)` | Restore a `db.backup()` directory and open it | +| `MiniDb.openOrRebuild(opts, { onRebuild? })` | Open; on corruption, discard + reopen empty (cache use). Never deletes a live-locked db | +| `get(key)` | Decoded value or `undefined` | +| `set(key, value, { ttl? })` | Set; `ttl` in ms. Resolves per fsync policy | +| `del(key)` | Delete; returns `true` if it existed | +| `has(key)`, `size` | Membership / live key count | +| `mget([keys])`, `mset([[k,v],...])` | Batch read / write | +| `batch([{op:'set'|'del', key, value?, ttl?, dt?}])` | Atomically commit multiple ops (all-or-nothing) | +| `expire(key, ttlMs)`, `ttl(key)` | Set / read TTL | +| `createIndex(name, { field, type?, unique?, sparse? })` | Secondary index (json codec) | +| `dropIndex(name)`, `listIndexes()` | Manage indexes | +| `findEq(name, value)`, `findRange(name, opts)` | Query value indexes | +| `createCompoundIndex(name, { groupBy, orderBy, orderType? })` | Compound index (group + order, e.g. workspace + updatedAt) | +| `compoundRange(name, groupValue, opts)` | Ordered range within a group, O(log N + limit), no full sort | +| `dropCompoundIndex(name)`, `listCompoundIndexes()` | Manage compound indexes | +| `scan({ gte, gt, lte, lt, limit, reverse })` | Ordered key range scan | +| `prefix(p, limit?)` | Key prefix scan | +| `dtColumns()`, `dtRange(col, opts)` | Datetime column range query | +| `query({ key, dt, text, filter, project, sort, skip, limit })` | Unified Mongo-like query | +| `createTextIndex(name, { fields? })`, `dropTextIndex(name)` | Full-text index | +| `search(name, q, { op?, limit? })` | Full-text search | +| `compact()` | Force a snapshot + WAL rewrite now | +| `backup(destDir, { compact? })` | Write a consistent online backup directory | +| `close()` | Flush, fsync, close | + +### Durability (`fsyncPolicy`) + +| Policy | Guarantees | Relative speed | +|---|---|---| +| `always` | fsync after every flush | slowest (safest) | +| `everysec` | fsync once per second (default) | fast, ≤1s loss window | +| `no` | OS decides when to flush | fastest, may lose seconds on power loss | + +### Value storage mode (`valueMode`) + +`valueMode` controls where value bulk lives: + +```js +const db = await MiniDb.open({ + dir: './data', + valueCodec: 'json', + valueMode: 'memory', // 'memory' | 'disk' | 'auto' +}); +``` + +- `memory` (default): values are kept in RAM, Redis-style. Reads are memory-bound. +- `disk`: values stay inline in the durable snapshot/WAL, while RAM keeps only + keys, metadata, indexes, and small `{ file, off, len }` value pointers. Reads + use synchronous positioned reads, so the public API stays synchronous. This + allows value bulk to exceed RAM, at the cost of disk reads on cold `get()` + paths. +- `auto`: at startup, compare the current `db.snapshot` + `db.wal` size with + `maxMemoryBytes`. If the persisted files exceed the budget, open as `disk`; + otherwise open as `memory`. If `maxMemoryBytes` is not set, `auto` falls back + to `memory`. + +### Memory limits + +With `valueMode: 'memory'` the budget bounds keys plus values. With +`valueMode: 'disk'` it bounds the in-RAM key/metadata/index footprint, not the +value bulk. You can bound writes with an approximate memory budget: + +```js +const db = await MiniDb.open({ + dir: './data', + valueCodec: 'json', + maxMemoryBytes: 512 * 1024 * 1024, + maxMemoryPolicy: 'reject', // or 'evict-lru' +}); +``` + +`reject` throws when a write would exceed the budget; `evict-lru` durably deletes +least-recently-used keys first. In `valueMode: 'disk'`, `evict-lru` trims keys to +bound the metadata/index footprint; it does not delete value bytes from disk +because values are already stored outside RAM. `db.stats.evictions` and +`db.stats.maxMemoryRejections` track the behavior. + +The budget is tracked in **approximate logical bytes** (key + value + dt +metadata), not real JS heap usage. Actual per-key overhead is higher — on the +order of several hundred bytes per key for the Map entry, the ordered index +node, and bookkeeping — so a database of many small keys needs far more RAM +than `store.bytes` suggests. (Measured: ~0.6 KB of heap per key for tiny +records, so 1M small keys ≈ 600 MB of heap.) For millions of small keys, +prefer `valueMode: 'disk'` and/or budget accordingly. + +### Online backup / restore + +```js +await db.backup('./backup'); +const restored = await MiniDb.restore('./backup', './restored', { valueCodec: 'json' }); +``` + +`backup()` optionally compacts, then fences writes at a linearization point — +writes submitted while the backup runs reject with a `BACKUP_IN_PROGRESS` +error, and every write acknowledged before the fence is included — and copies +the snapshot, WAL, index definitions, and text postings into a sibling temp +directory that is fsync'd and atomically renamed over the destination (the +manifest, written last, is the commit marker). A failed backup leaves no +partial directory behind, and `restore()` can reopen the result. + +### Write throughput & SSD endurance + +MiniDb's write path is append-only and sequential, which is already +SSD-friendly. A few choices have an outsized effect on write amplification +and flash wear: + +- **Use batch writes.** `set()` resolves after its own flush, so + `for (const x of xs) await db.set(...)` issues one flush (and, under + `fsyncPolicy: 'always'`, one fsync) per key. Coalesce writes with + `db.batch([...])` / `db.mset([[k, v], ...])` (single atomic WAL frame) or + `await Promise.all(xs.map(x => db.set(x)))` (group commit collapses the + tick into one `writev` + one fsync). +- **Keep the default `fsyncPolicy: 'everysec'`.** It bounds fsyncs to ~1/s. + `always` is the most durable but the hardest on flash (one fsync per + flush); reserve it for data that must survive any crash. +- **Tune `compactThresholdBytes` for large datasets.** Compaction rewrites + all live data, so steady-state write amplification is roughly + `1 + liveDataBytes / compactThresholdBytes`. Raising the threshold (e.g. + 256 MiB–1 GiB) trades a larger WAL / longer recovery for less rewrite. +- **Observe it via `db.stats`.** `walBytesWritten`, `walFsyncs`, + `snapshotBytesWritten`, `compactions`, `evictions`, `maxMemoryRejections`, and + `queryIndexHits` let you measure real write volume, fsync rate, memory + pressure, and index usage under your workload. + +## RESP server (redis-cli compatible) + +```bash +npm run server -- --dir ./data --port 6379 +# or: node --import tsx src/server.ts --dir ./data --port 6379 +``` + +Then in another shell: + +```bash +redis-cli -p 6379 SET foo bar +redis-cli -p 6379 GET foo +``` + +Supported commands: `PING ECHO GET SET DEL EXISTS MGET MSET TTL DBSIZE COMPACT INFO QUIT`. + +## Benchmarks + +Measured on Node v24, 100-byte values (`npm run bench`, `N=100000`): + +| Operation | Throughput | +|---|---| +| Raw `Map` set (baseline) | ~8.6 M ops/s | +| Raw `Map` get (baseline) | ~20 M ops/s | +| **DB get** (in-memory) | **~8.0 M ops/s** | +| **DB set, fsync=everysec** (concurrent, group commit) | **~725 k ops/s** | +| **DB set, fsync=no** (concurrent, group commit) | **~396 k ops/s** | +| DB set, fsync=always (sequential, 1 fsync/op) | ~328 ops/s | +| Compact snapshot of 100k keys | ~69 ms (12 MiB) | + +Reads are memory-bound and track the raw `Map` closely. Writes are +disk-bound; **group commit** makes concurrent writes very fast, while +`synchronous` (`always`) writes pay the fsync cost one would expect from any +database. Numbers vary by machine/disk. + +Query benchmarks (N=50k docs, 200 iters each, `node bench/query.js`): + +| Query | Throughput | +|---|---| +| dt range (small result) | ~183 k ops/s | +| key prefix scan (~100 rows) | ~23 k ops/s | +| full-text search (latin / CJK) | ~350–490 ops/s | +| value filter, **no index** (full scan of 50k) | ~23 ops/s | + +Indexed dimensions (key / dt / text) are fast; an unindexed value filter scans +the whole collection — create a secondary index (`createIndex`) for hot value +predicates. + +For **ordered pagination within a group** (e.g. "sessions in a workspace ordered +by updatedAt"), use a **compound index** instead of fetching the whole group and +sorting in memory. On 10k sessions in one workspace, paginating with +`compoundRange` is ~20–40× faster than "fetch-all + sort", and stays +sub-millisecond at any offset. + +Multi-process `ClusterDb` scaling across process counts × shard counts (the +headline: shard-affinity writes scale ~linearly until the single-shard speed +is reached; uniform cross-shard traffic pays lock handoffs): + +```bash +pnpm bench:cluster # bench/cluster.ts — spawns real writer/reader processes +``` + +## Testing + +Three layers of tests, run with the built-in `node:test` runner (no deps): + +```bash +npm test # unit tests (fast) +npm run test:e2e # end-to-end stability suite +npm run test:all # both +``` + +The **unit tests** (`test/*.test.js`) cover each module: frame codec/CRC, WAL +group commit, store TTL, snapshot/compaction, recovery truncation, skip list, +secondary/full-text indexes, and the RESP server. + +The **E2E stability suite** (`test/e2e/*.test.js`) covers crash-safety and +long-run behavior: + +| File | What it verifies | +|---|---| +| `fuzz-model.test.js` | thousands of random ops match a reference model (seeded, reproducible) | +| `crash-recovery.test.js` | `kill -9` mid-write and mid-compaction → recovery is always consistent | +| `index-consistency.test.js` | key/dt/secondary/full-text indexes never drift from the store | +| `compaction-race.test.js` | heavy concurrent writes during compaction lose nothing | +| `recovery-matrix.test.js` | WAL corruption at head/mid/tail under `resync` vs `strict` | +| `durability.test.js` | `always`/`everysec`/`no` close-durability + many open/close cycles | +| `boundary.test.js` | key-length limits, large values, many keys, empty db | +| `soak.test.js` | sustained ops + heap stability (opt-in: `SOAK=30 npm run test:e2e`) | + +The **cluster suite** (`test/cluster/*.test.ts`) covers the `ClusterDb` +sharding layer: topology/routing, merged scans, lock contention and lease +renewal in-process, cross-shard indexes/compaction, true multi-process +scenarios (concurrent writers on disjoint and shared shards, live cross-process +read visibility, read/write storms) and crash takeovers (`kill -9` → contiguous +recovery + stale-lock handoff). + +## Design in one paragraph + +Log-structured engine: all writes append to a CRC-framed **WAL** (group +committed, configurable fsync); all reads hit an in-memory `Map`. When the WAL +grows past a threshold, a **snapshot** of the live keys is written and the WAL +is rotated — **non-blocking**: writers keep appending to the WAL (which doubles +as a Redis-style rewrite buffer) while the snapshot is written, and pause only +for a brief final rotation. Recovery loads the latest +snapshot then replays the WAL, truncating any torn tail. Secondary indexes use +a Redis-style skip list for range queries. See +[`DESIGN_NOTES.md`](./DESIGN_NOTES.md) for the full rationale and the +source-code study behind each choice. + +## Concurrency & multi-process + +minidb is **single-writer**. Opening a directory for writing acquires an exclusive +lock file (`db.lock`); a second writer is rejected with a `LockError`. A lock is +taken over only when its owner PID is dead (stale-lock recovery), never merely +because it is old. + +```js +// second process: throws LockError +await MiniDb.open({ dir: './data' }); + +// degrade to read-only instead of throwing +const ro = await MiniDb.open({ dir: './data', onLockFail: 'readonly' }); +ro.get('k'); // ok (point-in-time view) +await ro.set('k'); // throws "read-only mode" + +// open read-only alongside a writer +const r = await MiniDb.open({ dir: './data', readOnly: true }); +``` + +For many clients, run the **RESP server** (single minidb process, many TCP +clients) — that is the intended concurrent-access model, like Redis. + +### ClusterDb: multi-process sharding + +When several **processes** must read and write the same logical database +without a server, `ClusterDb` shards the key space over N ordinary minidb +directories (each with its own WAL, snapshot, and `db.lock`): + +```js +import { ClusterDb } from '@moonshot-ai/minidb/cluster'; + +const db = await ClusterDb.open({ dir: './data', shardCount: 16, valueCodec: 'json' }); +await db.set('user:1', { name: 'alice' }); // routed by hash to one shard +await db.mset([['a:1', v1], ['b:2', v2]]); // grouped per shard, atomic per shard +const all = await db.scan({ prefix: 'user:' }); // merged over all shards +await db.close(); +``` + +- **Writes** never meet a single global writer: each process acquires shard + write locks on demand (with retry up to `lockAcquireTimeoutMs`), caches them + briefly (`lockPoolMaxShards`, LRU), and yields a held shard after + `lockHoldMs` (default 250ms) so other processes are never starved. Throughput + scales with the number of distinct shards being written — up to the + single-shard speed of MiniDb per shard. +- **Reads** never take locks: they use the cached writer when the local + process holds the shard, else a read-only instance that is revalidated + against the shard files on every use, so a read that starts after another + process's commit always observes it. +- **Consistency**: single-key and same-shard batch ops are strongly + consistent (single writer per shard, atomic WAL frames). Cross-shard + `mset`/`mdel`/`batch` are best-effort (atomic per shard, not globally; + `crossShard: 'none'` rejects them instead). Scans merge per-shard snapshots, + so entries from different shards may reflect different points in time. +- **Indexes** (`createIndex`/`createTextIndex`) are recorded in a cluster-wide + registry and applied by every shard writer on open; `findEq`/`findRange`/ + `search` merge per-shard results (text scores are per-shard). Index + management acquires every shard writer — run it from one process, off the + hot path. +- Crash recovery is per shard: a lock left by a dead PID is taken over by the + next opener, exactly like single MiniDb. + +`crossShard: '2pc'` is reserved for a future two-phase commit and is rejected +today. Performance numbers across process/shard counts: run +`pnpm bench:cluster` (see `bench/cluster.ts`). + +For a **rebuildable cache**, use `openOrRebuild`: a corrupt cache is discarded +and reopened empty, while a live-locked db is never destroyed: + +```js +const db = await MiniDb.openOrRebuild( + { dir: cacheDir, valueCodec: 'json' }, + { onRebuild: (err) => log.warn('cache rebuilt:', err.message) }, +); +``` + +## Caveats / roadmap + +- In the default `valueMode: 'memory'`, the dataset must fit in RAM Redis-style. + Use `valueMode: 'disk'` for larger-than-RAM value bulk; cold reads then perform + synchronous positioned reads against the snapshot/WAL. +- Full-text index postings are stored on disk (larger-than-RAM); only the term + dictionary and per-doc metadata stay in memory. Postings are rebuilt from the + store on open and on compaction. Search reads postings synchronously, so a + cold, very large postings list can briefly block the event loop. +- Compaction is **non-blocking for writes**: the WAL itself acts as a + `BGREWRITEAOF`-style rewrite buffer, so the (slow) snapshot is written while + writers keep appending. Writes pause only for the final rotation (a flush, a + tail copy, and two atomic renames). A pre-copy drains most of the tail + beforehand when writes are slow enough; under sustained writes that outrun + the pre-copy, the rotation absorbs a larger tail — the same bounded + end-of-rewrite pause Redis accepts for its AOF diff flush — so compaction + always terminates. Mid-compaction crashes leave `db.*.tmp` files behind, + which the next writer open removes automatically. +- Snapshot encoding runs on the main thread (chunked + yielding); offloading to + a `worker_thread` is a planned optimization. +- Single minidb directory = single process / single writer. For multi-process + access use `ClusterDb` (above): sharding scales writes, but hash routing + means whole-range scans fan out to all shards, and uniform cross-shard write + patterns pay shard-lock handoff costs (`lockHoldMs` per yield) — workloads + with per-process shard affinity scale best. + +## Credits + +Design distilled from reading: Redis (`references/redis`), the SQLite WAL +paper, NeDB (`references/nedb`), Bitcask (`references/bitcask`), and the +cstack SQLite tutorial (`references/db_tutorial`). diff --git a/packages/minidb/package.json b/packages/minidb/package.json new file mode 100644 index 0000000000000000000000000000000000000000..99c63a9ebac26f198d23f56da114e7498ddaf556 --- /dev/null +++ b/packages/minidb/package.json @@ -0,0 +1,55 @@ +{ + "name": "@moonshot-ai/minidb", + "version": "0.2.0", + "private": true, + "description": "A pure-Node.js embedded key-value database mixing Redis-style in-memory KV with SQLite-style durable persistence (WAL + snapshot).", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/minidb#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/minidb" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "kimi", + "database", + "key-value", + "embedded", + "wal", + "snapshot" + ], + "files": [ + "dist" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./cluster": { + "types": "./src/cluster/index.ts", + "default": "./src/cluster/index.ts" + }, + "./worker-runtime": { + "types": "./src/worker-runtime.ts", + "default": "./src/worker-runtime.ts" + } + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "vitest run", + "bench": "node --import tsx bench/bench.ts", + "bench:cluster": "node --import tsx bench/cluster.ts", + "bench:open": "node --import tsx bench/open-lifecycle.ts", + "clean": "rm -rf dist" + } +} diff --git a/packages/minidb/tsconfig.json b/packages/minidb/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..8e90bc90a59278a304b2a72a470b5680041c0974 --- /dev/null +++ b/packages/minidb/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": {}, + "include": ["src"] +} diff --git a/packages/minidb/tsdown.config.ts b/packages/minidb/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..1cff5881296d385f7fecada57d36127f3b406d77 --- /dev/null +++ b/packages/minidb/tsdown.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['./src/index.ts', './src/cluster/index.ts', './src/worker-runtime.ts'], + format: ['esm'], + dts: false, + outDir: 'dist', + clean: true, + deps: { + alwaysBundle: [/^@moonshot-ai\//], + neverBundle: [], + }, +}); diff --git a/packages/minidb/vitest.config.ts b/packages/minidb/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..513a55fa67393f6e24742f84e951c691da0f51e7 --- /dev/null +++ b/packages/minidb/vitest.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'minidb', + include: ['test/**/*.test.ts'], + // Package safety floor: process-spawning e2e's and multi-thousand-op + // tests legitimately need >5s (the vitest default) on shared CI runners + // under shard parallelism. Per-test explicit timeouts still win over this. + testTimeout: 30_000, + }, +}); diff --git a/packages/node-sdk/CHANGELOG.md b/packages/node-sdk/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..c2bde4d10125cf0597be2651bda56cebcbb16f90 --- /dev/null +++ b/packages/node-sdk/CHANGELOG.md @@ -0,0 +1,311 @@ +# @moonshot-ai/kimi-code-sdk + +## 0.20.0 + +### Minor Changes + +- [#3453](https://github.com/MoonshotAI/kimi-code/pull/3453) [`411572e`](https://github.com/MoonshotAI/kimi-code/commit/411572e166edee8581ba9c5a7f1bbf6c8b405606) Thanks [@Grapedge](https://github.com/Grapedge)! - Add `suggestFiles(workDir, { query, limit })` to `KimiHarness`: session-less fuzzy file suggestions from the agent-core-v2 workspace fs service, `undefined` on the v1 engine. + +## 0.19.2 + +### Patch Changes + +- [#3098](https://github.com/MoonshotAI/kimi-code/pull/3098) [`75550c5`](https://github.com/MoonshotAI/kimi-code/commit/75550c5686cb867c0cb34bc515997d5e6305fc94) Thanks [@LCZcn96](https://github.com/LCZcn96)! - Restore live context-window usage updates after switching to the v2 engine. + +- [#3002](https://github.com/MoonshotAI/kimi-code/pull/3002) [`d723cc4`](https://github.com/MoonshotAI/kimi-code/commit/d723cc47ee43e5ca3c3c4ec2473f205d44acede2) Thanks [@7Sageer](https://github.com/7Sageer)! - Add an optional `cwd` parameter to the global MCP management methods; `verify: false` on the global MCP authorization-status listing now returns a fully offline classification instead of behaving like an omitted `verify`. + +## 0.19.1 + +### Patch Changes + +- [#2862](https://github.com/MoonshotAI/kimi-code/pull/2862) [`3d77620`](https://github.com/MoonshotAI/kimi-code/commit/3d7762003a4a35cbeb8571d471c6898a006152e6) Thanks [@liruifengv](https://github.com/liruifengv)! - Add an optional region parameter to the auth login API for selecting the OAuth login endpoint (.com or .ai deployment). + +## 0.19.0 + +### Minor Changes + +- [#2593](https://github.com/MoonshotAI/kimi-code/pull/2593) [`d833a1a`](https://github.com/MoonshotAI/kimi-code/commit/d833a1a893c4d69d96af542f40557442992085e0) Thanks [@7Sageer](https://github.com/7Sageer)! - Daemon file references no longer persist a materialization path; the display path is derived from the session media store at read time. + +- [#2934](https://github.com/MoonshotAI/kimi-code/pull/2934) [`61591bc`](https://github.com/MoonshotAI/kimi-code/commit/61591bce09f4467aa1664cb8ecb6aa6904b7accd) Thanks [@chengluyu](https://github.com/chengluyu)! - Add `session.promptWithSkills(input, skills)` to submit one prompt with multiple skill activations in a single turn (v2 engine only). + +- [#2593](https://github.com/MoonshotAI/kimi-code/pull/2593) [`d833a1a`](https://github.com/MoonshotAI/kimi-code/commit/d833a1a893c4d69d96af542f40557442992085e0) Thanks [@7Sageer](https://github.com/7Sageer)! - Add `uploadFile` for uploading media and referencing it from prompts, and an optional `promptId` on prompt submissions. Both require the v2 harness. + +- [#3026](https://github.com/MoonshotAI/kimi-code/pull/3026) [`13857f3`](https://github.com/MoonshotAI/kimi-code/commit/13857f383200881aa77dc972a8963ba421eeb2b6) Thanks [@bj456736](https://github.com/bj456736)! - Unify the MCP management surface behind a source-tagged registry, covering plugin-declared servers in `listMcpServers` and adding `getMcpServer`, `testMcpServerConfig`, runtime `addMcpServer`, `inspectAppMcpServers`, and an `oauth-expired` auth state. + +## 0.18.0 + +### Minor Changes + +- [#2351](https://github.com/MoonshotAI/kimi-code/pull/2351) [`6be2697`](https://github.com/MoonshotAI/kimi-code/commit/6be26978b123bacf1c5ebce52bbeb6f7b7ff0629) Thanks [@7Sageer](https://github.com/7Sageer)! - Add `generateSessionTitle` (v2 engine) for managed AI session titles: optional `force` regeneration over generated/custom titles and selectable conversation excerpts (`user_prompts` / `first_turn` / `digest`). Gated by the experimental `auto_session_title` flag and a managed OAuth login. + +### Patch Changes + +- [#2916](https://github.com/MoonshotAI/kimi-code/pull/2916) [`7475c2e`](https://github.com/MoonshotAI/kimi-code/commit/7475c2e2e3dd86ac0b8a8d51d4f1d233ed7df797) Thanks [@Grapedge](https://github.com/Grapedge)! - Cascade turn cancellation to the session-level /init run in the v2-backed client. + +- [#2916](https://github.com/MoonshotAI/kimi-code/pull/2916) [`7475c2e`](https://github.com/MoonshotAI/kimi-code/commit/7475c2e2e3dd86ac0b8a8d51d4f1d233ed7df797) Thanks [@Grapedge](https://github.com/Grapedge)! - Implement session deletion in the v2-backed client. + +- [#2916](https://github.com/MoonshotAI/kimi-code/pull/2916) [`7475c2e`](https://github.com/MoonshotAI/kimi-code/commit/7475c2e2e3dd86ac0b8a8d51d4f1d233ed7df797) Thanks [@Grapedge](https://github.com/Grapedge)! - Support forking a session from a specific turn in the v2-backed client, and reject forking a live session while its turn is running. + +## 0.17.0 + +### Minor Changes + +- [#2700](https://github.com/MoonshotAI/kimi-code/pull/2700) [`c9bfe8b`](https://github.com/MoonshotAI/kimi-code/commit/c9bfe8b2c8314ba4ef8806fb3b92ac654c1d1860) Thanks [@7Sageer](https://github.com/7Sageer)! - Remove the secondary-model session API `Session.applyPersistedSecondaryModel`; subagent model selection is configured via `[secondary_model]` in config.toml instead. The `SECONDARY_DERIVED_MODEL_ALIAS` export stays (the v1 engine still synthesizes the entry at runtime, so hosts keep filtering it out of model pickers), and the SDK now also exports `PRIMARY_SUBAGENT_MODEL_CHOICE`, the v2 subagent model pool's reserved `primary` key. + +### Patch Changes + +- [#2843](https://github.com/MoonshotAI/kimi-code/pull/2843) [`c212ae9`](https://github.com/MoonshotAI/kimi-code/commit/c212ae9715371c0d7939c15e664acbe0d7cf7fc3) Thanks [@sailist](https://github.com/sailist)! - Show project MCP launch targets in the workspace trust prompt, default to declining trust, and resolve fd and stty binaries to absolute paths so untrusted workspaces cannot plant bare-name executables before confirmation. + + `@moonshot-ai/kimi-code-sdk` contract change: `WorkspaceTrustInfo.gatedMcpServers` now carries structured `WorkspaceTrustMcpServerInfo` records (`name`, `transport`, and `command`/`args`/`cwd` or `url`) instead of plain strings, so SDK consumers rendering a trust prompt can show the full launch target. + +## 0.16.0 + +### Minor Changes + +- [#2826](https://github.com/MoonshotAI/kimi-code/pull/2826) [`3c9e3b2`](https://github.com/MoonshotAI/kimi-code/commit/3c9e3b297cf5286c761159c1b4d642c478fd394d) Thanks [@liruifengv](https://github.com/liruifengv)! - Add `listSessionsPage` for keyset-paged session listing (`limit` / `before`, returns `nextCursor`). The v2 engine pages through the session index; the v1 engine keeps answering with a single full page. + +### Patch Changes + +- [#2731](https://github.com/MoonshotAI/kimi-code/pull/2731) [`437a1b8`](https://github.com/MoonshotAI/kimi-code/commit/437a1b8ba1b7e0f6662bdadc669564fdc58c3f5a) Thanks [@pvzheroes125](https://github.com/pvzheroes125)! - Detect MCP servers that require OAuth without needing `auth: "oauth"` in the config. + +- [#2706](https://github.com/MoonshotAI/kimi-code/pull/2706) [`0b2e803`](https://github.com/MoonshotAI/kimi-code/commit/0b2e803d5e71afaab45212bb2ee6117ecbf8bbc9) Thanks [@pvzheroes125](https://github.com/pvzheroes125)! - Expose persisted MCP authorization status without starting an OAuth flow. + +## 0.15.3 + +### Patch Changes + +- [#2666](https://github.com/MoonshotAI/kimi-code/pull/2666) [`335588e`](https://github.com/MoonshotAI/kimi-code/commit/335588e2594a61a767ce258b34b4049a32b18fe5) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Session listings keep how the last turn ended (completed, cancelled, or failed) across server restarts, so clients can mark previously failed sessions before they are opened. + +- [#2679](https://github.com/MoonshotAI/kimi-code/pull/2679) [`7b2784b`](https://github.com/MoonshotAI/kimi-code/commit/7b2784b9b7bf4749058da48923ecbbc8019eb7af) Thanks [@liruifengv](https://github.com/liruifengv)! - Subagent lifecycle events and background task info now carry the subagent's bound model and thinking effort. + +## 0.15.2 + +### Patch Changes + +- [#2601](https://github.com/MoonshotAI/kimi-code/pull/2601) [`75fe068`](https://github.com/MoonshotAI/kimi-code/commit/75fe068a01261ff6b34f176530b338ec6a24918e) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Fix built-in capability availability and installed status in `/plugins`, preserve legacy WebBridge skills as backups during updates, and prevent Computer Use updates from duplicating or disconnecting MCP servers. + +## 0.15.1 + +### Patch Changes + +- [#2567](https://github.com/MoonshotAI/kimi-code/pull/2567) [`98ef0f0`](https://github.com/MoonshotAI/kimi-code/commit/98ef0f0b2ffaef84903b9c116ada0eeb4c8e9a6c) Thanks [@7Sageer](https://github.com/7Sageer)! - Fix v1 replay ignoring v2 `profile.bind` records, which made sessions resumed from CLI-created wires lose their tool allowlist and send requests without `tools`. + +## 0.15.0 + +### Minor Changes + +- [#2382](https://github.com/MoonshotAI/kimi-code/pull/2382) [`40172c7`](https://github.com/MoonshotAI/kimi-code/commit/40172c7ca96ca981b043b793588dd32e898979fa) Thanks [@liruifengv](https://github.com/liruifengv)! - Rename `userAgentProduct` to `productName` and require `platform` in the host identity options exposed by the SDK. + +## 0.14.0 + +### Minor Changes + +- [#1735](https://github.com/MoonshotAI/kimi-code/pull/1735) [`ce0e3ce`](https://github.com/MoonshotAI/kimi-code/commit/ce0e3ceb04223bdaad8e8931bad46eff561055b6) Thanks [@7Sageer](https://github.com/7Sageer)! - Add global tool gating to constrain which tools agents may use, with a per-session override (v2 engine only). + +### Patch Changes + +- [#2030](https://github.com/MoonshotAI/kimi-code/pull/2030) [`ec88d35`](https://github.com/MoonshotAI/kimi-code/commit/ec88d352e8f4dc5e8ffd1212f016138458f69893) Thanks [@RealKai42](https://github.com/RealKai42)! - Fix catalog-imported Claude models being wrongly locked into always-on thinking, and stop offering a misleading thinking Off option for models that cannot truly disable reasoning (such as Gemini 3). Also normalizes configured thinking effort values and unifies context-usage reporting. + +- [#2015](https://github.com/MoonshotAI/kimi-code/pull/2015) [`b5efba7`](https://github.com/MoonshotAI/kimi-code/commit/b5efba7abcaf4041f81ec520097a61e6546e8c50) Thanks [@RealKai42](https://github.com/RealKai42)! - Import many more providers from the models.dev catalog: vendor SDKs like xai and openrouter now import instead of being refused (with a "guessed" note), deprecated and alpha models are filtered out, per-model gateway protocol and endpoint overrides are honored, and context limits are correct (input limit for compaction, total window for completion). Imports lacking a usable endpoint now ask for one via `--base-url` or a prompt. + +- [#1976](https://github.com/MoonshotAI/kimi-code/pull/1976) [`e458323`](https://github.com/MoonshotAI/kimi-code/commit/e45832398d0d9cad98dbad1cbf1e5b103a20aace) Thanks [@liruifengv](https://github.com/liruifengv)! - Improve TUI performance and resume speed for long-running sessions. + +## 0.13.4 + +### Patch Changes + +- [#1769](https://github.com/MoonshotAI/kimi-code/pull/1769) [`d1ca65e`](https://github.com/MoonshotAI/kimi-code/commit/d1ca65e1de189617e9edbc54010e62d472a1de3d) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Support in-process editor hosts with session lifecycle, context, MCP configuration, and cross-platform session storage APIs. + +## 0.13.3 + +### Patch Changes + +- [#1488](https://github.com/MoonshotAI/kimi-code/pull/1488) [`7bd29ab`](https://github.com/MoonshotAI/kimi-code/commit/7bd29ab0117a1c15691404f411fd67f511bbb897) Thanks [@starquakee](https://github.com/starquakee)! - Rename the dynamic tool loading model capability from `select_tools` to `dynamically_loaded_tools`. + +## 0.13.2 + +### Patch Changes + +- [#1501](https://github.com/MoonshotAI/kimi-code/pull/1501) [`b91099e`](https://github.com/MoonshotAI/kimi-code/commit/b91099ed7a2590d1afa4d6e3675671da52b7661c) Thanks [@liruifengv](https://github.com/liruifengv)! - Display Extra Usage (fuel pack) balance in `/usage` and `/status` commands. + +## 0.13.1 + +### Patch Changes + +- [#1460](https://github.com/MoonshotAI/kimi-code/pull/1460) [`474ce28`](https://github.com/MoonshotAI/kimi-code/commit/474ce289dd39aa42d1a77a9a2e15531aee49aa15) Thanks [@RealKai42](https://github.com/RealKai42)! - Raise the image downscale cap from 2000px to 3000px, and fix swapped width/height for EXIF-rotated (portrait) photos in compression captions and media read notes so region readback coordinates map correctly. + +## 0.13.0 + +### Minor Changes + +- [#1369](https://github.com/MoonshotAI/kimi-code/pull/1369) [`f0896a5`](https://github.com/MoonshotAI/kimi-code/commit/f0896a53b01f7e5b9bf5b8f93d2cd7387d765f07) Thanks [@starquakee](https://github.com/starquakee)! - Add experimental progressive tool disclosure (`select_tools`). When the `tool-select` experimental flag is on and the active model declares the `select_tools` capability, MCP tool schemas stay out of the request's top-level `tools[]` (preserving the provider prompt cache); the model loads tools on demand by exact name via the new built-in `select_tools` tool, guided by `/` announcements. Off by default and inert on models without the capability — behavior is unchanged until a supporting model is catalogued. The SDK additionally maps the `select_tools` capability when building model aliases from a catalog and reports the new flag through `getExperimentalFeatures()`. + +## 0.12.1 + +### Patch Changes + +- [#1349](https://github.com/MoonshotAI/kimi-code/pull/1349) [`e9db9ca`](https://github.com/MoonshotAI/kimi-code/commit/e9db9cafcf7a0d26122b2cac247d866d7724fd7a) - Record model response ids in session wire logs to make individual model requests easier to trace. + +## 0.12.0 + +### Minor Changes + +- [#1243](https://github.com/MoonshotAI/kimi-code/pull/1243) [`ace7901`](https://github.com/MoonshotAI/kimi-code/commit/ace79010669d19ad175bc25443b6efb41ca2e2ac) - Automatically compress oversized images before they reach the model. Whatever the source — pasted into the CLI, uploaded from the web/desktop client, sent over ACP, read via `ReadMediaFile`, or returned by an MCP tool — images are downsampled (longest edge ≤ 2000px) and re-encoded to fit a per-image byte budget, cutting vision-token cost and avoiding provider image-size errors. Screenshots stay lossless PNG and only degrade to JPEG when the byte budget cannot otherwise be met. Compression runs as an input-stage step at each ingestion point (while the content part is built), and guards against decompression bombs by skipping absurdly large pixel/byte payloads before decoding. Best-effort: if it fails for any reason the original image is sent unchanged. + +## 0.11.0 + +### Minor Changes + +- [#1132](https://github.com/MoonshotAI/kimi-code/pull/1132) [`108299b`](https://github.com/MoonshotAI/kimi-code/commit/108299be3cdffc31a23f64efd3ff5ba50976b412) - Refactor the thinking effort system + +## 0.10.1 + +### Patch Changes + +- [#1120](https://github.com/MoonshotAI/kimi-code/pull/1120) [`e736349`](https://github.com/MoonshotAI/kimi-code/commit/e736349a7c8ff55b73e05cc0192dfaf0114745fa) - Add optional feedback attachments for diagnostic logs and codebase context. + +## 0.10.0 + +### Minor Changes + +- [#812](https://github.com/MoonshotAI/kimi-code/pull/812) [`c0eeca2`](https://github.com/MoonshotAI/kimi-code/commit/c0eeca24692edd736eecd3c2541d7566bac9f80f) - Added the ability to add extra workspace directories: + + - Use the `/add-dir ` command to add extra working directories to the current session, or remember them for the project. + - Use `kimi --add-dir ` to add them on startup. + - Project-level local config is now managed in `.kimi-code/local.toml`; we recommend adding it to your `.gitignore`. + +### Patch Changes + +- [#821](https://github.com/MoonshotAI/kimi-code/pull/821) [`ba64072`](https://github.com/MoonshotAI/kimi-code/commit/ba64072559c1e9bb3447ede39991ac2e8bdb7645) - Allow long-running foreground commands and subagents to be moved into background tasks with Ctrl+B, and inspect them via the `/tasks` panel. + +## 0.9.4 + +### Patch Changes + +- [#838](https://github.com/MoonshotAI/kimi-code/pull/838) [`843a731`](https://github.com/MoonshotAI/kimi-code/commit/843a731097fc18b2e41ab0405b5fbcb6149ba55c) - Show the underlying connection error when OAuth token refresh fails after internal retries, instead of prompting for login. Token refresh failures are no longer re-retried at the agent loop level. + +- [#625](https://github.com/MoonshotAI/kimi-code/pull/625) [`9a8fea5`](https://github.com/MoonshotAI/kimi-code/commit/9a8fea5c85177cd887896108c05ba9e174f28250) - Add host-side config helpers `loadRuntimeConfigSafe` and `resolveConfigPath` for inspecting config without spinning up a full KimiCore. + +## 0.9.3 + +### Patch Changes + +- [#689](https://github.com/MoonshotAI/kimi-code/pull/689) [`8d251f8`](https://github.com/MoonshotAI/kimi-code/commit/8d251f8ab44ead65f6c1bb264980ee7d075142ad) - Drop invalid config.toml sections with a warning instead of failing to start. + +## 0.9.2 + +### Patch Changes + +- [#648](https://github.com/MoonshotAI/kimi-code/pull/648) [`54302ad`](https://github.com/MoonshotAI/kimi-code/commit/54302ad612294056a47ada74b76737f2284861b5) - Prevent overlapping interactive agent requests from using the wrong active agent. + +## 0.9.1 + +### Patch Changes + +- [#591](https://github.com/MoonshotAI/kimi-code/pull/591) [`e48234a`](https://github.com/MoonshotAI/kimi-code/commit/e48234af576e41e630736450c66b690226707bc3) - Fix Windows builds and development launches that could fail when package binaries resolve to command shims. + +## 0.9.0 + +### Minor Changes + +- [#487](https://github.com/MoonshotAI/kimi-code/pull/487) [`4d11394`](https://github.com/MoonshotAI/kimi-code/commit/4d113949c8e906c20c7188817926f44786653923) - Honor the standard `HTTP_PROXY` / `HTTPS_PROXY` / `ALL_PROXY` / `NO_PROXY` environment variables, including SOCKS proxies, for all outbound traffic. + +- [#424](https://github.com/MoonshotAI/kimi-code/pull/424) [`72c4b0a`](https://github.com/MoonshotAI/kimi-code/commit/72c4b0adaa6ae0466875cd8e4066c42456195f21) - Add the `/swarm` command for running agent swarms with live progress and rate-limit-aware retries. + +### Patch Changes + +- [#395](https://github.com/MoonshotAI/kimi-code/pull/395) [`879a7ee`](https://github.com/MoonshotAI/kimi-code/commit/879a7eeb33a8bedf18779d74a00d78369dae3db5) - Fix ACP slash skill routing, bootstrap context reads, file and permission edge cases, subagent event handling, and stale-file edit messaging. + +- [#552](https://github.com/MoonshotAI/kimi-code/pull/552) [`db82e33`](https://github.com/MoonshotAI/kimi-code/commit/db82e33a20fd1ec204672df4ba5bc38800ce8dea) - Fix goal resume behavior by restoring goal state from agent records. + +## 0.8.0 + +### Minor Changes + +- [#420](https://github.com/MoonshotAI/kimi-code/pull/420) [`86a42a2`](https://github.com/MoonshotAI/kimi-code/commit/86a42a26a1e01f1748a937031fa76ebeaa1e28a8) - Add persistent experimental feature toggles and a TUI panel that applies confirmed changes by reloading the current session. + +- [#383](https://github.com/MoonshotAI/kimi-code/pull/383) [`15d71b5`](https://github.com/MoonshotAI/kimi-code/commit/15d71b5130d949c35d9dc2641e807e08d72dce48) - Add /reload to reload the current session and apply updated config files, plus /reload-tui to reload only TUI preferences. + +- [#431](https://github.com/MoonshotAI/kimi-code/pull/431) [`6a4e4c7`](https://github.com/MoonshotAI/kimi-code/commit/6a4e4c75d4bf6db3fefbb5c115d7a7c324bcae16) - Add a doctor command for validating Kimi Code configuration files. + +### Patch Changes + +- [#399](https://github.com/MoonshotAI/kimi-code/pull/399) [`232ed87`](https://github.com/MoonshotAI/kimi-code/commit/232ed874d41de777e6ff9c539ac22d830d0b5c3a) - Keep managed OAuth credentials scoped to their configured authentication and API endpoints. + +- [#430](https://github.com/MoonshotAI/kimi-code/pull/430) [`be0da5f`](https://github.com/MoonshotAI/kimi-code/commit/be0da5ff39641e117d60045a43a7d5d2e0b85b75) - Fail early when Git Bash is missing on Windows before starting CLI sessions. + +## 0.7.0 + +### Minor Changes + +- [#338](https://github.com/MoonshotAI/kimi-code/pull/338) [`ba7dd73`](https://github.com/MoonshotAI/kimi-code/commit/ba7dd736a3b295b2a29c229a944208c232d51458) - Add `/btw` for side-channel conversations without steering the active main turn. + +- [#339](https://github.com/MoonshotAI/kimi-code/pull/339) [`a6b16ce`](https://github.com/MoonshotAI/kimi-code/commit/a6b16ce6b4bdc20ed33888975c7da7ff1919e22f) - Allow SDK runtime creation to use a separate RPC client while preserving local CLI startup. + +## 0.6.0 + +### Minor Changes + +- [#270](https://github.com/MoonshotAI/kimi-code/pull/270) [`ac37d74`](https://github.com/MoonshotAI/kimi-code/commit/ac37d7448458fdb73fbe00e35856dcf44a13f734) - Add experimental goal mode for longer tasks that need more than one turn. Turn it on with `KIMI_CODE_EXPERIMENTAL_GOAL_COMMAND=1` before you start Kimi. + + Use `/goal ` in the TUI when you want Kimi to keep working on one task across turns. For example: + + ```text + /goal Fix the failing checkout test + ``` + + Kimi shows the goal in the TUI and keeps progress visible while it works. Use `/goal status`, `/goal pause`, `/goal resume`, `/goal cancel`, and `/goal replace ` to manage the goal. This feature is still experimental. Try it and tell us what would make it more useful. + +- [#315](https://github.com/MoonshotAI/kimi-code/pull/315) [`191059d`](https://github.com/MoonshotAI/kimi-code/commit/191059d40049d3bfd07661ac03bb961eac1407f7) - Add background structured questions so agents can continue while waiting for user answers. + +### Patch Changes + +- [#145](https://github.com/MoonshotAI/kimi-code/pull/145) [`d912053`](https://github.com/MoonshotAI/kimi-code/commit/d912053b0d3983f4e67450c347616086cfbd1fe7) - Fix Git Bash path detection on Windows by also searching `usr\bin\bash.exe` locations, which is where bash lives in many Git for Windows installations where `bin\bash.exe` does not exist. + +## 0.5.0 + +### Minor Changes + +- [#204](https://github.com/MoonshotAI/kimi-code/pull/204) [`ee69d0a`](https://github.com/MoonshotAI/kimi-code/commit/ee69d0ac29f56bde4957c14767d7ca436697d9cf) - Render scheduled reminders distinctly in the TUI, expose cron fired events to SDK clients, and report cron fire times with local timezone offsets. + +## 0.4.0 + +### Minor Changes + +- [#221](https://github.com/MoonshotAI/kimi-code/pull/221) [`bab2da7`](https://github.com/MoonshotAI/kimi-code/commit/bab2da7b1c785d6deba25decb1411f8f5a70de8c) - Install plugins directly from GitHub repository URLs, and surface each install's origin and trust level (kimi-official, curated, third-party) in the plugin manager. + +- [#118](https://github.com/MoonshotAI/kimi-code/pull/118) [`8913440`](https://github.com/MoonshotAI/kimi-code/commit/891344054111a05171963cfa524ef749c2855321) - Support querying sessions by sessionId or workDir in listSessions, and show a helpful cd command when resuming a session from a different working directory. + +### Patch Changes + +- [#221](https://github.com/MoonshotAI/kimi-code/pull/221) [`bab2da7`](https://github.com/MoonshotAI/kimi-code/commit/bab2da7b1c785d6deba25decb1411f8f5a70de8c) - Restrict plugin trust badges to Kimi-hosted plugin CDN URL patterns. + +## 0.3.0 + +### Minor Changes + +- [#119](https://github.com/MoonshotAI/kimi-code/pull/119) [`ebf6e81`](https://github.com/MoonshotAI/kimi-code/commit/ebf6e8181ea20a0fcf6a609195ccf5b6cc2a665a) - Add user-global plugin installation, interactive plugin management, plugin-provided skills, and plugin-owned MCP servers. + +- [#113](https://github.com/MoonshotAI/kimi-code/pull/113) [`028d069`](https://github.com/MoonshotAI/kimi-code/commit/028d069b12d8377c5c307b94f11f02233d9c0a26) - Add `/export-md` slash command to export the current session as a Markdown file. + +### Patch Changes + +- [#105](https://github.com/MoonshotAI/kimi-code/pull/105) [`d599183`](https://github.com/MoonshotAI/kimi-code/commit/d599183c8eccea813d7aa5ddd974e72139cbb63c) - Enhance `kimi export` to include more diagnostic information in the manifest. + +## 0.2.1 + +### Patch Changes + +- [#70](https://github.com/MoonshotAI/kimi-code/pull/70) [`d95b013`](https://github.com/MoonshotAI/kimi-code/commit/d95b01342a7921f0863ceb37abad7984d0245509) - Preserve catalog-declared interleaved reasoning fields for OpenAI-compatible models configured through `/connect`. + +## 0.2.0 + +### Minor Changes + +- [#30](https://github.com/MoonshotAI/kimi-code/pull/30) [`a200a29`](https://github.com/MoonshotAI/kimi-code/commit/a200a297ac8986ec4baa8d2cdc881ef71bc3abfc) - Add a `/connect` command that configures a provider and model from a model catalog. + +### Patch Changes + +- [#33](https://github.com/MoonshotAI/kimi-code/pull/33) [`ab4bd09`](https://github.com/MoonshotAI/kimi-code/commit/ab4bd090825cffbd7ab656b47840b0060d6cf601) - Report the macOS product version in OAuth device information instead of the Darwin kernel version. + +- [#49](https://github.com/MoonshotAI/kimi-code/pull/49) [`cf2227e`](https://github.com/MoonshotAI/kimi-code/commit/cf2227e8a5222ad9bd1167b573b62599d0efd906) - Resume sessions with a newer wire protocol version instead of failing. A warning is now shown in the TUI and records are replayed without migration. diff --git a/packages/node-sdk/README.md b/packages/node-sdk/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dbf7790138f18a8d3be9909ce9fe47cf53579258 --- /dev/null +++ b/packages/node-sdk/README.md @@ -0,0 +1,11 @@ +# @moonshot-ai/kimi-code-sdk + +The TypeScript SDK for Kimi Code + +Part of the [Kimi Code](https://github.com/MoonshotAI/kimi-code) monorepo. + +See the main repository for documentation, issues, and contribution guidelines. + +## License + +MIT diff --git a/packages/node-sdk/api-extractor.json b/packages/node-sdk/api-extractor.json new file mode 100644 index 0000000000000000000000000000000000000000..f198b83344b9137988b6463f633b45cf461b5482 --- /dev/null +++ b/packages/node-sdk/api-extractor.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "/.tmp-api-extractor/dts/node-sdk/src/index.d.ts", + "bundledPackages": [ + "@moonshot-ai/kaos", + "@moonshot-ai/kimi-code-oauth", + "@moonshot-ai/kosong" + ], + "compiler": { + "tsconfigFilePath": "/tsconfig.api-extractor.json", + "skipLibCheck": true + }, + "apiReport": { + "enabled": false + }, + "docModel": { + "enabled": false + }, + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/dist/index.d.mts", + "omitTrimmingComments": true + }, + "tsdocMetadata": { + "enabled": false + }, + "messages": { + "extractorMessageReporting": { + "ae-forgotten-export": { + "logLevel": "none" + }, + "ae-missing-release-tag": { + "logLevel": "none" + }, + "ae-unresolved-link": { + "logLevel": "none" + } + }, + "tsdocMessageReporting": { + "tsdoc-escape-greater-than": { + "logLevel": "none" + }, + "tsdoc-escape-right-brace": { + "logLevel": "none" + }, + "tsdoc-malformed-inline-tag": { + "logLevel": "none" + } + } + } +} diff --git a/packages/node-sdk/package.json b/packages/node-sdk/package.json new file mode 100644 index 0000000000000000000000000000000000000000..756a96cf2800d117cb1cd6b4346c21e0a1617a3f --- /dev/null +++ b/packages/node-sdk/package.json @@ -0,0 +1,70 @@ +{ + "name": "@moonshot-ai/kimi-code-sdk", + "version": "0.20.0", + "private": true, + "description": "TypeScript SDK for the Kimi Code Agent", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/node-sdk#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/node-sdk" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "kimi", + "sdk", + "typescript", + "agent", + "api" + ], + "files": [ + "dist", + "README.md" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "default": "./dist/index.mjs" + } + }, + "provenance": true + }, + "scripts": { + "build": "tsdown && pnpm run build:dts", + "build:dts": "node scripts/build-dts.mjs", + "typecheck": "tsc -p tsconfig.json --noEmit", + "clean": "rm -rf dist .tmp-api-extractor" + }, + "dependencies": { + "@antfu/utils": "^9.3.0", + "smol-toml": "^1.6.1", + "yazl": "^3.3.1", + "zod": "^4.3.6" + }, + "devDependencies": { + "@moonshot-ai/agent-core-v2": "workspace:^", + "@moonshot-ai/kaos": "workspace:^", + "@moonshot-ai/kimi-code-oauth": "workspace:^", + "@moonshot-ai/klient": "workspace:^", + "@moonshot-ai/kosong": "workspace:^", + "@types/yazl": "^2.4.6", + "jimp": "^1.6.1" + } +} diff --git a/packages/node-sdk/tsconfig.api-extractor.json b/packages/node-sdk/tsconfig.api-extractor.json new file mode 100644 index 0000000000000000000000000000000000000000..eeccd7a89d402c111acda0c3864ad89bf1e838a4 --- /dev/null +++ b/packages/node-sdk/tsconfig.api-extractor.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noEmit": true, + "skipLibCheck": true + }, + "include": [".tmp-api-extractor/dts/**/*.d.ts"] +} diff --git a/packages/node-sdk/tsconfig.dts.json b/packages/node-sdk/tsconfig.dts.json new file mode 100644 index 0000000000000000000000000000000000000000..2887509c7e33fc7db5e69fb5d507fca9c5b26079 --- /dev/null +++ b/packages/node-sdk/tsconfig.dts.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": false, + "sourceMap": false, + "outDir": ".tmp-api-extractor/dts", + "rootDir": ".." + }, + "include": [ + "src/**/*.ts", + "../agent-core-v2/src/**/*.ts", + "../kaos/src/**/*.ts", + "../klient/src/**/*.ts", + "../kosong/src/**/*.ts", + "../oauth/src/**/*.ts", + "../protocol/src/**/*.ts" + ], + "exclude": ["dist", ".tmp-api-extractor", "examples", "test", "../*/dist", "../*/test", "../agent-core-v2/src/human/test"] +} diff --git a/packages/node-sdk/tsconfig.json b/packages/node-sdk/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..9475a94bee55401f34e36a64b39d48b43155365c --- /dev/null +++ b/packages/node-sdk/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "lib": ["ESNext"], + "experimentalDecorators": true + }, + "include": ["src", "test", "examples", "../agent-core-v2/src/env.d.ts"] +} diff --git a/packages/node-sdk/tsdown.config.ts b/packages/node-sdk/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..2caaea813b690cb7a51c0f8b0276ee05f0e6b285 --- /dev/null +++ b/packages/node-sdk/tsdown.config.ts @@ -0,0 +1,31 @@ +import { fileURLToPath } from 'node:url'; + +import { defineConfig } from 'tsdown'; + +import { rawTextPlugin } from '../../build/raw-text-plugin.mjs'; + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm'], + dts: false, + outDir: 'dist', + clean: true, + plugins: [rawTextPlugin()], + banner: { + js: [ + "import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';", + "import { dirname as __cjsShimDirname } from 'node:path';", + 'const __filename = __cjsShimFileURLToPath(import.meta.url);', + 'const __dirname = __cjsShimDirname(__filename);', + ].join('\n'), + }, + alias: { + '@moonshot-ai/kaos': fileURLToPath(new URL('../kaos/src/index.ts', import.meta.url)), + '@moonshot-ai/kimi-code-oauth': fileURLToPath(new URL('../oauth/src/index.ts', import.meta.url)), + '@moonshot-ai/kosong': fileURLToPath(new URL('../kosong/src/index.ts', import.meta.url)), + }, + deps: { + alwaysBundle: [/^@moonshot-ai\//], + neverBundle: [], + }, +}); diff --git a/packages/node-sdk/vitest.config.ts b/packages/node-sdk/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..68b888cc4fb0299d70891404136bf3b6c200a88b --- /dev/null +++ b/packages/node-sdk/vitest.config.ts @@ -0,0 +1,21 @@ +import { fileURLToPath } from 'node:url'; + +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + resolve: { + alias: { + '@moonshot-ai/kimi-code-oauth': fileURLToPath( + new URL('../oauth/src/index.ts', import.meta.url), + ), + }, + }, + test: { + name: 'kimi-sdk', + env: { + KIMI_LOG_LEVEL: 'off', + }, + include: ['test/**/*.test.ts'], + testTimeout: 15_000, + }, +}); diff --git a/packages/oauth/CHANGELOG.md b/packages/oauth/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..43a6043d1cddc165b5686503c464287370b391a7 --- /dev/null +++ b/packages/oauth/CHANGELOG.md @@ -0,0 +1,47 @@ +# @moonshot-ai/kimi-code-oauth + +## 0.4.0 + +### Minor Changes + +- [#2885](https://github.com/MoonshotAI/kimi-code/pull/2885) [`4a93f70`](https://github.com/MoonshotAI/kimi-code/commit/4a93f70aa2cf5f70a88b4f8eeb2e409aab2c8f59) Thanks [@liruifengv](https://github.com/liruifengv)! - Add a browser-safe `./device` subpath export exposing the device-code flow's pure-fetch HTTP wrappers and flow config, so browser bundles can run OAuth sign-in without pulling in Node-only modules. Import from `@moonshot-ai/kimi-code-oauth/device`. + +### Patch Changes + +- [#2351](https://github.com/MoonshotAI/kimi-code/pull/2351) [`6be2697`](https://github.com/MoonshotAI/kimi-code/commit/6be26978b123bacf1c5ebce52bbeb6f7b7ff0629) Thanks [@7Sageer](https://github.com/7Sageer)! - Add `fetchChatTitle` for the managed platform `/tools` `chat_title` method: protocol headers, an 8s timeout, response validation, and structured failures. + +## 0.3.0 + +### Minor Changes + +- [#2382](https://github.com/MoonshotAI/kimi-code/pull/2382) [`40172c7`](https://github.com/MoonshotAI/kimi-code/commit/40172c7ca96ca981b043b793588dd32e898979fa) Thanks [@liruifengv](https://github.com/liruifengv)! - Rework the host identity type: rename `userAgentProduct` to `productName` and add a required `platform` field, so every host explicitly declares the `X-Msh-Platform` value it reports instead of silently inheriting the CLI's. OAuth requests now also send the product User-Agent (with the optional runtime suffix), so the OAuth host can tell client families and surfaces apart. + +## 0.2.2 + +### Patch Changes + +- [#399](https://github.com/MoonshotAI/kimi-code/pull/399) [`232ed87`](https://github.com/MoonshotAI/kimi-code/commit/232ed874d41de777e6ff9c539ac22d830d0b5c3a) - Keep managed OAuth credentials scoped to their configured authentication and API endpoints. + +## 0.2.1 + +### Patch Changes + +- [#335](https://github.com/MoonshotAI/kimi-code/pull/335) [`7284f30`](https://github.com/MoonshotAI/kimi-code/commit/7284f30479142fd66b1e8a731fd00198b1e8684f) - Fix custom registry provider handling during re-import. Prevent loss of multi-provider entries and remove stale providers along with their model aliases and default model references. + +## 0.2.0 + +### Minor Changes + +- [#264](https://github.com/MoonshotAI/kimi-code/pull/264) [`42bb914`](https://github.com/MoonshotAI/kimi-code/commit/42bb9141d8ee7023639f943dd4c6a0f6c8fa8945) - Add `/provider` command for managing AI providers, support custom registry imports, and introduce a tabbed model selector. + +### Patch Changes + +- [#274](https://github.com/MoonshotAI/kimi-code/pull/274) [`a1dfbfe`](https://github.com/MoonshotAI/kimi-code/commit/a1dfbfeb16bcad0c2c8faa232d6d1ce4a2681d57) - Clarify Kimi Platform API key login labels and prompt details. + +## 0.1.2 + +### Patch Changes + +- [#52](https://github.com/MoonshotAI/kimi-code/pull/52) [`064343a`](https://github.com/MoonshotAI/kimi-code/commit/064343a6e565a525fbf38b3a1f70f7ff0235a5ed) - Correct the `X-Msh-Platform` header value to `kimi_code_cli`. + +- [#11](https://github.com/MoonshotAI/kimi-code/pull/11) [`15b018f`](https://github.com/MoonshotAI/kimi-code/commit/15b018fc84a36a9ebde598970e5b44bebe5d68c6) - Surface API-provided error messages during feedback, usage, login, and model setup failures. diff --git a/packages/oauth/README.md b/packages/oauth/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6cc8d6ec71c58e5ab91c7ee8e2830d50f2582d8d --- /dev/null +++ b/packages/oauth/README.md @@ -0,0 +1,11 @@ +# @moonshot-ai/kimi-code-oauth + +OAuth toolkit for Kimi Code managed authentication. + +Part of the [Kimi Code](https://github.com/MoonshotAI/kimi-code) monorepo. + +See the main repository for documentation, issues, and contribution guidelines. + +## License + +MIT diff --git a/packages/oauth/package.json b/packages/oauth/package.json new file mode 100644 index 0000000000000000000000000000000000000000..7bdb32b0bff59dbe2e64153260b15812ff46a274 --- /dev/null +++ b/packages/oauth/package.json @@ -0,0 +1,53 @@ +{ + "name": "@moonshot-ai/kimi-code-oauth", + "version": "0.4.0", + "private": true, + "description": "Kimi OAuth toolkit for managed Kimi Code authentication", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/oauth#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/oauth" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "kimi", + "oauth", + "authentication", + "auth", + "cli" + ], + "files": [ + "dist" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./device": { + "types": "./src/device.ts", + "default": "./src/device.ts" + } + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json --noEmit", + "clean": "rm -rf dist" + }, + "dependencies": { + "proper-lockfile": "^4.1.2", + "zod": "catalog:" + }, + "devDependencies": { + "@types/proper-lockfile": "^4.1.4" + } +} diff --git a/packages/oauth/tsconfig.json b/packages/oauth/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..b999c0575173d6cf089bf154e5fab5acf1b82c8f --- /dev/null +++ b/packages/oauth/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src", "test", "examples"] +} diff --git a/packages/oauth/tsdown.config.ts b/packages/oauth/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..349cfef1550050fd89fba5607d8793d3e74937b5 --- /dev/null +++ b/packages/oauth/tsdown.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['./src/index.ts', './src/device.ts'], + format: ['esm'], + dts: true, + outDir: 'dist', + clean: true, +}); diff --git a/packages/oauth/vitest.config.ts b/packages/oauth/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f5ef4273e7e0f178a623c8a3e42b5603608a18b --- /dev/null +++ b/packages/oauth/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'kimi-oauth', + include: ['test/**/*.test.ts'], + }, +}); diff --git a/packages/pi-tui/AGENTS.md b/packages/pi-tui/AGENTS.md new file mode 100644 index 0000000000000000000000000000000000000000..f11246cb4ced2b0f173fb8491220eb6413f4b7f3 --- /dev/null +++ b/packages/pi-tui/AGENTS.md @@ -0,0 +1,21 @@ +# pi-tui + +Vendored fork of [`earendil-works/pi`](https://github.com/earendil-works/pi) `packages/tui`. Keep the fork small so upstream syncs stay cheap. + +**Syncing from upstream, adding a local patch, or reviewing a pi-tui diff:** read [UPSTREAM.md](./UPSTREAM.md). The fork is the diff against the pinned upstream commit; that file records why those diffs exist. + +## Changing this package + +Put TUI product behavior in `apps/kimi-code/src/tui` (composition, subclassing, existing host callbacks). Change this package only when the public API cannot express the behavior. + +A patch that lands here must: + +1. Be a library defect (crash, wrong render) or an extension point the app cannot reach (input state machine, render hot path, tokenizer). +2. Be additive: optional argument, callback, or default-off switch. Defaults match upstream. +3. Add an intent card in `UPSTREAM.md` and a test that fails without the change. + +Skip step 3 and the change is not done. Do not rewrite a rendering strategy. + +## Tests + +This package runs `node --test` via `pnpm --filter @moonshot-ai/pi-tui test`. The repo-root vitest run does not execute these tests. diff --git a/packages/pi-tui/CHANGELOG.md b/packages/pi-tui/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..e5f888273084f0cc512a925c6d91c95843e9e521 --- /dev/null +++ b/packages/pi-tui/CHANGELOG.md @@ -0,0 +1,79 @@ +# @moonshot-ai/pi-tui + +## 0.84.5 + +### Patch Changes + +- [#3780](https://github.com/MoonshotAI/kimi-code/pull/3780) [`486dcd2`](https://github.com/MoonshotAI/kimi-code/commit/486dcd26c76f2854fc351515a45d8f0fc2d31ed6) Thanks [@Grapedge](https://github.com/Grapedge)! - Re-baseline the fork on upstream pi-tui v0.85.1 plus upstream main up to `53816d7` (2026-09-14), which adds component mouse input (`handleMouse`, `MouseRegion`), a bordered fullscreen search panel with clickable navigation and a jump-to-end indicator, native clipboard helpers for darwin/win32/linux-X11 (the platform modules are renamed to `darwin-platform`, `win32-platform`, and `linux-platform-x11`), main-screen render chunking for large outputs, terminal capability overrides, and Alt-modified wheel scroll acceleration. Upstream also removed the library's own `PI_*` environment/config reads; logging destinations are now constructor-provided only. All local patches are retained: narrow-terminal hardening, overwide-line truncation, processed-line render caching, editor history hooks, the paste-burst fallback, inline slash autocomplete, host-marked completions, CJK-aware autolinks, fullscreen nav fall-through, and multi-root `@` completion. + +## 0.84.4 + +### Patch Changes + +- [#2935](https://github.com/MoonshotAI/kimi-code/pull/2935) [`44a6c70`](https://github.com/MoonshotAI/kimi-code/commit/44a6c70e66762ea9e122f8dceae16dc759086a7c) Thanks [@chengluyu](https://github.com/chengluyu)! - Add an opt-in inline slash autocomplete trigger that fires after whitespace mid-input. + +## 0.84.3 + +### Patch Changes + +- [#2917](https://github.com/MoonshotAI/kimi-code/pull/2917) [`6cf315b`](https://github.com/MoonshotAI/kimi-code/commit/6cf315b7bdea8a04cfaeba1bb8931c1730853aec) Thanks [@wbxl2000](https://github.com/wbxl2000)! - Stop GFM autolinks at CJK/full-width punctuation so a bare URL followed by CJK text no longer swallows the CJK characters into the link target. + +## 0.84.2 + +### Patch Changes + +- [#2830](https://github.com/MoonshotAI/kimi-code/pull/2830) [`ec84a6f`](https://github.com/MoonshotAI/kimi-code/commit/ec84a6f9a3eb35e1118f8a327f7a11b3978a899c) Thanks [@liruifengv](https://github.com/liruifengv)! - Add fullscreen groundwork to the alternate-screen renderer: `ScrollView.canScroll`, `TuiAltScreen.getLayoutRoot()`, and viewport navigation keys (PageUp/PageDown/Home/End and friends) now fall through to the focused component when the primary scroll view has nothing to scroll. Terminal focus in/out reports are no longer consumed by the viewport input handler, so app-level listeners (focus-aware notifications, clipboard-image hints) keep working in fullscreen. + +- [#2830](https://github.com/MoonshotAI/kimi-code/pull/2830) [`ec84a6f`](https://github.com/MoonshotAI/kimi-code/commit/ec84a6f9a3eb35e1118f8a327f7a11b3978a899c) Thanks [@liruifengv](https://github.com/liruifengv)! - Re-baseline the fork on upstream pi-tui v0.84.1 plus upstream main up to `40a3d85` (2026-08-11), which adds the fullscreen transcript search (`ctrl+shift+f`), single-line scroll actions, the ~9-18x alternate-screen render-churn reduction, and an SSH-aware escape-timeout default. The upstream renderer is now split into main-screen and alternate-screen implementations (the `TUI` class is now an interface implemented by `TuiMainScreen` and `TuiAltScreen`), and the Markdown component gained opt-out LaTeX math rendering. All local patches are retained: narrow-terminal hardening, processed-line render caching, editor history hooks, the paste-burst fallback, and multi-root `@` completion. `Editor.setText` accepts a `preservePasteRegistry` option so subclasses can replace text without orphaning live paste markers (upstream resets the registry on every `setText`). + +## 0.84.1 + +### Patch Changes + +- Re-baseline the fork on upstream `@earendil-works/pi-tui` v0.84.1 plus upstream main up to `40a3d85` (2026-08-11), keeping all local patches (narrow-terminal hardening, processed-line render caching, editor history hooks, paste-burst fallback, multi-root `@` completion). The upstream renderer is now split into main-screen and alternate-screen implementations, the `TUI` class is now an interface implemented by `TuiMainScreen` and `TuiAltScreen`, and the Markdown component gained opt-out LaTeX math rendering (`renderLatex`). The post-release main merge adds the fullscreen transcript search, single-line scroll actions, the alternate-screen render-churn reduction, and the SSH-aware escape-timeout default. The version line now tracks the upstream baseline it forks from. + +## 0.80.8 + +### Patch Changes + +- [#1976](https://github.com/MoonshotAI/kimi-code/pull/1976) [`e458323`](https://github.com/MoonshotAI/kimi-code/commit/e45832398d0d9cad98dbad1cbf1e5b103a20aace) Thanks [@liruifengv](https://github.com/liruifengv)! - Speed up the terminal renderer in long sessions by reusing processed lines across frames. + +## 0.80.7 + +### Patch Changes + +- [#1408](https://github.com/MoonshotAI/kimi-code/pull/1408) [`fc259ab`](https://github.com/MoonshotAI/kimi-code/commit/fc259abdb415fe9ac10132a142bdb5ce507ccda2) Thanks [@liruifengv](https://github.com/liruifengv)! - Support searching multiple workspace roots for `@` file completion through fd, deduplicated by absolute path. + +## 0.80.6 + +### Patch Changes + +- [#1367](https://github.com/MoonshotAI/kimi-code/pull/1367) [`23daf0f`](https://github.com/MoonshotAI/kimi-code/commit/23daf0f3c199b4aaa9bd9388a2903d7827f98d32) - Revert the fork's viewport and scrollback rendering patches, restoring the upstream differential-rendering behavior. The narrow-terminal fixes (width clamping, overwide-line truncation) are kept. + +## 0.80.5 + +### Patch Changes + +- [#1305](https://github.com/MoonshotAI/kimi-code/pull/1305) [`9091627`](https://github.com/MoonshotAI/kimi-code/commit/909162725770700efd3051f4cfa68156d9b84fa8) - Add a paste-burst fallback that treats Enter as a newline during rapid non-bracketed multi-line input bursts. + +- [#1353](https://github.com/MoonshotAI/kimi-code/pull/1353) [`68ad686`](https://github.com/MoonshotAI/kimi-code/commit/68ad686211760eb1c3e6b5c23eb28ace9009c17f) - Pin the viewport anchor on partial shrinks and repaint above-viewport shifts in place, so streaming shrink/grow cycles no longer stack duplicate copies of content in scrollback; only a collapse past the viewport top re-anchors the view. + +## 0.80.4 + +### Patch Changes + +- [#1315](https://github.com/MoonshotAI/kimi-code/pull/1315) [`b40bb71`](https://github.com/MoonshotAI/kimi-code/commit/b40bb7139939eb2ba734ce5dd4871b894d7033e8) - Re-anchor the viewport with an in-place repaint whenever content shrinks below the screen bottom, and clamp deleted-line clearing to the screen bottom, so large shrinks no longer blank the screen, desync the cursor, or leave the UI hovering above dead rows. + +- [#1295](https://github.com/MoonshotAI/kimi-code/pull/1295) [`77eb3a9`](https://github.com/MoonshotAI/kimi-code/commit/77eb3a9fe40c93fa32e335f07160b8128355bab6) - Add history hooks to the editor so hosts can filter entries (`setHistoryFilter`), decorate recalled entries (`onRecall`), and save and restore their own state alongside the history draft (`onHistoryDraftSave` / `onHistoryDraftRestore`). + +- [#1303](https://github.com/MoonshotAI/kimi-code/pull/1303) [`2639786`](https://github.com/MoonshotAI/kimi-code/commit/2639786ce578f15c020a2c11c344797dae18de61) - Fix crashes on very narrow terminals: word-wrapping wide graphemes no longer recurses infinitely at one-column width, render width is clamped to a minimum of one column, and overwide rendered lines are truncated instead of throwing. + +## 0.80.3 + +### Patch Changes + +- [#1254](https://github.com/MoonshotAI/kimi-code/pull/1254) [`7859b0a`](https://github.com/MoonshotAI/kimi-code/commit/7859b0afe8898852806e5a0c21b9dd52cb82f834) - Export the package manifest so the bundled binary can locate its native assets. + +- [#1254](https://github.com/MoonshotAI/kimi-code/pull/1254) [`7859b0a`](https://github.com/MoonshotAI/kimi-code/commit/7859b0afe8898852806e5a0c21b9dd52cb82f834) - Integrate the fork into the monorepo and load it directly from source. + +- [#1254](https://github.com/MoonshotAI/kimi-code/pull/1254) [`7859b0a`](https://github.com/MoonshotAI/kimi-code/commit/7859b0afe8898852806e5a0c21b9dd52cb82f834) - Clamp the differential render to the visible viewport so scrolling up during streaming no longer jumps to the top. diff --git a/packages/pi-tui/LICENSE b/packages/pi-tui/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..b0a8e9b81083294360c69b4ec45d3d39a2b28197 --- /dev/null +++ b/packages/pi-tui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Mario Zechner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/pi-tui/README.md b/packages/pi-tui/README.md new file mode 100644 index 0000000000000000000000000000000000000000..01c388034d44dc1e04835d0e24e6ef33b2e006a9 --- /dev/null +++ b/packages/pi-tui/README.md @@ -0,0 +1,791 @@ +# @moonshot-ai/pi-tui + +Minimal terminal UI framework with differential rendering and synchronized output for flicker-free interactive CLI applications. + +## Features + +- **Differential Rendering**: Three-strategy rendering system that only updates what changed +- **Synchronized Output**: Uses CSI 2026 for atomic screen updates (no flicker) +- **Bracketed Paste Mode**: Handles large pastes correctly with markers for >10 line pastes +- **Component-based**: Simple Component interface with render() method +- **Theme Support**: Components accept theme interfaces for customizable styling +- **Built-in Components**: Text, TruncatedText, Input, Editor, Markdown, Loader, SelectList, SettingsList, Spacer, Image, Box, Container +- **Inline Images**: Renders images in terminals that support Kitty or iTerm2 graphics protocols +- **Autocomplete Support**: File paths and slash commands + +## Quick Start + +```typescript +import { TUI, Text, Editor, ProcessTerminal, matchesKey } from "@moonshot-ai/pi-tui"; + +// Create terminal +const terminal = new ProcessTerminal(); + +// Create TUI +const tui = new TUI(terminal); + +// Add components +tui.addChild(new Text("Welcome to my app!")); + +import { defaultEditorTheme as editorTheme } from './test/test-themes.ts'; +const editor = new Editor(tui, editorTheme); +editor.onSubmit = (text) => { + console.log("Submitted:", text); + tui.addChild(new Text(`You said: ${text}`)); +}; +tui.addChild(editor); + +// Focus the editor so it receives keyboard input +tui.setFocus(editor); + +// In raw mode Ctrl+C doesn't send SIGINT — intercept it here to allow exit +tui.addInputListener((data) => { + if (matchesKey(data, 'ctrl+c')) { + tui.stop(); + process.exit(0); + } +}); + +// Start +tui.start(); +``` + +## Core API + +### TUI + +Main container that manages components and rendering. + +```typescript +const tui = new TUI(terminal); +tui.addChild(component); +tui.removeChild(component); +tui.start(); +tui.stop(); +tui.requestRender(); // Request a re-render + +// Global debug key handler (Shift+Ctrl+D) +tui.onDebug = () => console.log("Debug triggered"); +``` + +### Overlays + +Overlays render components on top of existing content without replacing it. Useful for dialogs, menus, and modal UI. + +```typescript +// Show overlay with default options (centered, max 80 cols) +const handle = tui.showOverlay(component); + +// Show overlay with custom positioning and sizing +// Values can be numbers (absolute) or percentage strings (e.g., "50%") +const handle = tui.showOverlay(component, { + // Sizing + width: 60, // Fixed width in columns + width: "80%", // Width as percentage of terminal + minWidth: 40, // Minimum width floor + maxHeight: 20, // Maximum height in rows + maxHeight: "50%", // Maximum height as percentage of terminal + + // Anchor-based positioning (default: 'center') + anchor: 'bottom-right', // Position relative to anchor point + offsetX: 2, // Horizontal offset from anchor + offsetY: -1, // Vertical offset from anchor + + // Percentage-based positioning (alternative to anchor) + row: "25%", // Vertical position (0%=top, 100%=bottom) + col: "50%", // Horizontal position (0%=left, 100%=right) + + // Absolute positioning (overrides anchor/percent) + row: 5, // Exact row position + col: 10, // Exact column position + + // Margin from terminal edges + margin: 2, // All sides + margin: { top: 1, right: 2, bottom: 1, left: 2 }, + + // Responsive visibility + visible: (termWidth, termHeight) => termWidth >= 100 // Hide on narrow terminals + + // Focus behavior + nonCapturing: true // Don't auto-focus when shown +}); + +// OverlayHandle methods +handle.hide(); // Permanently remove the overlay +handle.setHidden(true); // Temporarily hide (can show again) +handle.setHidden(false); // Show again after hiding +handle.isHidden(); // Check if temporarily hidden +handle.focus(); // Focus and bring to visual front +handle.unfocus(); // Release focus to normal fallback +handle.unfocus({ target: baseComponent }); // Release this overlay to a specific component +handle.unfocus({ target: null }); // Release this overlay and leave focus empty +handle.isFocused(); // Check if overlay has focus + +handle.unfocus(); +// Overlay loses focus; TUI falls back to another visible capturing overlay or the previous focus target. + +handle.unfocus({ target: null }); +// Overlay loses focus; no component receives input until focus is set again. + +// A focused visible overlay reclaims keyboard input after temporary replacement UI +// releases focus. If you want a specific component to receive input while overlays remain +// visible, call handle.unfocus({ target: component }). + +// Hide topmost overlay +tui.hideOverlay(); + +// Check if any visible overlay is active +tui.hasOverlay(); +``` + +**Anchor values**: `'center'`, `'top-left'`, `'top-right'`, `'bottom-left'`, `'bottom-right'`, `'top-center'`, `'bottom-center'`, `'left-center'`, `'right-center'` + +**Resolution order**: +1. `minWidth` is applied as a floor after width calculation +2. For position: absolute `row`/`col` > percentage `row`/`col` > `anchor` +3. `margin` clamps final position to stay within terminal bounds +4. `visible` callback controls whether overlay renders (called each frame) + +### Component Interface + +All components implement: + +```typescript +interface Component { + render(width: number): string[]; + handleInput?(data: string): void; + invalidate?(): void; +} +``` + +| Method | Description | +|--------|-------------| +| `render(width)` | Returns an array of strings, one per line. Each line **must not exceed `width`** or the TUI will error. Use `truncateToWidth()` or manual wrapping to ensure this. | +| `handleInput?(data)` | Called when the component has focus and receives keyboard input. The `data` string contains raw terminal input (may include ANSI escape sequences). | +| `invalidate?()` | Called to clear any cached render state. Components should re-render from scratch on the next `render()` call. | + +The TUI appends a full SGR reset and OSC 8 reset at the end of each rendered line. Styles do not carry across lines. If you emit multi-line text with styling, reapply styles per line or use `wrapTextWithAnsi()` so styles are preserved for each wrapped line. + +### Focusable Interface (IME Support) + +Components that display a text cursor and need IME (Input Method Editor) support should implement the `Focusable` interface: + +```typescript +import { CURSOR_MARKER, type Component, type Focusable } from "@moonshot-ai/pi-tui"; + +class MyInput implements Component, Focusable { + focused: boolean = false; // Set by TUI when focus changes + + render(width: number): string[] { + const marker = this.focused ? CURSOR_MARKER : ""; + // Emit marker right before the fake cursor + return [`> ${beforeCursor}${marker}\x1b[7m${atCursor}\x1b[27m${afterCursor}`]; + } +} +``` + +When a `Focusable` component has focus, TUI: +1. Sets `focused = true` on the component +2. Scans rendered output for `CURSOR_MARKER` (a zero-width APC escape sequence) +3. Positions the hardware terminal cursor at that location +4. Shows the hardware cursor only when `showHardwareCursor` is enabled + +The cursor remains hidden by default. This keeps the fake cursor rendering, while still positioning the hardware cursor for terminals that track IME candidate windows with hidden cursors. Some terminals require a visible hardware cursor for IME positioning; enable it with the `TUI` constructor option, `setShowHardwareCursor(true)`, or `PI_HARDWARE_CURSOR=1`. The `Editor` and `Input` built-in components already implement this interface. + +**Container components with embedded inputs:** When a container component (dialog, selector, etc.) contains an `Input` or `Editor` child, the container must implement `Focusable` and propagate the focus state to the child: + +```typescript +import { Container, type Focusable, Input } from "@moonshot-ai/pi-tui"; + +class SearchDialog extends Container implements Focusable { + private searchInput: Input; + + // Propagate focus to child input for IME cursor positioning + private _focused = false; + get focused(): boolean { return this._focused; } + set focused(value: boolean) { + this._focused = value; + this.searchInput.focused = value; + } + + constructor() { + super(); + this.searchInput = new Input(); + this.addChild(this.searchInput); + } +} +``` + +Without this propagation, typing with an IME (Chinese, Japanese, Korean, etc.) will show the candidate window in the wrong position. + +## Built-in Components + +### Container + +Groups child components. + +```typescript +const container = new Container(); +container.addChild(component); +container.removeChild(component); +``` + +### Box + +Container that applies padding and background color to all children. + +```typescript +const box = new Box( + 1, // paddingX (default: 1) + 1, // paddingY (default: 1) + (text) => chalk.bgGray(text) // optional background function +); +box.addChild(new Text("Content")); +box.setBgFn((text) => chalk.bgBlue(text)); // Change background dynamically +``` + +### Text + +Displays multi-line text with word wrapping and padding. + +```typescript +const text = new Text( + "Hello World", // text content + 1, // paddingX (default: 1) + 1, // paddingY (default: 1) + (text) => chalk.bgGray(text) // optional background function +); +text.setText("Updated text"); +text.setCustomBgFn((text) => chalk.bgBlue(text)); +``` + +### TruncatedText + +Single-line text that truncates to fit viewport width. Useful for status lines and headers. + +```typescript +const truncated = new TruncatedText( + "This is a very long line that will be truncated...", + 0, // paddingX (default: 0) + 0 // paddingY (default: 0) +); +``` + +### Input + +Single-line text input with horizontal scrolling. + +```typescript +const input = new Input(); +input.onSubmit = (value) => console.log(value); +input.setValue("initial"); +input.getValue(); +``` + +**Key Bindings:** +- `Enter` - Submit +- `Ctrl+A` / `Ctrl+E` - Line start/end +- `Ctrl+W` or `Alt+Backspace` - Delete word backwards +- `Ctrl+U` - Delete to start of line +- `Ctrl+K` - Delete to end of line +- `Ctrl+Left` / `Ctrl+Right` - Word navigation +- `Alt+Left` / `Alt+Right` - Word navigation +- Arrow keys, Backspace, Delete work as expected + +### Editor + +Multi-line text editor with autocomplete, file completion, paste handling, and vertical scrolling when content exceeds terminal height. + +```typescript +interface EditorTheme { + borderColor: (str: string) => string; + selectList: SelectListTheme; +} + +interface EditorOptions { + paddingX?: number; // Horizontal padding (default: 0) +} + +const editor = new Editor(tui, theme, options?); // tui is required for height-aware scrolling +editor.onSubmit = (text) => console.log(text); +editor.onChange = (text) => console.log("Changed:", text); +editor.disableSubmit = true; // Disable submit temporarily +editor.setAutocompleteProvider(provider); +editor.borderColor = (s) => chalk.blue(s); // Change border dynamically +editor.setPaddingX(1); // Update horizontal padding dynamically +editor.getPaddingX(); // Get current padding +``` + +**Features:** +- Multi-line editing with word wrap +- Slash command autocomplete (type `/`) +- File path autocomplete (press `Tab`) +- Large paste handling (>10 lines creates `[paste #1 +50 lines]` marker) +- Horizontal lines above/below editor +- Fake cursor rendering (hidden real cursor) + +**Key Bindings:** +- `Enter` - Submit +- `Shift+Enter`, `Ctrl+Enter`, or `Alt+Enter` - New line (terminal-dependent, Alt+Enter most reliable) +- `Tab` - Autocomplete +- `Ctrl+K` - Delete to end of line +- `Ctrl+U` - Delete to start of line +- `Ctrl+W` or `Alt+Backspace` - Delete word backwards +- `Alt+D` or `Alt+Delete` - Delete word forwards +- `Ctrl+A` / `Ctrl+E` - Line start/end +- `Ctrl+]` - Jump forward to character (awaits next keypress, then moves cursor to first occurrence) +- `Ctrl+Alt+]` - Jump backward to character +- Arrow keys, Backspace, Delete work as expected + +### Markdown + +Renders markdown with syntax highlighting and theming support. + +```typescript +interface MarkdownTheme { + heading: (text: string) => string; + link: (text: string) => string; + linkUrl: (text: string) => string; + code: (text: string) => string; + codeBlock: (text: string) => string; + codeBlockBorder: (text: string) => string; + quote: (text: string) => string; + quoteBorder: (text: string) => string; + hr: (text: string) => string; + listBullet: (text: string) => string; + bold: (text: string) => string; + italic: (text: string) => string; + strikethrough: (text: string) => string; + underline: (text: string) => string; + highlightCode?: (code: string, lang?: string) => string[]; +} + +interface DefaultTextStyle { + color?: (text: string) => string; + bgColor?: (text: string) => string; + bold?: boolean; + italic?: boolean; + strikethrough?: boolean; + underline?: boolean; +} + +const md = new Markdown( + "# Hello\n\nSome **bold** text", + 1, // paddingX + 1, // paddingY + theme, // MarkdownTheme + defaultStyle // optional DefaultTextStyle +); +md.setText("Updated markdown"); +``` + +**Features:** +- Headings, bold, italic, code blocks, lists, links, blockquotes +- HTML tags rendered as plain text +- Optional syntax highlighting via `highlightCode` +- Padding support +- Render caching for performance + +### Loader + +Animated loading spinner. + +```typescript +const loader = new Loader( + tui, // TUI instance for render updates + (s) => chalk.cyan(s), // spinner color function + (s) => chalk.gray(s), // message color function + "Loading..." // message (default: "Loading...") +); +loader.start(); +loader.setMessage("Still loading..."); +loader.stop(); +``` + +### CancellableLoader + +Extends Loader with Escape key handling and an AbortSignal for cancelling async operations. + +```typescript +const loader = new CancellableLoader( + tui, // TUI instance for render updates + (s) => chalk.cyan(s), // spinner color function + (s) => chalk.gray(s), // message color function + "Working..." // message +); +loader.onAbort = () => done(null); // Called when user presses Escape +doAsyncWork(loader.signal).then(done); +``` + +**Properties:** +- `signal: AbortSignal` - Aborted when user presses Escape +- `aborted: boolean` - Whether the loader was aborted +- `onAbort?: () => void` - Callback when user presses Escape + +### SelectList + +Interactive selection list with keyboard navigation. + +```typescript +interface SelectItem { + value: string; + label: string; + description?: string; +} + +interface SelectListTheme { + selectedPrefix: (text: string) => string; + selectedText: (text: string) => string; + description: (text: string) => string; + scrollInfo: (text: string) => string; + noMatch: (text: string) => string; +} + +const list = new SelectList( + [ + { value: "opt1", label: "Option 1", description: "First option" }, + { value: "opt2", label: "Option 2", description: "Second option" }, + ], + 5, // maxVisible + theme // SelectListTheme +); + +list.onSelect = (item) => console.log("Selected:", item); +list.onCancel = () => console.log("Cancelled"); +list.onSelectionChange = (item) => console.log("Highlighted:", item); +list.setFilter("opt"); // Filter items +``` + +**Controls:** +- Arrow keys: Navigate +- Enter: Select +- Escape: Cancel + +### SettingsList + +Settings panel with value cycling and submenus. + +```typescript +interface SettingItem { + id: string; + label: string; + description?: string; + currentValue: string; + values?: string[]; // If provided, Enter/Space cycles through these + submenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component; +} + +interface SettingsListTheme { + label: (text: string, selected: boolean) => string; + value: (text: string, selected: boolean) => string; + description: (text: string) => string; + cursor: string; + hint: (text: string) => string; +} + +const settings = new SettingsList( + [ + { id: "theme", label: "Theme", currentValue: "dark", values: ["dark", "light"] }, + { id: "model", label: "Model", currentValue: "gpt-4", submenu: (val, done) => modelSelector }, + ], + 10, // maxVisible + theme, // SettingsListTheme + (id, newValue) => console.log(`${id} changed to ${newValue}`), + () => console.log("Cancelled") +); +settings.updateValue("theme", "light"); +``` + +**Controls:** +- Arrow keys: Navigate +- Enter/Space: Activate (cycle value or open submenu) +- Escape: Cancel + +### Spacer + +Empty lines for vertical spacing. + +```typescript +const spacer = new Spacer(2); // 2 empty lines (default: 1) +``` + +### Image + +Renders images inline for terminals that support the Kitty graphics protocol (Kitty, Ghostty, WezTerm) or iTerm2 inline images. Falls back to a text placeholder on unsupported terminals. + +```typescript +interface ImageTheme { + fallbackColor: (str: string) => string; +} + +interface ImageOptions { + maxWidthCells?: number; + maxHeightCells?: number; + filename?: string; +} + +const image = new Image( + base64Data, // base64-encoded image data + "image/png", // MIME type + theme, // ImageTheme + options // optional ImageOptions +); +tui.addChild(image); +``` + +Supported formats: PNG, JPEG, GIF, WebP. Dimensions are parsed from the image headers automatically. + +## Autocomplete + +### CombinedAutocompleteProvider + +Supports both slash commands and file paths. + +```typescript +import { CombinedAutocompleteProvider } from "@moonshot-ai/pi-tui"; + +const provider = new CombinedAutocompleteProvider( + [ + { name: "help", description: "Show help" }, + { name: "clear", description: "Clear screen" }, + { name: "delete", description: "Delete last message" }, + ], + process.cwd() // base path for file completion +); + +editor.setAutocompleteProvider(provider); +``` + +**Features:** +- Type `/` to see slash commands +- Press `Tab` for file path completion +- Works with `~/`, `./`, `../`, and `@` prefix +- Filters to attachable files for `@` prefix + +## Key Detection + +Use `matchesKey()` with the `Key` helper for detecting keyboard input (supports Kitty keyboard protocol): + +```typescript +import { matchesKey, Key } from "@moonshot-ai/pi-tui"; + +if (matchesKey(data, Key.ctrl("c"))) { + process.exit(0); +} + +if (matchesKey(data, Key.enter)) { + submit(); +} else if (matchesKey(data, Key.escape)) { + cancel(); +} else if (matchesKey(data, Key.up)) { + moveUp(); +} +``` + +**Key identifiers** (use `Key.*` for autocomplete, or string literals): +- Basic keys: `Key.enter`, `Key.escape`, `Key.tab`, `Key.space`, `Key.backspace`, `Key.delete`, `Key.home`, `Key.end` +- Arrow keys: `Key.up`, `Key.down`, `Key.left`, `Key.right` +- With modifiers: `Key.ctrl("c")`, `Key.shift("tab")`, `Key.alt("left")`, `Key.ctrlShift("p")` +- String format also works: `"enter"`, `"ctrl+c"`, `"shift+tab"`, `"ctrl+shift+p"` + +## Differential Rendering + +The TUI uses three rendering strategies: + +1. **First Render**: Output all lines without clearing scrollback +2. **Width Changed or Change Above Viewport**: Clear screen and full re-render +3. **Normal Update**: Move cursor to first changed line, clear to end, render changed lines + +All updates are wrapped in **synchronized output** (`\x1b[?2026h` ... `\x1b[?2026l`) for atomic, flicker-free rendering. + +## Terminal Interface + +The TUI works with any object implementing the `Terminal` interface: + +```typescript +interface Terminal { + start(onInput: (data: string) => void, onResize: () => void): void; + stop(): void; + write(data: string): void; + get columns(): number; + get rows(): number; + moveBy(lines: number): void; + hideCursor(): void; + showCursor(): void; + clearLine(): void; + clearFromCursor(): void; + clearScreen(): void; +} +``` + +**Built-in implementations:** +- `ProcessTerminal` - Uses `process.stdin/stdout` +- `VirtualTerminal` - For testing (uses `@xterm/headless`) + +## Utilities + +```typescript +import { visibleWidth, truncateToWidth, wrapTextWithAnsi } from "@moonshot-ai/pi-tui"; + +// Get visible width of string (ignoring ANSI codes) +const width = visibleWidth("\x1b[31mHello\x1b[0m"); // 5 + +// Truncate string to width (preserving ANSI codes, adds ellipsis) +const truncated = truncateToWidth("Hello World", 8); // "Hello..." + +// Truncate without ellipsis +const truncatedNoEllipsis = truncateToWidth("Hello World", 8, ""); // "Hello Wo" + +// Wrap text to width (preserving ANSI codes across line breaks) +const lines = wrapTextWithAnsi("This is a long line that needs wrapping", 20); +// ["This is a long line", "that needs wrapping"] +``` + +## Creating Custom Components + +When creating custom components, **each line returned by `render()` must not exceed the `width` parameter**. The TUI will error if any line is wider than the terminal. + +### Handling Input + +Use `matchesKey()` with the `Key` helper for keyboard input: + +```typescript +import { matchesKey, Key, truncateToWidth } from "@moonshot-ai/pi-tui"; +import type { Component } from "@moonshot-ai/pi-tui"; + +class MyInteractiveComponent implements Component { + private selectedIndex = 0; + private items = ["Option 1", "Option 2", "Option 3"]; + + public onSelect?: (index: number) => void; + public onCancel?: () => void; + + handleInput(data: string): void { + if (matchesKey(data, Key.up)) { + this.selectedIndex = Math.max(0, this.selectedIndex - 1); + } else if (matchesKey(data, Key.down)) { + this.selectedIndex = Math.min(this.items.length - 1, this.selectedIndex + 1); + } else if (matchesKey(data, Key.enter)) { + this.onSelect?.(this.selectedIndex); + } else if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) { + this.onCancel?.(); + } + } + + render(width: number): string[] { + return this.items.map((item, i) => { + const prefix = i === this.selectedIndex ? "> " : " "; + return truncateToWidth(prefix + item, width); + }); + } +} +``` + +### Handling Line Width + +Use the provided utilities to ensure lines fit: + +```typescript +import { visibleWidth, truncateToWidth } from "@moonshot-ai/pi-tui"; +import type { Component } from "@moonshot-ai/pi-tui"; + +class MyComponent implements Component { + private text: string; + + constructor(text: string) { + this.text = text; + } + + render(width: number): string[] { + // Option 1: Truncate long lines + return [truncateToWidth(this.text, width)]; + + // Option 2: Check and pad to exact width + const line = this.text; + const visible = visibleWidth(line); + if (visible > width) { + return [truncateToWidth(line, width)]; + } + // Pad to exact width (optional, for backgrounds) + return [line + " ".repeat(width - visible)]; + } +} +``` + +### ANSI Code Considerations + +Both `visibleWidth()` and `truncateToWidth()` correctly handle ANSI escape codes: + +- `visibleWidth()` ignores ANSI codes when calculating width +- `truncateToWidth()` preserves ANSI codes and properly closes them when truncating + +```typescript +import chalk from "chalk"; + +const styled = chalk.red("Hello") + " " + chalk.blue("World"); +const width = visibleWidth(styled); // 11 (not counting ANSI codes) +const truncated = truncateToWidth(styled, 8); // Red "Hello" + " W..." with proper reset +``` + +### Caching + +For performance, components should cache their rendered output and only re-render when necessary: + +```typescript +class CachedComponent implements Component { + private text: string; + private cachedWidth?: number; + private cachedLines?: string[]; + + render(width: number): string[] { + if (this.cachedLines && this.cachedWidth === width) { + return this.cachedLines; + } + + const lines = [truncateToWidth(this.text, width)]; + + this.cachedWidth = width; + this.cachedLines = lines; + return lines; + } + + invalidate(): void { + this.cachedWidth = undefined; + this.cachedLines = undefined; + } +} +``` + +## Example + +See `test/chat-simple.ts` for a complete chat interface example with: +- Markdown messages with custom background colors +- Loading spinner during responses +- Editor with autocomplete and slash commands +- Spacers between messages + +Run it: +```bash +npx tsx test/chat-simple.ts +``` + +## Development + +```bash +# Install dependencies (from monorepo root) +npm install + +# Run type checking +npm run check + +# Run the demo +npx tsx test/chat-simple.ts +``` + +### Debug logging + +Set `PI_TUI_WRITE_LOG` to capture the raw ANSI stream written to stdout. + +```bash +PI_TUI_WRITE_LOG=/tmp/tui-ansi.log npx tsx test/chat-simple.ts +``` diff --git a/packages/pi-tui/UPSTREAM.md b/packages/pi-tui/UPSTREAM.md new file mode 100644 index 0000000000000000000000000000000000000000..a831a74300400c85030c658d9c83c13f8ce638d1 --- /dev/null +++ b/packages/pi-tui/UPSTREAM.md @@ -0,0 +1,188 @@ +# pi-tui upstream + +The fork is the diff against the pinned upstream tree. This file records **why** those diffs exist, not where they live. Paths and function names move when upstream refactors; intents do not. + +## Last Sync Point + +Update this section after every sync. Do not reuse the previous range. + +- **Repo:** `https://github.com/earendil-works/pi.git` +- **Subtree:** `packages/tui` +- **Commit:** `53816d7dcc5ebe3a0eedec3cd07196c3a66d83fd` (2026-09-14; v0.85.1 plus upstream main through this commit) +- **This commit is an upstream marker.** It may not exist in this repo's object database. + +## Reconstruct the fork + +Done when the **file list** of `packages/tui` at the Last Sync Point versus this directory is on screen, with scaffolding excluded, and every named path has been opened as a per-file diff. + +```bash +sha= +tmp=$(mktemp -d) +git clone --filter=blob:none --sparse https://github.com/earendil-works/pi.git "$tmp/pi" +git -C "$tmp/pi" sparse-checkout set packages/tui +git -C "$tmp/pi" fetch --depth 1 origin "$sha" +git -C "$tmp/pi" checkout --detach FETCH_HEAD +diff -rq \ + --exclude package.json \ + --exclude AGENTS.md \ + --exclude UPSTREAM.md \ + --exclude CHANGELOG.md \ + --exclude vitest.config.ts \ + --exclude node_modules \ + --exclude dist \ + "$tmp/pi/packages/tui" packages/pi-tui +``` + +Run from the monorepo root. Replace `` with the Last Sync Point commit. Do not dump a recursive unified diff of the whole tree. + +Then diff a named file yourself, for example: + +```bash +diff -u "$tmp/pi/packages/tui/src/components/editor.ts" packages/pi-tui/src/components/editor.ts +``` + +The file list is an index, not the contract. Cards below are the contract: behaviors we must not lose. + +For each per-file diff, decide only this: + +- If it changes **behavior** already described by a card, keep it. +- If it changes **behavior** no card describes, do not keep it quietly — drop it or add a card. +- Otherwise leave it. Extra files are normal (style, identity, tests, docs). Do not invent cards for them, and do not revert them just to shrink the list. + +If a `keep` card has no matching behavior left, mark it `absorbed` (do not delete the card). + +## Add a local patch + +Done when all of the following hold: + +1. The behavior cannot live in `apps/kimi-code/src/tui`. +2. A new intent card is in this file (decision / why not in the app). +3. A test fails without the change and passes with it. +4. Reconstructing the fork shows a per-file diff this card explains. + +Prefer an optional argument, callback, or default-off switch. Defaults match upstream. + +## Sync from upstream + +Done when all of the following hold: + +1. The target upstream ref is written down before any copy. +2. Files are ported, not wholesale-copied. New upstream files are added explicitly and read. +3. `package.json` `name`, `exports`, `imports`, and the `test` script stay ours. +4. The fork is reconstructed against the **new** Last Sync Point. Every `keep` intent still has a matching per-file diff, or is marked `absorbed`. +5. `pnpm --filter @moonshot-ai/pi-tui test` passes. +6. The Last Sync Point section is updated to the new commit. Do not reuse the previous range. + +When upstream reworked a module (new abstractions, renamed concepts, changed data flow), port by behavior against the intent cards. Do not merge by file identity. + +## Intents + +Each card: **decision** and **why not in the app**. Status is `keep` or `absorbed`. + +### wide-grapheme-does-not-recurse — keep + +**Decision:** A single grapheme wider than the terminal does not recurse until the stack overflows. + +**Why not in the app:** Wrap lives inside the editor's line breaker, before any host render. + +### non-positive-width-is-one-column — keep + +**Decision:** A zero or negative reported width is treated as one column before children render. + +**Why not in the app:** Width is clamped at the container entry; children never see the illegal value. + +### overwide-lines-truncate — keep + +**Decision:** A rendered line wider than the terminal is truncated. The renderer does not write a crash log and throw. + +**Why not in the app:** The width check is on the differential render path after components return. + +### negative-width-repeat-does-not-throw — keep + +**Decision:** Blank lines, rules, and editor borders clamp their repeat count to ≥ 0 so a negative width does not throw. + +**Why not in the app:** The `repeat` calls sit in built-in component render, not in the host. + +### unchanged-lines-reuse-processed-output — keep + +**Decision:** A line whose raw string is reference-identical to the previous frame reuses that frame's processed output (truncate, normalize, reset). Steady frames cost pointer compares plus work on changed lines. + +**Why not in the app:** This is the main-screen render hot path. The host cannot intercept per-line processing. + +### editor-history-host-hooks — keep + +**Decision:** The host can filter history entries, decorate a recalled entry, and save/restore its own state next to the history draft. + +**Why not in the app:** History recall mutates editor state internally; the host is not on that path unless the editor calls out. + +### unbracketed-paste-enter-is-newline — keep + +**Decision:** After a rapid burst of unbracketed printable characters, Enter inserts a newline instead of submitting. + +**Why not in the app:** Submit-versus-newline is decided when the editor handles Enter, before any host callback. + +### set-text-can-keep-paste-markers — keep + +**Decision:** Replacing editor text can keep the paste-marker registry for markers that still appear in the new text. + +**Why not in the app:** Upstream `setText` always clears the registry. A subclass that rewrites the buffer cannot preserve live markers without this option. + +### at-completion-searches-multiple-roots — keep + +**Decision:** `@` file completion searches additional workspace roots through fd and dedupes by absolute path. + +**Why not in the app:** The file walker is inside the combined autocomplete provider. + +### opt-in-inline-slash-autocomplete — keep + +**Decision:** When enabled, `/` after whitespace mid-input or at the start of a later line opens autocomplete, and further token characters refresh the in-flight request. + +**Why not in the app:** Slash detection is inside the editor's input handler, before the provider runs. + +### marked-completion-enter-does-not-submit — keep + +**Decision:** Autocomplete items may carry opaque host data. Confirming a host-marked item with Enter applies the completion and does not submit. Unmarked slash completions still submit on Enter. + +**Why not in the app:** Enter-to-submit is handled in the editor while the completion list is open. + +### autolink-stops-at-cjk-punctuation — keep + +**Decision:** A bare URL followed by CJK or full-width punctuation does not swallow those characters into the link text and href. Balanced full-width parentheses stay in the URL, matching GFM's ASCII-paren rule. + +**Why not in the app:** Autolink matching is in the markdown tokenizer. + +### fullscreen-nav-falls-through-when-idle — keep + +**Decision:** Fullscreen can swap the layout root. When the primary scroll view has nothing to scroll, viewport keys go to the focused component. Terminal focus in/out reports are not consumed, so app-level listeners still see them. + +**Why not in the app:** Viewport key handling and focus-report consumption sit in the alternate-screen input path. + +### input-click-uses-prompt-width — keep + +**Decision:** Click-to-position in `Input` subtracts the configured prompt's visible width instead of the default two columns. + +**Why not in the app:** The click-to-caret mapping is inside `Input.handleMouse`, before any host callback. + +### alt-screen-search-field-forwards-mouse — keep + +**Decision:** The fullscreen search component forwards pointer input on its text row to the embedded `Input` with translated coordinates, so the caret can be positioned by mouse. Navigation-button hit regions are unaffected. + +**Why not in the app:** The search component and the overlay mouse dispatch both live in the library; the app cannot reach the inner `Input`. + +### export-mouse-dispatch-result — keep + +**Decision:** The package entry exports the `TuiMouseDispatchResult` type so hosts can type components that delegate mouse events to children. + +**Why not in the app:** Type-only export surface; the app cannot name the base `Container.handleMouse` return type without it. + +### mouse-dispatch-accounts-for-cropped-rows — keep + +**Decision:** When the layout crops an over-tall component to keep its cursor row visible, alternate-screen mouse dispatch includes the box's `lineOffset` in the local coordinate transform and uses the uncropped rendered height, so clicks map to the rows actually displayed. + +**Why not in the app:** The crop offset is computed inside the layout engine and the translation happens in the alternate-screen dispatch path. + +### input-scroll-origin-aligns-to-grapheme — keep + +**Decision:** The cached horizontal-scroll origin used for click mapping in `Input` is the grapheme boundary actually displayed first, not the raw column the scroller chose. + +**Why not in the app:** The scroll origin is computed inside `Input.render`; the click mapper only sees the cached value. diff --git a/packages/pi-tui/package.json b/packages/pi-tui/package.json new file mode 100644 index 0000000000000000000000000000000000000000..58ae41986abee130d81af3b262ecd26852858a1b --- /dev/null +++ b/packages/pi-tui/package.json @@ -0,0 +1,70 @@ +{ + "name": "@moonshot-ai/pi-tui", + "version": "0.84.5", + "private": true, + "description": "Terminal User Interface library with differential rendering for efficient text-based applications", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/pi-tui#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/pi-tui" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "tui", + "terminal", + "ui", + "text-editor", + "differential-rendering", + "typescript", + "cli" + ], + "files": [ + "dist", + "native", + "README.md" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public", + "exports": { + ".": { + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "default": "./dist/index.mjs" + } + }, + "provenance": true + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "node --test test/*.test.ts", + "clean": "rm -rf dist" + }, + "dependencies": { + "get-east-asian-width": "1.6.0", + "marked": "18.0.11" + }, + "devDependencies": { + "@xterm/headless": "5.5.0", + "chalk": "^5.4.1" + }, + "engines": { + "node": ">=22.19.0" + } +} diff --git a/packages/pi-tui/tsconfig.json b/packages/pi-tui/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..5c3ca434f25a3bc994312e0c9adb1b2e71fbe61f --- /dev/null +++ b/packages/pi-tui/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "lib": ["ESNext"] + }, + "include": ["src"] +} diff --git a/packages/pi-tui/vitest.config.ts b/packages/pi-tui/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..8dbb6fd118824d94b7773dd754f220bbbfb3f53b --- /dev/null +++ b/packages/pi-tui/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "vitest/config"; + +// pi-tui's suite is written for `node:test` and runs through the package +// `test` script (`node --test test/*.test.ts`). Vitest cannot execute +// `node:test`-style tests, so the repo's projects-mode `vitest run` is +// pointed at no files here and allowed to pass with none. Convert a test +// file to vitest's API and add it to `include` to opt it in. +export default defineConfig({ + test: { + include: [], + passWithNoTests: true, + }, +}); diff --git a/packages/remote-control/package.json b/packages/remote-control/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cdf5c42fdf2b9328542aa01b9d0163981a78ead1 --- /dev/null +++ b/packages/remote-control/package.json @@ -0,0 +1,50 @@ +{ + "name": "@moonshot-ai/remote-control", + "version": "0.0.0", + "private": true, + "description": "Kimi Remote Control tunnel client: registers this machine with the relay and forwards HTTP/WebSocket traffic to the local server.", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/remote-control#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/remote-control" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "kimi", + "remote-control", + "relay", + "tunnel" + ], + "files": [ + "dist" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "vitest run", + "clean": "rm -rf dist" + }, + "dependencies": { + "@moonshot-ai/agent-core-v2": "workspace:^", + "@moonshot-ai/kimi-code-oauth": "workspace:^", + "ws": "^8.18.0" + }, + "devDependencies": { + "@types/ws": "^8.18.0" + } +} diff --git a/packages/remote-control/tsconfig.json b/packages/remote-control/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..46f71c10fe9bf3db4a842fcf49a4efcdf1c297be --- /dev/null +++ b/packages/remote-control/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": {}, + "include": ["src", "test"] +} diff --git a/packages/remote-control/tsdown.config.ts b/packages/remote-control/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..b27e00afd787b9235f7dda93ae5f68453a0246de --- /dev/null +++ b/packages/remote-control/tsdown.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm'], + dts: false, + outDir: 'dist', + clean: true, + deps: { + alwaysBundle: [/^@moonshot-ai\//], + neverBundle: [], + }, +}); diff --git a/packages/remote-control/vitest.config.ts b/packages/remote-control/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..60b1f62e406b2b6c7f9725ae84a1cfbedc4aa168 --- /dev/null +++ b/packages/remote-control/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'remote-control', + include: ['test/**/*.test.ts'], + testTimeout: 30_000, + }, +}); diff --git a/packages/telemetry/README.md b/packages/telemetry/README.md new file mode 100644 index 0000000000000000000000000000000000000000..414dfda9a0b43e89088c776651da586e6dbc84ad --- /dev/null +++ b/packages/telemetry/README.md @@ -0,0 +1,11 @@ +# @moonshot-ai/kimi-telemetry + +Shared telemetry infrastructure for Kimi Code. + +Part of the [Kimi Code](https://github.com/MoonshotAI/kimi-code) monorepo. + +See the main repository for documentation, issues, and contribution guidelines. + +## License + +MIT diff --git a/packages/telemetry/package.json b/packages/telemetry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..36d0f60a396e215bcd89e2d9259440011eee08ce --- /dev/null +++ b/packages/telemetry/package.json @@ -0,0 +1,43 @@ +{ + "name": "@moonshot-ai/kimi-telemetry", + "version": "0.1.1", + "private": true, + "description": "Shared telemetry infrastructure for Kimi Code", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/telemetry#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/telemetry" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "kimi", + "telemetry", + "analytics", + "events", + "client" + ], + "files": [ + "dist" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "build": "tsdown", + "test": "vitest run", + "typecheck": "tsc -p tsconfig.json --noEmit", + "clean": "rm -rf dist" + } +} diff --git a/packages/telemetry/tsconfig.json b/packages/telemetry/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..46f71c10fe9bf3db4a842fcf49a4efcdf1c297be --- /dev/null +++ b/packages/telemetry/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": {}, + "include": ["src", "test"] +} diff --git a/packages/telemetry/tsdown.config.ts b/packages/telemetry/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb99d9ffb8e94a84c8ca5d67fadd07fc7f082837 --- /dev/null +++ b/packages/telemetry/tsdown.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm'], + dts: true, + outDir: 'dist', + clean: true, +}); diff --git a/packages/telemetry/vitest.config.ts b/packages/telemetry/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1924a1b0d49b6edf066d05755083a8703cfa783 --- /dev/null +++ b/packages/telemetry/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'kimi-telemetry', + include: ['test/**/*.test.ts'], + }, +}); diff --git a/packages/transcript/CHANGELOG.md b/packages/transcript/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..c09f91b7113dc0115af4e14f6559cfeb51922c1b --- /dev/null +++ b/packages/transcript/CHANGELOG.md @@ -0,0 +1,13 @@ +# @moonshot-ai/transcript + +## 0.0.2 + +### Patch Changes + +- [#3289](https://github.com/MoonshotAI/kimi-code/pull/3289) [`f143130`](https://github.com/MoonshotAI/kimi-code/commit/f143130c072e9dba8d60ef40c49d4305b93ab2fe) Thanks [@liruifengv](https://github.com/liruifengv)! - Carry the orchestrator's prompt on subagent turns: `isDisplayablePromptOrigin` now accepts `system_trigger/subagent`, so live `turn.started` events include the prompt, and cold rebuild folds the opening input (text and attachments) into turns opened by subagent run messages. Other system triggers (goal_continuation, stop_hook, loadable-tools) remain promptless. + +## 0.0.1 + +### Patch Changes + +- [#1888](https://github.com/MoonshotAI/kimi-code/pull/1888) [`5ae60fa`](https://github.com/MoonshotAI/kimi-code/commit/5ae60fa6736b63b80bd764ef01d6c0334eb80595) Thanks [@sailist](https://github.com/sailist)! - Add a unified, agent-granular transcript rendering data layer and serve it from the v2 server: clients can fetch turn-paginated transcripts via `GET /sessions/{id}/transcript` and subscribe to per-agent transcript updates over the v1 WebSocket with per-connection granularity control (off / turn / block / delta). All transcript wire types are owned by the transcript package itself. `turn.started` now carries the turn's prompt text so live transcripts render the user input as soon as the turn opens. diff --git a/packages/transcript/package.json b/packages/transcript/package.json new file mode 100644 index 0000000000000000000000000000000000000000..b7a109cdc47ab26826d8f67b4831df6e77bb7355 --- /dev/null +++ b/packages/transcript/package.json @@ -0,0 +1,35 @@ +{ + "name": "@moonshot-ai/transcript", + "version": "0.0.2", + "private": true, + "description": "Isomorphic transcript rendering data layer: agent-granular L1 store, idempotent L2 operations, granularity-gated L3 subscriptions, framework-free L4 view registry.", + "license": "MIT", + "author": "Moonshot AI", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/transcript" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "vitest run", + "clean": "rm -rf dist" + }, + "dependencies": { + "zod": "catalog:" + } +} diff --git a/packages/transcript/tsconfig.json b/packages/transcript/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..2abca3c5c85afafde65ad81dafbf5ff4a08ab8dc --- /dev/null +++ b/packages/transcript/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "lib": ["ESNext"] + }, + "include": ["src", "test"] +} diff --git a/packages/transcript/tsdown.config.ts b/packages/transcript/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..b27e00afd787b9235f7dda93ae5f68453a0246de --- /dev/null +++ b/packages/transcript/tsdown.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm'], + dts: false, + outDir: 'dist', + clean: true, + deps: { + alwaysBundle: [/^@moonshot-ai\//], + neverBundle: [], + }, +}); diff --git a/packages/transcript/vitest.config.ts b/packages/transcript/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..7bddda3ef7428bbecb1318e268b67fab44ec9780 --- /dev/null +++ b/packages/transcript/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'transcript', + include: ['test/**/*.test.ts'], + }, +}); diff --git a/packages/tree-sitter-bash/README.md b/packages/tree-sitter-bash/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8ef128d62fbd803ae6d4b2aa096fd7f0cfa3a906 --- /dev/null +++ b/packages/tree-sitter-bash/README.md @@ -0,0 +1,273 @@ +# @moonshot-ai/tree-sitter-bash + +A pure-TypeScript bash parser that produces a syntax tree whose named node +types match [tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash) +0.25.0 one-to-one, built for agent-side command permission analysis. + +- No native addons; offsets are UTF-16 code units (`node.text` is always a + direct `source.slice(startIndex, endIndex)`). +- Parsing runs under a hard budget and never throws: budget exhaustion + returns `{ ok: false, reason: 'aborted' }`, malformed input returns a + degraded tree with `hasError: true`. +- Correctness is enforced by a differential test suite that parses hundreds + of samples — plus the complete official tree-sitter-bash 0.25.0 corpus — + with both this parser and the real tree-sitter-bash (wasm) and compares + the trees byte-for-byte (see `test/fixtures/`). The only remaining + deviations are the documented ones listed under + [Known differences](#known-differences-from-tree-sitter-bash) below. + +## API + +```ts +import { parse } from '@moonshot-ai/tree-sitter-bash'; + +const result = parse('git status && rm -rf /'); +if (result.ok) { + // result.rootNode: program → list → command … +} +``` + +- `parse(source: string, options?: ParseOptions): ParseResult` +- `ParseResult` is one of: + - `{ ok: true; rootNode: SyntaxNode; hasError: boolean }` + - `{ ok: false; reason: 'aborted' }` +- `ParseOptions`: `{ timeoutMs?: number; maxNodes?: number }` (defaults + 50 ms / 50 000 nodes; `timeoutMs: Infinity` disables the time check). +- `SyntaxNode`: `{ type, text, startIndex, endIndex, isNamed, parent, + children, namedChildren }`. Named node types come from tree-sitter-bash's + `node-types.json`; `children` includes the anonymous (punctuation / + keyword token) nodes as well, `namedChildren` only the named ones, and + `descendantsOfType(root, ...types)` walks named descendants. +- Depth caps (pathological nesting degrades locally — ERROR nodes, + `hasError: true` — instead of overflowing the stack): + - `MAX_SUBSTITUTION_DEPTH = 150` for the $( … ) / `…` / <( … ) + sub-parser chain (the deepest per level, ~13 frames — measured stack + overflow at ~380–500 levels on a default Node stack, so the cap keeps + a ≥2.5× margin); + - `MAX_PARSE_DEPTH = 500` for subshell/compound/`${…}`/expression + nesting (verified safe at those caps); + - `MAX_SCAN_DEPTH = 1024` for the lexer's own scan recursion. + +## Budget semantics + +The budget caps total work, not input size: a multi-hundred-KB string or +heredoc body parses fine (it produces only a handful of nodes), but a +source whose tree would exceed 50 000 nodes — a megabyte-long `case` +statement, tens of thousands of arithmetic expressions — is aborted under +the defaults. Every created node ticks the budget; long character-level +scan loops re-check the deadline periodically. When either limit is hit, +`parse` returns `{ ok: false, reason: 'aborted' }` and the abort is prompt +(see Performance). Pass `timeoutMs` / `maxNodes` to raise the limits. + +## Error recovery + +Malformed input never throws either. Unterminated constructs (quotes, +expansions, substitutions, heredocs, compound commands) are kept as +partial nodes and flagged with `hasError: true`; tokens that cannot start +or continue a statement (stray `)`, a leading `&&`, …) are wrapped in +`ERROR` nodes and parsing continues. Newlines never appear in the tree: +statement-terminating `\n`s produce no nodes at all (matching +tree-sitter-bash, whose scanner only emits `\n` tokens in heredoc +position), while `;` / `&` terminators are anonymous children. As a +last-resort guard against parser bugs, any unexpected internal exception +degrades to a `program` root with a single `ERROR` child spanning the +source and `hasError: true` — callers still get a usable tree. + +## Known differences from tree-sitter-bash + +Named node types always come from tree-sitter-bash's `node-types.json`, but +for the following constructs the tree shape deliberately deviates from what +tree-sitter-bash 0.25.0 produces (each verified against the real parser, +and pinned by a stored expectation in `test/fixtures/` — see +`test/helpers/known-differences.ts`): + +- `<>` (read-write redirect) is parsed as a normal `file_redirect` + operator; tree-sitter-bash 0.25.0 fails to parse it. +- Several heredocs on one line (`cat <`) is a + `word` in the reference even when its content would make it a glob + (`cmake_modules` — a scanner-state quirk); this parser classifies + patterns by content, so such a pattern is an `extglob_pattern` here. A + continuation INSIDE a pattern (`cont\ued)`) is an error in the + reference (word "cont" + `ERROR` "ued", `hasError: true`), and a + continuation fused with a digit (`a\1)`) is an + `extglob_pattern` there; this parser keeps the continuation and parses + the whole pattern cleanly as one `word` — which is also how bash itself + reads it. +- A comparison right side with TWO substitutions or quotes + (`*${x}*${y}`, `*"s"*"t"`) does not fit the reference's one-construct + pattern rule either; it recovers with a nested `binary_expression` + there, while this parser keeps a single `concatenation` right side. +- A few `[[ … ]]` comparison right-hand sides deviate: + - A negative decimal operand (`[[ $n == -0.5 ]]`) is a + `unary_expression` (`-` over word "0.5") in the reference; this parser + produces a single `extglob_pattern` "-0.5" (the unary-minus reading + only covers integers here). + - A test operator fused with an expansion (`[[ -x$f && … ]]`) is a + `unary_expression` (`-` over a `concatenation` of `x` and `$f`) in the + reference; this parser produces a flat `concatenation` of `-x` and + `$f` with no unary wrapper. + - An escaped `|` inside a pattern (`[[ $a == foo\|bar ]]`) splits the + expression in the reference — `binary_expression(==, extglob "foo\")` + then `|` then word "bar" (a reference quirk); this parser keeps one + `extglob_pattern` "foo\|bar". +- `${!# }` and `${!## }` (and `${!##/}`) are pathological expansion forms: + the reference recovers with zero-width operator tokens, this parser with + a flagged partial `expansion`; the shapes differ. (The sane forms + `${#}`, `${!#}`, `${!##}`, `${#!}` all match exactly.) +- A base prefix fused with an expansion (`10#${x}`) is one `number` node + spanning the expansion in the reference (a quirk); this parser produces + a `concatenation` of word "10#" and the expansion. +- `${v:-(default)}` (a parenthesized default value) is a plain `word` + here; the reference parses it as an `array` node (a quirk). +- `${=1}` (zsh-style word splitting flag) produces a `variable_name` "1" + in the reference; this parser produces a `word`. +- An escaped space or tab between arguments is dropped by the reference + as invisible extras (its tree has gaps: `echo 1 \ 2` produces number + "1" and number "2", and `echo a\b` splits into word "a" and word + "b"); this parser keeps the escape inside the word. (An escaped space + INSIDE a word, `a\ b`, is kept by both parsers and matches.) +- A `$` directly fused with a backtick substitution (`` $`echo x` ``) is + one `command_substitution` with a `$`+backtick token in the reference; + this parser produces a `($)` token followed by the substitution. +- A non-ASCII “identifier” in assignment position (`变量=值`, `é=1`) is a + `variable_assignment` flagged `hasError` in the reference; this parser + keeps it a plain command word — which is also how bash itself treats it + (variable names are ASCII-only, so the text runs as a command). +- A negative literal after a compound assignment in a c-style for header + (`for (( … j *= -1, … ))`) is folded into a `number` "-1" by the + reference; this parser produces a `unary_expression` (`-` over number + "1") — matching what the reference itself produces everywhere else. +- A double backslash in a replacement value (`${x// /\\|}`) loses its + first backslash in the reference's tree (a quirk — the `word` starts + one character later); this parser keeps both. +- `string_content` is not split at newlines (tree-sitter-bash's scanner + splits it). + +For completeness, a few constructs that LOOK like deviations but are not — +the reference behaves the same way (verified): + +- `coproc` has no grammar support in tree-sitter-bash 0.25.0 and parses as + an ordinary command; so does this parser. +- `select` is parsed as a `for_statement` with a `select` keyword token — + that is exactly the reference's tree (there is no `select_statement` + node type). +- `$"…"` (translated string): in command-argument position it is an + anonymous `$` argument followed by the `string` argument; everywhere + else (assignment values, redirect destinations, for-loop values, …) it + is a `translated_string` node. Both match the reference exactly. + `$'…'` is a single-child-free `ansi_c_string` node, also matching. +- Brace expansion: only `{N..M}` (unsigned digits) is a `brace_expression`; + `{a..z}`, `{1..10..2}` and `{-5..5}` are plain word concatenations in the + reference and here. +- Statement-position `((word++…))` (inner text starting with a bare + identifier plus a postfix `++`/`--`) is a `test_command` in the + reference — its statement-position arithmetic grammar does not accept + that form — while `((x = 1))`, `((b + a++))`, `((a[i]++))` and + argument-position `((a++))` are `arithmetic_expansion`. This parser + matches all of these, including after `!`. +- Command-prefix redirects take exactly one destination (`> a cmd x` makes + `cmd` the `command_name`), while redirects after the command name consume + every following word (`cmd > out arg` puts both words in the redirect) — + this matches tree-sitter-bash's actual disambiguation. + +## Performance + +Measured on an Apple-silicon MacBook (Node 24, default 50 ms / 50 000-node +budget): + +- A typical one-line command (`git status && rm -rf /`): ~4 µs per parse. +- A 100 KB realistic deployment script (functions, loops, redirects, + expansions, heredocs): tens of milliseconds per parse (~20–60 ms across + runs and machines) — the same order of magnitude as the default 50 ms + budget, so such inputs may return `ok: true` or a prompt abort depending + on the machine; raise `timeoutMs` when parsing whole scripts. +- A 500 KB heredoc body: parses within the default budget (the tree has + only a handful of nodes). +- The abort path is prompt: a 400 KB node-budget bomb aborts in ~20 ms + (hard guarantee asserted by the test suite: < 100 ms). + +These numbers are smoke-tested as orders of magnitude in +`test/performance.test.ts` to guard against accidental quadratic +complexity; absolute timings vary by machine. diff --git a/packages/tree-sitter-bash/package.json b/packages/tree-sitter-bash/package.json new file mode 100644 index 0000000000000000000000000000000000000000..dab858aa31228b8b50f8b59e52896fb2de75fda8 --- /dev/null +++ b/packages/tree-sitter-bash/package.json @@ -0,0 +1,47 @@ +{ + "name": "@moonshot-ai/tree-sitter-bash", + "version": "0.1.0", + "private": true, + "description": "A pure-TypeScript bash parser producing a syntax tree whose named node types match tree-sitter-bash one-to-one.", + "license": "MIT", + "author": "Moonshot AI", + "homepage": "https://github.com/MoonshotAI/kimi-code/tree/main/packages/tree-sitter-bash#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/MoonshotAI/kimi-code.git", + "directory": "packages/tree-sitter-bash" + }, + "bugs": { + "url": "https://github.com/MoonshotAI/kimi-code/issues" + }, + "keywords": [ + "kimi", + "bash", + "shell", + "parser", + "tree-sitter" + ], + "files": [ + "dist" + ], + "type": "module", + "imports": { + "#/*": "./src/*.ts" + }, + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "scripts": { + "build": "tsdown", + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "vitest run", + "clean": "rm -rf dist" + }, + "devDependencies": { + "tree-sitter-bash": "0.25.0", + "web-tree-sitter": "0.25.10" + } +} diff --git a/packages/tree-sitter-bash/tsconfig.json b/packages/tree-sitter-bash/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..46f71c10fe9bf3db4a842fcf49a4efcdf1c297be --- /dev/null +++ b/packages/tree-sitter-bash/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": {}, + "include": ["src", "test"] +} diff --git a/packages/tree-sitter-bash/tsdown.config.ts b/packages/tree-sitter-bash/tsdown.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..b27e00afd787b9235f7dda93ae5f68453a0246de --- /dev/null +++ b/packages/tree-sitter-bash/tsdown.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm'], + dts: false, + outDir: 'dist', + clean: true, + deps: { + alwaysBundle: [/^@moonshot-ai\//], + neverBundle: [], + }, +}); diff --git a/packages/tree-sitter-bash/vitest.config.ts b/packages/tree-sitter-bash/vitest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..85c8b889e83a60764b6037371428a13763e886c6 --- /dev/null +++ b/packages/tree-sitter-bash/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + name: 'tree-sitter-bash', + include: ['test/**/*.test.ts'], + }, +});