diff --git a/.changeset/agent-manager-prompt-picker.md b/.changeset/agent-manager-prompt-picker.md deleted file mode 100644 index 5d88c9825ad..00000000000 --- a/.changeset/agent-manager-prompt-picker.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Keep long New Worktree prompts clear of selector controls and show inline model picker options without clipping. diff --git a/.changeset/background-process-ports.md b/.changeset/background-process-ports.md new file mode 100644 index 00000000000..dfaaddcc676 --- /dev/null +++ b/.changeset/background-process-ports.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Show detected ports for tracked background processes in the TUI sidebar and process detail dialog. diff --git a/.changeset/background-processes-cli.md b/.changeset/background-processes-cli.md new file mode 100644 index 00000000000..6aed067705b --- /dev/null +++ b/.changeset/background-processes-cli.md @@ -0,0 +1,5 @@ +--- +"kilo-code": minor +--- + +Support tracked background processes in the CLI and VS Code so agents can start long-running dev servers and clean them up when sessions change or end. The CLI also includes process management UI, status, and logs. diff --git a/.changeset/breezy-models-float.md b/.changeset/breezy-models-float.md deleted file mode 100644 index 84b355eb520..00000000000 --- a/.changeset/breezy-models-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Improve the JetBrains model picker with sections, favorites, and smart filtering. diff --git a/.changeset/bright-searches-count.md b/.changeset/bright-searches-count.md deleted file mode 100644 index d518bc898d4..00000000000 --- a/.changeset/bright-searches-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/cli": patch ---- - -Capture aggregate usage telemetry for experimental Morph-backed codebase search. diff --git a/.changeset/bright-windows-logo.md b/.changeset/bright-windows-logo.md new file mode 100644 index 00000000000..c0ed555e384 --- /dev/null +++ b/.changeset/bright-windows-logo.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Use the fallback logo in old Windows terminal emulators while keeping the Unicode logo available over SSH. diff --git a/.changeset/chilly-dancers-build.md b/.changeset/chilly-dancers-build.md deleted file mode 100644 index 3f8b568bc5d..00000000000 --- a/.changeset/chilly-dancers-build.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Add a JetBrains tool window action for starting new sessions and let recent sessions reopen in the side panel without duplicate views. diff --git a/.changeset/continue-worktree-sessions.md b/.changeset/continue-worktree-sessions.md deleted file mode 100644 index 95a49a2b807..00000000000 --- a/.changeset/continue-worktree-sessions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Keep continued Agent Manager sessions in the selected worktree instead of moving them to Local. diff --git a/.changeset/custom-question-jetbrains.md b/.changeset/custom-question-jetbrains.md new file mode 100644 index 00000000000..97a63d7f16c --- /dev/null +++ b/.changeset/custom-question-jetbrains.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Support typed custom responses to question prompts in the JetBrains plugin. diff --git a/.changeset/editor-sized-jetbrains-chat.md b/.changeset/editor-sized-jetbrains-chat.md deleted file mode 100644 index 221bd814f6e..00000000000 --- a/.changeset/editor-sized-jetbrains-chat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Scale JetBrains chat transcript fonts from the editor font settings. diff --git a/.changeset/favorite-picker-index.md b/.changeset/favorite-picker-index.md deleted file mode 100644 index 602a32bfe03..00000000000 --- a/.changeset/favorite-picker-index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Keep the JetBrains model picker at the same row position when models are favorited or unfavorited. diff --git a/.changeset/fix-command-template-serialization.md b/.changeset/fix-command-template-serialization.md new file mode 100644 index 00000000000..eb158322998 --- /dev/null +++ b/.changeset/fix-command-template-serialization.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Fix JetBrains startup when command templates are returned as lazy objects. diff --git a/.changeset/fuzzy-berries-press.md b/.changeset/fuzzy-berries-press.md deleted file mode 100644 index 0c48bad5166..00000000000 --- a/.changeset/fuzzy-berries-press.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Show JetBrains session connection status inline above the prompt, cap expanded connection details, and keep empty sessions in the shared chat scroll area. diff --git a/.changeset/green-planes-reply.md b/.changeset/green-planes-reply.md deleted file mode 100644 index f9b3517d9c4..00000000000 --- a/.changeset/green-planes-reply.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Show detailed JetBrains session connection and configuration issues in the connection panel, and make retry recover app-side problems more reliably. diff --git a/.changeset/inline-review-speech.md b/.changeset/inline-review-speech.md deleted file mode 100644 index 30cf6eeb87b..00000000000 --- a/.changeset/inline-review-speech.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Support speech-to-text voice input in Agent Manager inline review comments. diff --git a/.changeset/jetbrains-chat-renderers.md b/.changeset/jetbrains-chat-renderers.md deleted file mode 100644 index 0a099733c1b..00000000000 --- a/.changeset/jetbrains-chat-renderers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Match VS Code-style reasoning and tool run rendering in JetBrains chat. diff --git a/.changeset/jetbrains-empty-panel-layout.md b/.changeset/jetbrains-empty-panel-layout.md deleted file mode 100644 index 3f13739eeb8..00000000000 --- a/.changeset/jetbrains-empty-panel-layout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Center description text and remove the fixed-width cap from the empty session panel so recent sessions can stretch naturally. diff --git a/.changeset/jetbrains-existing-session-scroll.md b/.changeset/jetbrains-existing-session-scroll.md deleted file mode 100644 index 534092cc3f9..00000000000 --- a/.changeset/jetbrains-existing-session-scroll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Open existing JetBrains sessions scrolled to the latest message after history loads. diff --git a/.changeset/jetbrains-header-tooltips.md b/.changeset/jetbrains-header-tooltips.md deleted file mode 100644 index eabe4154aa9..00000000000 --- a/.changeset/jetbrains-header-tooltips.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Remember the JetBrains session header metrics expansion preference and show file names in read/write timeline tooltips. diff --git a/.changeset/jetbrains-history-navigation.md b/.changeset/jetbrains-history-navigation.md deleted file mode 100644 index 92f361fc775..00000000000 --- a/.changeset/jetbrains-history-navigation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Improve JetBrains history navigation with Back support and a Show History action in recent sessions. diff --git a/.changeset/jetbrains-history-tabs.md b/.changeset/jetbrains-history-tabs.md deleted file mode 100644 index 859a598e3e8..00000000000 --- a/.changeset/jetbrains-history-tabs.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Improve the JetBrains history panel with native tabs, independent local and cloud search, and date-grouped cloud sessions. diff --git a/.changeset/jetbrains-logged-out-account-panel.md b/.changeset/jetbrains-logged-out-account-panel.md new file mode 100644 index 00000000000..67599a66745 --- /dev/null +++ b/.changeset/jetbrains-logged-out-account-panel.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Show the logged-out account status in the same rounded panel as the logged-in account overlay, with a "Not logged in" label, hidden picker/balance, and a profile icon to open settings. diff --git a/.changeset/jetbrains-login-dismiss.md b/.changeset/jetbrains-login-dismiss.md new file mode 100644 index 00000000000..4df6bb9e3b3 --- /dev/null +++ b/.changeset/jetbrains-login-dismiss.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Add a Dismiss button to the paid-model sign-in prompt so users can close it and choose a different model. diff --git a/.changeset/jetbrains-login-qr.md b/.changeset/jetbrains-login-qr.md new file mode 100644 index 00000000000..2e3447eee2e --- /dev/null +++ b/.changeset/jetbrains-login-qr.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Improve JetBrains sign-in UI: step labels are left-aligned, the URL field selects all on click, copying the URL or device code shows a confirmation balloon, and the click-to-copy code card and balance card share the same themed background and border. diff --git a/.changeset/jetbrains-mode-picker.md b/.changeset/jetbrains-mode-picker.md deleted file mode 100644 index 7d3b6b2011d..00000000000 --- a/.changeset/jetbrains-mode-picker.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Improve the JetBrains mode picker with descriptions, deprecated badges, and native IntelliJ selection behavior. diff --git a/.changeset/jetbrains-paid-model-login.md b/.changeset/jetbrains-paid-model-login.md new file mode 100644 index 00000000000..f2ed31b2e8a --- /dev/null +++ b/.changeset/jetbrains-paid-model-login.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Show a sign-in prompt in JetBrains sessions when a paid model requires login. diff --git a/.changeset/jetbrains-permission-compact-rows.md b/.changeset/jetbrains-permission-compact-rows.md new file mode 100644 index 00000000000..495d1ded6cd --- /dev/null +++ b/.changeset/jetbrains-permission-compact-rows.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Improve JetBrains permission prompts with compact action rows and diff badges. diff --git a/.changeset/jetbrains-profile-polish.md b/.changeset/jetbrains-profile-polish.md new file mode 100644 index 00000000000..5af1f098434 --- /dev/null +++ b/.changeset/jetbrains-profile-polish.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Polish the JetBrains user profile settings layout with a compact account stack, copyable email, simplified organization names, and a refreshable balance card. diff --git a/.changeset/jetbrains-profile-settings.md b/.changeset/jetbrains-profile-settings.md new file mode 100644 index 00000000000..7c715449215 --- /dev/null +++ b/.changeset/jetbrains-profile-settings.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Add native Kilo profile settings page to JetBrains plugin. Settings > Tools > Kilo > User Profile shows login/logout, balance, personal/org account switching, and a dashboard link, and refreshes immediately after login, logout, or active account changes. A new Profile button in the tool window toolbar opens the page directly. The profile settings page now keeps its native UI mounted while login state and active account details change. diff --git a/.changeset/jetbrains-scroll-bottom.md b/.changeset/jetbrains-scroll-bottom.md deleted file mode 100644 index b98469fac73..00000000000 --- a/.changeset/jetbrains-scroll-bottom.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Keep the JetBrains chat transcript pinned to bottom reliably while responses stream. diff --git a/.changeset/jetbrains-scroll-button.md b/.changeset/jetbrains-scroll-button.md deleted file mode 100644 index 31762b7e48c..00000000000 --- a/.changeset/jetbrains-scroll-button.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Show a scroll-to-bottom button when JetBrains chat sessions are scrolled away from the latest message. diff --git a/.changeset/jetbrains-send-action.md b/.changeset/jetbrains-send-action.md deleted file mode 100644 index 6f6f30a3d41..00000000000 --- a/.changeset/jetbrains-send-action.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Support rebinding the JetBrains prompt Send action in the IntelliJ keymap. diff --git a/.changeset/jetbrains-session-account-overlay.md b/.changeset/jetbrains-session-account-overlay.md new file mode 100644 index 00000000000..600bc055108 --- /dev/null +++ b/.changeset/jetbrains-session-account-overlay.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Show account login, switching, and balance controls on the empty JetBrains session screen. diff --git a/.changeset/jetbrains-session-header.md b/.changeset/jetbrains-session-header.md deleted file mode 100644 index 9c13aa6c9d5..00000000000 --- a/.changeset/jetbrains-session-header.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Show collapsible session metadata, context usage, token usage, and compaction controls in the JetBrains session header. diff --git a/.changeset/jetbrains-session-history.md b/.changeset/jetbrains-session-history.md deleted file mode 100644 index 8aa827208cc..00000000000 --- a/.changeset/jetbrains-session-history.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Add a native session history panel to the JetBrains plugin. diff --git a/.changeset/jetbrains-session-layout-padding.md b/.changeset/jetbrains-session-layout-padding.md deleted file mode 100644 index 2fbf40c42d8..00000000000 --- a/.changeset/jetbrains-session-layout-padding.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Control JetBrains chat transcript spacing from the session layout. diff --git a/.changeset/jetbrains-session-loading-state.md b/.changeset/jetbrains-session-loading-state.md deleted file mode 100644 index bc930ebcbca..00000000000 --- a/.changeset/jetbrains-session-loading-state.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Show loading immediately when opening JetBrains sessions without showing duplicate progress for new sessions. diff --git a/.changeset/jetbrains-session-scroll-layout.md b/.changeset/jetbrains-session-scroll-layout.md deleted file mode 100644 index ea065c67885..00000000000 --- a/.changeset/jetbrains-session-scroll-layout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Reduce redundant JetBrains chat scroll layout work while keeping bottom-follow behavior. diff --git a/.changeset/jetbrains-step-finish-timeline.md b/.changeset/jetbrains-step-finish-timeline.md deleted file mode 100644 index 6afba10a4bc..00000000000 --- a/.changeset/jetbrains-step-finish-timeline.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Show completed assistant steps in the JetBrains session timeline. diff --git a/.changeset/jetbrains-stop-action.md b/.changeset/jetbrains-stop-action.md deleted file mode 100644 index 34bdae579dc..00000000000 --- a/.changeset/jetbrains-stop-action.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Support stopping active JetBrains sessions from the prompt action button. diff --git a/.changeset/markdown-review-voice.md b/.changeset/markdown-review-voice.md deleted file mode 100644 index d883a488ca4..00000000000 --- a/.changeset/markdown-review-voice.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Keep inline review voice capture stable in rendered Markdown diffs. diff --git a/.changeset/mermaid-security-fixes.md b/.changeset/mermaid-security-fixes.md deleted file mode 100644 index 4a9947d7248..00000000000 --- a/.changeset/mermaid-security-fixes.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@kilocode/cli": patch -"@kilocode/kilo-docs": patch ---- - -Harden Mermaid diagram rendering with upstream security fixes. diff --git a/.changeset/mingw-terminal-keyboard.md b/.changeset/mingw-terminal-keyboard.md new file mode 100644 index 00000000000..c6135cc3e10 --- /dev/null +++ b/.changeset/mingw-terminal-keyboard.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Avoid leaving mouse and advanced keyboard modes enabled after exiting the TUI in mintty and MINGW terminals. diff --git a/.changeset/model-picker-natural-size.md b/.changeset/model-picker-natural-size.md deleted file mode 100644 index 5fa0954e274..00000000000 --- a/.changeset/model-picker-natural-size.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Size the JetBrains model picker from its rendered model rows instead of fixed popup dimensions. diff --git a/.changeset/quiet-otters-reason.md b/.changeset/quiet-otters-reason.md deleted file mode 100644 index ad7b31eb35f..00000000000 --- a/.changeset/quiet-otters-reason.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Support reasoning effort selection and resetting JetBrains chat model overrides to the default model. diff --git a/.changeset/reasoning-picker-align.md b/.changeset/reasoning-picker-align.md deleted file mode 100644 index 4a21b9e9762..00000000000 --- a/.changeset/reasoning-picker-align.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Align checked and unchecked reasoning picker rows in the JetBrains plugin. diff --git a/.changeset/session-expandable-defaults.md b/.changeset/session-expandable-defaults.md new file mode 100644 index 00000000000..905b3adb933 --- /dev/null +++ b/.changeset/session-expandable-defaults.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Start expandable session sections collapsed by default. diff --git a/.changeset/session-question-view-style.md b/.changeset/session-question-view-style.md new file mode 100644 index 00000000000..ca25c743d45 --- /dev/null +++ b/.changeset/session-question-view-style.md @@ -0,0 +1,5 @@ +--- +"@kilocode/kilo-jetbrains": patch +--- + +Improve question-based session views so UI text uses editor-sized interface fonts, actions align consistently, and permission prompts show a header icon. diff --git a/.changeset/shiny-sessions-export.md b/.changeset/shiny-sessions-export.md deleted file mode 100644 index 57a07807cae..00000000000 --- a/.changeset/shiny-sessions-export.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Export full VS Code session transcripts as Markdown files. diff --git a/.changeset/slow-terms-dance.md b/.changeset/slow-terms-dance.md deleted file mode 100644 index 777d5bec8e7..00000000000 --- a/.changeset/slow-terms-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Keep the JetBrains session connection status above the prompt without shifting the chat layout. diff --git a/.changeset/smart-views-restore.md b/.changeset/smart-views-restore.md deleted file mode 100644 index 8cfb0295f83..00000000000 --- a/.changeset/smart-views-restore.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Restore only the Kilo Code sidebar, Agent Manager, or both on VS Code restart based on which views were open before shutdown. diff --git a/.changeset/soft-garlic-care.md b/.changeset/soft-garlic-care.md deleted file mode 100644 index ee6f55a6d61..00000000000 --- a/.changeset/soft-garlic-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Refine JetBrains session loading UI and settings actions. diff --git a/.changeset/steady-crabs-scroll.md b/.changeset/steady-crabs-scroll.md deleted file mode 100644 index 9688855539f..00000000000 --- a/.changeset/steady-crabs-scroll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Preserve JetBrains chat scroll position when reviewing earlier session output. diff --git a/.changeset/swift-voices-send.md b/.changeset/swift-voices-send.md deleted file mode 100644 index 6ee05869f9b..00000000000 --- a/.changeset/swift-voices-send.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Send recorded voice prompts directly when the prompt send button is pressed. diff --git a/.changeset/tidy-otters-wait.md b/.changeset/tidy-otters-wait.md deleted file mode 100644 index 151fcfe79af..00000000000 --- a/.changeset/tidy-otters-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-jetbrains": patch ---- - -Avoid flickering transient loading and connection error states in JetBrains sessions. diff --git a/.github/workflows/check-forbidden-strings.yml b/.github/workflows/check-forbidden-strings.yml new file mode 100644 index 00000000000..e199ab4b46e --- /dev/null +++ b/.github/workflows/check-forbidden-strings.yml @@ -0,0 +1,21 @@ +# kilocode_change - new file +name: Check forbidden strings + +on: + pull_request: + workflow_dispatch: + +jobs: + check: + name: Check forbidden strings + if: github.repository == 'Kilo-Org/kilocode' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 # kilocode_change + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - uses: oven-sh/setup-bun@v2 + + - name: Run check + run: bun run script/check-forbidden-strings.ts diff --git a/.github/workflows/check-opencode-annotations.yml b/.github/workflows/check-opencode-annotations.yml index 810371d6d3e..514958ad494 100644 --- a/.github/workflows/check-opencode-annotations.yml +++ b/.github/workflows/check-opencode-annotations.yml @@ -5,7 +5,6 @@ on: paths: - ".github/**" - "github/**" - - "sdks/vscode/**" - "packages/extensions/**" - "packages/opencode/**" - "packages/script/**" diff --git a/.github/workflows/disabled/daily-issues-recap.yml.disabled b/.github/workflows/disabled/daily-issues-recap.yml.disabled deleted file mode 100644 index 789712ef519..00000000000 --- a/.github/workflows/disabled/daily-issues-recap.yml.disabled +++ /dev/null @@ -1,170 +0,0 @@ -name: daily-issues-recap - -on: - schedule: - # Run at 6 PM EST (23:00 UTC, or 22:00 UTC during daylight saving) - - cron: "0 23 * * *" - workflow_dispatch: # Allow manual trigger for testing - -jobs: - daily-recap: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - issues: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://kilo.ai/install | bash - - - name: Generate daily issues recap - id: recap - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - KILO_PERMISSION: | - { - "bash": { - "*": "deny", - "gh issue*": "allow", - "gh search*": "allow" - }, - "webfetch": "deny", - "edit": "deny", - "write": "deny" - } - run: | - # Get today's date range - TODAY=$(date -u +%Y-%m-%d) - - opencode run -m opencode/claude-sonnet-4-5 "Generate a daily issues recap for the Kilo repository. - - TODAY'S DATE: ${TODAY} - - STEP 1: Gather today's issues - Search for all OPEN issues created today (${TODAY}) using: - gh issue list --repo ${{ github.repository }} --state open --search \"created:${TODAY}\" --json number,title,body,labels,state,comments,createdAt,author --limit 500 - - IMPORTANT: EXCLUDE all issues authored by Anomaly team members. Filter out issues where the author login matches ANY of these: - adamdotdevin, Brendonovich, fwang, Hona, iamdavidhill, jayair, kitlangton, kommander, MrMushrooooom, R44VC0RP, rekram1-node, thdxr - This recap is specifically for COMMUNITY (external) issues only. - - STEP 2: Analyze and categorize - For each issue created today, categorize it: - - **Severity Assessment:** - - CRITICAL: Crashes, data loss, security issues, blocks major functionality - - HIGH: Significant bugs affecting many users, important features broken - - MEDIUM: Bugs with workarounds, minor features broken - - LOW: Minor issues, cosmetic, nice-to-haves - - **Activity Assessment:** - - Note issues with high comment counts or engagement - - Note issues from repeat reporters (check if author has filed before) - - STEP 3: Cross-reference with existing issues - For issues that seem like feature requests or recurring bugs: - - Search for similar older issues to identify patterns - - Note if this is a frequently requested feature - - Identify any issues that are duplicates of long-standing requests - - STEP 4: Generate the recap - Create a structured recap with these sections: - - ===DISCORD_START=== - **Daily Issues Recap - ${TODAY}** - - **Summary Stats** - - Total issues opened today: [count] - - By category: [bugs/features/questions] - - **Critical/High Priority Issues** - [List any CRITICAL or HIGH severity issues with brief descriptions and issue numbers] - - **Most Active/Discussed** - [Issues with significant engagement or from active community members] - - **Trending Topics** - [Patterns noticed - e.g., 'Multiple reports about X', 'Continued interest in Y feature'] - - **Duplicates & Related** - [Issues that relate to existing open issues] - ===DISCORD_END=== - - STEP 5: Format for Discord - Format the recap as a Discord-compatible message: - - Use Discord markdown (**, __, etc.) - - BE EXTREMELY CONCISE - this is an EOD summary, not a detailed report - - Use hyperlinked issue numbers with suppressed embeds: [#1234]() - - Group related issues on single lines where possible - - Add emoji sparingly for critical items only - - HARD LIMIT: Keep under 1800 characters total - - Skip sections that have nothing notable (e.g., if no critical issues, omit that section) - - Prioritize signal over completeness - only surface what matters - - OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/recap_raw.txt - - # Extract only the Discord message between markers - sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/recap_raw.txt | grep -v '===DISCORD' > /tmp/recap.txt - - echo "recap_file=/tmp/recap.txt" >> $GITHUB_OUTPUT - - - name: Post to Discord - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} - run: | - if [ -z "$DISCORD_WEBHOOK_URL" ]; then - echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" - cat /tmp/recap.txt - exit 0 - fi - - # Read the recap - RECAP_RAW=$(cat /tmp/recap.txt) - RECAP_LENGTH=${#RECAP_RAW} - - echo "Recap length: ${RECAP_LENGTH} chars" - - # Function to post a message to Discord - post_to_discord() { - local msg="$1" - local content=$(echo "$msg" | jq -Rs '.') - curl -s -H "Content-Type: application/json" \ - -X POST \ - -d "{\"content\": ${content}}" \ - "$DISCORD_WEBHOOK_URL" - sleep 1 - } - - # If under limit, send as single message - if [ "$RECAP_LENGTH" -le 1950 ]; then - post_to_discord "$RECAP_RAW" - else - echo "Splitting into multiple messages..." - remaining="$RECAP_RAW" - while [ ${#remaining} -gt 0 ]; do - if [ ${#remaining} -le 1950 ]; then - post_to_discord "$remaining" - break - else - chunk="${remaining:0:1900}" - last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) - if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then - chunk="${remaining:0:$last_newline}" - remaining="${remaining:$((last_newline+1))}" - else - chunk="${remaining:0:1900}" - remaining="${remaining:1900}" - fi - post_to_discord "$chunk" - fi - done - fi - - echo "Posted daily recap to Discord" diff --git a/.github/workflows/disabled/daily-pr-recap.yml.disabled b/.github/workflows/disabled/daily-pr-recap.yml.disabled deleted file mode 100644 index ff026917f81..00000000000 --- a/.github/workflows/disabled/daily-pr-recap.yml.disabled +++ /dev/null @@ -1,173 +0,0 @@ -name: daily-pr-recap - -on: - schedule: - # Run at 5pm EST (22:00 UTC, or 21:00 UTC during daylight saving) - - cron: "0 22 * * *" - workflow_dispatch: # Allow manual trigger for testing - -jobs: - pr-recap: - runs-on: blacksmith-4vcpu-ubuntu-2404 - permissions: - contents: read - pull-requests: read - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - uses: ./.github/actions/setup-bun - - - name: Install opencode - run: curl -fsSL https://kilo.ai/install | bash - - - name: Generate daily PR recap - id: recap - env: - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - KILO_PERMISSION: | - { - "bash": { - "*": "deny", - "gh pr*": "allow", - "gh search*": "allow" - }, - "webfetch": "deny", - "edit": "deny", - "write": "deny" - } - run: | - TODAY=$(date -u +%Y-%m-%d) - - opencode run -m opencode/claude-sonnet-4-5 "Generate a daily PR activity recap for the Kilo repository. - - TODAY'S DATE: ${TODAY} - - STEP 1: Gather PR data - Run these commands to gather PR information. ONLY include OPEN PRs created or updated TODAY (${TODAY}): - - # Open PRs created today - gh pr list --repo ${{ github.repository }} --state open --search \"created:${TODAY}\" --json number,title,author,labels,createdAt,updatedAt,reviewDecision,isDraft,additions,deletions --limit 100 - - # Open PRs with activity today (updated today) - gh pr list --repo ${{ github.repository }} --state open --search \"updated:${TODAY}\" --json number,title,author,labels,createdAt,updatedAt,reviewDecision,isDraft,additions,deletions --limit 100 - - IMPORTANT: EXCLUDE all PRs authored by Anomaly team members. Filter out PRs where the author login matches ANY of these: - adamdotdevin, Brendonovich, fwang, Hona, iamdavidhill, jayair, kitlangton, kommander, MrMushrooooom, R44VC0RP, rekram1-node, thdxr - This recap is specifically for COMMUNITY (external) contributions only. - - - - STEP 2: For high-activity PRs, check comment counts - For promising PRs, run: - gh pr view [NUMBER] --repo ${{ github.repository }} --json comments --jq '[.comments[] | select(.author.login != \"copilot-pull-request-reviewer\" and .author.login != \"github-actions\")] | length' - - IMPORTANT: When counting comments/activity, EXCLUDE these bot accounts: - - copilot-pull-request-reviewer - - github-actions - - STEP 3: Identify what matters (ONLY from today's PRs) - - **Bug Fixes From Today:** - - PRs with 'fix' or 'bug' in title created/updated today - - Small bug fixes (< 100 lines changed) that are easy to review - - Bug fixes from community contributors - - **High Activity Today:** - - PRs with significant human comments today (excluding bots listed above) - - PRs with back-and-forth discussion today - - **Quick Wins:** - - Small PRs (< 50 lines) that are approved or nearly approved - - PRs that just need a final review - - STEP 4: Generate the recap - Create a structured recap: - - ===DISCORD_START=== - **Daily PR Recap - ${TODAY}** - - **New PRs Today** - [PRs opened today - group by type: bug fixes, features, etc.] - - **Active PRs Today** - [PRs with activity/updates today - significant discussion] - - **Quick Wins** - [Small PRs ready to merge] - ===DISCORD_END=== - - STEP 5: Format for Discord - - Use Discord markdown (**, __, etc.) - - BE EXTREMELY CONCISE - surface what we might miss - - Use hyperlinked PR numbers with suppressed embeds: [#1234]() - - Include PR author: [#1234]() (@author) - - For bug fixes, add brief description of what it fixes - - Show line count for quick wins: \"(+15/-3 lines)\" - - HARD LIMIT: Keep under 1800 characters total - - Skip empty sections - - Focus on PRs that need human eyes - - OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/pr_recap_raw.txt - - # Extract only the Discord message between markers - sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/pr_recap_raw.txt | grep -v '===DISCORD' > /tmp/pr_recap.txt - - echo "recap_file=/tmp/pr_recap.txt" >> $GITHUB_OUTPUT - - - name: Post to Discord - env: - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_ISSUES_WEBHOOK_URL }} - run: | - if [ -z "$DISCORD_WEBHOOK_URL" ]; then - echo "Warning: DISCORD_ISSUES_WEBHOOK_URL secret not set, skipping Discord post" - cat /tmp/pr_recap.txt - exit 0 - fi - - # Read the recap - RECAP_RAW=$(cat /tmp/pr_recap.txt) - RECAP_LENGTH=${#RECAP_RAW} - - echo "Recap length: ${RECAP_LENGTH} chars" - - # Function to post a message to Discord - post_to_discord() { - local msg="$1" - local content=$(echo "$msg" | jq -Rs '.') - curl -s -H "Content-Type: application/json" \ - -X POST \ - -d "{\"content\": ${content}}" \ - "$DISCORD_WEBHOOK_URL" - sleep 1 - } - - # If under limit, send as single message - if [ "$RECAP_LENGTH" -le 1950 ]; then - post_to_discord "$RECAP_RAW" - else - echo "Splitting into multiple messages..." - remaining="$RECAP_RAW" - while [ ${#remaining} -gt 0 ]; do - if [ ${#remaining} -le 1950 ]; then - post_to_discord "$remaining" - break - else - chunk="${remaining:0:1900}" - last_newline=$(echo "$chunk" | grep -bo $'\n' | tail -1 | cut -d: -f1) - if [ -n "$last_newline" ] && [ "$last_newline" -gt 500 ]; then - chunk="${remaining:0:$last_newline}" - remaining="${remaining:$((last_newline+1))}" - else - chunk="${remaining:0:1900}" - remaining="${remaining:1900}" - fi - post_to_discord "$chunk" - fi - done - fi - - echo "Posted daily PR recap to Discord" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 34f35c22ce0..93f79d63cb9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -175,6 +175,7 @@ jobs: cli_version: ${{ needs.version.outputs.version }} secrets: inherit # kilocode_change end + publish: needs: - version @@ -208,6 +209,7 @@ jobs: with: node-version: "24" registry-url: "https://registry.npmjs.org" + package-manager-cache: false # kilocode_change - name: Install @vscode/vsce run: bun install -g @vscode/vsce @@ -265,7 +267,6 @@ jobs: GH_REPO: ${{ github.repository }} AUR_KEY: ${{ secrets.AUR_KEY }} GITHUB_TOKEN: ${{ steps.committer.outputs.token }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_CONFIG_PROVENANCE: true VSCE_PAT: ${{ secrets.VSCE_TOKEN }} OPENVSX_TOKEN: ${{ secrets.OVSX_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0af05b88e17..bdfe2e18a15 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,6 +59,14 @@ jobs: - name: Setup Bun uses: ./.github/actions/setup-bun + # kilocode_change start + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "21" + # kilocode_change end + - name: Configure git identity run: | git config --global user.email "kilo-maintainer[bot]@users.noreply.github.com" diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index 6c7ae420953..f49ea2bd277 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -17,5 +17,13 @@ jobs: - name: Setup Bun uses: ./.github/actions/setup-bun + # kilocode_change start + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: "21" + # kilocode_change end + - name: Run typecheck run: bun typecheck diff --git a/.gitignore b/.gitignore index 91bf7230c02..812dece5848 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .husky/_ .DS_Store +.secrets/ node_modules .worktrees .sst @@ -33,9 +34,11 @@ a.out target .scripts .direnv/ +packages/kilo-jetbrains/build-tasks/.gradle/ # Local dev files opencode-dev +.kilo-dev/ UPCOMING_CHANGELOG.md logs/ *.bun-build diff --git a/.kilo/agent/upstream-merge.md b/.kilo/agent/upstream-merge.md index e81c9cea361..559f59e890a 100644 --- a/.kilo/agent/upstream-merge.md +++ b/.kilo/agent/upstream-merge.md @@ -249,7 +249,15 @@ be broken. Check every auto-merged file for: files changed. Note that this tool compares against the merge base via `HEAD` and will be silent until the merge commit lands - other CI guards that touched files imply (knip for `kilo-vscode/`, - `check-kilocode-change`, source-links, visual regression) + `check-kilocode-change`, source-links, visual regression, + `script/check-forbidden-strings.ts`) +- if you encounter a hardcoded upstream URL, repo path, or attribution string + during conflict resolution that obviously shouldn't ship in Kilo (e.g. another + `https://opencode.ai/...` link, an `anomalyco/opencode` reference, an + attribution header naming "opencode"), suggest adding a literal pattern for + it to `script/check-forbidden-strings.ts` in the merge summary so future + merges catch it automatically. Don't add it silently mid-merge — flag it for + the user. ### 9. Commit with the standard message diff --git a/.opencode-version b/.opencode-version index 9866d345648..2aa995bb4eb 100644 --- a/.opencode-version +++ b/.opencode-version @@ -1 +1 @@ -v1.14.33 +v1.14.41 diff --git a/.opencode/agent/triage.md b/.opencode/agent/triage.md index d85586c6678..69ab7ac86b6 100644 --- a/.opencode/agent/triage.md +++ b/.opencode/agent/triage.md @@ -1,7 +1,7 @@ --- mode: primary hidden: true -model: kilo/minimax/minimax-m2.5 +model: openai/gpt-5-nano color: "#44BA81" tools: "*": false @@ -14,95 +14,38 @@ Use your github-triage tool to triage issues. This file is the source of truth for ownership/routing rules. -## Labels +Assign issues by choosing the team with the strongest overlap. The github-triage tool will assign a random member from that team. -### windows +Do not add labels to issues. Only assign an owner. -Use for any issue that mentions Windows (the OS). Be sure they are saying that they are on Windows. +When calling github-triage, pass one of these team values: tui, desktop_web, core, inference, windows, jetbrains, extension -- Use if they mention WSL too +## Teams -#### perf +### TUI -Performance-related issues: +Terminal UI issues, including rendering, keybindings, scrolling, terminal compatibility, SSH behavior, crashes in the TUI, and low-level TUI performance. -- Slow performance -- High RAM usage -- High CPU usage +### Desktop / Web -**Only** add if it's likely a RAM or CPU issue. **Do not** add for LLM slowness. +Desktop application and browser-based app issues, including `opencode web`, desktop-specific UI behavior, packaging, and web view problems. -#### nix +### Core -**Only** add if the issue explicitly mentions nix. +Core opencode server and harness issues, including sqlite, snapshots, memory, API behavior, agent context construction, tool execution, provider integrations, model behavior, documentation, and larger architectural features. -If the issue does not mention nix, do not add nix. +### Inference -If the issue mentions nix, assign to `catrielmuller`. +Kilo Provider, Provider implementation, and billing issues. -#### core +### Windows -Use for core server issues in `packages/opencode/`, excluding `packages/opencode/src/cli/cmd/tui/`. +Windows-specific issues, including native Windows behavior, WSL interactions, path handling, shell compatibility, and installation or runtime problems that only happen on Windows. -Examples: +### Jetbrains -- LSP server behavior -- Harness behavior (agent + tools) -- Feature requests for server behavior -- Agent context construction -- API endpoints -- Provider integration issues -- New, broken, or poor-quality models +Jetbrains extension related issues. -#### vscode +### Extension -Use for issues related to the VS Code extension in `packages/kilo-vscode/`. - -#### gateway - -Use for issues related to the Kilo Gateway in `packages/kilo-gateway/`. - -When assigning to people here are the following rules: - -Nix: -ONLY assign if the issue will have the "nix" label. - -- catrielmuller - -Models / Providers: -Use for issues about model quality, provider integrations, or broken/new models. - -- chrarnoldus - -Cloud Agents: -Use for issues about cloud agent behavior or infrastructure. - -- pandemicsyn -- eshurakov - -Core (`packages/opencode/...`): - -- kevinvandijk -- marius-kilocode -- catrielmuller - -VSCode Extension (`packages/kilo-vscode/...`): - -- markijbema - -Kilo Gateway (`packages/kilo-gateway/...`): - -- jrf0110 - -Windows: - -- catrielmuller (assign any issue that mentions Windows or is likely Windows-specific) - -Determinism rules: - -- If "nix" label is added but title + body does not mention nix/nixos, the tool will drop "nix" -- If title + body mentions nix/nixos, assign to `catrielmuller` -- If "vscode" label is added, assign to `markijbema` -- If "gateway" label is added, assign to `jrf0110` - -In all other cases, choose the team/section with the most overlap with the issue and assign a member from that team at random. +VSCode Extension related issues. diff --git a/.opencode/command/changelog.md b/.opencode/command/changelog.md index 4cd30a704a4..b28d963d005 100644 --- a/.opencode/command/changelog.md +++ b/.opencode/command/changelog.md @@ -18,9 +18,12 @@ Do not use `git log` or author metadata when deciding attribution. Rules: -- Write the final file with sections in this order: +- Write the final file with release sections in this order: `## Core`, `## TUI`, `## Desktop`, `## SDK`, `## Extensions` - Only include sections that have at least one notable entry +- Within each release section, keep bug fixes grouped under `### Bugfixes` +- Keep other notable entries under `### Improvements` when a section has bug fixes too +- Omit empty subsections - Keep one bullet per commit you keep - Skip commits that are entirely internal, CI, tests, refactors, or otherwise not user-facing - Start each bullet with a capital letter diff --git a/.opencode/tool/github-triage.ts b/.opencode/tool/github-triage.ts index 8f80f868577..ce07fdebc60 100644 --- a/.opencode/tool/github-triage.ts +++ b/.opencode/tool/github-triage.ts @@ -1,15 +1,16 @@ /// import { tool } from "@kilocode/plugin" -const TEAM = { - desktop: ["adamdotdevin", "iamdavidhill", "Brendonovich", "nexxeln"], - zen: ["fwang", "MrMushrooooom"], - tui: ["kommander", "rekram1-node", "simonklee"], - core: ["kitlangton", "rekram1-node", "jlongster"], - docs: ["R44VC0RP"], - windows: ["Hona"], -} as const -const ASSIGNEES = [...new Set(Object.values(TEAM).flat())] +// kilocode_change start +const TEAM = { + tui: ["catrielmuller"], + desktop_web: ["markijbema"], + core: ["markijbema", "marius-kilocode", "catrielmuller", "chrarnoldus", "imanolmzd-svg"], + jetbrains: ["kirillk"], + inference: ["chrarnoldus", "markijbema"], + windows: ["catrielmuller"], +} as const +// kilocode_change end function pick(items: readonly T[]) { return items[Math.floor(Math.random() * items.length)]! @@ -38,70 +39,27 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) { } export default tool({ - description: `Use this tool to assign and/or label a GitHub issue. + description: `Use this tool to assign a GitHub issue. -Choose labels and assignee using the current triage policy and ownership rules. -Pick the most fitting labels for the issue and assign one owner. - -If unsure, choose the team/section with the most overlap with the issue and assign a member from that team at random.`, +Provide the team that should own the issue. This tool picks a random assignee from that team and does not apply labels.`, args: { - assignee: tool.schema - .enum(["thdxr", "adamdotdevin", "rekram1-node", "fwang", "jayair", "kommander"]) - .describe("The username of the assignee") - .default("rekram1-node"), - labels: tool.schema - .array(tool.schema.enum(["nix", "opentui", "perf", "desktop", "zen", "docs", "windows"])) - .describe("The labels(s) to add to the issue") - .default([]), + team: tool.schema + .enum(Object.keys(TEAM) as [keyof typeof TEAM, ...(keyof typeof TEAM)[]]) + .describe("The owning team"), }, async execute(args) { const issue = getIssueNumber() - // const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }) - const owner = "anomalyco" - const repo = "opencode" + // kilocode_change start + const owner = "Kilo-Org" + const repo = "kilocode" + // kilocode_change end + const assignee = pick(TEAM[args.team]) - const results: string[] = [] - - if (args.assignee === "adamdotdevin" && !args.labels.includes("desktop")) { - throw new Error("Only desktop issues should be assigned to adamdotdevin") - } - - if (args.assignee === "fwang" && !args.labels.includes("zen")) { - throw new Error("Only zen issues should be assigned to fwang") - } - - if (args.assignee === "kommander" && !args.labels.includes("opentui")) { - throw new Error("Only opentui issues should be assigned to kommander") - } - - // await octokit.rest.issues.addAssignees({ - // owner, - // repo, - // issue_number: issue, - // assignees: [args.assignee], - // }) await githubFetch(`/repos/${owner}/${repo}/issues/${issue}/assignees`, { method: "POST", - body: JSON.stringify({ assignees: [args.assignee] }), + body: JSON.stringify({ assignees: [assignee] }), }) - results.push(`Assigned @${args.assignee} to issue #${issue}`) - const labels: string[] = args.labels.map((label) => (label === "desktop" ? "web" : label)) - - if (labels.length > 0) { - // await octokit.rest.issues.addLabels({ - // owner, - // repo, - // issue_number: issue, - // labels, - // }) - await githubFetch(`/repos/${owner}/${repo}/issues/${issue}/labels`, { - method: "POST", - body: JSON.stringify({ labels }), - }) - results.push(`Added labels: ${args.labels.join(", ")}`) - } - - return results.join("\n") + return `Assigned @${assignee} from ${args.team} to issue #${issue}` }, }) diff --git a/AGENTS.md b/AGENTS.md index 34fec96cc6a..914d394946b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ Kilo CLI is an open source AI coding agent that generates code from natural lang - **Dev**: `bun run dev` (runs from root) or `bun run --cwd packages/opencode --conditions=browser src/index.ts` - **Dev with params**: `bun dev -- help` - **Extension**: `bun run extension` (build + launch VS Code with the extension in dev mode). Pass `--no-build` to skip the build. -- **Typecheck**: `bun turbo typecheck` (uses `tsgo`, not `tsc`) +- **Typecheck**: `bun turbo typecheck` (uses `tsgo`, not `tsc`). Includes the JetBrains plugin — requires Java 21. Check with `java -version` before running. If missing, install via SDKMAN: `sdk install java 21-tem && sdk use java 21-tem`. If SDKMAN is not installed, see https://sdkman.io/install. - **Test**: `bun test` from `packages/opencode/` (NOT from root -- root blocks tests) - **Single test**: `bun test ./test/tool/tool-define.test.ts` from `packages/opencode/` - **CLI build artifact size check**: after `bun run script/build.ts --single --skip-install` in `packages/opencode/`, use `du -h dist/*/*/bin/kilo` (scoped package output lives under `dist/@kilocode/`) @@ -34,6 +34,7 @@ Before saying an implementation is ready, run the smallest relevant checks that | CLI | From `packages/opencode/`: `bun run typecheck`, `bun test` or targeted `bun test ./path/to/file.test.ts` | | VS Code extension | From `packages/kilo-vscode/`: `bun run typecheck`, `bun run lint`, `bun run test:unit` or `bun run test` | | Extension build/package | From `packages/kilo-vscode/`: `bun run compile` or `bun run package` when touching build, packaging, SDK, or webview integration paths | +| JetBrains plugin | From `packages/kilo-jetbrains/`: `./gradlew typecheck`, `./gradlew test`. Requires Java 21 — check first with `java -version`. Install via SDKMAN if missing: `sdk install java 21-tem && sdk use java 21-tem`. | | CI-only guards | Run affected guards documented above, such as `bun run knip`, `bun run check-kilocode-change`, `bun run script/check-opencode-annotations.ts`, or source link extraction | Never run root `bun test`; the root script prints `do not run tests from root` and exits with code 1. Use package-level tests instead. @@ -53,8 +54,7 @@ Extension-specific settings should live in the Kilo extension settings, not defa ## Package Instructions -- When a task primarily touches `packages/kilo-jetbrains/`, read `packages/kilo-jetbrains/AGENTS.md` before planning or editing. -- For JetBrains Kotlin/Swing UI work, also apply `packages/kilo-jetbrains/.kilo/skills/jetbrains-ui-style/SKILL.md`. +- When a task primarily touches `packages/kilo-jetbrains/`, read `packages/kilo-jetbrains/AGENTS.md` before planning or editing. It covers split-mode architecture, IntelliJ source lookup, threading fundamentals, UI guidelines, and session component architecture. ## Monorepo Structure @@ -89,17 +89,6 @@ Prefer `const`. Good: -### Naming Enforcement (Read This) - -THIS RULE IS MANDATORY FOR AGENT WRITTEN CODE. - -- Use single word names by default for new locals, params, and helper functions. -- Multi-word names are allowed only when a single word would be unclear or ambiguous. -- Do not introduce new camelCase compounds when a short single-word alternative is clear. -- Before finishing edits, review touched lines and shorten newly introduced identifiers where possible. -- Good short names to prefer: `pid`, `cfg`, `err`, `opts`, `dir`, `root`, `child`, `state`, `timeout`. -- Examples to avoid unless truly required: `inputPID`, `existingClient`, `connectTimeout`, `workerPath`. - ```ts const foo = condition ? 1 : 2 ``` @@ -113,6 +102,17 @@ if (condition) foo = 1 else foo = 2 ``` +### Naming Enforcement (Read This) + +THIS RULE IS MANDATORY FOR AGENT WRITTEN CODE. + +- Use single word names by default for new locals, params, and helper functions. +- Multi-word names are allowed only when a single word would be unclear or ambiguous. +- Do not introduce new camelCase compounds when a short single-word alternative is clear. +- Before finishing edits, review touched lines and shorten newly introduced identifiers where possible. +- Good short names to prefer: `pid`, `cfg`, `err`, `opts`, `dir`, `root`, `child`, `state`, `timeout`. +- Examples to avoid unless truly required: `inputPID`, `existingClient`, `connectTimeout`, `workerPath`. + ### Avoid else statements Prefer early returns or using an `iife` to avoid else statements. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9bb4a775994..d31f9bf6901 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,9 +14,34 @@ There are lots of ways to contribute to the project: The Kilo Community is [on Discord](https://kilo.ai/discord). +## Prerequisites + +- **Bun 1.3.13+** — required for all packages. +- **Java 21** — required by the JetBrains plugin. The root `bun turbo typecheck` and `bun turbo test:ci` commands include `@kilocode/kilo-jetbrains` and will fail without Java 21. + + The preferred way to install Java is via [SDKMAN](https://sdkman.io/install): + + ```bash + # Install SDKMAN (if not already installed) + curl -s "https://get.sdkman.io" | bash + + # Install and activate Java 21 (Eclipse Temurin) + sdk install java 21-tem + sdk use java 21-tem + + # Verify + java -version + ``` + + If you don't plan to work on the JetBrains plugin, you can still run non-JetBrains checks directly: + + ```bash + bun turbo typecheck --filter=!@kilocode/kilo-jetbrains + ``` + ## Developing Kilo CLI -- **Requirements:** Bun 1.3.13+ +- **Requirements:** Bun 1.3.13+, Java 21 (see [Prerequisites](#prerequisites) above) - Install dependencies and start the dev server from the repo root: ```bash @@ -34,6 +59,23 @@ bun run extension # Build + launch in dev mode This auto-detects VS Code on macOS, Linux, and Windows. Override with `--app-path PATH` or `VSCODE_EXEC_PATH`. Use `--insiders` to prefer Insiders, `--workspace PATH` to open a specific folder, or `--clean` to reset cached state. +### Developing the JetBrains Plugin + +Requires Java 21 (see [Prerequisites](#prerequisites)). From `packages/kilo-jetbrains/`: + +```bash +./gradlew typecheck # Compile-check all Kotlin sources +./gradlew test # Run all tests (backend + frontend) +./gradlew runIde # Launch sandboxed IntelliJ with the plugin +``` + +Or via the root turbo filter to run only JetBrains checks from the repo root: + +```bash +bun turbo typecheck --filter=@kilocode/kilo-jetbrains +bun turbo test:ci --filter=@kilocode/kilo-jetbrains +``` + ### Running against a different directory By default, `bun dev` runs Kilo CLI in the `packages/opencode` directory. To run it against a different directory or repository: diff --git a/REVIEW.md b/REVIEW.md new file mode 100644 index 00000000000..72876657091 --- /dev/null +++ b/REVIEW.md @@ -0,0 +1,90 @@ +# REVIEW.md + +Guidance for the automated reviewer (kilo-code-bot) on PRs in this repo. + +The goal of the review is to catch things CI **cannot** catch: bugs, design issues, and judgment calls about style and fork hygiene. Be helpful, not pedantic — frame everything as a suggestion the human can accept or reject. + +## Don't duplicate CI + +CI already runs and will report failures directly. Do **not** comment on: + +- Lint, formatting, or typecheck errors (root `lint`, `turbo typecheck`) +- Test failures (CLI tests, vscode tests) +- `knip` unused exports +- `kilocode_change` marker rules — both directions: + - Missing markers on shared opencode files (`script/check-opencode-annotations.ts`) + - Markers present in kilo-only paths like `packages/kilo-vscode/`, `packages/kilo-ui/`, `packages/opencode/src/kilocode/` (`bun run check-kilocode-change`) +- Workflow allowlist drift (`script/check-workflows.ts`) +- Stale `packages/kilo-docs/source-links.md` (`script/extract-source-links.ts`) +- Markdown table padding (`script/check-md-table-padding.ts`) +- Visual regression snapshots (CI generates baselines on Linux) +- SDK regeneration drift (`generate.yml`) +- Generated artifact freshness (`check-kilo-generated-artifacts.yml`) +- Docs link checks, nix evals, container builds + +If the only issue you'd raise is one of the above, just say `lgtm`. + +## What to focus on + +### 1. Bugs and correctness + +Read enough of the surrounding file to actually understand the change — diffs alone hide context. Look for: + +- Logic errors, off-by-one, wrong conditions, swapped arguments +- Unhandled error paths, swallowed promises, missing `await` +- Race conditions, especially around session/process lifecycle in the CLI and Agent Manager +- Resource leaks (unclosed file handles, child processes, subscriptions) +- Inputs that aren't validated where they cross trust boundaries (server routes, IPC, config loading) + +### 2. Style guide judgment calls + +The full guide is in `AGENTS.md`. Don't be a zealot — only flag actual violations, and recognize when the existing code already complies through a different mechanism. + +- **No `let`**: prefer `const` with ternary or IIFE (`packages/opencode/src/util/iife.ts`). But `let` is fine when it's genuinely the simplest option; don't demand IIFE rewrites for trivial cases. +- **No `else`**: prefer early returns. Don't complain about `else` if the code already uses early returns elsewhere. You **may** flag excessive nesting regardless. +- **No empty `catch`**: always flag — empty catches hide bugs. +- **Avoid `try`/`catch` where possible**: if a try/catch is added, consider whether it's needed at all. +- **Avoid `any`**: flag new `any` usage unless there's a clear reason. +- **Single-word names**: prefer `cfg`, `pid`, `dir`, `opts`, `err` over `inputPID`, `connectTimeout`. Only flag newly introduced multi-word names where a clear single-word alternative exists. +- **Avoid unnecessary destructuring**: prefer `obj.a` over `const { a } = obj` to preserve context. +- **Bun APIs**: prefer `Bun.file()` etc. over node equivalents in CLI code. +- **Type inference**: avoid explicit annotations unless needed for exports/clarity. + +When suggesting fixes, ensure the suggestion is valid TypeScript (matched braces, correct syntax). Prefer prose comments over `suggestion` blocks unless the fix is trivially mechanical. + +### 3. Fork merge hygiene + +Kilo CLI is a fork of opencode. Minimizing diff against upstream is a top priority. + +- If a change modifies a shared opencode file (anything under `packages/opencode/` not in a path containing `kilocode`), ask whether the logic could live in a Kilo-only directory instead (`packages/opencode/src/kilocode/`, `packages/kilo-gateway/`, etc.) or be reduced to a smaller hook. +- Refactors or reorganizations of upstream code are a red flag — flag them unless clearly justified. +- See `.kilo/skills/kilocode-merge-minimizer/SKILL.md` for the decision rules. + +### 4. Cloud config schema mirror + +When `Config.Info` in `packages/opencode/src/config/config.ts` gains a new `kilocode_change` field, the matching JSON Schema entry must also be added in the cloud repo (`apps/web/src/app/config.json/extras.ts`). CI does **not** check this — flag it as a reminder if you see a new config field added. + +### 5. Test quality + +- Tests should exercise real implementation, not duplicate logic into the test. +- Mocks should be avoided where reasonable; flag mock-heavy tests that look like they're testing the mock rather than the code. +- New behavior in `packages/opencode/` should generally come with a test under `packages/opencode/test/`. + +### 6. User-facing changes + +- Features, bug fixes, and breaking changes should include a changeset (`.changeset/*.md`). If a PR clearly changes user-visible behavior and has no changeset, mention it. +- Changeset descriptions are read by end users — if one is present but written as implementation notes ("Add a new export handler that serializes…"), suggest a user-facing rewrite ("Support exporting conversations as markdown"). +- PR descriptions should explain **why**, not enumerate files. Skip file-by-file inventories. + +### 7. UI changes + +For changes under `packages/kilo-vscode/webview-ui/`: + +- Significant visual or layout changes should have a Storybook story added under `webview-ui/src/stories/`. Minor tweaks and i18n-only changes don't need one. +- Don't ask for locally generated baseline PNGs — those must come from Linux CI. + +## How to comment + +- Leave comments on the exact line via `gh api .../pulls/{n}/comments`. +- Make it clear suggestions are suggestions; the human decides. +- If the PR is clean against the above, comment `lgtm` and nothing else. diff --git a/bun.lock b/bun.lock index 2314b1d6c8a..1028ef07ec4 100644 --- a/bun.lock +++ b/bun.lock @@ -28,12 +28,12 @@ "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.8.13", + "turbo": "2.9.14", }, }, "packages/core": { "name": "@opencode-ai/core", - "version": "7.3.0", + "version": "7.3.8", "bin": { "opencode": "./bin/opencode", }, @@ -68,7 +68,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -98,7 +98,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@ai-sdk/alibaba": "1.0.17", "@ai-sdk/anthropic": "3.0.71", @@ -134,7 +134,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.3.0", + "version": "7.3.8", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -144,7 +144,7 @@ }, "packages/kilo-indexing": { "name": "@kilocode/kilo-indexing", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@aws-sdk/client-bedrock-runtime": "3.1005.0", "@aws-sdk/credential-provider-ini": "3.972.31", @@ -154,6 +154,7 @@ "@qdrant/js-client-rest": "1.17.0", "async-mutex": "0.5.0", "chokidar": "4.0.3", + "effect": "catalog:", "glob": "13.0.6", "hono": "catalog:", "hono-openapi": "catalog:", @@ -175,10 +176,11 @@ }, "packages/kilo-jetbrains": { "name": "@kilocode/kilo-jetbrains", + "version": "7.3.8", }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "posthog-node": "4.4.0", @@ -192,7 +194,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "0.13.11", @@ -229,7 +231,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-gateway": "workspace:*", @@ -292,7 +294,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.3.0", + "version": "7.3.8", "bin": { "kilo": "./bin/kilo", "kilocode": "./bin/kilo", @@ -300,7 +302,7 @@ "dependencies": { "@actions/core": "1.11.1", "@actions/github": "6.0.1", - "@agentclientprotocol/sdk": "0.16.1", + "@agentclientprotocol/sdk": "0.21.0", "@ai-sdk/alibaba": "1.0.17", "@ai-sdk/amazon-bedrock": "4.0.96", "@ai-sdk/anthropic": "3.0.71", @@ -450,7 +452,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@kilocode/sdk": "workspace:*", "effect": "catalog:", @@ -475,7 +477,7 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "semver": "^7.6.3", }, @@ -486,7 +488,7 @@ }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "cross-spawn": "catalog:", }, @@ -501,7 +503,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.3.0", + "version": "7.3.8", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -524,7 +526,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.3.0", + "version": "7.3.8", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -574,6 +576,13 @@ }, }, }, + "trustedDependencies": [ + "esbuild", + "tree-sitter-powershell", + "protobufjs", + "web-tree-sitter", + "tree-sitter-bash", + ], "patchedDependencies": { "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch", @@ -606,7 +615,7 @@ "@openauthjs/openauth": "0.0.0-20250322224806", "@opentui/core": "0.2.2", "@opentui/solid": "0.2.2", - "@pierre/diffs": "1.1.0-beta.18", + "@pierre/diffs": "1.1.22", "@playwright/test": "1.59.1", "@solid-primitives/storage": "4.3.3", "@solidjs/meta": "0.29.4", @@ -618,7 +627,7 @@ "@types/bun": "1.3.12", "@types/cross-spawn": "6.0.6", "@types/luxon": "3.7.1", - "@types/node": "22.13.9", + "@types/node": "24.12.2", "@types/semver": "7.7.1", "@typescript/native-preview": "7.0.0-dev.20260316.1", "ai": "6.0.168", @@ -627,7 +636,7 @@ "dompurify": "3.4.2", "drizzle-kit": "1.0.0-beta.19-d95b7a4", "drizzle-orm": "1.0.0-beta.19-d95b7a4", - "effect": "4.0.0-beta.57", + "effect": "4.0.0-beta.59", "fuzzysort": "3.1.0", "hono": "4.12.12", "hono-openapi": "1.1.2", @@ -664,7 +673,7 @@ "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], - "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.16.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-1ad+Sc/0sCtZGHthxxvgEUo5Wsbw16I+aF+YwdiLnPwkZG8KAGUEAPK6LM6Pf69lCyJPt1Aomk1d+8oE3C4ZEw=="], + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.21.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-ONj+Q8qOdNQp5XbH5jnMwzT9IKZJsSN0p0lkceS4GtUtNOPVLpNzSS8gqQdGMKfBvA0ESbkL8BTaSN1Rc9miEw=="], "@ai-sdk/alibaba": ["@ai-sdk/alibaba@1.0.17", "", { "dependencies": { "@ai-sdk/openai-compatible": "2.0.41", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZbE+U5bWz2JBc5DERLowx5+TKbjGBE93LqKZAWvuEn7HOSQMraxFMZuc0ST335QZJAyfBOzh7m1mPQ+y7EaaoA=="], @@ -1636,9 +1645,9 @@ "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], - "@pierre/diffs": ["@pierre/diffs@1.1.0-beta.18", "", { "dependencies": { "@pierre/theme": "0.0.22", "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-7ZF3YD9fxdbYsPnltz5cUqHacN7ztp8RX/fJLxwv8wIEORpP4+7dHz1h/qx3o4EW2xUrIhmbM8ImywLasB787Q=="], + "@pierre/diffs": ["@pierre/diffs@1.1.22", "", { "dependencies": { "@pierre/theme": "0.0.28", "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-1Iv7kdl6OABFCd1n2HQbGUiRHouXPaHoIjcb7Lwg8zeJKY5ph+cESFcGEyIiwW0NCbKGtYS2bTnXmI+Eze5dwg=="], - "@pierre/theme": ["@pierre/theme@0.0.22", "", {}, "sha512-ePUIdQRNGjrveELTU7fY89Xa7YGHHEy5Po5jQy/18lm32eRn96+tnYJEtFooGdffrx55KBUtOXfvVy/7LDFFhA=="], + "@pierre/theme": ["@pierre/theme@0.0.28", "", {}, "sha512-1j/H/fECBuc9dEvntdWI+l435HZapw+RCJTlqCA6BboQ5TjlnE005j/ROWutXIs8aq5OAc82JI2Kwk4A1WWBgw=="], "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], @@ -2020,6 +2029,18 @@ "@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], + "@turbo/darwin-64": ["@turbo/darwin-64@2.9.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A=="], + + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw=="], + + "@turbo/linux-64": ["@turbo/linux-64@2.9.14", "", { "os": "linux", "cpu": "x64" }, "sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA=="], + + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g=="], + + "@turbo/windows-64": ["@turbo/windows-64@2.9.14", "", { "os": "win32", "cpu": "x64" }, "sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A=="], + + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], @@ -2144,7 +2165,7 @@ "@types/mssql": ["@types/mssql@9.1.11", "", { "dependencies": { "@types/node": "*", "tarn": "^3.0.1", "tedious": "*" } }, "sha512-vcujgrDbDezCxNDO4KY6gjwduLYOKfrexpRUwhoysRvcXZ3+IgZ/PMYFDgh8c3cQIxZ6skAwYo+H6ibMrBWPjQ=="], - "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="], "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], @@ -2824,7 +2845,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "effect": ["effect@4.0.0-beta.57", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-rg32VgXnLKaPRs9tbRDaZ5jxmzNY7ojXt85gSHGUTwdlbWH5Ik+OCUY2q14TXliygPGoHwCAvNWS4bQJOqf00g=="], + "effect": ["effect@4.0.0-beta.59", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-xyUDLeHSe8d6lWGOvR6Fgn2HL6gYeTZ/S4Jzk9uc4ZUxMPPsNZlNXrvk0C7/utQFzeX7uAWcVnG2BjbA0SRoAA=="], "electron-to-chromium": ["electron-to-chromium@1.5.340", "", {}, "sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA=="], @@ -4288,19 +4309,7 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.8.13", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.13", "turbo-darwin-arm64": "2.8.13", "turbo-linux-64": "2.8.13", "turbo-linux-arm64": "2.8.13", "turbo-windows-64": "2.8.13", "turbo-windows-arm64": "2.8.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A=="], - - "turbo-darwin-64": ["turbo-darwin-64@2.8.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA=="], - - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ=="], - - "turbo-linux-64": ["turbo-linux-64@2.8.13", "", { "os": "linux", "cpu": "x64" }, "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw=="], - - "turbo-linux-arm64": ["turbo-linux-arm64@2.8.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg=="], - - "turbo-windows-64": ["turbo-windows-64@2.8.13", "", { "os": "win32", "cpu": "x64" }, "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA=="], - - "turbo-windows-arm64": ["turbo-windows-arm64@2.8.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA=="], + "turbo": ["turbo@2.9.14", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.14", "@turbo/darwin-arm64": "2.9.14", "@turbo/linux-64": "2.9.14", "@turbo/linux-arm64": "2.9.14", "@turbo/windows-64": "2.9.14", "@turbo/windows-arm64": "2.9.14" }, "bin": { "turbo": "bin/turbo" } }, "sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw=="], "turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="], @@ -4330,7 +4339,7 @@ "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], - "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], @@ -4544,6 +4553,8 @@ "@antfu/install-pkg/tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + "@anthropic-ai/sdk/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], @@ -4648,6 +4659,8 @@ "@kilocode/kilo-indexing/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@manypkg/find-root/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@manypkg/find-root/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], "@manypkg/find-root/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], @@ -4704,6 +4717,8 @@ "@openauthjs/openauth/jose": ["jose@5.9.6", "", {}, "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ=="], + "@opencode-ai/plugin/effect": ["effect@4.0.0-beta.57", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-rg32VgXnLKaPRs9tbRDaZ5jxmzNY7ojXt85gSHGUTwdlbWH5Ik+OCUY2q14TXliygPGoHwCAvNWS4bQJOqf00g=="], + "@opencode-ai/storybook/@storybook/addon-a11y": ["@storybook/addon-a11y@10.3.5", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.3.5" } }, "sha512-5k6lpgfIeLxvNhE8v3wEzdiu73ONKjF4gmH1AHvfqYd8kIVzQJai0KCDxgvqNncXHQhIWkaf1fg6+9hKaYJyaw=="], "@opencode-ai/storybook/@storybook/addon-docs": ["@storybook/addon-docs@10.3.5", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.3.5", "@storybook/icons": "^2.0.1", "@storybook/react-dom-shim": "10.3.5", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.3.5" } }, "sha512-WuHbxia/o5TX4Rg/IFD0641K5qId/Nk0dxhmAUNoFs5L0+yfZUwh65XOBbzXqrkYmYmcVID4v7cgDRmzstQNkA=="], @@ -4750,6 +4765,10 @@ "@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="], + "@standard-community/standard-json/effect": ["effect@4.0.0-beta.57", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-rg32VgXnLKaPRs9tbRDaZ5jxmzNY7ojXt85gSHGUTwdlbWH5Ik+OCUY2q14TXliygPGoHwCAvNWS4bQJOqf00g=="], + + "@standard-community/standard-openapi/effect": ["effect@4.0.0-beta.57", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.6.0", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.9", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^13.0.0", "yaml": "^2.8.3" } }, "sha512-rg32VgXnLKaPRs9tbRDaZ5jxmzNY7ojXt85gSHGUTwdlbWH5Ik+OCUY2q14TXliygPGoHwCAvNWS4bQJOqf00g=="], + "@storybook/addon-links/storybook": ["storybook@10.3.5", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "@webcontainer/env": "^1.1.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-uBSZu/GZa9aEIW3QMGvdQPMZWhGxSe4dyRWU8B3/Vd47Gy/XLC7tsBxRr13txmmPOEDHZR94uLuq0H50fvuqBw=="], "@storybook/addon-onboarding/storybook": ["storybook@10.3.5", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "@webcontainer/env": "^1.1.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0", "open": "^10.2.0", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.18.0" }, "peerDependencies": { "prettier": "^2 || ^3" }, "optionalPeers": ["prettier"], "bin": "./dist/bin/dispatcher.js" }, "sha512-uBSZu/GZa9aEIW3QMGvdQPMZWhGxSe4dyRWU8B3/Vd47Gy/XLC7tsBxRr13txmmPOEDHZR94uLuq0H50fvuqBw=="], @@ -4790,6 +4809,30 @@ "@textlint/linter-formatter/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@types/cacache/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/cross-spawn/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/mssql/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/node-fetch/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/npm-registry-fetch/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/npmcli__arborist/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/npmlog/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/pacote/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/qrcode/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/readable-stream/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/ssri/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + + "@types/ws/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], "@vscode/ripgrep/yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], @@ -4826,6 +4869,8 @@ "ai-gateway-provider/@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@2.5.1", "", { "peerDependencies": { "ai": "^6.0.0", "zod": "^3.25.0 || ^4.0.0" } }, "sha512-r1fJL1Cb3gQDa2MpWH/sfx1BsEW0uzlRriJM6eihaKqbtKDmZoBisF32VcVaQYassighX7NGCkF68EsrZA43uQ=="], + "apache-arrow/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "archiver-utils/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "archiver-utils/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], @@ -4860,6 +4905,8 @@ "buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "bun-types/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "c12/dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="], @@ -4952,6 +4999,8 @@ "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + "image-q/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], "isomorphic-git/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -5074,6 +5123,8 @@ "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "protobufjs/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "qrcode/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], @@ -5140,6 +5191,8 @@ "tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + "tedious/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "tedious/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "test-exclude/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], @@ -5198,6 +5251,8 @@ "@ai-sdk/vercel/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@anthropic-ai/sdk/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@aws-crypto/sha1-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], @@ -5236,10 +5291,14 @@ "@kilocode/kilo-gateway/@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.9", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.1" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.8" }, "optionalPeers": ["solid-js"] }, "sha512-pCnxWrciluXCeli/dj5PIEHgbNzim3evtTn12snjqqg8QZWJNMjH1AWIp4iG/tbVjqQ72aBEymMSagvmgxubXw=="], + "@manypkg/find-root/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@manypkg/find-root/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "@morphllm/morphsdk/ai/@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.95", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZmUNNbZl3V42xwQzPaNUi+s8eqR2lnrxf0bvB6YbLXpLjHYv0k2Y78t12cNOfY0bxGeuVVTLyk856uLuQIuXEQ=="], + "@morphllm/morphsdk/openai/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@morphllm/morphsdk/openai/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], @@ -5274,6 +5333,10 @@ "@octokit/rest/@octokit/core/before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="], + "@opencode-ai/plugin/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@opencode-ai/plugin/effect/uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="], + "@opencode-ai/storybook/@storybook/addon-docs/@storybook/csf-plugin": ["@storybook/csf-plugin@10.3.5", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.3.5", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-qlEzNKxOjq86pvrbuMwiGD/bylnsXk1dg7ve0j77YFjEEchqtl7qTlrXvFdNaLA89GhW6D/EV6eOCu/eobPDgw=="], "@opencode-ai/storybook/@storybook/addon-docs/@storybook/react-dom-shim": ["@storybook/react-dom-shim@10.3.5", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.3.5" } }, "sha512-Gw8R7XZm0zSUH0XAuxlQJhmizsLzyD6x00KOlP6l7oW9eQHXGfxg3seNDG3WrSAcW07iP1/P422kuiriQlOv7g=="], @@ -5292,6 +5355,14 @@ "@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@standard-community/standard-json/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@standard-community/standard-json/effect/uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="], + + "@standard-community/standard-openapi/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@standard-community/standard-openapi/effect/uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="], + "@storybook/addon-links/storybook/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], "@storybook/addon-onboarding/storybook/open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], @@ -5334,6 +5405,30 @@ "@textlint/linter-formatter/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@types/cacache/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/cross-spawn/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/mssql/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/node-fetch/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/npm-registry-fetch/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/npmcli__arborist/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/npmlog/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/pacote/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/qrcode/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/readable-stream/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/ssri/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + + "@types/ws/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@vscode/ripgrep/yauzl/buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], "@vscode/test-cli/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -5376,6 +5471,8 @@ "ai-gateway-provider/@ai-sdk/xai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="], + "apache-arrow/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "archiver-utils/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "archiver-utils/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], @@ -5406,6 +5503,8 @@ "bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "bun-types/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], "c8/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], @@ -5510,10 +5609,14 @@ "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "image-q/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "jszip/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "kilo-code/openai/@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "lazystream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -5576,6 +5679,8 @@ "posthog-js/@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.7.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ=="], + "protobufjs/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "qrcode/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], "qrcode/yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -5606,6 +5711,8 @@ "tar-fs/tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "tedious/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "test-exclude/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "test-exclude/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], @@ -5638,6 +5745,8 @@ "@morphllm/morphsdk/ai/@ai-sdk/gateway/@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], + "@morphllm/morphsdk/openai/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "@octokit/graphql/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], "@octokit/rest/@octokit/core/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@11.0.3", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag=="], @@ -5750,6 +5859,8 @@ "gray-matter/js-yaml/argparse/sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "kilo-code/openai/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + "mocha/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], "mocha/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], diff --git a/install b/install index c6d0e37e0b6..f78cbc8d1b6 100755 --- a/install +++ b/install @@ -348,6 +348,10 @@ download_and_install() { # kilocode_change start mv "$tmp_dir/kilo" "$INSTALL_DIR" + rm -rf "${INSTALL_DIR}/tree-sitter" + if [ -d "$tmp_dir/tree-sitter" ]; then + mv "$tmp_dir/tree-sitter" "$INSTALL_DIR" + fi chmod 755 "${INSTALL_DIR}/kilo" # kilocode_change end rm -rf "$tmp_dir" @@ -517,10 +521,46 @@ if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then fi # kilocode_change start +logo_supports() { + case "${KILO_UNICODE_LOGO:-}" in + 1|true|TRUE|yes|YES|on|ON) + return 0 + ;; + 0|false|FALSE|no|NO|off|OFF) + return 1 + ;; + esac + + if [ "${TERM:-}" = "dumb" ]; then + return 1 + fi + + if [ -n "${SSH_TTY:-}" ] || [ -n "${SSH_CLIENT:-}" ] || [ -n "${SSH_CONNECTION:-}" ]; then + return 1 + fi + + if [ -n "${ConEmuPID:-}" ] || [ -n "${ANSICON:-}" ]; then + return 1 + fi + + return 0 +} + +print_logo() { + if logo_supports; then + echo -e "██ ██ ██🬺🬏 ██ ██ ██🬺🬏 ████ ██ ██🬺🬏 " + echo -e "████🬺🬏 ██ ██ ██ ██ ██ ██ ██ " + echo -e "██ ██ ██████ 🬁🬬████ 🬁🬬██ 🬁🬬████ 🬁🬬████ ██████ " + return + fi + + echo -e "██ ██ ████ ██ ██ ███ ████ ██ ████ " + echo -e "████ ██ ██ ██ ██ ██ ██ ██ " + echo -e "██ ██ ██████ ██████ ██ ████ ██████ ██████ " +} + echo -e "" -echo -e "██ ▄█▀ ██ ██ ▄████▄ ▄█████ ██ ██ " -echo -e "████ ██ ██ ██ ██ ██ ██ ██ " -echo -e "██ ▀█▄ ██ ██████ ▀████▀ ▀█████ ██████ ██ " +print_logo echo -e "" echo -e "" echo -e "${MUTED}Kilo includes free models so you can start immediately:${NC}" diff --git a/nix/hashes.json b/nix/hashes.json index 585b1d7461e..e8171c93a62 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-NZqcbv0MX1WV/BkAT1poERcDEFiA4s1Gsf7W4p5wjlk=", - "aarch64-linux": "sha256-WSl5114O35I9Fae7+BbYXWznKSApPXN/Ripjqr6NO5U=", - "aarch64-darwin": "sha256-VemzuMnNbZo7vgHS5UiHVFGPVy9VL3gVwm+cw6ij1cg=", - "x86_64-darwin": "sha256-tg2Zt8qE5EZWCVNLxKzXtaygvzAkO0IFysMfFhIfZBs=" + "x86_64-linux": "sha256-EbXkvlbexL1Gyy4vvGG5j+JWjv7SsVk6T5YnDfo3AQY=", + "aarch64-linux": "sha256-+MuJE4XGr0dArD/HuozaoK9Oymfgvx1CisE/Sm4ZstY=", + "aarch64-darwin": "sha256-Qdk+tZLydGld471ApL1cxfd85QQNFelTfqq7uAznfK4=", + "x86_64-darwin": "sha256-Fo6W65MfAcXaulBGCaE7+GfHtq3VVJyVDJpIENvR7lQ=" } } diff --git a/package.json b/package.json index 9d074301c1b..478b03234d8 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "packageManager": "bun@1.3.13", "scripts": { "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts", - "dev-setup": "bun run --cwd packages/opencode --conditions=browser src/index.ts dev-setup", "dev:storybook": "bun --cwd packages/storybook storybook", "lint": "oxlint", "typecheck": "bun turbo typecheck", @@ -16,7 +15,8 @@ "random": "echo 'Random script'", "hello": "echo 'Hello World!'", "test": "echo 'do not run tests from root' && exit 1", - "extension": "bun --cwd packages/kilo-vscode script/launch.ts" + "extension": "bun --cwd packages/kilo-vscode script/launch.ts", + "dev-setup": "bun run --cwd packages/opencode --conditions=browser src/index.ts dev-setup" }, "workspaces": { "packages": [ @@ -36,13 +36,13 @@ "ulid": "3.0.1", "@kobalte/core": "0.13.11", "@types/luxon": "3.7.1", - "@types/node": "22.13.9", + "@types/node": "24.12.2", "@types/semver": "7.7.1", "@tsconfig/node22": "22.0.2", "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/diffs": "1.1.0-beta.18", + "@pierre/diffs": "1.1.22", "opentui-spinner": "0.0.6", "@solid-primitives/storage": "4.3.3", "@tailwindcss/vite": "4.1.11", @@ -50,7 +50,7 @@ "dompurify": "3.4.2", "drizzle-kit": "1.0.0-beta.19-d95b7a4", "drizzle-orm": "1.0.0-beta.19-d95b7a4", - "effect": "4.0.0-beta.57", + "effect": "4.0.0-beta.59", "ai": "6.0.168", "cross-spawn": "7.0.6", "hono": "4.12.12", @@ -91,7 +91,7 @@ "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.8.13", + "turbo": "2.9.14", "@types/bun": "catalog:", "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.27.10" @@ -114,6 +114,16 @@ "semi": false, "printWidth": 120 }, + "trustedDependencies": [ + "esbuild", + "node-pty", + "protobufjs", + "tree-sitter", + "tree-sitter-bash", + "tree-sitter-powershell", + "web-tree-sitter", + "electron" + ], "overrides": { "@types/bun": "catalog:", "@types/node": "catalog:", @@ -135,6 +145,6 @@ "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", "solid-js@1.9.10": "patches/solid-js@1.9.10.patch" }, - "version": "7.3.0", + "version": "7.3.8", "peerDependencies": {} } diff --git a/packages/core/package.json b/packages/core/package.json index 9f1fd76ff76..bbd292174e9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.0", + "version": "7.3.8", "name": "@opencode-ai/core", "type": "module", "license": "MIT", diff --git a/packages/core/src/filesystem.ts b/packages/core/src/filesystem.ts index bc149d586e6..2e7a450d9b4 100644 --- a/packages/core/src/filesystem.ts +++ b/packages/core/src/filesystem.ts @@ -46,6 +46,7 @@ export namespace AppFileSystem { readonly isDir: (path: string) => Effect.Effect readonly isFile: (path: string) => Effect.Effect readonly existsSafe: (path: string) => Effect.Effect + readonly readFileStringSafe: (path: string) => Effect.Effect readonly readJson: (path: string) => Effect.Effect readonly writeJson: (path: string, data: unknown, mode?: number) => Effect.Effect readonly ensureDir: (path: string) => Effect.Effect @@ -69,6 +70,12 @@ export namespace AppFileSystem { return yield* fs.exists(path).pipe(Effect.orElseSucceed(() => false)) }) + const readFileStringSafe = Effect.fn("FileSystem.readFileStringSafe")(function* (path: string) { + return yield* fs + .readFileString(path) + .pipe(Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(undefined))) + }) + const isDir = Effect.fn("FileSystem.isDir")(function* (path: string) { const info = yield* fs.stat(path).pipe(Effect.catch(() => Effect.void)) return info?.type === "Directory" @@ -195,6 +202,7 @@ export namespace AppFileSystem { return Service.of({ ...fs, existsSafe, + readFileStringSafe, isDir, isFile, readDirectoryEntries, diff --git a/packages/core/src/flag/flag.ts b/packages/core/src/flag/flag.ts index ff01b402d0b..ffcf867286b 100644 --- a/packages/core/src/flag/flag.ts +++ b/packages/core/src/flag/flag.ts @@ -1,4 +1,5 @@ import { Config } from "effect" +import { InstallationChannel } from "../installation/version" function truthy(key: string) { const value = process.env[key]?.toLowerCase() @@ -10,6 +11,10 @@ function falsy(key: string) { return value === "false" || value === "0" } +// Channels that default to the new effect-httpapi server backend. The legacy +// hono backend remains the default for stable (`prod`/`latest`) installs. +const HTTPAPI_DEFAULT_ON_CHANNELS = new Set(["dev", "beta", "local"]) + function number(key: string) { const value = process.env[key] if (!value) return undefined @@ -78,8 +83,16 @@ export const Flag = { KILO_STRICT_CONFIG_DEPS: truthy("KILO_STRICT_CONFIG_DEPS"), KILO_WORKSPACE_ID: process.env["KILO_WORKSPACE_ID"], - KILO_EXPERIMENTAL_HTTPAPI: truthy("KILO_EXPERIMENTAL_HTTPAPI"), + // Defaults to true on dev/beta/local channels so internal users exercise the + // new effect-httpapi server backend. Stable (`prod`/`latest`) installs stay + // on the legacy hono backend until the rollout is complete. An explicit env + // var ("true"/"1" or "false"/"0") always wins, providing an opt-in for + // stable users and an escape hatch for dev/beta users. + KILO_EXPERIMENTAL_HTTPAPI: + truthy("KILO_EXPERIMENTAL_HTTPAPI") || + (!falsy("KILO_EXPERIMENTAL_HTTPAPI") && HTTPAPI_DEFAULT_ON_CHANNELS.has(InstallationChannel)), KILO_EXPERIMENTAL_WORKSPACES: KILO_EXPERIMENTAL || truthy("KILO_EXPERIMENTAL_WORKSPACES"), + KILO_EXPERIMENTAL_EVENT_SYSTEM: KILO_EXPERIMENTAL || truthy("KILO_EXPERIMENTAL_EVENT_SYSTEM"), // Evaluated at access time (not module load) because tests, the CLI, and // external tooling set these env vars at runtime. diff --git a/packages/core/src/global.ts b/packages/core/src/global.ts index 645c1a976f3..223322300fa 100644 --- a/packages/core/src/global.ts +++ b/packages/core/src/global.ts @@ -87,6 +87,8 @@ export const layer = Layer.effect( Effect.sync(() => Service.of(make())), ) +export const defaultLayer = layer + export const layerWith = (input: Partial) => Layer.effect( Service, diff --git a/packages/core/src/kilocode/global.ts b/packages/core/src/kilocode/global.ts index eb5b5d06b55..b57d06f7ae9 100644 --- a/packages/core/src/kilocode/global.ts +++ b/packages/core/src/kilocode/global.ts @@ -12,7 +12,10 @@ import fs from "fs/promises" */ export async function ensureRealDir(p: string) { await fs.mkdir(p, { recursive: true }) - const ok = await fs.stat(p).then(() => true).catch(() => false) + const ok = await fs + .stat(p) + .then(() => true) + .catch(() => false) if (!ok) { await fs.rm(p, { force: true }) await fs.mkdir(p, { recursive: true }) diff --git a/packages/core/src/util/log.ts b/packages/core/src/util/log.ts index 1181317e082..85ffbd915dc 100644 --- a/packages/core/src/util/log.ts +++ b/packages/core/src/util/log.ts @@ -1,3 +1,5 @@ +export * as Log from "./log" + import path from "path" import { existsSync, writeFileSync } from "fs" // kilocode_change import fs from "fs/promises" diff --git a/packages/core/test/filesystem/filesystem.test.ts b/packages/core/test/filesystem/filesystem.test.ts index b77f4e356fa..1d9405333da 100644 --- a/packages/core/test/filesystem/filesystem.test.ts +++ b/packages/core/test/filesystem/filesystem.test.ts @@ -65,6 +65,34 @@ describe("AppFileSystem", () => { ) }) + describe("readFileStringSafe", () => { + it( + "returns file contents when file exists", + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const filesys = yield* FileSystem.FileSystem + const tmp = yield* filesys.makeTempDirectoryScoped() + const file = path.join(tmp, "exists.txt") + yield* filesys.writeFileString(file, "hello") + + const result = yield* fs.readFileStringSafe(file) + expect(result).toBe("hello") + }), + ) + + it( + "returns undefined for missing file (NotFound)", + Effect.gen(function* () { + const fs = yield* AppFileSystem.Service + const filesys = yield* FileSystem.FileSystem + const tmp = yield* filesys.makeTempDirectoryScoped() + + const result = yield* fs.readFileStringSafe(path.join(tmp, "does-not-exist.txt")) + expect(result).toBeUndefined() + }), + ) + }) + describe("readJson / writeJson", () => { it( "round-trips JSON data", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 6087a11fe55..7d432b02ba1 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "7.3.0" +version = "7.3.8" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/Kilo-Org/kilocode" @@ -11,26 +11,26 @@ name = "Kilo" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.0/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.8/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.0/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.8/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.0/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.8/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.0/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.8/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.0/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.8/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/components/FlowDiagram/diagrams/wanted-lifecycle.ts b/packages/kilo-docs/components/FlowDiagram/diagrams/wanted-lifecycle.ts index fa94cff9ba0..54c7574bec2 100644 --- a/packages/kilo-docs/components/FlowDiagram/diagrams/wanted-lifecycle.ts +++ b/packages/kilo-docs/components/FlowDiagram/diagrams/wanted-lifecycle.ts @@ -134,7 +134,6 @@ const edges: Edge[] = [ type: "smoothstep", style: { strokeWidth: 2, stroke: "#888", strokeDasharray: "5 3" }, }, - ] export const wantedLifecycle: DiagramDefinition = { diff --git a/packages/kilo-docs/components/FlowDiagram/index.tsx b/packages/kilo-docs/components/FlowDiagram/index.tsx index dc1924c5838..d6b32190b8b 100644 --- a/packages/kilo-docs/components/FlowDiagram/index.tsx +++ b/packages/kilo-docs/components/FlowDiagram/index.tsx @@ -9,11 +9,7 @@ import { diagrams } from "./diagrams" * re-renders of FlowDiagram (otherwise React would unmount/remount it * on every parent render and tear down the ResizeObserver each time). */ -function FitOnResize({ - useReactFlow, -}: { - useReactFlow: typeof import("@xyflow/react").useReactFlow -}) { +function FitOnResize({ useReactFlow }: { useReactFlow: typeof import("@xyflow/react").useReactFlow }) { const { fitView } = useReactFlow() const containerRef = useRef(null) diff --git a/packages/kilo-docs/markdoc/partials/cli-commands-table.md b/packages/kilo-docs/markdoc/partials/cli-commands-table.md index 6243af9f0a8..e2ae23c4c5e 100644 --- a/packages/kilo-docs/markdoc/partials/cli-commands-table.md +++ b/packages/kilo-docs/markdoc/partials/cli-commands-table.md @@ -14,6 +14,7 @@ | `kilo uninstall` | uninstall kilo and remove all related files | | `kilo serve` | starts a headless kilo server | | `kilo models [provider]` | list all available models | +| `kilo roll-call ` | batch-test text models matching a filter for connectivity and latency | | `kilo stats` | show token usage and cost statistics | | `kilo export [sessionID]` | export session data as JSON | | `kilo import ` | import session data from JSON file or URL | diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index 86b1b174dad..9b0d75f6267 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.3.0", + "version": "7.3.8", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", @@ -33,5 +33,6 @@ "tailwindcss": "^4.1.18", "typescript": "^5.9.3", "vitest": "^3.2.3" - } + }, + "peerDependencies": {} } diff --git a/packages/kilo-docs/pages/code-with-ai/features/autocomplete/index.md b/packages/kilo-docs/pages/code-with-ai/features/autocomplete/index.md index 45b5072fb05..ca9c6b1bdaa 100644 --- a/packages/kilo-docs/pages/code-with-ai/features/autocomplete/index.md +++ b/packages/kilo-docs/pages/code-with-ai/features/autocomplete/index.md @@ -17,7 +17,7 @@ The extension uses **Fill-in-the-Middle (FIM)** completion routed through the ** You can choose between two FIM models: - **Codestral** (`mistralai/codestral-2508`) by Mistral AI — the default, billed through your Kilo account. -- **Mercury Edit** (`inception/mercury-edit`) by Inception — temporarily available via **BYOK** (Bring Your Own Key) only; Kilo Gateway support is coming soon. +- **Mercury Edit 2** (`inception/mercury-edit-2`) by Inception — temporarily available via **BYOK** (Bring Your Own Key) only; Kilo Gateway support is coming soon. ## Triggering Options @@ -38,10 +38,10 @@ This keybinding requires `kilo-code.new.autocomplete.enableSmartInlineTaskKeybin Autocomplete requests are routed through the **Kilo Gateway**. You can pick the FIM model under **Settings → Models → Autocomplete model**: - **Codestral** (`mistralai/codestral-2508`) — the default. Billed through your Kilo account, or free when you add your own Mistral Codestral key via BYOK. See [Setting Up Mistral for Free Autocomplete](/docs/code-with-ai/features/autocomplete/mistral-setup). -- **Mercury Edit** (`inception/mercury-edit`) — a fast diffusion-based FIM model by Inception. Temporarily requires an **Inception BYOK key** until Kilo Gateway support lands. Add one from the [BYOK page](https://app.kilo.ai/byok) in the Kilo platform. See [Bring Your Own Key (BYOK)](/docs/getting-started/byok) for setup details. +- **Mercury Edit 2** (`inception/mercury-edit-2`) — a fast diffusion-based FIM model by Inception. Temporarily requires an **Inception BYOK key** until Kilo Gateway support lands. Add one from the [BYOK page](https://app.kilo.ai/byok) in the Kilo platform. See [Bring Your Own Key (BYOK)](/docs/getting-started/byok) for setup details. {% callout type="note" %} -Mercury Edit is only available through BYOK for now — Kilo Gateway support is coming soon. If you select Mercury Edit without a valid Inception BYOK key configured, autocomplete requests will fail — switch back to Codestral or add an Inception key to continue. +Mercury Edit 2 is only available through BYOK for now — Kilo Gateway support is coming soon. If you select Mercury Edit 2 without a valid Inception BYOK key configured, autocomplete requests will fail — switch back to Codestral or add an Inception key to continue. {% /callout %} ## Status Bar diff --git a/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md b/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md index 0f82886d335..e66a937f10d 100644 --- a/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md +++ b/packages/kilo-docs/pages/code-with-ai/features/speech-to-text.md @@ -1,21 +1,23 @@ --- title: Voice Transcription -description: Kilo Code now includes experimental support for voice input in the chat interface. +description: Dictate prompts through your signed-in Kilo account. --- # Voice Transcription -{% callout type="warning" title="🧪 Experimental Feature" %} -Voice Transcription / speech-to-text (STT) is currently in experimental status. Expect potential issues and changes as the feature matures. +{% callout type="warning" title="Experimental feature" %} +Speech to Text is experimental. Expect issues and changes as it matures. {% /callout %} -Kilo Code now includes experimental support for voice input in the chat interface. This feature allows you to dictate your messages using speech-to-text (STT) technology powered by OpenAI's Whisper API. +Use voice input in prompt fields instead of typing. Transcription uses your Kilo account through Kilo Gateway. -## Prerequisites +--- -Voice transcription requires two components to be set up: +## Get ready -### 1. FFmpeg Installation +Voice input needs FFmpeg plus access to the Kilo provider. + +### Install FFmpeg FFmpeg is required for audio capture and processing. Install it for your platform: @@ -35,56 +37,72 @@ sudo apt install ffmpeg **Windows:** Download from [ffmpeg.org/download.html](https://ffmpeg.org/download.html) and add to your system PATH. -### 2. OpenAI API Key +### Sign in -Voice transcription uses OpenAI's Whisper API for speech recognition. You need an OpenAI API configuration in Kilo Code: +Enable and sign in to the Kilo provider to use voice input in prompt fields. Requests use your Kilo account through Kilo Gateway, so no separate OpenAI provider profile or API key is needed. -1. Configure an OpenAI provider profile in Kilo Code settings -2. Add your OpenAI API key to the profile -3. Either **OpenAI** or **OpenAI Native** provider types will work +--- -## Enabling Voice Transcription +## Enable input -Voice transcription is an experimental feature that must be enabled: +Voice input is experimental and must be enabled: 1. Open Kilo Code settings -2. Navigate to **Experimental Features** +2. Open **Experimental** settings 3. Enable the **Speech to Text** experiment -## Using Voice Input +Kilo stores this toggle in your global Kilo CLI config (`~/.config/kilo/kilo.jsonc`), not VS Code user settings: -Once configured and enabled, a microphone button will appear in the chat input area: +```json +{ + "experimental": { + "speech_to_text": true + } +} +``` + +--- + +## Record prompts + +Once enabled, a microphone button appears in prompt fields: 1. Click the microphone button to start recording 2. Speak your message clearly 3. Click again to stop recording -4. Your speech will be automatically transcribed into text +4. Your speech is transcribed into text The feature includes real-time audio level visualization and voice activity detection to automatically detect when you're speaking. -## Technical Details +--- -- **Audio Processing**: Uses FFmpeg for system audio capture -- **Voice Recognition**: OpenAI Whisper API for transcription +## Review details -## Troubleshooting +- **Audio processing**: Uses FFmpeg for system audio capture +- **Transcription**: Sends audio through Kilo Gateway with the selected transcription model + +--- + +## Fix issues **Microphone button not appearing:** - Ensure the Speech to Text experiment is enabled - Verify FFmpeg is installed and in your PATH -- Check that you have an OpenAI provider configured with a valid API key +- Enable and sign in to the Kilo provider **Transcription errors:** -- Verify your OpenAI API key is valid and has available credits +- Confirm the Kilo provider remains enabled and signed in - Check your internet connection - Try speaking more clearly or adjusting your microphone settings -## Limitations +--- -This feature is currently experimental and may have limitations: +## Know limits -- Requires active internet connection -- Uses OpenAI API credits based on audio duration +Speech to Text is experimental and may have limitations: + +- Requires an active internet connection +- Requires Kilo Gateway access through your Kilo account - Transcription accuracy depends on audio quality and speech clarity diff --git a/packages/kilo-docs/pages/code-with-ai/platforms/cli-reference.md b/packages/kilo-docs/pages/code-with-ai/platforms/cli-reference.md index 09c5ad62c8c..9488f7a8fcd 100644 --- a/packages/kilo-docs/pages/code-with-ai/platforms/cli-reference.md +++ b/packages/kilo-docs/pages/code-with-ai/platforms/cli-reference.md @@ -154,6 +154,7 @@ Options: --fork fork the session when continuing (use with --continue or --session) [boolean] --cloud-fork fetch session from cloud and continue locally (use with --session) [boolean] -p, --password basic auth password (defaults to KILO_SERVER_PASSWORD) [string] + -u, --username basic auth username (defaults to KILO_SERVER_USERNAME or 'kilo') [string] ``` ## kilo run @@ -171,6 +172,7 @@ Options: -c, --continue continue the last session [boolean] -s, --session session id to continue [string] --fork fork the session before continuing (requires --continue or --session) [boolean] + --cloud-fork fetch session from cloud and continue locally (use with --session) [boolean] --share share the session [boolean] -m, --model model to use in the format of provider/model [string] --agent agent to use [string] @@ -179,10 +181,12 @@ Options: --title title for the session (uses truncated prompt if no value provided) [string] --attach attach to a running opencode server (e.g., http://localhost:4096) [string] -p, --password basic auth password (defaults to KILO_SERVER_PASSWORD) [string] + -u, --username basic auth username (defaults to KILO_SERVER_USERNAME or 'kilo') [string] --dir directory to run in, path on remote server if attaching [string] --port port for the local server (defaults to random port if no value provided) [number] --variant model variant (provider-specific reasoning effort, e.g., high, max, minimal) [string] --thinking show thinking blocks [boolean] [default: false] + --dangerously-skip-permissions auto-approve permissions that are not explicitly denied (dangerous!) [boolean] [default: false] --auto auto-approve all permissions (for autonomous/pipeline usage) [boolean] [default: false] ``` @@ -201,6 +205,7 @@ Commands: kilo debug snapshot snapshot debugging utilities kilo debug startup print startup timing kilo debug agent show agent configuration details + kilo debug info show debug information kilo debug paths show global paths (data, config, cache, state) kilo debug wait wait indefinitely (for debugging) @@ -502,6 +507,16 @@ Options: --params Tool params as JSON or a JS object literal [string] ``` +### kilo debug info + +``` +show debug information + +Options: + --help Show help [boolean] + --version Show version number [boolean] +``` + ### kilo debug paths ``` @@ -528,7 +543,7 @@ Options: manage AI providers and credentials Commands: - kilo auth list list providers [aliases: ls] + kilo auth list list providers and credentials [aliases: ls] kilo auth login [url] log in to a provider kilo auth logout log out from a configured provider @@ -540,7 +555,7 @@ Options: ### kilo auth list ``` -list providers +list providers and credentials Options: --help Show help [boolean] @@ -669,6 +684,25 @@ Options: --refresh refresh the models cache from models.dev [boolean] ``` +## kilo roll-call + +``` +batch-test text models matching a filter for connectivity and latency + +Positionals: + filter regex to filter models by provider/modelID (required) [string] + +Options: + --help Show help [boolean] + --version Show version number [boolean] + --prompt Prompt to send to each model [string] [default: "Hello"] + --timeout Timeout for each model call in milliseconds [number] [default: 25000] + --parallel Number of parallel model calls [number] [default: 5] + --verbose Show verbose output [boolean] [default: false] + --quiet Suppress progress and decoration [boolean] [default: false] + --output Output format (table, json, or md) [string] [choices: "table", "json", "md"] [default: "table"] +``` + ## kilo stats ``` diff --git a/packages/kilo-docs/pages/code-with-ai/platforms/github.md b/packages/kilo-docs/pages/code-with-ai/platforms/github.md index cc03869eb91..d275c81d02c 100644 --- a/packages/kilo-docs/pages/code-with-ai/platforms/github.md +++ b/packages/kilo-docs/pages/code-with-ai/platforms/github.md @@ -25,6 +25,8 @@ When you're reviewing a pull request and want a second opinion on a piece of cod The bot reads the review comment, the surrounding diff, and the relevant code in the repository to give you an informed answer. +{% image src="/docs/img/connect/github/github-review.png" alt="Asking @kilocode-bot a question on a GitHub pull request review comment" width="800" /%} + ### Fix issues directly from GitHub Tag the bot on any issue and ask it to handle the fix: @@ -40,6 +42,8 @@ The bot will: - Create a branch with the implementation - Open a pull request +{% image src="/docs/img/connect/github/github-issue.png" alt="Asking @kilocode-bot to fix a GitHub issue" width="800" /%} + ### Diagnose bug reports When a bug report comes in and you want to understand what's going on before diving in: @@ -50,6 +54,8 @@ When a bug report comes in and you want to understand what's going on before div The bot examines the bug report, searches the codebase for related code paths, and shares its analysis directly in the issue thread. +{% image src="/docs/img/connect/github/github-bug.png" alt="Asking @kilocode-bot to diagnose a bug report on a GitHub issue" width="800" /%} + --- ## How It Works diff --git a/packages/kilo-docs/pages/code-with-ai/platforms/linear.md b/packages/kilo-docs/pages/code-with-ai/platforms/linear.md index b383e53f65b..52d3b15a2ed 100644 --- a/packages/kilo-docs/pages/code-with-ai/platforms/linear.md +++ b/packages/kilo-docs/pages/code-with-ai/platforms/linear.md @@ -26,6 +26,8 @@ The bot will: - Show a thinking/processing animation in Linear while it works - Link the resulting pull request back to the issue +{% image src="/docs/img/connect/linear/linear-fix-issue.png" alt="Asking @kilo to fix an issue in Linear" width="800" /%} + ### Apply changes across multiple repositories If a fix or upgrade needs to land in several repos at once: @@ -36,6 +38,8 @@ If a fix or upgrade needs to land in several repos at once: The bot handles each repository independently, creating separate branches and pull requests for each. +{% image src="/docs/img/connect/linear/linear-multi-repo.png" alt="Asking @kilo to apply changes across multiple repositories from Linear" width="800" /%} + ### Get help understanding an issue Before jumping into a fix, ask the bot to analyze the problem: @@ -46,6 +50,8 @@ Before jumping into a fix, ask the bot to analyze the problem: The bot examines the issue context and searches the connected codebase to surface likely causes. +{% image src="/docs/img/connect/linear/linear-understand-issue.png" alt="Asking @kilo to analyze the cause of a Linear issue" width="800" /%} + --- ## How It Works diff --git a/packages/kilo-docs/pages/code-with-ai/platforms/slack.md b/packages/kilo-docs/pages/code-with-ai/platforms/slack.md index abcf6862bee..20691d8c381 100644 --- a/packages/kilo-docs/pages/code-with-ai/platforms/slack.md +++ b/packages/kilo-docs/pages/code-with-ai/platforms/slack.md @@ -28,6 +28,8 @@ When you mention `@Kilo` in a thread, the bot: @Kilo how is error handling implemented in the payment processing module? ``` +{% image src="/docs/img/connect/slack/slackbot-ask-questions.webp" alt="Asking Kilo a question about the codebase in Slack" width="800" /%} + ### Implement fixes and features from Slack discussions When your team identifies a bug or improvement in a thread, ask the bot to handle it: @@ -43,6 +45,8 @@ The bot will: - Create a branch with the implementation - Push a pull request to your repository +{% image src="/docs/img/connect/slack/slackbot-turn-discussions-into-PRs.webp" alt="Kilo turning a Slack thread discussion into a pull request" width="800" /%} + ### Implement changes across multiple repositories If the same change needs to land in several repos, just tell the bot: @@ -51,6 +55,8 @@ If the same change needs to land in several repos, just tell the bot: @Kilo please fix this in the cloud, landing, and handbook repos ``` +{% image src="/docs/img/connect/slack/slackbot-coding.webp" alt="Kilo implementing changes across multiple repositories from Slack" width="800" /%} + ### Debug issues Paste an error message or stack trace and ask for help: @@ -61,6 +67,8 @@ Paste an error message or stack trace and ask for help: Can you help me understand what's causing it? ``` +{% image src="/docs/img/connect/slack/slackbot-bugs.webp" alt="Kilo helping debug a production error in Slack" width="800" /%} + --- ## How to Interact diff --git a/packages/kilo-docs/pages/collaborate/teams/billing.md b/packages/kilo-docs/pages/collaborate/teams/billing.md index 545c8887818..c8b89f50c98 100644 --- a/packages/kilo-docs/pages/collaborate/teams/billing.md +++ b/packages/kilo-docs/pages/collaborate/teams/billing.md @@ -68,7 +68,7 @@ To fill empty seats or remove members ahead of seat deletion, see the [team mana ## Automatic Top-Up -Ensure your team has uninterrupted access to Kilo Code by enabling Automatic Top-Up. This feature keeps your organization's balance funded so you never have to worry about manual recharges. +Ensure your team has uninterrupted access to Kilo Code by enabling [Automatic Top-Up](https://kilo.ai/features/auto-top-ups). This feature keeps your organization's balance funded so you never have to worry about manual recharges. Auto top-up is also available for individual accounts — see [Adding Credits](/docs/getting-started/adding-credits) for details. ### How It Works diff --git a/packages/kilo-docs/pages/getting-started/adding-credits.md b/packages/kilo-docs/pages/getting-started/adding-credits.md index f5c89de697c..a8b021abcea 100644 --- a/packages/kilo-docs/pages/getting-started/adding-credits.md +++ b/packages/kilo-docs/pages/getting-started/adding-credits.md @@ -9,9 +9,9 @@ Once you've used any initial free Kilo Credits, you can easily add more: - Subscribe to the [Kilo Pass](https://kilo.ai/features/kilo-pass), the most cost effective way to add credits. - Purchase additional credits as a one-time transaction. -- Enable automatic top-up, which purchases additional credits when your balance is below $5. +- Enable [automatic top-up](https://kilo.ai/features/auto-top-ups), which purchases additional credits when your balance runs low. Auto top-up is available for both individual and organization accounts. -These options are available to purchase from your [personal profile page](https://app.kilo.ai/profile). +These options are available to purchase from your [personal profile page](https://app.kilo.ai/profile). Organization owners can manage credits and auto top-up from the [Organization dashboard](https://app.kilo.ai). You can also use subscriptions or credits you may have purchased directly with an AI provider by adding your keys on the [Bring your own Key (BYOK)](https://app.kilo.ai/byok) settings screen. For setup details and supported providers, see [AI Providers documentation](/docs/ai-providers). If your provider is not yet supported, you can also [directly connect your provider](/docs/getting-started/setup-authentication) in the extension and CLI. diff --git a/packages/kilo-docs/pages/getting-started/settings/index.md b/packages/kilo-docs/pages/getting-started/settings/index.md index a947eebab69..f9645eca76c 100644 --- a/packages/kilo-docs/pages/getting-started/settings/index.md +++ b/packages/kilo-docs/pages/getting-started/settings/index.md @@ -198,10 +198,21 @@ Available experimental toggles include: - **Share mode** — `manual`, `auto`, or `disabled` session sharing - **LSP integration** — expose language server diagnostics to the agent - **Paste summary** — summarize large clipboard pastes before including them +- **Speech to Text**: enable voice transcription in chat - **Batch tool** — allow the agent to batch multiple tool calls in one step - **Agent Manager Tool** - allow agents to start Agent Manager local and worktree sessions from chat - **OpenTelemetry** — enable Kilo telemetry and optional OTLP export when configured +Speech to Text is enabled from this Experimental tab. Kilo stores that toggle in your global Kilo CLI config (`~/.config/kilo/kilo.jsonc`), not VS Code user settings: + +```json +{ + "experimental": { + "speech_to_text": true + } +} +``` + Advanced options not exposed in the UI can be configured via the `experimental` key in `kilo.jsonc`: ```json diff --git a/packages/kilo-docs/pages/kiloclaw/dashboard.md b/packages/kilo-docs/pages/kiloclaw/dashboard.md index 0d6a388a5c7..6661aa069ba 100644 --- a/packages/kilo-docs/pages/kiloclaw/dashboard.md +++ b/packages/kilo-docs/pages/kiloclaw/dashboard.md @@ -189,10 +189,6 @@ Each instance runs on a dedicated machine — there is no shared infrastructure Your storage is region-pinned — once your instance is created in a region (e.g., DFW), it always runs there. OpenClaw config lives at `/root/.openclaw` and the workspace at `/root/clawd`. -{% callout type="info" %} -These are the beta specifications for machines and subject to change without notice. -{% /callout %} - ## Related - [KiloClaw Overview](/docs/kiloclaw/overview) diff --git a/packages/kilo-docs/pages/kiloclaw/faq/pricing.md b/packages/kilo-docs/pages/kiloclaw/faq/pricing.md index e63d9aa99b2..949aa62ffeb 100644 --- a/packages/kilo-docs/pages/kiloclaw/faq/pricing.md +++ b/packages/kilo-docs/pages/kiloclaw/faq/pricing.md @@ -9,10 +9,7 @@ KiloClaw uses Kilo Gateway credits by default — if you route requests through ## Instance Hosting -KiloClaw hosting is **free during the beta period**. Each user gets a dedicated machine (2 shared vCPUs, 3 GB RAM, 10 GB SSD) at no cost. - -> ℹ️ **Info** -> Beta pricing is subject to change. Paid hosting tiers may be introduced after the beta period ends. Any changes will be announced in advance. +Each user gets a dedicated machine (2 shared vCPUs, 3 GB RAM, 10 GB SSD). Visit [kilo.ai/pricing](https://kilo.ai/pricing) for current pricing and plans. ## Model Inference diff --git a/packages/kilo-docs/pages/kiloclaw/overview.md b/packages/kilo-docs/pages/kiloclaw/overview.md index 19d8b695913..7a1c518d10d 100644 --- a/packages/kilo-docs/pages/kiloclaw/overview.md +++ b/packages/kilo-docs/pages/kiloclaw/overview.md @@ -7,7 +7,7 @@ description: "One-click deployment of your personal AI agent with OpenClaw" KiloClaw is Kilo's hosted [OpenClaw](https://openclaw.ai) service — a one-click deployment that gives you a personal AI agent without the complexity of self-hosting. OpenClaw is a 24/7, open source AI agent that connects to chat platforms like Telegram, Discord, and Slack so it can take real actions automatically, not just chat. -KiloClaw is powered by KiloCode. The API key is platform-managed, so you never need to bring your own. KiloClaw is currently in **Beta**. +KiloClaw is powered by KiloCode. The API key is platform-managed, so you never need to bring your own. ## Why KiloClaw? diff --git a/packages/kilo-docs/previous-docs-redirects.js b/packages/kilo-docs/previous-docs-redirects.js index 1d872b63f5d..270e4874ccf 100644 --- a/packages/kilo-docs/previous-docs-redirects.js +++ b/packages/kilo-docs/previous-docs-redirects.js @@ -871,4 +871,10 @@ module.exports = [ basePath: false, permanent: true, }, + { + source: "/auto-top-ups", + destination: "https://kilo.ai/features/auto-top-ups", + basePath: false, + permanent: true, + }, ] diff --git a/packages/kilo-docs/public/img/connect/github/github-bug.png b/packages/kilo-docs/public/img/connect/github/github-bug.png new file mode 100644 index 00000000000..1095aa4ab4d Binary files /dev/null and b/packages/kilo-docs/public/img/connect/github/github-bug.png differ diff --git a/packages/kilo-docs/public/img/connect/github/github-issue.png b/packages/kilo-docs/public/img/connect/github/github-issue.png new file mode 100644 index 00000000000..092ce869d21 Binary files /dev/null and b/packages/kilo-docs/public/img/connect/github/github-issue.png differ diff --git a/packages/kilo-docs/public/img/connect/github/github-review.png b/packages/kilo-docs/public/img/connect/github/github-review.png new file mode 100644 index 00000000000..cea6ea000cb Binary files /dev/null and b/packages/kilo-docs/public/img/connect/github/github-review.png differ diff --git a/packages/kilo-docs/public/img/connect/linear/linear-fix-issue.png b/packages/kilo-docs/public/img/connect/linear/linear-fix-issue.png new file mode 100644 index 00000000000..b4862a05703 Binary files /dev/null and b/packages/kilo-docs/public/img/connect/linear/linear-fix-issue.png differ diff --git a/packages/kilo-docs/public/img/connect/linear/linear-multi-repo.png b/packages/kilo-docs/public/img/connect/linear/linear-multi-repo.png new file mode 100644 index 00000000000..13555708901 Binary files /dev/null and b/packages/kilo-docs/public/img/connect/linear/linear-multi-repo.png differ diff --git a/packages/kilo-docs/public/img/connect/linear/linear-understand-issue.png b/packages/kilo-docs/public/img/connect/linear/linear-understand-issue.png new file mode 100644 index 00000000000..ec6743a2436 Binary files /dev/null and b/packages/kilo-docs/public/img/connect/linear/linear-understand-issue.png differ diff --git a/packages/kilo-docs/public/img/connect/slack/slackbot-ask-questions.webp b/packages/kilo-docs/public/img/connect/slack/slackbot-ask-questions.webp new file mode 100644 index 00000000000..74920beddab Binary files /dev/null and b/packages/kilo-docs/public/img/connect/slack/slackbot-ask-questions.webp differ diff --git a/packages/kilo-docs/public/img/connect/slack/slackbot-bugs.webp b/packages/kilo-docs/public/img/connect/slack/slackbot-bugs.webp new file mode 100644 index 00000000000..9efc3e80496 Binary files /dev/null and b/packages/kilo-docs/public/img/connect/slack/slackbot-bugs.webp differ diff --git a/packages/kilo-docs/public/img/connect/slack/slackbot-coding.webp b/packages/kilo-docs/public/img/connect/slack/slackbot-coding.webp new file mode 100644 index 00000000000..cc2f4104a8a Binary files /dev/null and b/packages/kilo-docs/public/img/connect/slack/slackbot-coding.webp differ diff --git a/packages/kilo-docs/public/img/connect/slack/slackbot-turn-discussions-into-PRs.webp b/packages/kilo-docs/public/img/connect/slack/slackbot-turn-discussions-into-PRs.webp new file mode 100644 index 00000000000..64670c4563b Binary files /dev/null and b/packages/kilo-docs/public/img/connect/slack/slackbot-turn-discussions-into-PRs.webp differ diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/background-process-tool-cards-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/background-process-tool-cards-chromium-linux.png new file mode 100644 index 00000000000..b557ae59935 --- /dev/null +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/background-process-tool-cards-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18d394d726ebee312e54db5d45f55cca3a1728d2b41f9f73bb9b610096bf53e0 +size 41004 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png index a17e69d6219..db19d08e861 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7aa0924c6679cbff6e816dd86371a2d483afb7f0840824503ef4ba325c25d6c5 -size 26282 +oid sha256:97728b91ed1c92556abfde08824b91536e87cc7afa4d121bb5b1b488946c1d05 +size 26009 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-edit-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-edit-chromium-linux.png index cdca3764fb9..0aadc161dc2 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-edit-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-edit-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f28a551185ec9d7607d02295803b155e0f7bac378fcefdf0996c6ca51c0afad6 -size 21892 +oid sha256:7b8e9f6e0b9a9a62efc9b1e807936049c7627674ba241239dfd777698f951acc +size 21820 diff --git a/packages/kilo-docs/source-links.md b/packages/kilo-docs/source-links.md index 7bfc0a61504..bf6b1ebceef 100644 --- a/packages/kilo-docs/source-links.md +++ b/packages/kilo-docs/source-links.md @@ -30,6 +30,8 @@ - +- + - - @@ -42,8 +44,6 @@ - -- - - - @@ -68,6 +68,7 @@ - + - - @@ -83,8 +84,10 @@ - + - + - @@ -113,7 +116,6 @@ - - - - diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index 6aef452b3c4..dc0b0236abd 100644 --- a/packages/kilo-gateway/package.json +++ b/packages/kilo-gateway/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-gateway", - "version": "7.3.0", + "version": "7.3.8", "type": "module", "license": "MIT", "description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration", diff --git a/packages/kilo-gateway/src/index.ts b/packages/kilo-gateway/src/index.ts index e84cb0c7dcf..429575d093d 100644 --- a/packages/kilo-gateway/src/index.ts +++ b/packages/kilo-gateway/src/index.ts @@ -48,11 +48,24 @@ export { type OrganizationModeConfig, } from "./api/modes.js" export { fetchKilocodeNotifications, type KilocodeNotification } from "./api/notifications.js" +export { fetchCloudSession, fetchCloudSessionForImport, importSessionToDb } from "./cloud-sessions.js" // ============================================================================ // Server Routes (optional - requires hono and OpenCode dependencies) // ============================================================================ export { createKiloRoutes } from "./server/routes.js" +export { + GatewayError, + UnauthorizedError, + getOrganizationId, + getClawChatCredentials, + getClawStatus, + getCloudSessions, + getNotifications, + getProfile, + getToken, + setOrganization, +} from "./server/handlers.js" // ============================================================================ // Note: TUI exports moved to separate entry point @@ -88,6 +101,8 @@ export { ENV_KILO_API_URL, DEFAULT_KILO_API_URL, KILO_API_BASE, + KILO_CHAT_URL, + KILO_EVENT_SERVICE_URL, KILO_OPENROUTER_BASE, POLL_INTERVAL_MS, DEFAULT_MODEL, diff --git a/packages/kilo-gateway/src/server/handlers.ts b/packages/kilo-gateway/src/server/handlers.ts new file mode 100644 index 00000000000..4e3fca63762 --- /dev/null +++ b/packages/kilo-gateway/src/server/handlers.ts @@ -0,0 +1,190 @@ +import { fetchBalance, fetchProfile } from "../api/profile.js" +import { fetchKilocodeNotifications } from "../api/notifications.js" +import { clearModesCache } from "../api/modes.js" +import { HEADER_ORGANIZATIONID, KILO_API_BASE, KILO_CHAT_URL, KILO_EVENT_SERVICE_URL } from "../api/constants.js" +import type { KilocodeBalance, KilocodeProfile } from "../types.js" +import { buildKiloHeaders } from "../headers.js" + +export type KiloAuth = + | { type: "api"; key: string } + | { type: "oauth"; access: string; refresh: string; expires: number; accountId?: string } + | { type: "wellknown"; key: string; token: string } + +export interface KiloProfileResult { + profile: KilocodeProfile + balance: KilocodeBalance | null + currentOrgId: string | null +} + +export interface ClawChatCredentials { + token: string + expiresAt: string + kiloChatUrl: string + eventServiceUrl: string +} + +export interface AuthStore { + get(provider: string): Promise + set(provider: string, auth: Extract): Promise +} + +export interface OrganizationDeps { + auth: AuthStore + clear(): void + dispose(): Promise +} + +export interface CloudSessionsInput { + cursor?: string + limit?: number + gitUrl?: string +} + +export class UnauthorizedError extends Error {} + +export class GatewayError extends Error { + constructor( + message: string, + readonly status: number, + ) { + super(message) + } +} + +export function getToken(auth: KiloAuth | undefined) { + if (auth?.type === "api") return auth.key + if (auth?.type === "oauth") return auth.access + return undefined +} + +export function getOrganizationId(auth: KiloAuth | undefined) { + if (auth?.type === "oauth") return auth.accountId + return undefined +} + +export async function getProfile(auth: AuthStore): Promise { + const info = await auth.get("kilo") + if (!info || info.type !== "oauth") throw new UnauthorizedError("Not authenticated with Kilo Gateway") + + const currentOrgId = info.accountId ?? null + const [profile, balance] = await Promise.all([ + fetchProfile(info.access), + fetchBalance(info.access, currentOrgId ?? undefined), + ]) + return { profile, balance, currentOrgId } +} + +export async function getNotifications(auth: AuthStore) { + const info = await auth.get("kilo") + const token = getToken(info) + if (!token) return [] + + return fetchKilocodeNotifications({ + kilocodeToken: token, + kilocodeOrganizationId: getOrganizationId(info), + }) +} + +export async function setOrganization(deps: OrganizationDeps, organizationId: string | null) { + const info = await deps.auth.get("kilo") + if (!info || info.type !== "oauth") throw new UnauthorizedError("Not authenticated with Kilo Gateway") + + await deps.auth.set("kilo", { + type: "oauth", + refresh: info.refresh, + access: info.access, + expires: info.expires, + ...(organizationId && { accountId: organizationId }), + }) + + deps.clear() + clearModesCache() + await deps.dispose() + return true +} + +export async function getClawStatus(auth: AuthStore) { + const info = await auth.get("kilo") + const token = getToken(info) + if (!token) throw new UnauthorizedError("No valid token found") + + const headers: Record = { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + } + const org = getOrganizationId(info) + if (org) headers[HEADER_ORGANIZATIONID] = org + + const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/status`, { headers }) + if (!response.ok) throw new GatewayError(await response.text(), response.status) + return response.json() +} + +export async function getClawChatCredentials(auth: AuthStore): Promise { + const info = await auth.get("kilo") + const token = getToken(info) + if (!token) throw new UnauthorizedError("No valid token found") + + const expires = info?.type === "oauth" ? info.expires : Date.now() + 365 * 24 * 60 * 60 * 1000 + return { + token, + expiresAt: new Date(expires).toISOString(), + kiloChatUrl: KILO_CHAT_URL, + eventServiceUrl: KILO_EVENT_SERVICE_URL, + } +} + +export async function getCloudSessions(token: string, input: CloudSessionsInput) { + const query: Record = {} + if (input.cursor) query.cursor = input.cursor + if (input.limit) query.limit = input.limit + if (input.gitUrl) query.gitUrl = input.gitUrl + + const params = new URLSearchParams({ + batch: "1", + input: JSON.stringify({ "0": query }), + }) + + const response = await fetch(`${KILO_API_BASE}/api/trpc/cliSessionsV2.list?${params.toString()}`, { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + ...buildKiloHeaders(), + }, + }) + + if (!response.ok) { + const text = await response.text() + console.error("[Kilo Gateway] cloud-sessions: tRPC request failed", { + status: response.status, + body: text.slice(0, 500), + }) + throw new GatewayError(`Cloud sessions fetch failed: ${response.status}`, response.status) + } + + const raw = await response.text() + const json = JSON.parse(raw) + const data = Array.isArray(json) ? json[0]?.result?.data : null + const result = data?.json ?? data + if (!result) return { cliSessions: [], nextCursor: null } + + const cliSessions = (result.cliSessions ?? []).map((item: any) => ({ + session_id: item.session_id, + title: item.title ?? null, + created_at: + typeof item.created_at === "string" + ? item.created_at + : item.created_at + ? new Date(item.created_at).toISOString() + : new Date().toISOString(), + updated_at: + typeof item.updated_at === "string" + ? item.updated_at + : item.updated_at + ? new Date(item.updated_at).toISOString() + : new Date().toISOString(), + version: item.version ?? 0, + })) + + return { cliSessions, nextCursor: result.nextCursor ?? null } +} diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts index f92c00f3f31..78c2bfda6b5 100644 --- a/packages/kilo-gateway/src/server/routes.ts +++ b/packages/kilo-gateway/src/server/routes.ts @@ -5,19 +5,22 @@ * This factory function accepts OpenCode dependencies to create Kilo-specific routes */ -import { fetchProfile, fetchBalance } from "../api/profile.js" import { fetchKilocodeNotifications, KilocodeNotificationSchema } from "../api/notifications.js" import { fetchOrganizationModes, clearModesCache } from "../api/modes.js" -import { - KILO_API_BASE, - KILO_CHAT_URL, - KILO_EVENT_SERVICE_URL, - HEADER_FEATURE, - HEADER_ORGANIZATIONID, -} from "../api/constants.js" +import { KILO_API_BASE, HEADER_FEATURE, HEADER_ORGANIZATIONID } from "../api/constants.js" import { buildKiloHeaders } from "../headers.js" import type { ImportDeps, DrizzleDb } from "../cloud-sessions.js" import { fetchCloudSession, fetchCloudSessionForImport, importSessionToDb } from "../cloud-sessions.js" +import { + GatewayError, + UnauthorizedError, + getClawChatCredentials, + getClawStatus, + getCloudSessions, + getNotifications, + getProfile, + setOrganization, +} from "./handlers.js" // Type definitions for OpenCode dependencies (injected at runtime) type Hono = any @@ -38,7 +41,7 @@ interface KiloRoutesDeps extends ImportDeps { Auth: Auth ModelCache: ModelCache z: Z - InstanceStore: { disposeAllInstances(): Promise } + Instances: { disposeAllInstances(): Promise } } const FIM_TIMEOUT_MS = 30_000 @@ -85,7 +88,7 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { SessionCreatedEvent, Identifier, ModelCache, - InstanceStore, + Instances, } = deps const Organization = z.object({ @@ -167,24 +170,12 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { }, }), async (c: any) => { - // Get Kilo auth - const auth = await Auth.get("kilo") - - if (!auth || auth.type !== "oauth") { + try { + return c.json(await getProfile(Auth)) + } catch (err) { + if (!(err instanceof UnauthorizedError)) throw err return c.json({ error: "Not authenticated with Kilo Gateway" }, 401) } - - const token = auth.access - const currentOrgId = auth.accountId ?? null - - // Fetch profile and balance in parallel - // Pass organizationId to fetchBalance to get team balance when in org context - const [profile, balance] = await Promise.all([ - fetchProfile(token), - fetchBalance(token, currentOrgId ?? undefined), - ]) - - return c.json({ profile, balance, currentOrgId }) }, ) .post( @@ -214,27 +205,21 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { async (c: any) => { const { organizationId } = c.req.valid("json") - // Get current Kilo auth - const auth = await Auth.get("kilo") - - if (!auth || auth.type !== "oauth") { + try { + return c.json( + await setOrganization( + { + auth: Auth, + clear: () => ModelCache.clear("kilo"), + dispose: () => Instances.disposeAllInstances(), + }, + organizationId, + ), + ) + } catch (err) { + if (!(err instanceof UnauthorizedError)) throw err return c.json({ error: "Not authenticated with Kilo Gateway" }, 401) } - - // Update auth with new organization ID - await Auth.set("kilo", { - type: "oauth", - refresh: auth.refresh, - access: auth.access, - expires: auth.expires, - ...(organizationId && { accountId: organizationId }), - }) - - ModelCache.clear("kilo") - clearModesCache() - await InstanceStore.disposeAllInstances() - - return c.json(true) }, ) .get( @@ -482,19 +467,7 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { }, }), async (c: any) => { - const auth = await Auth.get("kilo") - if (!auth) return c.json([]) - - const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined - if (!token) return c.json([]) - - const organizationId = auth.type === "oauth" ? auth.accountId : undefined - const notifications = await fetchKilocodeNotifications({ - kilocodeToken: token, - kilocodeOrganizationId: organizationId, - }) - - return c.json(notifications) + return c.json(await getNotifications(Auth)) }, ) .get( @@ -643,29 +616,11 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { }), async (c: any) => { try { - const auth = await Auth.get("kilo") - if (!auth) return c.json({ error: "Not authenticated with Kilo Gateway" }, 401) - const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined - if (!token) return c.json({ error: "No valid token found" }, 401) - - const organizationId = auth.type === "oauth" ? auth.accountId : undefined - const headers: Record = { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - } - if (organizationId) { - headers[HEADER_ORGANIZATIONID] = organizationId - } - - const response = await fetch(`${KILO_API_BASE}/api/kiloclaw/status`, { headers }) - - if (!response.ok) { - const text = await response.text() - return c.json({ error: `KiloClaw request failed: ${response.status} ${text}` }, response.status as any) - } - - return c.json(await response.json()) + return c.json(await getClawStatus(Auth)) } catch (err: any) { + if (err instanceof GatewayError) { + return c.json({ error: `KiloClaw request failed: ${err.status} ${err.message}` }, err.status as any) + } console.error("[Kilo Gateway] claw/status: error", err?.message ?? err) return c.json({ error: "Failed to reach KiloClaw" }, 502) } @@ -702,25 +657,12 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { }, }), async (c: any) => { - const auth = await Auth.get("kilo") - if (!auth) return c.json({ error: "Not authenticated with Kilo Gateway" }, 401) - const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined - if (!token) return c.json({ error: "No valid token found" }, 401) - - // For OAuth, expires is a millisecond epoch we already track. For - // API tokens we don't have a verified expiry locally — the JWT is - // signed by the cloud and validated by kilo-chat/event-service on - // every request. Use a far-future placeholder so the client cache - // doesn't refetch unnecessarily; on 401 the client clears the - // cache and prompts re-auth. - const expiresAtMs = auth.type === "oauth" ? auth.expires : Date.now() + 365 * 24 * 60 * 60 * 1000 - - return c.json({ - token, - expiresAt: new Date(expiresAtMs).toISOString(), - kiloChatUrl: KILO_CHAT_URL, - eventServiceUrl: KILO_EVENT_SERVICE_URL, - }) + try { + return c.json(await getClawChatCredentials(Auth)) + } catch (err) { + if (!(err instanceof UnauthorizedError)) throw err + return c.json({ error: "Not authenticated with Kilo Gateway" }, 401) + } }, ) .get( @@ -770,63 +712,9 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { const token = auth.type === "api" ? auth.key : auth.type === "oauth" ? auth.access : undefined if (!token) return c.json({ error: "No valid token found" }, 401) - const { cursor, limit, gitUrl } = c.req.valid("query") - - const input: Record = {} - if (cursor) input.cursor = cursor - if (limit) input.limit = limit - if (gitUrl) input.gitUrl = gitUrl - - const params = new URLSearchParams({ - batch: "1", - input: JSON.stringify({ "0": input }), - }) - - const url = `${KILO_API_BASE}/api/trpc/cliSessionsV2.list?${params.toString()}` - - const response = await fetch(url, { - headers: { - Authorization: `Bearer ${token}`, - "Content-Type": "application/json", - ...buildKiloHeaders(), - }, - }) - - if (!response.ok) { - const text = await response.text() - console.error("[Kilo Gateway] cloud-sessions: tRPC request failed", { - status: response.status, - body: text.slice(0, 500), - }) - return c.json({ error: `Cloud sessions fetch failed: ${response.status}` }, response.status as any) - } - - const raw = await response.text() - const json = JSON.parse(raw) - const data = Array.isArray(json) ? json[0]?.result?.data : null - const result = data?.json ?? data - if (!result) return c.json({ cliSessions: [], nextCursor: null }) - - const sessions = (result.cliSessions ?? []).map((s: any) => ({ - session_id: s.session_id, - title: s.title ?? null, - created_at: - typeof s.created_at === "string" - ? s.created_at - : s.created_at - ? new Date(s.created_at).toISOString() - : new Date().toISOString(), - updated_at: - typeof s.updated_at === "string" - ? s.updated_at - : s.updated_at - ? new Date(s.updated_at).toISOString() - : new Date().toISOString(), - version: s.version ?? 0, - })) - - return c.json({ cliSessions: sessions, nextCursor: result.nextCursor ?? null }) + return c.json(await getCloudSessions(token, c.req.valid("query"))) } catch (err: any) { + if (err instanceof GatewayError) return c.json({ error: err.message }, err.status as any) console.error("[Kilo Gateway] cloud-sessions: unhandled error", err?.message ?? err) return c.json({ error: "Internal error" }, 500) } diff --git a/packages/kilo-gateway/test/api/models.test.ts b/packages/kilo-gateway/test/api/models.test.ts index c9224687459..579f0621bc0 100644 --- a/packages/kilo-gateway/test/api/models.test.ts +++ b/packages/kilo-gateway/test/api/models.test.ts @@ -91,11 +91,12 @@ test("returns error with kind=http on non-auth HTTP error (e.g. 500)", async () test("returns models without error on success", async () => { const orig = globalThis.fetch - stubFetch(async () => - new Response(VALID_RESPONSE, { - status: 200, - headers: { "content-type": "application/json" }, - }), + stubFetch( + async () => + new Response(VALID_RESPONSE, { + status: 200, + headers: { "content-type": "application/json" }, + }), ) const result = await fetchKiloModels({}) @@ -108,11 +109,12 @@ test("returns models without error on success", async () => { test("returns error with kind=schema when response body is invalid JSON", async () => { const orig = globalThis.fetch - stubFetch(async () => - new Response("not valid json{{{{", { - status: 200, - headers: { "content-type": "application/json" }, - }), + stubFetch( + async () => + new Response("not valid json{{{{", { + status: 200, + headers: { "content-type": "application/json" }, + }), ) const result = await fetchKiloModels({}) diff --git a/packages/kilo-i18n/package.json b/packages/kilo-i18n/package.json index 581dd55bb85..bd5b2396af6 100644 --- a/packages/kilo-i18n/package.json +++ b/packages/kilo-i18n/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-i18n", - "version": "7.3.0", + "version": "7.3.8", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", @@ -16,5 +16,7 @@ "@types/bun": "catalog:", "typescript": "catalog:", "@typescript/native-preview": "catalog:" - } + }, + "dependencies": {}, + "peerDependencies": {} } diff --git a/packages/kilo-indexing/package.json b/packages/kilo-indexing/package.json index da79c2e85db..e6069c60a4d 100644 --- a/packages/kilo-indexing/package.json +++ b/packages/kilo-indexing/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-indexing", - "version": "7.3.0", + "version": "7.3.8", "type": "module", "license": "MIT", "description": "Standalone indexing engine and host helpers for Kilo Code", @@ -40,6 +40,7 @@ "@qdrant/js-client-rest": "1.17.0", "async-mutex": "0.5.0", "chokidar": "4.0.3", + "effect": "catalog:", "glob": "13.0.6", "hono": "catalog:", "hono-openapi": "catalog:", @@ -57,5 +58,6 @@ "@types/node": "catalog:", "@typescript/native-preview": "catalog:", "typescript": "catalog:" - } + }, + "peerDependencies": {} } diff --git a/packages/kilo-indexing/src/config.ts b/packages/kilo-indexing/src/config.ts index 7eafc17b06f..8eae226e0ca 100644 --- a/packages/kilo-indexing/src/config.ts +++ b/packages/kilo-indexing/src/config.ts @@ -1,3 +1,4 @@ +import { Schema } from "effect" import z from "zod" import type { IndexingConfigInput } from "./indexing/config-manager" import type { EmbedderProvider } from "./indexing/interfaces/manager" @@ -14,6 +15,7 @@ const providers = [ "openrouter", "voyage", ] as const satisfies readonly EmbedderProvider[] +const stores = ["lancedb", "qdrant"] as const export const IndexingConfig = z .object({ @@ -26,7 +28,7 @@ export const IndexingConfig = z .positive() .optional() .describe("Override embedding vector dimension (auto-detected from model if omitted)"), - vectorStore: z.enum(["lancedb", "qdrant"]).optional().describe("Vector store backend (default: qdrant)"), + vectorStore: z.enum(stores).optional().describe("Vector store backend (default: qdrant)"), kilo: z .object({ apiKey: z.string().optional(), @@ -128,6 +130,106 @@ export const IndexingConfig = z export type IndexingConfig = z.infer +const Provider = Schema.Literals(providers) +const Store = Schema.Literals(stores) +const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0)) +const Score = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(1)) + +export const IndexingSchema = Schema.Struct({ + enabled: Schema.optional(Schema.Boolean).annotate({ description: "Enable codebase indexing" }), + provider: Schema.optional(Provider).annotate({ + description: "Embedding provider to use for codebase indexing", + }), + model: Schema.optional(Schema.String).annotate({ + description: "Embedding model ID (uses provider default if omitted)", + }), + dimension: Schema.optional(PositiveInt).annotate({ + description: "Override embedding vector dimension (auto-detected from model if omitted)", + }), + vectorStore: Schema.optional(Store).annotate({ description: "Vector store backend (default: qdrant)" }), + kilo: Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + baseUrl: Schema.optional(Schema.String), + organizationId: Schema.optional(Schema.String), + }), + ).annotate({ description: "Kilo-hosted embedding provider options" }), + openai: Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "OpenAI embedding provider options" }), + ollama: Schema.optional( + Schema.Struct({ + baseUrl: Schema.optional(Schema.String), + }), + ).annotate({ description: "Ollama embedding provider options" }), + "openai-compatible": Schema.optional( + Schema.Struct({ + baseUrl: Schema.optional(Schema.String), + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "OpenAI-compatible embedding provider options" }), + gemini: Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "Gemini embedding provider options" }), + mistral: Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "Mistral embedding provider options" }), + "vercel-ai-gateway": Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "Vercel AI Gateway embedding provider options" }), + bedrock: Schema.optional( + Schema.Struct({ + region: Schema.optional(Schema.String), + profile: Schema.optional(Schema.String), + }), + ).annotate({ description: "AWS Bedrock embedding provider options" }), + openrouter: Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + specificProvider: Schema.optional(Schema.String), + }), + ).annotate({ description: "OpenRouter embedding provider options" }), + voyage: Schema.optional( + Schema.Struct({ + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "Voyage embedding provider options" }), + qdrant: Schema.optional( + Schema.Struct({ + url: Schema.optional(Schema.String), + apiKey: Schema.optional(Schema.String), + }), + ).annotate({ description: "Qdrant vector store connection options" }), + lancedb: Schema.optional( + Schema.Struct({ + directory: Schema.optional(Schema.String), + }), + ).annotate({ description: "LanceDB vector store options" }), + searchMinScore: Schema.optional(Score).annotate({ + description: "Minimum similarity score for search results (default: 0.4)", + }), + searchMaxResults: Schema.optional(PositiveInt).annotate({ + description: "Maximum number of search results (default: 50)", + }), + embeddingBatchSize: Schema.optional(PositiveInt).annotate({ + description: "Number of code segments per embedding batch (default: 60)", + }), + scannerMaxBatchRetries: Schema.optional(PositiveInt).annotate({ + description: "Maximum retry attempts for failed embedding batches (default: 3)", + }), +}).annotate({ + identifier: "IndexingConfig", + description: "Codebase indexing configuration", +}) + export function toIndexingConfigInput(cfg: IndexingConfig | undefined): IndexingConfigInput { const provider = cfg?.provider ?? "openai" diff --git a/packages/kilo-indexing/src/indexing/config-manager.ts b/packages/kilo-indexing/src/indexing/config-manager.ts index 1c5124de2dd..fd8c63210d9 100644 --- a/packages/kilo-indexing/src/indexing/config-manager.ts +++ b/packages/kilo-indexing/src/indexing/config-manager.ts @@ -302,10 +302,9 @@ export class CodeIndexConfigManager { } public get currentModelDimension(): number | undefined { + if (this.modelDimension && this.modelDimension > 0) return this.modelDimension const id = this.modelId ?? getDefaultModelId(this.embedderProvider) - const dim = getModelDimension(this.embedderProvider, id) - if (!dim && this.modelDimension && this.modelDimension > 0) return this.modelDimension - return dim + return getModelDimension(this.embedderProvider, id) } public get currentSearchMinScore(): number { diff --git a/packages/kilo-indexing/src/indexing/embedders/openrouter.ts b/packages/kilo-indexing/src/indexing/embedders/openrouter.ts index c055964a5c3..bc8deea083a 100644 --- a/packages/kilo-indexing/src/indexing/embedders/openrouter.ts +++ b/packages/kilo-indexing/src/indexing/embedders/openrouter.ts @@ -25,7 +25,8 @@ interface EmbeddingItem { } interface OpenRouterEmbeddingResponse { - data: EmbeddingItem[] + data?: EmbeddingItem[] + error?: string | { code?: string | number; message?: string } usage?: { prompt_tokens?: number total_tokens?: number @@ -193,10 +194,7 @@ export class OpenRouterEmbedder implements IEmbedder { const requestParams: any = { input: batchTexts, model: model, - // OpenAI package (as of v4.78.1) has a parsing issue that truncates embedding dimensions to 256 - // when processing numeric arrays, which breaks compatibility with models using larger dimensions. - // By requesting base64 encoding, we bypass the package's parser and handle decoding ourselves. - encoding_format: "base64", + encoding_format: "float", } if (this.dimensions !== undefined) { @@ -213,8 +211,24 @@ export class OpenRouterEmbedder implements IEmbedder { } const response = (await this.embeddingsClient.embeddings.create(requestParams)) as OpenRouterEmbeddingResponse + const err = response.error + const msg = typeof err === "string" ? err : err?.message + const code = typeof err === "object" && err ? err.code : undefined + if (!response.data || response.data.length === 0) { + log.warn("OpenRouter embedder batch returned invalid response", { + location: "OpenRouterEmbedder:_embedBatchWithRetries", + model, + dimensions: this.dimensions, + provider: this.specificProvider, + code, + err: msg, + }) + const invalid = new Error(msg ?? "Invalid response from OpenRouter embedding endpoint") as HttpError + invalid.status = typeof code === "number" ? code : 422 + throw invalid + } - // Convert base64 embeddings to float32 arrays + // Normalize base64 embeddings if OpenRouter returns them despite the float request. const processedEmbeddings = response.data.map((item: EmbeddingItem) => { if (typeof item.embedding === "string") { const buffer = Buffer.from(item.embedding, "base64") @@ -292,7 +306,7 @@ export class OpenRouterEmbedder implements IEmbedder { const requestParams: any = { input: testTexts, model: modelToUse, - encoding_format: "base64", + encoding_format: "float", } if (this.dimensions !== undefined) { @@ -315,6 +329,18 @@ export class OpenRouterEmbedder implements IEmbedder { // Check if we got a valid response if (!response?.data || response.data.length === 0) { + const err = response?.error + const msg = typeof err === "string" ? err : err?.message + const code = typeof err === "object" && err ? err.code : undefined + log.warn("OpenRouter embedder validation returned invalid response", { + location: "OpenRouterEmbedder:validateConfiguration", + model: modelToUse, + dimensions: this.dimensions, + provider: this.specificProvider, + dataCount: response?.data?.length ?? 0, + code, + err: msg, + }) return { valid: false, error: "Invalid response from OpenRouter embedding endpoint", diff --git a/packages/kilo-indexing/src/indexing/embedding-profile.ts b/packages/kilo-indexing/src/indexing/embedding-profile.ts index 843288e80a9..9d37d8eacb2 100644 --- a/packages/kilo-indexing/src/indexing/embedding-profile.ts +++ b/packages/kilo-indexing/src/indexing/embedding-profile.ts @@ -20,7 +20,7 @@ export function resolveEmbeddingProfile( modelDimension?: number, ): EmbeddingProfile | undefined { const id = modelId ?? getDefaultModelId(provider) - const dim = getModelDimension(provider, id) ?? parseDimension(modelDimension) + const dim = parseDimension(modelDimension) ?? getModelDimension(provider, id) if (!dim) return undefined return { provider, diff --git a/packages/kilo-indexing/src/indexing/model-registry.ts b/packages/kilo-indexing/src/indexing/model-registry.ts index 12a427d210b..d02b488cbe1 100644 --- a/packages/kilo-indexing/src/indexing/model-registry.ts +++ b/packages/kilo-indexing/src/indexing/model-registry.ts @@ -48,6 +48,7 @@ const profiles: Record> = { openrouter: { "openai/text-embedding-3-small": { dimension: 1536, scoreThreshold: 0.4 }, "openai/text-embedding-3-large": { dimension: 3072, scoreThreshold: 0.4 }, + "google/gemini-embedding-2-preview": { dimension: 3072, scoreThreshold: 0.35 }, }, "openai-compatible": {}, "vercel-ai-gateway": { diff --git a/packages/kilo-indexing/src/tree-sitter/languageParser.ts b/packages/kilo-indexing/src/tree-sitter/languageParser.ts index e7ba0c3f388..dce528004b1 100644 --- a/packages/kilo-indexing/src/tree-sitter/languageParser.ts +++ b/packages/kilo-indexing/src/tree-sitter/languageParser.ts @@ -41,7 +41,7 @@ export interface LanguageParser { } } -function resolveModulePath(specifier: string): string | undefined { +export function resolveModulePath(specifier: string): string | undefined { try { return require.resolve(specifier) } catch { @@ -53,7 +53,7 @@ function uniquePaths(paths: Array): string[] { return [...new Set(paths.filter((item): item is string => !!item))] } -function wasmDirectories(sourceDirectory?: string): string[] { +export function wasmDirectories(sourceDirectory?: string): string[] { const baseDir = sourceDirectory || __dirname const execDir = path.dirname(process.execPath) const envDir = process.env.KILO_TREE_SITTER_WASM_DIR @@ -80,7 +80,7 @@ function resolveFromDirectories(file: string, dirs: string[]): string | undefine } } -function resolveCoreRuntimeWasmPath(sourceDirectory?: string): string | undefined { +export function resolveCoreRuntimeWasmPath(sourceDirectory?: string): string | undefined { const dirs = wasmDirectories(sourceDirectory) const localPath = resolveFromDirectories("tree-sitter.wasm", dirs) if (localPath) { @@ -89,7 +89,7 @@ function resolveCoreRuntimeWasmPath(sourceDirectory?: string): string | undefine return resolveModulePath("web-tree-sitter/tree-sitter.wasm") } -function resolveLanguageWasmPath(langName: string, sourceDirectory?: string) { +export function resolveLanguageWasmPath(langName: string, sourceDirectory?: string) { const dirs = wasmDirectories(sourceDirectory) const fileName = `tree-sitter-${langName}.wasm` const wasmPath = resolveFromDirectories(fileName, dirs) diff --git a/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts b/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts index cc56020ab7f..4ba3338df49 100644 --- a/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts +++ b/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts @@ -83,6 +83,20 @@ describe("CodeIndexConfigManager", () => { expect(cfg.currentModelDimension).toBe(2048) }) + test("uses configured dimension before static model metadata", () => { + const cfg = new CodeIndexConfigManager( + createInput({ + embedderProvider: "openrouter", + openAiKey: undefined, + openRouterApiKey: "or-test", + modelId: "google/gemini-embedding-2-preview", + modelDimension: 1536, + }), + ) + + expect(cfg.currentModelDimension).toBe(1536) + }) + describe("loadConfiguration restart checks", () => { test("requires restart when model changes with same dimension", () => { const cfg = new CodeIndexConfigManager(createInput({ modelId: "text-embedding-3-small" })) diff --git a/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts b/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts index 729e5c77875..098dd007508 100644 --- a/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts +++ b/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts @@ -68,14 +68,10 @@ describe("OpenRouterEmbedder", () => { }) test("should create embeddings successfully", async () => { - // Create base64 encoded embedding with values that can be exactly represented in Float32 - const testEmbedding = new Float32Array([0.25, 0.5, 0.75]) - const base64String = Buffer.from(testEmbedding.buffer).toString("base64") - const mockResponse = { data: [ { - embedding: base64String, + embedding: [0.25, 0.5, 0.75], }, ], usage: { @@ -91,7 +87,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test text"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", }) expect(result.embeddings).toHaveLength(1) expect(result.embeddings[0]).toEqual([0.25, 0.5, 0.75]) @@ -99,6 +95,20 @@ describe("OpenRouterEmbedder", () => { expect(result.usage?.totalTokens).toBe(5) }) + test("should not retry invalid responses without embedding data", async () => { + mockEmbeddingsCreate.mockResolvedValue({ + error: { + code: 404, + message: "No successful provider responses.", + }, + }) + + await expect(embedder.createEmbeddings(["test"])).rejects.toThrow( + "Embedding request failed after 3 attempts with status 404: No successful provider responses.", + ) + expect(mockEmbeddingsCreate).toHaveBeenCalledTimes(1) + }) + test("should handle multiple texts", async () => { const embedding1 = new Float32Array([0.25, 0.5]) const embedding2 = new Float32Array([0.75, 1.0]) @@ -156,7 +166,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: customModel, - encoding_format: "base64", + encoding_format: "float", }) }) @@ -187,7 +197,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", provider: { order: [specificProvider], only: [specificProvider], @@ -221,7 +231,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", dimensions: 1024, }) }) @@ -257,7 +267,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", }) }) }) @@ -271,13 +281,10 @@ describe("OpenRouterEmbedder", () => { }) test("should validate configuration successfully", async () => { - const testEmbedding = new Float32Array([0.25, 0.5]) - const base64String = Buffer.from(testEmbedding.buffer).toString("base64") - const mockResponse = { data: [ { - embedding: base64String, + embedding: [0.25, 0.5], }, ], usage: { @@ -296,7 +303,7 @@ describe("OpenRouterEmbedder", () => { { input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", }, { timeout: REMOTE_EMBEDDER_VALIDATION_TIMEOUT_MS, @@ -305,6 +312,20 @@ describe("OpenRouterEmbedder", () => { ) }) + test("should reject responses without embedding data", async () => { + mockEmbeddingsCreate.mockResolvedValue({ + error: { + code: 404, + message: "No successful provider responses.", + }, + }) + + const result = await embedder.validateConfiguration() + + expect(result.valid).toBe(false) + expect(result.error).toBe("Invalid response from OpenRouter embedding endpoint") + }) + test("should handle validation failure", async () => { const authError = new Error("Invalid API key") ;(authError as any).status = 401 @@ -346,7 +367,7 @@ describe("OpenRouterEmbedder", () => { { input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", provider: { order: [specificProvider], only: [specificProvider], @@ -388,7 +409,7 @@ describe("OpenRouterEmbedder", () => { { input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", dimensions: 1024, }, { diff --git a/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts b/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts index 67aff168c98..86d50ccc4a1 100644 --- a/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts +++ b/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts @@ -149,11 +149,42 @@ describe("CodeIndexServiceFactory", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["hello"], model: "openai/text-embedding-3-small", - encoding_format: "base64", + encoding_format: "float", dimensions: 1024, }) }) + test("creates vector store for OpenRouter Gemini embedding preview", () => { + const factory = createFactory({ + embedderProvider: "openrouter", + openAiKey: undefined, + openRouterApiKey: "or-test", + modelId: "google/gemini-embedding-2-preview", + vectorStoreProvider: "lancedb", + }) + + const store = factory.createVectorStore() as unknown as { vectorSize: number } + + expect(store).toBeDefined() + expect(store.vectorSize).toBe(3072) + }) + + test("uses configured dimension before static model metadata for vector stores", () => { + const factory = createFactory({ + embedderProvider: "openrouter", + openAiKey: undefined, + openRouterApiKey: "or-test", + modelId: "openai/text-embedding-3-small", + modelDimension: 1024, + vectorStoreProvider: "lancedb", + }) + + const store = factory.createVectorStore() as unknown as { vectorSize: number } + + expect(store).toBeDefined() + expect(store.vectorSize).toBe(1024) + }) + test("creates Kilo embedder with Cloud-provided model", async () => { const factory = createFactory({ embedderProvider: "kilo", @@ -177,6 +208,7 @@ describe("CodeIndexServiceFactory", () => { input: ["hello"], model: "mistralai/mistral-embed-2312", encoding_format: "base64", + dimensions: 1024, }) }) }) diff --git a/packages/kilo-indexing/test/kilocode/tree-sitter/wasm-resolution.test.ts b/packages/kilo-indexing/test/kilocode/tree-sitter/wasm-resolution.test.ts new file mode 100644 index 00000000000..d2acef7ffd7 --- /dev/null +++ b/packages/kilo-indexing/test/kilocode/tree-sitter/wasm-resolution.test.ts @@ -0,0 +1,32 @@ +import { afterEach, describe, expect, test } from "bun:test" +import { mkdir, mkdtemp, rm, writeFile } from "fs/promises" +import { join } from "path" +import { tmpdir } from "os" +import { resolveCoreRuntimeWasmPath, resolveLanguageWasmPath } from "../../../src/tree-sitter/languageParser" + +const env = "KILO_TREE_SITTER_WASM_DIR" +const prev = process.env[env] + +describe("tree-sitter WASM resolution", () => { + afterEach(() => { + if (prev === undefined) delete process.env[env] + if (prev !== undefined) process.env[env] = prev + }) + + test("prefers installed CLI tree-sitter resources over module resolution", async () => { + const root = await mkdtemp(join(tmpdir(), "kilo-tree-sitter-wasm-")) + try { + const dir = join(root, "bin", "tree-sitter") + await mkdir(dir, { recursive: true }) + await writeFile(join(dir, "tree-sitter.wasm"), "runtime") + await writeFile(join(dir, "tree-sitter-typescript.wasm"), "language") + + process.env[env] = dir + + expect(resolveCoreRuntimeWasmPath()).toBe(join(dir, "tree-sitter.wasm")) + expect(resolveLanguageWasmPath("typescript").wasmPath).toBe(join(dir, "tree-sitter-typescript.wasm")) + } finally { + await rm(root, { recursive: true, force: true }) + } + }) +}) diff --git a/packages/kilo-jetbrains/.kilo/skills/jetbrains-ui-style/SKILL.md b/packages/kilo-jetbrains/.kilo/skills/jetbrains-ui-style/SKILL.md deleted file mode 100644 index 81667fea96d..00000000000 --- a/packages/kilo-jetbrains/.kilo/skills/jetbrains-ui-style/SKILL.md +++ /dev/null @@ -1,1335 +0,0 @@ ---- -name: jetbrains-ui-style -description: Use when creating, modifying, or reviewing Kotlin/Swing UI code for the Kilo JetBrains plugin. Applies to dialogs, settings pages, tool windows, forms, panels, component layout, sizing, spacing, colors, borders, icons, lists, trees, popups, notifications, and IntelliJ platform UI components. ---- - -# JetBrains UI Style - -Use this skill whenever creating, modifying, or reviewing UI code in `packages/kilo-jetbrains`. - -## Scope - -This skill covers Kotlin/Swing UI code for the Kilo JetBrains plugin, including dialogs, settings pages, tool windows, forms, panels, component layout, sizing, spacing, colors, borders, icons, lists, trees, popups, notifications, and IntelliJ Platform UI components. - -This plugin is a split-mode JetBrains plugin. UI code belongs in `frontend` unless there is a specific split-mode reason to place it elsewhere. - -## IntelliJ Platform Source Lookup - -When looking for IntelliJ Platform API usage, implementation examples, extension points, services, actions, inspections, PSI/VFS/editor behavior, or plugin patterns, prefer real IntelliJ source code over Gradle caches, downloaded jars, generated parser artifacts, or decompiled classes. - -Use this priority order: - -1. Check whether `$INTELLIJ_REPO` is set and points to a readable IntelliJ Community checkout. - - If `$INTELLIJ_REPO` is set, search source files under that directory first. - - Prefer implementation source files from directories such as `platform/`, `plugins/`, `java/`, `xml/`, `json/`, `jvm/`, and related modules. - - Do not assume the IntelliJ checkout is a sibling of the current repo or worktree. -2. If `$INTELLIJ_REPO` is unset, empty, unreadable, or does not appear to contain an IntelliJ source checkout, tell the user to set it up. - - Suggested instruction: `Set INTELLIJ_REPO to the path of a local intellij-community checkout, for example: export INTELLIJ_REPO=/path/to/intellij-community` - - Do not invent or hardcode a machine-specific absolute path. -3. If a local checkout is unavailable, use the public IntelliJ Community repository as the fallback source: - - https://github.com/JetBrains/intellij-community -4. Only inspect Gradle caches, downloaded jars, generated parser jars, decompiled classes, or dependency internals as a last resort when neither a local IntelliJ source checkout nor the public GitHub repository provides the needed information. - -Avoid starting searches in: - -- `~/.gradle/caches` -- `.gradle/` -- downloaded dependency jars -- generated parser artifacts -- decompiled library sources - -## Primary Rules - -- Prefer Kotlin UI DSL v2 whenever the UI is a dialog, settings page, form, options panel, or structured component layout. -- Use manual Swing only for custom rendering, transcript/chat surfaces, highly dynamic panels, virtualized lists, custom painting, or layouts the DSL cannot express cleanly. -- Keep generated UI code minimal. -- Do not set default Swing properties explicitly. For example, avoid `isOpaque = false` unless the component default differs or there is a documented rendering reason. -- Avoid hardcoded dimensions. Prefer layout semantics, component defaults, DSL sizing helpers, and `JBUI` utilities. -- Do not add decorative helper functions, wrappers, or defensive UI code unless they materially improve clarity or correctness. -- Prefer IntelliJ platform components and theme-aware APIs. -- Do not use hardcoded runtime colors in generated UI examples or implementation code. -- Derive UI colors from semantic IntelliJ theme APIs such as `UIUtil`, `JBUI.CurrentTheme`, `NamedColorUtil`, `JBColor.namedColor`, or `JBColor.lazy`. -- Do not use hardcoded font sizes or font families in generated UI examples or implementation code. -- Use component defaults, `JBFont`, `RelativeFont`, or existing component fonts for typography. -- Put user-visible strings in `*.properties` files. - -## Decision Tree - -- Use Kotlin UI DSL v2 for dialogs, settings pages, forms, options panels, and structured component layouts. -- Use Kotlin UI DSL v2 inside tool windows when rendering form-like controls or structured subpanels. -- Use standard Swing with IntelliJ Platform component replacements for tool-window shells, action-driven UI, custom components, transcript surfaces, and custom renderers. -- Use the Action System for menus and toolbars. -- Do not use Kotlin Compose. -- Do not use JCEF. - -| Need | API | -|---|---| -| Dialogs, settings pages, forms, any layout with components | Preferred: Kotlin UI DSL v2 (`com.intellij.ui.dsl.builder`) | -| Tool window panels, action-driven UI, custom components | Standard Swing with IntelliJ Platform component replacements | -| Menus and toolbars | Action System | - -## Minimal Code Rule - -Avoid explicit defaults and manual layout when the DSL can express the UI: - -```kotlin -// Avoid -val panel = JPanel(BorderLayout()).apply { - isOpaque = false - preferredSize = Dimension(420, 260) - border = EmptyBorder(12, 12, 12, 12) -} -``` - -Prefer DSL and platform spacing: - -```kotlin -panel { - row(KiloBundle.message("settings.name")) { - textField() - .align(AlignX.FILL) - .resizableColumn() - } -} -``` - -Avoid explicit default properties: - -```kotlin -// Avoid unless there is a documented rendering reason -component.isOpaque = false -``` - -Prefer omitting the assignment and relying on the component/platform default. - -Avoid raw fixed sizes: - -```kotlin -// Avoid -component.preferredSize = Dimension(300, 40) -``` - -Prefer semantic sizing: - -```kotlin -textField() - .columns(COLUMNS_MEDIUM) - .align(AlignX.FILL) -``` - -If a fixed size is genuinely required, use `JBUI.size(...)` or `JBUI.scale(...)` and keep the reason obvious from context. - -## Do Not Use Kotlin Compose - -Do not use Kotlin Compose or `intellij.platform.compose` in this plugin. The JetBrains modular template uses Compose for its demo tool window, but Kilo should use standard Swing with IntelliJ Platform components only. Keep all plugin UI in the existing Swing-based stack. - -## Do Not Use JCEF - -Do not use JCEF (`JBCefBrowser`) in this plugin. JCEF does not work in JetBrains remote development (split mode): the frontend process runs on the client machine but JCEF requires a display on the host, making it effectively unusable for remote users. Use standard Swing with IntelliJ Platform components for all UI. - -## Kotlin UI DSL v2 - -Use Kotlin UI DSL v2 as the default way to build UI for dialogs, settings pages, forms, and any layout composed of standard components. It produces correct spacing, label alignment, HiDPI scaling, and accessibility automatically. Only fall back to manual Swing layout when you need a fully custom component, such as a canvas, rich list renderer, transcript surface, or tool-window chrome that the DSL cannot express. - -The top-level builder is `panel { }` and returns `DialogPanel`. Structure is `panel -> row -> cells`. Cell factory methods such as `textField()`, `checkBox()`, and `label()` add components. The DSL lives in `com.intellij.ui.dsl.builder`. - -To explore DSL capabilities interactively: Tools -> Internal Actions -> UI -> Kotlin UI DSL -> UI DSL Showcase. This requires internal mode: `-Didea.is.internal=true`. - -### Basics: Panel, Row, Cell - -Rows occupy full width. The last cell in a row takes remaining space. Rows have a `layout` property. - -```kotlin -panel { - row("Row1 label:") { - textField() - label("Some text") - } - row("Row2:") { - label("This text is aligned with previous row") - } -} -``` - -### Row Layout - -Every row uses one of three layouts. Default is `LABEL_ALIGNED` when a label is provided for the row, `INDEPENDENT` otherwise. - -| Layout | Behavior | -|---|---| -| `LABEL_ALIGNED` | Label column and content columns, aligned across rows | -| `INDEPENDENT` | All cells are independent, no cross-row alignment | -| `PARENT_GRID` | Cells align with the parent grid columns across rows | - -```kotlin -panel { - row("PARENT_GRID:") { - label("Col 1") - label("Col 2") - }.layout(RowLayout.PARENT_GRID) - - row("PARENT_GRID:") { - textField() - textField() - }.layout(RowLayout.PARENT_GRID) - - row("LABEL_ALIGNED default with label:") { - textField() - } - - row { - label("INDEPENDENT default without label:") - textField() - } -} -``` - -### Components Reference - -All cell factory methods available inside `row { }`: - -| Method | Description | -|---|---| -| `checkBox("text")` | Checkbox | -| `threeStateCheckBox("text")` | Three-state checkbox | -| `radioButton("text", value)` | Radio button, must be inside `buttonsGroup {}` | -| `button("text") {}` | Push button | -| `actionButton(action)` | Icon button bound to an `AnAction` | -| `actionsButton(action1, action2, ...)` | Dropdown actions button | -| `segmentedButton(items) { text = it }` | Segmented control | -| `tabbedPaneHeader(items)` | Tab header strip | -| `label("text")` | Static label | -| `text("html")` | Rich text with links, icons, line-width control | -| `link("text") {}` | Focusable clickable link | -| `browserLink("text", "url")` | Opens URL in browser | -| `dropDownLink("default", listOf(...))` | Dropdown link selector | -| `icon(AllIcons.*)` | Icon display | -| `contextHelp("description", "title")` | Help icon with popup | -| `textField()` | Text input | -| `passwordField()` | Password input | -| `textFieldWithBrowseButton()` | Text field and browse dialog | -| `expandableTextField()` | Expandable multi-line text field | -| `extendableTextField()` | Text field with extension icons | -| `intTextField(range)` | Integer input with validation | -| `spinner(intRange)` / `spinner(doubleRange, step)` | Numeric spinner | -| `slider(min, max, minorTick, majorTick)` | Slider, use `.labelTable()` for tick labels | -| `textArea()` | Multi-line text, use `.rows(n)` and `.align(AlignX.FILL)` | -| `comboBox(items)` | Combo box / dropdown | -| `comment("text")` | Gray comment text, standalone | -| `cell(component)` | Wrap any arbitrary Swing component | -| `scrollCell(component)` | Wrap component in a scroll pane | -| `cell()` | Empty placeholder cell for grid alignment | - -Key component examples: - -```kotlin -panel { - var mode = "auto" - - buttonsGroup { - row("Mode:") { - radioButton("Automatic", "auto") - radioButton("Manual", "manual") - } - }.bind({ mode }, { mode = it }) - - row("Slider:") { - slider(0, 10, 1, 5) - .labelTable(mapOf( - 0 to JBLabel("0"), - 5 to JBLabel("5"), - 10 to JBLabel("10"), - )) - } - - row { - label("Text area:") - .align(AlignY.TOP) - .gap(RightGap.SMALL) - textArea() - .rows(5) - .align(AlignX.FILL) - }.layout(RowLayout.PARENT_GRID) -} -``` - -### Component Labels - -Labels for modifiable components must be connected via one of two methods. This ensures correct spacing, mnemonic support, and accessibility. - -- Row label: `row("&Label:") { textField() }`, mnemonic via `&`, label in left column -- Cell label: `textField().label("&Label:", LabelPosition.TOP)`, label attached to cell, optionally on top - -```kotlin -panel { - row("&Row label:") { - textField() - textField() - .label("Cell label at &left:") - } - row { - textField() - .label("Cell label at &top:", LabelPosition.TOP) - } -} -``` - -When a row contains a `checkBox` or `radioButton`, the DSL automatically increases space after the row label per IntelliJ UI Guidelines. - -### Comments - -Three types of comments, each with different placement and semantics: - -| Type | Method | Placement | -|---|---|---| -| Cell comment, bottom | `cell.comment("text")` | Below the cell | -| Cell comment, right | `cell.commentRight("text")` | Right of the cell | -| Cell context help | `cell.contextHelp("text", "title")` | Help icon with popup | -| Row comment | `row.rowComment("text")` | Below the entire row | -| Arbitrary comment | `comment("text")` | Standalone gray text | - -```kotlin -panel { - row { - textField() - .comment("Bottom comment") - textField() - .commentRight("Right comment") - textField() - .contextHelp("Help popup text") - } - - row("Label:") { - textField() - }.rowComment("This comment sits below the whole row") - - row { - comment("Standalone comment, supports links and  icons") - } -} -``` - -Comments support HTML with clickable links, bundled icons via ``, and line width control via `maxLineLength`. Use `MAX_LINE_LENGTH_NO_WRAP` to prevent wrapping. - -### Groups and Structure - -| Method | Grid | Description | -|---|---|---| -| `panel {}` | Own grid | Sub-panel occupying full width | -| `rowsRange {}` | Parent grid | Grouped rows sharing parent grid, useful with `enabledIf` | -| `group("Title") {}` | Own grid | Titled section with vertical spacing before/after | -| `groupRowsRange("Title") {}` | Parent grid | Titled section sharing parent grid alignment | -| `collapsibleGroup("Title") {}` | Own grid | Expandable section, Tab-focusable, supports mnemonics | -| `buttonsGroup("Title") {}` | None | Groups `radioButton` or `checkBox` under a title | -| `separator()` | None | Horizontal separator line | -| Row `panel {}` | Own grid | Sub-panel inside a cell | - -```kotlin -panel { - group("Settings") { - row("Name:") { textField() } - row("Path:") { textFieldWithBrowseButton() } - } - - collapsibleGroup("Advanced") { - row("Timeout:") { intTextField(0..1000) } - } - - var enabled = true - buttonsGroup("Mode:") { - row { radioButton("Automatic", true) } - row { radioButton("Manual", false) } - }.bind({ enabled }, { enabled = it }) - - separator() - - row { - label("Nested panels:") - panel { - row("Sub row 1:") { textField() } - row("Sub row 2:") { textField() } - } - } -} -``` - -### Gaps and Spacing - -- Horizontal gaps: `cell.gap(RightGap.SMALL)` between a label-like checkbox and its related field. Medium gap is the default between cells. -- Two-column layout: `twoColumnsRow({}, {})` or `gap(RightGap.COLUMNS)` with `.layout(RowLayout.PARENT_GRID)`. -- Left indent: `indent {}` for indented sub-content. -- Vertical gaps: `.topGap(TopGap.MEDIUM)` / `.bottomGap(BottomGap.MEDIUM)` on rows to separate unrelated groups. Attach gaps to the related row so hiding rows does not break layout. - -Common Kotlin UI DSL spacing values from `IntelliJSpacingConfiguration`: - -| Constant | Unscaled px | Usage | -|---|---|---| -| `RightGap.SMALL` | 6 | Related inline components, such as field to button | -| Default row/cell gap | 16 | Automatic gap between components in a row | -| `RightGap.COLUMNS` | 60 | Logical column separation | -| `TopGap.SMALL` / `BottomGap.SMALL` | 8 | Minor section separation | -| `TopGap.MEDIUM` / `BottomGap.MEDIUM` | 20 | Major section or group separation | -| `verticalComponentGap` | 6 | Automatic gap between rows | - -These are semantic IntelliJ spacing constants. They handle DPI scaling and the IntelliJ spacing model, but they are not theme keys and are not overridden by theme JSON. - -```kotlin -panel { - group("Horizontal Gaps") { - row { - val cb = checkBox("Use mail:") - .gap(RightGap.SMALL) - textField() - .enabledIf(cb.selected) - } - row("Width:") { - textField() - .gap(RightGap.SMALL) - label("pixels") - } - } - - group("Indent") { - row { label("Not indented") } - indent { - row { label("Indented row") } - } - } - - group("Two Columns") { - twoColumnsRow({ - checkBox("First column") - }, { - checkBox("Second column") - }) - } - - group("Vertical Gaps") { - row { checkBox("Option 1") } - row { checkBox("Option 2") } - row { checkBox("Unrelated option") } - .topGap(TopGap.MEDIUM) - } -} -``` - -### Enabled and Visible State - -Bind enabled/visible state to a checkbox or other observable. Works on rows, `indent {}` blocks, `rowsRange {}`, and individual cells. - -```kotlin -panel { - group("Enabled") { - lateinit var cb: Cell - row { cb = checkBox("Enable options") } - indent { - row { checkBox("Option 1") } - row { checkBox("Option 2") } - }.enabledIf(cb.selected) - } - - group("Visible") { - lateinit var cb: Cell - row { cb = checkBox("Show options") } - indent { - row { checkBox("Option 1") } - row { checkBox("Option 2") } - }.visibleIf(cb.selected) - } -} -``` - -### Binding - -Bind component values to model properties. Values are applied on `DialogPanel.apply()`, checked with `.isModified()`, and reverted with `.reset()`. - -| Method | Component | -|---|---| -| `bindSelected(model::prop)` | checkBox | -| `bindText(model::prop)` | textField | -| `bindIntText(model::prop)` | intTextField | -| `bindItem(model::prop.toNullableProperty())` | comboBox | -| `bindValue(model::prop)` | slider | -| `bindIntValue(model::prop)` | spinner | -| `buttonsGroup {}.bind(model::prop)` | radio group | - -```kotlin -enum class Theme { LIGHT, DARK } - -data class Settings( - var name: String = "", - var count: Int = 0, - var enabled: Boolean = false, - var theme: Theme = Theme.LIGHT, -) - -val model = Settings() - -val panel = panel { - row("Name:") { - textField().bindText(model::name) - } - row("Count:") { - intTextField(0..100).bindIntText(model::count) - } - row { - checkBox("Enabled").bindSelected(model::enabled) - } - buttonsGroup("Theme:") { - row { radioButton("Light", Theme.LIGHT) } - row { radioButton("Dark", Theme.DARK) } - }.bind(model::theme) -} - -panel.isModified() -panel.apply() -panel.reset() -``` - -### Validation - -Attach input validation rules to cells. Rules run continuously and display inline error/warning indicators. - -```kotlin -panel { - row("Username:") { - textField() - .columns(COLUMNS_MEDIUM) - .cellValidation { - addInputRule("Must not be empty") { - it.text.isBlank() - } - } - } - row("Port:") { - textField() - .columns(COLUMNS_MEDIUM) - .cellValidation { - addInputRule("Contains non-numeric characters", level = Level.WARNING) { - it.text.contains(Regex("[^0-9]")) - } - } - } -} -``` - -Activate validators by calling `dialogPanel.registerValidators(disposable)` after creating the panel. - -### Tips and Common Patterns - -| Pattern | Usage | -|---|---| -| `.bold()` | Bold text on any cell | -| `.columns(COLUMNS_MEDIUM)` | Set preferred width of textField / comboBox / textArea | -| `.text("initial")` | Set initial text on text components | -| `.resizableColumn()` | Column fills remaining horizontal space | -| `cell()` | Empty placeholder cell for grid alignment | -| `.widthGroup("name")` | Equalize widths across rows, cannot combine with `AlignX.FILL` | -| `.align(AlignX.FILL)` | Stretch component to fill available width | -| `.align(AlignY.TOP)` | Top-align component in its cell | -| `.applyToComponent { }` | Direct access to the underlying Swing component | -| `.selected(true)` | Default-select a radioButton when no bound value matches | -| `.gap(RightGap.COLUMNS)` | Column-level gap for multi-column layouts | - -```kotlin -panel { - row { label("Title").bold() } - - row("Name:") { - textField() - .columns(COLUMNS_MEDIUM) - .resizableColumn() - .align(AlignX.FILL) - } - - row("") { - textField() - }.rowComment("""Use row("") for an empty label column that aligns with labeled rows""") - - row { - text("Comment-colored text") - .applyToComponent { foreground = JBUI.CurrentTheme.ContextHelp.FOREGROUND } - } -} -``` - -## Manual Swing - -Use manual Swing only when Kotlin UI DSL cannot express the UI cleanly. - -Preferred manual Swing rules: - -- Use IntelliJ platform components instead of raw Swing components. -- Use layout managers and component defaults rather than fixed sizes. -- Use `JBUI.Borders.empty(...)`, `JBUI.insets(...)`, `JBUI.size(...)`, and `JBUI.scale(...)` instead of raw AWT/Swing sizing primitives. -- Do not set default properties explicitly. -- Keep custom components small and focused. -- For painting, use theme-aware colors and `JBUI.scale(...)` for pixel values. - -## Swing Component State - -Swing is retained-mode UI, not React-style declarative rendering. For dynamic Swing surfaces such as session cards, transcript parts, hover rows, and collapsible panels, build a stable component tree once and then mutate existing components in response to model or interaction changes. - -- Do not use a React-style `state -> render()` loop for Swing components. -- Avoid card-level `render()` methods that remove/recreate headers, text areas, markdown views, controls, or scroll panes after every click, hover, or model update. -- Give each renderer an `update(model)` method that applies model changes directly to existing UI components. -- In `update(model)`, compare before assigning when practical: label text, icons, foregrounds, fonts, body text, visibility, cursor, and containment. -- Do not duplicate state in booleans when Swing component state already answers the question. -- Derive expanded state from containment, such as `scroll.parent === root`, rather than maintaining an `open` boolean. -- Derive hover state from the current header background or other component property, rather than maintaining a `hover` boolean. -- Expand/collapse should attach or detach the existing body component and update controls only if attachment changed. -- Hover should update only the affected component, usually the header background, and repaint only that component when the effective color changed. -- Lazy-create expensive bodies such as `JBTextArea`, `JBScrollPane`, markdown panes, and HTML panes on first expansion or first direct access. -- Keep source/model text separately only when needed to initialize a lazy component before it exists. -- Store the current style snapshot so lazily-created children receive the latest `SessionStyle` when they are first created. -- Parent containers should refresh for add/remove/reorder operations, not automatically after every delegated child update or streaming delta. -- Child views should call `revalidate()`/`repaint()` only when they changed preferred size, visibility, containment, or paint output. -- Empty deltas, identical text, unchanged styles, repeated hover values, and no-op toggles should not repaint the whole card. -- Private helpers named `render()` in Swing views tend to invite full tree rebuilds. Prefer names that describe the mutation, such as `syncBody()`, `syncArrow()`, `syncHtml()`, or `applyModel()`. -- It is fine for markdown internals to call library APIs such as `renderer.render(...)`; the problem is UI-level rerendering that rebuilds Swing component trees. - -Avoid this React-style pattern: - -```kotlin -private var open = false - -fun toggle() { - open = !open - render() -} - -private fun render() { - root.removeAll() - header.removeAll() - header.add(title) - if (open) root.add(JBScrollPane(JBTextArea(text)), BorderLayout.CENTER) - revalidate() - repaint() -} -``` - -Prefer mutating stable Swing components and deriving state from the UI: - -```kotlin -fun isExpanded(): Boolean = scroll?.parent === root - -fun toggle() { - if (!canExpand()) return - val changed = if (isExpanded()) collapse() else expand() - if (!changed) return - syncArrow() - revalidate() - repaint() -} - -private fun expand(): Boolean { - if (isExpanded()) return false - root.add(scroll(), BorderLayout.CENTER) - return true -} - -private fun collapse(): Boolean { - val pane = scroll ?: return false - if (pane.parent !== root) return false - root.remove(pane) - return true -} - -private fun scroll(): JBScrollPane { - scroll?.let { return it } - val pane = JBScrollPane(body()) - scroll = pane - return pane -} -``` - -For tests around dynamic Swing components, assert retained component behavior instead of only final text: - -- Collapsed components start unattached, and expensive bodies are not created until first expansion. -- First expansion creates the body once, collapse detaches it, and re-expansion reuses the same instance. -- `isExpanded()` agrees with actual containment. -- `update(model)` changes existing labels/body text without duplicating components. -- Updates while collapsed do not eagerly create lazy bodies unless direct body access requires it. -- No-op updates, empty deltas, repeated hover values, and toggling non-expandable cards do not repaint/revalidate the whole view. - -## Platform Spacing and Insets - -Use semantic spacing APIs before inventing numbers. Do not copy fallback values from IntelliJ source into generated UI code; those values are defaults behind theme keys and may change by UI theme, New UI, OS, or IDE version. - -| Need | Preferred source | -|---|---| -| Dialogs, forms, settings | Kotlin UI DSL row/group/indent/gap APIs | -| Component gaps in Kotlin UI DSL | `RightGap.SMALL`, `RightGap.COLUMNS`, `TopGap.MEDIUM`, `BottomGap.MEDIUM`, `.customize(UnscaledGaps(...))` as a last resort | -| Manual Swing empty padding | `JBUI.Borders.empty(...)` | -| Manual Swing insets | `JBUI.insets(...)`, `JBUI.emptyInsets()`, `JBUI.insetsTop(...)`, `JBUI.insetsLeft(...)`, `JBUI.insetsBottom(...)`, `JBUI.insetsRight(...)` | -| Manual Swing dimensions | `JBUI.size(...)`, `JBDimension`, `JBUI.scale(...)` | -| Side separators | `JBUI.Borders.customLineTop(...)`, `customLineBottom(...)`, `customLineLeft(...)`, `customLineRight(...)` | -| Composed borders | `JBUI.Borders.compound(...)`, `JBUI.Borders.merge(...)` | -| Simple `BorderLayout` panels | `JBUI.Panels.simplePanel(...)`, `BorderLayoutPanel` | -| Simple vertical custom Swing groups | `VerticalLayout` | -| Fluent platform panels | `JBPanel.withBorder(...)`, `.andTransparent()`, `.andOpaque()`, `.withBackground(...)` | - -For themeable custom layouts, keep the `JBValue.UIInteger` object and call `.get()` during layout and size calculation. Do not cache the resolved `Int`, because that freezes the value from the current Look and Feel and scale context. - -```kotlin -private val gap = JBValue.UIInteger("KiloComponent.gap", 16) - -override fun doLayout() { - val value = gap.get() - // layout using value -} - -override fun getPreferredSize(): Dimension { - val value = gap.get() - // calculate using value -} -``` - -Avoid resolving the value once in a constructor or property initializer: - -```kotlin -private val gap = JBValue.UIInteger("KiloComponent.gap", 16).get() -``` - -When raw AWT layout constructors are unavoidable, legacy Swing defaults exist but must still be scaled before use: - -| Constant | Value | -|---|---| -| `UIUtil.DEFAULT_HGAP` | 10 | -| `UIUtil.DEFAULT_VGAP` | 4 | -| `UIUtil.LARGE_VGAP` | 12 | - -```kotlin -val panel = JPanel(BorderLayout(JBUI.scale(UIUtil.DEFAULT_HGAP), 0)) -``` - -Use `JBUI.CurrentTheme` for context-specific spacing and dimensions: - -| UI area | Preferred source | -|---|---| -| Action list rows | `JBUI.CurrentTheme.ActionsList.cellPadding()` | -| Action icon/text gaps | `JBUI.CurrentTheme.ActionsList.elementIconGap()` | -| Action mnemonic gaps | `JBUI.CurrentTheme.ActionsList.mnemonicIconGap()` / `mnemonicInsets()` | -| Popup selection interior | `JBUI.CurrentTheme.Popup.Selection.innerInsets()` | -| Popup separators | `JBUI.CurrentTheme.Popup.separatorInsets()` / `separatorLabelInsets()` | -| Popup header/search field | `JBUI.CurrentTheme.Popup.headerInsets()`, `searchFieldBorderInsets()`, `searchFieldInputInsets()` | -| Complex popup headers | `JBUI.CurrentTheme.ComplexPopup.headerInsets()` | -| Complex popup text fields | `JBUI.CurrentTheme.ComplexPopup.textFieldBorderInsets()` / `textFieldInputInsets()` | -| Search Everywhere / big popup header | `JBUI.CurrentTheme.BigPopup.headerBorder()` / `headerToolbarInsets()` / `tabInsets()` | -| Popup advertiser/footer | `JBUI.CurrentTheme.Advertiser.border()` | -| Toolbar buttons | `JBUI.CurrentTheme.Toolbar.toolbarButtonInsets()` / `mainToolbarButtonInsets()` | -| Toolbar containers | `JBUI.CurrentTheme.Toolbar.horizontalToolbarInsets()` / `verticalToolbarInsets()` | -| Tool-window headers | `JBUI.CurrentTheme.ToolWindow.headerLabelLeftRightInsets()` / `headerToolbarLeftRightInsets()` / `headerTabLeftRightInsets()` | -| Lists | `JBUI.CurrentTheme.List.rowHeight()` | -| Trees | `JBUI.CurrentTheme.Tree.rowHeight()` | -| VCS log rows | `JBUI.CurrentTheme.VersionControl.Log.rowHeight()` / `verticalPadding()` | -| Help tooltips | `JBUI.CurrentTheme.HelpTooltip.defaultTextBorderInsets()` / `smallTextBorderInsets()` | -| Navigation bar items | `JBUI.CurrentTheme.NavBar.itemInsets()` | - -When using Kotlin UI DSL, prefer DSL semantics over manual padding: - -```kotlin -panel { - group(KiloBundle.message("settings.section")) { - row(KiloBundle.message("settings.name")) { - textField() - .align(AlignX.FILL) - .resizableColumn() - } - indent { - row { checkBox(KiloBundle.message("settings.enabled")) } - } - } -} -``` - -When manual Swing is necessary, get padding from platform utilities: - -```kotlin -val panel = JBUI.Panels.simplePanel(content) - .withBorder(JBUI.Borders.empty(JBUI.CurrentTheme.Popup.headerInsets())) -``` - -For row heights, prefer platform row height APIs over fixed heights: - -```kotlin -component.preferredSize = JBDimension(0, JBUI.CurrentTheme.Tree.rowHeight()) -``` - -## Generic Platform Utilities - -Use existing platform utility classes instead of hand-rolled labels, renderers, borders, colors, fonts, and validation behavior. - -| Need | Preferred API | -|---|---| -| Concise border layout | `BorderLayoutPanel`, `JBUI.Panels.simplePanel(...)` | -| Platform panel helpers | `JBPanel.withBorder(...)`, `.andTransparent()`, `.andOpaque()` | -| Platform label behavior | `JBLabel` | -| Context help | `ContextHelpLabel` | -| Links | `HyperlinkLabel`, `LinkLabel`, Kotlin UI DSL `link(...)` / `browserLink(...)` | -| Error/validation label in legacy UI | `ErrorLabel` only when an inline validation component is required and DSL validation is not available | -| High-performance rich fragments | `SimpleColoredComponent` | -| List renderers | `ColoredListCellRenderer`, Kotlin `listCellRenderer` / `textListCellRenderer` / `LcrRow` | -| Tree renderers | `ColoredTreeCellRenderer` | -| Renderer text styles | `SimpleTextAttributes` | -| Editable list toolbar | `ToolbarDecorator` | -| Platform list | `JBList` | -| Platform tree | `Tree` | - -For renderer text, prefer `SimpleTextAttributes` over direct color/font mutation: - -```kotlin -append(text, SimpleTextAttributes.ERROR_ATTRIBUTES) -append(detail, SimpleTextAttributes.GRAYED_ATTRIBUTES) -append(link, SimpleTextAttributes.LINK_ATTRIBUTES) -``` - -## Tool Windows - -- Register declaratively in module XML via `com.intellij.toolWindow` extension point. -- Implement `ToolWindowFactory.createToolWindowContent()`, called lazily on first click. -- Use `SimpleToolWindowPanel(vertical = true)` as a convenient base for toolbar and content layout. -- Add tabs via `ToolWindow.contentManager`: create content with `ContentFactory.getInstance().createContent(component, title, isLockable)`, then `contentManager.addContent()`. -- For conditional display, implement `ToolWindowFactory.isApplicableAsync(project)`. -- Always use `ToolWindowManager.invokeLater()` instead of `Application.invokeLater()` for tool-window-related EDT tasks. - -## Dialogs - -- Extend `DialogWrapper`. -- Call `init()` from the constructor. -- Override `createCenterPanel()` to return UI content. -- Prefer Kotlin UI DSL v2 for panel contents. -- Override `getPreferredFocusedComponent()` for initial focus. -- Override `getDimensionServiceKey()` for size persistence when useful. -- Show with `showAndGet()` for modal boolean result, or `show()` and then `getExitCode()`. -- For input validation, call `initValidation()` in the constructor and override `doValidate()` to return `null` if valid or `ValidationInfo(message, component)` if invalid. - -## Platform Components - -Always use IntelliJ platform components instead of raw Swing where an equivalent exists. - -| Instead of | Use | Package | -|---|---|---| -| `JLabel` | `JBLabel` | `com.intellij.ui.components` | -| `JTextField` | `JBTextField` | `com.intellij.ui.components` | -| `JTextArea` | `JBTextArea` | `com.intellij.ui.components` | -| `JList` | `JBList` | `com.intellij.ui.components` | -| `JScrollPane` | `JBScrollPane` | `com.intellij.ui.components` | -| `JTable` | `JBTable` | `com.intellij.ui.table` | -| `JTree` | `Tree` | `com.intellij.ui.treeStructure` | -| `JSplitPane` | `JBSplitter` | `com.intellij.ui` | -| `JTabbedPane` | `JBTabs` | `com.intellij.ui.tabs` | -| `JCheckBox` | `JBCheckBox` | `com.intellij.ui.components` | -| Raw runtime colors | `UIUtil`, `JBUI.CurrentTheme`, `NamedColorUtil`, `JBColor.namedColor`, `JBColor.lazy` | `com.intellij.util.ui`, `com.intellij.ui` | -| `EmptyBorder` | `JBUI.Borders.empty()` | `com.intellij.util.ui` | -| Hardcoded pixel sizes | `JBUI.scale(px)` | `com.intellij.util.ui` | - -Inspection `Plugin DevKit | Code | Undesirable class usage` highlights raw Swing usage where a platform replacement exists. - -## Multi-line and Rich Text - -| Need | Component | -|---|---| -| Rich HTML with modern CSS, icons, shortcuts | `JBHtmlPane` (`com.intellij.ui.components.JBHtmlPane`) | -| Simple multi-line label with HTML | `JBLabel` + `XmlStringUtil.wrapInHtml()` | -| Scrollable / wrapping HTML panel | `SwingHelper.createHtmlViewer()` | -| High-performance colored text fragments in trees/lists/tables | `SimpleColoredComponent` | -| Plain-text newline splitting | `MultiLineLabel`, legacy, do not use in new code | - -- Build HTML programmatically with `HtmlChunk` / `HtmlBuilder` (`com.intellij.openapi.util.text.HtmlChunk`). Avoid raw HTML string concatenation because it risks injection and breaks localization. -- For simple wrapping/escaping, use `XmlStringUtil.wrapInHtml(content)`, `XmlStringUtil.wrapInHtmlLines(lines...)`, and `XmlStringUtil.escapeString(text)`. -- For selectable/copyable label text, use `JBLabel.setCopyable(true)`, which switches internally to `JEditorPane` while preserving label appearance. Use `setAllowAutoWrapping(true)` for auto-wrap. -- When creating a `JEditorPane` manually, always use `HTMLEditorKitBuilder` instead of constructing `HTMLEditorKit` directly: `editorPane.setEditorKit(HTMLEditorKitBuilder.simple())` or `.withWordWrapViewFactory().build()`. -- For single-line overflow/ellipsis, use `SwingTextTrimmer`. Do not manually truncate strings. -- Put all user-visible strings in `*.properties` files. HTML markup in values is acceptable. - -## Theme-Derived Colors - -Do not hardcode runtime colors. IntelliJ UI colors must come from the current theme, component state, editor color scheme, or a centralized semantic named color key. - -Prefer semantic helpers for common UI roles: - -| Need | Preferred API | -|---|---| -| Ordinary label text | `UIUtil.getLabelForeground()` | -| Secondary/help text | `UIUtil.getContextHelpForeground()` | -| Info label text | `UIUtil.getLabelInfoForeground()` | -| Success label text | `UIUtil.getLabelSuccessForeground()` | -| Error label text | `UIUtil.getErrorForeground()` | -| Warning label text | `JBUI.CurrentTheme.Label.warningForeground()` | -| Generic label foreground by state | `JBUI.CurrentTheme.Label.foreground(selected)` / `disabledForeground(selected)` | -| Inactive secondary text | `NamedColorUtil.getInactiveTextColor()` | -| Bounds and standard border color | `NamedColorUtil.getBoundsColor()` / `JBColor.border()` | -| Tooltips | `UIUtil.getToolTipForeground()` / `getToolTipBackground()` / `JBUI.CurrentTheme.Tooltip.*` | -| Links | `JBUI.CurrentTheme.Link.Foreground.ENABLED` / `HOVERED` / `PRESSED` / `VISITED` / `DISABLED` / `SECONDARY` | -| List renderer text/background | `UIUtil.getListForeground(selected, focused)` / `UIUtil.getListBackground(selected, focused)` | -| Tree renderer text/background | `UIUtil.getTreeForeground(selected, focused)` / `UIUtil.getTreeBackground(selected, focused)` | -| Non-selected tree content | `UIUtil.getTreeForeground()` / `UIUtil.getTreeBackground()` | - -Prefer `JBUI.CurrentTheme` for component-area colors and borders: - -| Need | Preferred API | -|---|---| -| Popup background | `JBUI.CurrentTheme.Popup.BACKGROUND` | -| Complex popup header | `JBUI.CurrentTheme.ComplexPopup.HEADER_BACKGROUND` | -| Separators | `JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground()` | -| Advertiser/footer surfaces | `JBUI.CurrentTheme.Advertiser.foreground()` / `background()` / `border()` | -| Links | `JBUI.CurrentTheme.Link.Foreground.ENABLED` | -| Tree selection state | `JBUI.CurrentTheme.Tree.foreground(...)` and selection helpers | -| Validation errors | `JBUI.CurrentTheme.Validator.errorBorderColor()` / `errorBackgroundColor()` | -| Validation warnings | `JBUI.CurrentTheme.Validator.warningBorderColor()` / `warningBackgroundColor()` | -| Focus error/warning outlines | `JBUI.CurrentTheme.Focus.errorColor(active)` / `warningColor(active)` | -| Banner-like surfaces | `JBUI.CurrentTheme.Banner.*` | -| Notification tool-window surfaces | `JBUI.CurrentTheme.NotificationError.*`, `NotificationWarning.*`, `NotificationInfo.*` | -| Icon badges | `JBUI.CurrentTheme.IconBadge.*` | - -Use `JBColor.lazy { ... }` for colors that depend on runtime state or the active editor color scheme: - -```kotlin -val bg = JBColor.lazy { EditorColorsManager.getInstance().globalScheme.defaultBackground } -``` - -Use `JBColor.namedColor("Some.Semantic.Key", fallback)` only when defining or consuming a semantic color key. Prefer a fallback from an existing theme API over numeric RGB values in examples. - -For HTML/CSS snippets, compute the color from a theme API and convert it with `ColorUtil.toHtmlColor(...)`. Do not write hardcoded CSS color literals. - -```kotlin -val fg = ColorUtil.toHtmlColor(UIUtil.getContextHelpForeground()) -val html = HtmlChunk.span("color: $fg").addText(text) -``` - -Recommended examples: - -```kotlin -label.applyToComponent { - foreground = UIUtil.getContextHelpForeground() - font = JBFont.medium() -} -``` - -```kotlin -foreground = if (selected) { - UIUtil.getTreeForeground(true, hasFocus) -} else { - UIUtil.getContextHelpForeground() -} -``` - -Avoid inline `Color(...)`, numeric `JBColor(...)`, `Gray.xNN`, `JBColor.GRAY`, and hex color literals in runtime UI code. The exception is a centralized semantic color definition with a named color key when no existing platform key exists. - -## Theme-Derived Fonts - -Do not hardcode font sizes or font families. IntelliJ fonts must come from component defaults, platform typography helpers, or existing component fonts. - -- Prefer component default fonts when no style change is needed. -- Use `JBFont.h1()`, `JBFont.h2()`, `JBFont.h3()`, and `JBFont.h4()` for headings. -- Use `.asBold()`, `.asItalic()`, and `.asPlain()` for style changes on `JBFont` values. -- Use `JBFont.regular()`, `JBFont.medium()`, and `JBFont.small()` for regular and secondary text. -- Use `UIUtil.getLabelFont(UIUtil.FontSize.SMALL)` / `MINI` only when an API expects a raw `Font` and `JBFont` / `RelativeFont` is not a good fit. -- Use `RelativeFont` when adjusting an existing component font relatively. -- Use `RelativeFont.fromResource(...)` for theme-configurable font offsets when matching platform component patterns. -- Use `JBUI.Fonts.smallFont()` only when matching an existing platform component pattern that expects it. -- If editor-like text needs editor typography, derive it from the editor color scheme or existing editor component instead of hardcoding a font. - -For errors, grayed text, shortcuts, and links in renderers, prefer `SimpleTextAttributes.ERROR_ATTRIBUTES`, `GRAYED_ATTRIBUTES`, `SHORTCUT_ATTRIBUTES`, and `LINK_ATTRIBUTES` rather than manually selecting colors and styles. - -Recommended examples: - -```kotlin -label(title).applyToComponent { - font = JBFont.h3().asBold() -} -``` - -```kotlin -RelativeFont.BOLD.install(label) -``` - -Avoid `Font("...")`, raw font sizes, and `deriveFont(14f)` style examples. - -## Kilo Session Styling - -For session/chat UI under `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/`, keep general UI chrome separate from transcript styling. - -- Use `ai.kilocode.client.ui.UiStyle` for general UI helpers: `Colors`, `Borders`, `Insets`, `Gap`, `Space`, `Size`, and `Buttons`. -- Use `ai.kilocode.client.session.ui.SessionStyle` for session transcript/content styling that follows editor settings or live transcript configuration. -- `SessionStyle` is for user/assistant transcript text, reasoning text, tool output, prompt editor text, and markdown renderer fields such as `font`, `codeFont`, and future link/code-block styles. -- Long-lived session components should implement or propagate `SessionStyleTarget.applyStyle(style)` instead of reading editor globals once in constructors. -- Do not call `EditorColorsManager.getInstance().globalScheme` directly from individual views unless extending `SessionStyle.current()`. -- New transcript renderers must apply the current `SessionStyle` snapshot and ensure child parts created after a style change receive the queued style. -- Keep non-transcript IDE chrome on platform/UI style unless it is intentionally part of the transcript reading experience. - -Use `UiStyle` for the surrounding card chrome and `SessionStyle` for transcript content inside it: - -```kotlin -class ExamplePartView : PartView() { - override fun applyStyle(style: SessionStyle) { - var changed = false - if (md.font != style.transcriptFont) { - md.font = style.transcriptFont - changed = true - } - if (md.codeFont != style.editorFamily) { - md.codeFont = style.editorFamily - changed = true - } - if (!changed) return - revalidate() - repaint() - } -} -``` - -## Borders, Insets, and Spacing - -- Always create borders via `JBUI.Borders.empty(top, left, bottom, right)` and insets via `JBUI.insets()` so they are DPI-aware and auto-update on zoom. -- Use `JBUI.scale(int)` for any pixel dimension to ensure proper HiDPI scaling. -- Prefer Kotlin UI DSL gaps and row layout semantics over manually assigning borders or insets. -- Do not use `EmptyBorder`, raw `Insets`, or raw `Dimension` unless there is no platform alternative and the reason is obvious. - -Theme-dependent borders, insets, colors, and corner arcs must be re-evaluated when the Look and Feel changes. Do not assign a theme-derived border once in a constructor for a long-lived component. - -Prefer overriding `updateUI()` for component-local updates: - -```kotlin -class KiloPanel : JPanel() { - override fun updateUI() { - super.updateUI() - border = JBUI.Borders.customLine( - JBColor.namedColor("KiloPanel.borderColor", JBColor.border()), - 1, - ) - } -} -``` - -For long-lived tool-window panels or components that need explicit Look and Feel handling outside normal Swing updates, subscribe to `LafManagerListener.TOPIC` and reapply theme-dependent borders or cached UI state there. - -Use `JBValue.UIInteger` for themeable arc values, because defaults differ by theme: - -| Key | Use | -|---|---| -| `Component.arc` | General component corners | -| `Button.arc` | Button corners | -| `Popup.Selection.arc` | Popup selection background | -| `TabbedPane.tabSelectionArc` | Tab selection indicator | -| `Tree.Selection.arc` | Tree selection background | - -```kotlin -val arc = JBValue.UIInteger("Component.arc", 5).get() -val button = JBValue.UIInteger("Button.arc", 6).get() -``` - -Only define plugin-owned theme keys when a platform key is not enough. Themeable insets can use `JBUI.insets("KiloPanel.insets", JBUI.insets(4, 8))`; themeable colors should use `JBColor.namedColor("KiloPanel.borderColor", fallback)`. - -Themes can override plugin-owned UI keys through the `ui` section: - -```json -{ - "ui": { - "KiloPanel.insets": "6,12,6,12", - "KiloPanel.gap": 20, - "KiloPanel.borderColor": "#FF0000", - "KiloPanel.arc": 10 - } -} -``` - -Expose intentional custom UI keys to theme authors with the `themeMetadataProvider` extension point and a `*.themeMetadata.json` file. - -```xml - -``` - -```json -{ - "name": "Kilo Code", - "fixed": false, - "ui": [ - { "key": "KiloPanel.borderColor", "description": "Panel border color" }, - { "key": "KiloPanel.gap", "description": "Gap between panel items" } - ] -} -``` - -## Validation and Error UI - -Prefer built-in validation mechanisms over custom error rendering. - -- For Kotlin UI DSL, use `validationOnInput`, `validationOnApply`, `validationInfo`, `errorOnApply`, and `addValidationRule` on cells. -- For DSL dialogs and settings panels, call `DialogPanel.registerValidators(disposable)` when input validation should run continuously. -- Call `DialogPanel.validateAll()` before `apply()` when submitting a DSL panel manually. -- In `DialogWrapper`, use `doValidate()` and return `ValidationInfo(message, component)` for errors. -- Use `ValidationInfo.asWarning()` for warnings and `withOKEnabled()` when a warning should not block submission. -- For hand-built Swing forms, use `ComponentValidator` with `withValidator`, `withFocusValidator`, and `andRegisterOnDocumentListener` instead of custom tooltip/error border logic. -- If custom validation painting is unavoidable, use `JBUI.CurrentTheme.Validator.*` and `JBUI.CurrentTheme.Focus.*` colors. - -Kotlin UI DSL example: - -```kotlin -textField() - .validationOnInput { - if (it.text.isBlank()) error(KiloBundle.message("settings.name.required")) else null - } -``` - -Dialog validation example: - -```kotlin -override fun doValidate(): ValidationInfo? { - if (field.text.isBlank()) return ValidationInfo(KiloBundle.message("settings.name.required"), field) - return null -} -``` - -## Icons - -- Reuse platform icons. Browse at https://intellij-icons.jetbrains.design and access via `AllIcons.*` constants. -- Custom icons belong in `resources/icons/`. -- Load custom icons via `IconLoader.getIcon("/icons/foo.svg", MyClass::class.java)`. -- Organize custom icons in an `icons` package or a `*Icons` object with `@JvmField` on each constant. -- Icon sizing guideline values: actions/nodes = 16x16, tool window = 13x13 classic or 20x20 + 16x16 compact New UI, editor gutter = 12x12 classic or 14x14 New UI. -- Dark variants: `icon.svg` + `icon_dark.svg`. -- HiDPI variants: `icon@2x.svg` + `icon@2x_dark.svg`. -- New UI support: place New UI icons in `expui/`, create `*IconMappings.json`, register via `com.intellij.iconMapper` extension point. -- For SVG asset palette values, follow the IntelliJ icon asset guidelines. Do not copy guideline color literals into runtime Swing UI code. - -### SVG Assets - -IntelliJ does not theme SVG icons with `currentColor`, CSS classes, CSS variables, inherited styles, or ` + + + + + + + + { expect(text(view, "additions")).toBe("one\nthree\n") }) + test("keeps missing final newlines from unified patches", () => { + const diff = { + file: "a.ts", + patch: + "Index: a.ts\n===================================================================\n--- a.ts\t\n+++ a.ts\t\n@@ -1,2 +1,2 @@\n one\n-two\n\\ No newline at end of file\n+three\n\\ No newline at end of file\n", + additions: 1, + deletions: 1, + status: "modified" as const, + } + const view = normalize(diff) + + expect(text(view, "deletions")).toBe("one\ntwo") + expect(text(view, "additions")).toBe("one\nthree") + }) + test("converts legacy content into a patch", () => { const diff = { file: "a.ts", @@ -34,4 +49,20 @@ describe("session diff", () => { expect(text(view, "deletions")).toBe("one\n") expect(text(view, "additions")).toBe("two\n") }) + + test("ignores malformed persisted patches", () => { + const diff = { + file: "a.ts", + patch: + "diff --git a/a.ts b/a.ts\nindex ff4ceb2..65a1de0 100644\n--- a/a.ts\n+++ b/a.ts\n@@ -1,3 +1,3 @@\n keep\n+add\n same\r", + additions: 1, + deletions: 1, + status: "modified" as const, + } + const view = normalize(diff) + + expect(view.patch).toBe(diff.patch) + expect(text(view, "deletions")).toBe("") + expect(text(view, "additions")).toBe("") + }) }) diff --git a/packages/ui/src/components/session-diff.ts b/packages/ui/src/components/session-diff.ts index 26c45cb3214..7bd43ceda18 100644 --- a/packages/ui/src/components/session-diff.ts +++ b/packages/ui/src/components/session-diff.ts @@ -36,26 +36,49 @@ const cache = new Map() export function contents(diff: ReviewDiff): DiffText { if (typeof diff.patch === "string") { - const [patch] = parsePatch(diff.patch) + try { + const [patch] = parsePatch(diff.patch) + const beforeLines: Array<{ text: string; newline: boolean }> = [] + const afterLines: Array<{ text: string; newline: boolean }> = [] + let previous: "-" | "+" | " " | undefined - const beforeLines = [] - const afterLines = [] + for (const hunk of patch.hunks) { + for (const line of hunk.lines) { + if (line.startsWith("\\")) { + if (previous === "-" || previous === " ") { + const before = beforeLines.at(-1) + if (before) before.newline = false + } + if (previous === "+" || previous === " ") { + const after = afterLines.at(-1) + if (after) after.newline = false + } + continue + } - for (const hunk of patch.hunks) { - for (const line of hunk.lines) { - if (line.startsWith("-")) { - beforeLines.push(line.slice(1)) - } else if (line.startsWith("+")) { - afterLines.push(line.slice(1)) - } else { - // context line (starts with ' ') - beforeLines.push(line.slice(1)) - afterLines.push(line.slice(1)) + if (line.startsWith("-")) { + beforeLines.push({ text: line.slice(1), newline: true }) + previous = "-" + } else if (line.startsWith("+")) { + afterLines.push({ text: line.slice(1), newline: true }) + previous = "+" + } else { + // context line (starts with ' ') + beforeLines.push({ text: line.slice(1), newline: true }) + afterLines.push({ text: line.slice(1), newline: true }) + previous = " " + } } } - } - return { before: beforeLines.join("\n") + "\n", after: afterLines.join("\n") + "\n", patch: diff.patch } + return { + before: beforeLines.map((line) => line.text + (line.newline ? "\n" : "")).join(""), + after: afterLines.map((line) => line.text + (line.newline ? "\n" : "")).join(""), + patch: diff.patch, + } + } catch { + return { before: "", after: "", patch: diff.patch } + } } return { before: "before" in diff && typeof diff.before === "string" ? diff.before : "", diff --git a/packages/ui/src/file-path.test.ts b/packages/ui/src/file-path.test.ts index 16e8dc47627..a2df1f15f06 100644 --- a/packages/ui/src/file-path.test.ts +++ b/packages/ui/src/file-path.test.ts @@ -1,3 +1,4 @@ +// kilocode_change - new file import { describe, expect, it } from "bun:test" import { parseFilePath, extractFilePathFromHref } from "./file-path" @@ -154,6 +155,18 @@ describe("extractFilePathFromHref", () => { it("path with multiple extensions", () => { expect(extractFilePathFromHref("config.test.ts")).toBe("config.test.ts") }) + + it("file:// URL on Unix", () => { + expect(extractFilePathFromHref("file:///foo/bar.ts")).toBe("/foo/bar.ts") + }) + + it("file:// URL with Windows drive", () => { + expect(extractFilePathFromHref("file:///C:/Users/dev/file.ts")).toBe("C:/Users/dev/file.ts") + }) + + it("file:// URL with encoded characters", () => { + expect(extractFilePathFromHref("file:///foo%20bar/baz.ts")).toBe("/foo bar/baz.ts") + }) }) describe("strips fragments and queries", () => { @@ -195,10 +208,6 @@ describe("extractFilePathFromHref", () => { expect(extractFilePathFromHref("javascript:void(0)")).toBeUndefined() }) - it("file:// URL", () => { - expect(extractFilePathFromHref("file:///foo/bar.ts")).toBeUndefined() - }) - it("ftp URL", () => { expect(extractFilePathFromHref("ftp://server/file.txt")).toBeUndefined() }) diff --git a/script/check-forbidden-strings.ts b/script/check-forbidden-strings.ts new file mode 100644 index 00000000000..aa1aa8ad7f9 --- /dev/null +++ b/script/check-forbidden-strings.ts @@ -0,0 +1,103 @@ +#!/usr/bin/env bun +// kilocode_change - new file + +/** + * Greps tracked files for forbidden strings that must not appear in the repo. + * + * Each entry is a literal substring (no regex / globs) plus a one-line reason. + * If a hit is genuinely legitimate (e.g. inside upstream-merge tooling), fix the + * call site rather than weakening the rule -- the list is intentionally + * narrow so it stays low-noise. + */ + +import { spawnSync } from "node:child_process" +import path from "node:path" + +const ROOT = path.resolve(import.meta.dir, "..") +const SELF = path.relative(ROOT, import.meta.path).replaceAll("\\", "/") + +// Each entry: pattern (literal substring) + reason + optional allow list of path +// prefixes where the string is legitimate (e.g. docs describing the fork lineage, +// upstream-merge tooling, generated source-link manifests). +const forbidden: { pattern: string; reason: string; allow?: string[] }[] = [ + { pattern: "opncd.ai/s/", reason: "legacy upstream share URL pattern" }, + { + pattern: "github.com/anomalyco/opencode", + reason: "upstream repo URL -- should be Kilo-Org/kilocode", + allow: [ + "AGENTS.md", + "README.md", + ".opencode/glossary/", + "packages/kilo-vscode/AGENTS.md", + "packages/kilo-docs/source-links.md", + "patches/", + "script/upstream/", + ], + }, + { + pattern: "sst/opencode", + reason: "old upstream org path -- should be Kilo-Org/kilocode", + allow: [".kilo/agent/upstream-merge.md", "script/upstream/"], + }, + { pattern: `"HTTP-Referer": "https://opencode.ai/"`, reason: "attributes outbound LLM traffic to upstream" }, + { pattern: `"http-referer": "https://opencode.ai/"`, reason: "attributes outbound LLM traffic to upstream" }, + + // Candidates -- enable once the underlying call sites have been rebranded. + // Each one currently fires on real leaks; uncomment after fixing the listed + // file(s) (and add an allowlist if there are unavoidable legitimate hits). + // + // { pattern: "opencode.ai/auth", reason: "upstream auth URL -- providers.ts opencode-provider help text" }, + // { pattern: "opencode.ai/go", reason: "upstream upsell URL -- dialog-go-upsell.tsx" }, + // { pattern: "opencode.ai/docs", reason: "upstream docs URL -- config.ts schema descriptions, providers.ts cloudflare help" }, + // { pattern: "opencode.ai/tui.json", reason: "upstream-hosted schema URL -- tui-migrate.ts" }, + // { pattern: `?? "https://opncd.ai"`, reason: "default share base URL still points at upstream -- share-next.ts" }, + // { pattern: "opencode.ai/theme.json", reason: "upstream-hosted theme JSON-Schema URL -- theme/*.json $schema fields" }, + // { pattern: "opencode.ai/desktop-theme.json", reason: "upstream-hosted desktop theme schema URL" }, +] + +const isAllowed = (file: string, allow?: string[]) => { + if (!allow) return false + return allow.some((prefix) => file === prefix || file.startsWith(prefix)) +} + +const ls = spawnSync("git", ["ls-files", "-z"], { cwd: ROOT, encoding: "buffer" }) +if (ls.status !== 0) { + console.error(ls.stderr?.toString().trim() || "git ls-files failed") + process.exit(1) +} + +const files = ls.stdout + .toString("utf8") + .split("\0") + .filter(Boolean) + .filter((f) => f !== SELF) + +const hits: string[] = [] +for (const file of files) { + const buf = Bun.file(path.join(ROOT, file)) + if (!(await buf.exists())) continue + // Skip binary-ish files: read as text and skip if it contains a NUL byte. + const text = await buf.text().catch(() => null) + if (text === null) continue + if (text.includes("\0")) continue + for (const f of forbidden) { + if (isAllowed(file, f.allow)) continue + let idx = 0 + while (true) { + const at = text.indexOf(f.pattern, idx) + if (at === -1) break + const line = text.slice(0, at).split("\n").length + hits.push(`${file}:${line}: ${f.pattern} (${f.reason})`) + idx = at + f.pattern.length + } + } +} + +if (hits.length === 0) { + console.log(`check-forbidden-strings: ${files.length} file(s) checked, no forbidden strings found.`) + process.exit(0) +} + +console.error("Found forbidden strings:") +for (const h of hits) console.error(` ${h}`) +process.exit(1) diff --git a/script/check-opencode-annotations.ts b/script/check-opencode-annotations.ts index cc75e152778..be65e4e60bc 100644 --- a/script/check-opencode-annotations.ts +++ b/script/check-opencode-annotations.ts @@ -35,7 +35,6 @@ import path from "node:path" const ROOT = path.resolve(import.meta.dir, "..") const SOURCE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".yml", ".yaml", ".toml", ".sh", ".bash", ".zsh"]) const SCOPES = [ - "sdks/vscode", "packages/opencode", "packages/extensions", "packages/ui", diff --git a/script/check-workflows.ts b/script/check-workflows.ts index 64588fb79d2..addb9e9ba8f 100644 --- a/script/check-workflows.ts +++ b/script/check-workflows.ts @@ -29,6 +29,7 @@ const DIR = path.join(ROOT, ".github", "workflows") const active = new Set([ "auto-docs.yml", "beta.yml", + "check-forbidden-strings.yml", "check-kilo-generated-artifacts.yml", "check-md-table-padding.yml", "check-opencode-annotations.yml", diff --git a/script/extract-source-links.ts b/script/extract-source-links.ts index b3179fb7294..20f014fb8cf 100755 --- a/script/extract-source-links.ts +++ b/script/extract-source-links.ts @@ -85,7 +85,7 @@ const SKIP_DIRS = ["node_modules", ".storybook", "stories", "test", "tests", "__ const SKIP_PATH_SEGMENTS = ["continuedev"] // Individual files to skip (data files full of non-user-facing URLs) -const SKIP_FILES = ["models-snapshot.ts", "models-snapshot.js"] +const SKIP_FILES = ["models-snapshot.ts", "models-snapshot.js", "check-forbidden-strings.ts"] // kilocode_change function shouldExclude(url: string): boolean { return EXCLUDE_PATTERNS.some((re) => re.test(url)) diff --git a/script/publish.ts b/script/publish.ts index 3ca9b355ae6..9e676d0a13a 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -129,6 +129,13 @@ console.log("\n=== vscode ===\n") await import(`../packages/kilo-vscode/script/publish.ts`) // kilocode_change end +// kilocode_change start - Kilo does not ship the opencode desktop app +// if (Script.release) { +// await $`bun ./packages/desktop/scripts/finalize-latest-json.ts` +// await $`bun ./packages/desktop/scripts/finalize-latest-yml.ts` +// } +// kilocode_change end + const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) diff --git a/script/raw-changelog.ts b/script/raw-changelog.ts index 2ae81fa7806..1cfc230e53f 100644 --- a/script/raw-changelog.ts +++ b/script/raw-changelog.ts @@ -80,6 +80,11 @@ function section(areas: Set) { return "Core" } +function type(message: string) { + if (message.match(/fix/i)) return "Bugfixes" + return "Improvements" +} + function reverted(commits: Commit[]) { const seen = new Map() @@ -114,7 +119,7 @@ async function commits(from: string, to: string) { } const log = - await $`git log ${base}..${head} --format=%H -- packages/opencode packages/sdk packages/plugin sdks/vscode packages/extensions github`.text() // kilocode_change + await $`git log ${base}..${head} --format=%H -- packages/opencode packages/sdk packages/plugin packages/extensions github`.text() // kilocode_change const list: Commit[] = [] for (const hash of log.split("\n").filter(Boolean)) { @@ -130,7 +135,7 @@ async function commits(from: string, to: string) { else if (file.startsWith("packages/opencode/")) areas.add("core") else if (file.startsWith("packages/sdk/") || file.startsWith("packages/plugin/")) areas.add("sdk") else if (file.startsWith("packages/extensions/")) areas.add("extensions/zed") - else if (file.startsWith("sdks/vscode/") || file.startsWith("github/")) areas.add("extensions/vscode") + else if (file.startsWith("github/")) areas.add("extensions/vscode") } if (areas.size === 0) continue @@ -189,13 +194,20 @@ async function thanks(from: string, to: string, reuse: boolean) { } function format(from: string, to: string, list: Commit[], thanks: string[]) { - const grouped = new Map() - for (const title of order) grouped.set(title, []) + const grouped = new Map>() + for (const title of order) { + grouped.set( + title, + new Map([ + ["Improvements", []], + ["Bugfixes", []], + ]), + ) + } for (const commit of list) { - const title = section(commit.areas) const attr = commit.author && !team.includes(commit.author) ? ` (@${commit.author})` : "" - grouped.get(title)!.push(`- \`${commit.hash}\` ${commit.message}${attr}`) + grouped.get(section(commit.areas))!.get(type(commit.message))!.push(`- \`${commit.hash}\` ${commit.message}${attr}`) } const lines = [`Last release: ${ref(from)}`, `Target ref: ${to}`, ""] @@ -205,11 +217,23 @@ function format(from: string, to: string, list: Commit[], thanks: string[]) { } for (const title of order) { - const entries = grouped.get(title) - if (!entries || entries.length === 0) continue + const groups = grouped.get(title) + if (!groups || [...groups.values()].every((entries) => entries.length === 0)) continue lines.push(`## ${title}`) - lines.push(...entries) - lines.push("") + const improvements = groups.get("Improvements")! + const bugfixes = groups.get("Bugfixes")! + if (bugfixes.length === 0) { + lines.push(...improvements) + lines.push("") + continue + } + + for (const [subtitle, entries] of groups) { + if (entries.length === 0) continue + lines.push(`### ${subtitle}`) + lines.push(...entries) + lines.push("") + } } if (thanks.length > 0) { diff --git a/script/upstream/package.json b/script/upstream/package.json index 4ac5a74a5b9..e56392d8676 100644 --- a/script/upstream/package.json +++ b/script/upstream/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/upstream-merge", - "version": "7.3.0", + "version": "7.3.8", "private": true, "type": "module", "description": "Scripts for automating upstream opencode merges into Kilo", @@ -23,5 +23,6 @@ }, "devDependencies": { "@types/bun": "1.3.13" - } + }, + "peerDependencies": {} } diff --git a/script/upstream/transforms/skip-files.test.ts b/script/upstream/transforms/skip-files.test.ts index e31d9a9689e..bcccf19120d 100644 --- a/script/upstream/transforms/skip-files.test.ts +++ b/script/upstream/transforms/skip-files.test.ts @@ -11,6 +11,11 @@ test("matches removed app package glob paths", () => { expect(shouldSkip("packages/app/package.json", ["packages/app/**"])).toBe(true) }) +test("matches removed vscode sdk glob paths", () => { + expect(shouldSkip("sdks/vscode/package.json", ["sdks/vscode/**"])).toBe(true) + expect(shouldSkip("sdks/vscode/src/extension.ts", ["sdks/vscode/**"])).toBe(true) +}) + test("matches extension glob paths", () => { expect(shouldSkip(".github/VOUCHED.td", [".github/VOUCHED.*"])).toBe(true) }) diff --git a/script/upstream/transforms/transform-package-json.test.ts b/script/upstream/transforms/transform-package-json.test.ts index a239bcc5edf..227ff2e4964 100644 --- a/script/upstream/transforms/transform-package-json.test.ts +++ b/script/upstream/transforms/transform-package-json.test.ts @@ -5,8 +5,8 @@ test("fixScripts preserves Kilo-only root scripts from base", () => { const ours = { scripts: { "dev-setup": "kilo dev-setup", - "postinstall": "bun run --cwd packages/opencode fix-node-pty && bun run script/setup-git.ts", - "extension": "bun --cwd packages/kilo-vscode script/launch.ts", + postinstall: "bun run --cwd packages/opencode fix-node-pty && bun run script/setup-git.ts", + extension: "bun --cwd packages/kilo-vscode script/launch.ts", }, } const pkg: Record = { @@ -25,7 +25,7 @@ test("fixScripts preserves Kilo-only root scripts from base", () => { test("fixScripts removes upstream-only dead scripts from root", () => { const pkg: Record = { scripts: { - "dev": "bun run --cwd packages/opencode src/index.ts", + dev: "bun run --cwd packages/opencode src/index.ts", "dev:desktop": "bun --cwd packages/desktop-electron dev", "dev:web": "bun --cwd packages/app dev", "dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev", diff --git a/script/upstream/transforms/transform-package-json.ts b/script/upstream/transforms/transform-package-json.ts index 501786e1453..e65432cd219 100644 --- a/script/upstream/transforms/transform-package-json.ts +++ b/script/upstream/transforms/transform-package-json.ts @@ -247,7 +247,12 @@ const DELETE_UPSTREAM_CATALOG: Record = { * Re-apply Kilo-specific scripts on top of the upstream-shaped scripts block, * and prune upstream-only scripts that target packages Kilo doesn't ship. */ -export function fixScripts(pkg: Record, path: string, ours: Record | null, changes: string[]): void { +export function fixScripts( + pkg: Record, + path: string, + ours: Record | null, + changes: string[], +): void { const theirs = (pkg.scripts as Record | undefined) || {} const oursScripts = (ours?.scripts as Record | undefined) || {} diff --git a/script/upstream/utils/config.ts b/script/upstream/utils/config.ts index 28a1c770b48..2bb5a0eb5a9 100644 --- a/script/upstream/utils/config.ts +++ b/script/upstream/utils/config.ts @@ -156,6 +156,7 @@ export const defaultConfig: MergeConfig = { "packages/app/**", "packages/desktop/**", "packages/desktop-electron/**", + "sdks/vscode/**", // GitHub Action - Kilo version is fully ported and complete "github/index.ts", "github/package.json", diff --git a/sdks/vscode/.gitignore b/sdks/vscode/.gitignore deleted file mode 100644 index 53c37a16608..00000000000 --- a/sdks/vscode/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist \ No newline at end of file diff --git a/sdks/vscode/.vscode-test.mjs b/sdks/vscode/.vscode-test.mjs deleted file mode 100644 index 993a118acb7..00000000000 --- a/sdks/vscode/.vscode-test.mjs +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from "@vscode/test-cli" - -export default defineConfig({ - files: "out/test/**/*.test.js", -}) diff --git a/sdks/vscode/.vscodeignore b/sdks/vscode/.vscodeignore deleted file mode 100644 index 3e4b35c0743..00000000000 --- a/sdks/vscode/.vscodeignore +++ /dev/null @@ -1,16 +0,0 @@ -.vscode/** -.vscode-test/** -out/** -node_modules/** -src/** -script/** -.gitignore -.yarnrc -bun.lock -esbuild.js -vsc-extension-quickstart.md -**/tsconfig.json -**/eslint.config.mjs -**/*.map -**/*.ts -**/.vscode-test.* diff --git a/sdks/vscode/README.md b/sdks/vscode/README.md deleted file mode 100644 index 72e9124448b..00000000000 --- a/sdks/vscode/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# opencode VS Code Extension - -A Visual Studio Code extension that integrates [opencode](https://opencode.ai) directly into your development workflow. - -## Prerequisites - -This extension requires the [opencode CLI](https://opencode.ai) to be installed on your system. Visit [opencode.ai](https://opencode.ai) for installation instructions. - -## Features - -- **Quick Launch**: Use `Cmd+Esc` (Mac) or `Ctrl+Esc` (Windows/Linux) to open opencode in a split terminal view, or focus an existing terminal session if one is already running. -- **New Session**: Use `Cmd+Shift+Esc` (Mac) or `Ctrl+Shift+Esc` (Windows/Linux) to start a new opencode terminal session, even if one is already open. You can also click the opencode button in the UI. -- **Context Awareness**: Automatically share your current selection or tab with opencode. -- **File Reference Shortcuts**: Use `Cmd+Option+K` (Mac) or `Alt+Ctrl+K` (Linux/Windows) to insert file references. For example, `@File#L37-42`. - -## Support - -This is an early release. If you encounter issues or have feedback, please create an issue at https://github.com/Kilo-Org/kilocode/issues. - -## Development - -1. `code sdks/vscode` - Open the `sdks/vscode` directory in VS Code. **Do not open from repo root.** -2. `bun install` - Run inside the `sdks/vscode` directory. -3. Press `F5` to start debugging - This launches a new VS Code window with the extension loaded. - -#### Making Changes - -`tsc` and `esbuild` watchers run automatically during debugging (visible in the Terminal tab). Changes to the extension are automatically rebuilt in the background. - -To test your changes: - -1. In the debug VS Code window, press `Cmd+Shift+P` -2. Search for `Developer: Reload Window` -3. Reload to see your changes without restarting the debug session diff --git a/sdks/vscode/bun.lock b/sdks/vscode/bun.lock deleted file mode 100644 index 085f0661a09..00000000000 --- a/sdks/vscode/bun.lock +++ /dev/null @@ -1,589 +0,0 @@ -{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "opencode-agent", - "devDependencies": { - "@types/mocha": "^10.0.10", - "@types/node": "20.x", - "@types/vscode": "^1.94.0", - "@typescript-eslint/eslint-plugin": "^8.31.1", - "@typescript-eslint/parser": "^8.31.1", - "@vscode/test-cli": "^0.0.11", - "@vscode/test-electron": "^2.5.2", - "esbuild": "^0.25.3", - "eslint": "^9.25.1", - "typescript": "^5.8.3", - }, - }, - }, - "packages": { - "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.8", "", { "os": "aix", "cpu": "ppc64" }, "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.8", "", { "os": "android", "cpu": "arm" }, "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.8", "", { "os": "android", "cpu": "arm64" }, "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.8", "", { "os": "android", "cpu": "x64" }, "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.8", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.8", "", { "os": "linux", "cpu": "arm" }, "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.8", "", { "os": "linux", "cpu": "ia32" }, "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.8", "", { "os": "linux", "cpu": "ppc64" }, "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.8", "", { "os": "linux", "cpu": "none" }, "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.8", "", { "os": "linux", "cpu": "s390x" }, "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.8", "", { "os": "linux", "cpu": "x64" }, "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ=="], - - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.8", "", { "os": "none", "cpu": "x64" }, "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg=="], - - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.8", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.8", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ=="], - - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.8", "", { "os": "none", "cpu": "arm64" }, "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.8", "", { "os": "sunos", "cpu": "x64" }, "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="], - - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], - - "@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="], - - "@eslint/config-helpers": ["@eslint/config-helpers@0.3.0", "", {}, "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw=="], - - "@eslint/core": ["@eslint/core@0.15.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA=="], - - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], - - "@eslint/js": ["@eslint/js@9.31.0", "", {}, "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw=="], - - "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], - - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.3", "", { "dependencies": { "@eslint/core": "^0.15.1", "levn": "^0.4.1" } }, "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag=="], - - "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], - - "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - - "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.4", "", {}, "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.29", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ=="], - - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], - - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - - "@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="], - - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - - "@types/mocha": ["@types/mocha@10.0.10", "", {}, "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q=="], - - "@types/node": ["@types/node@20.19.9", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw=="], - - "@types/vscode": ["@types/vscode@1.102.0", "", {}, "sha512-V9sFXmcXz03FtYTSUsYsu5K0Q9wH9w9V25slddcxrh5JgORD14LpnOA7ov0L9ALi+6HrTjskLJ/tY5zeRF3TFA=="], - - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.37.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/type-utils": "8.37.0", "@typescript-eslint/utils": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.37.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.37.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/types": "8.37.0", "@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.37.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.37.0", "@typescript-eslint/types": "^8.37.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.37.0", "", { "dependencies": { "@typescript-eslint/types": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0" } }, "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.37.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.37.0", "", { "dependencies": { "@typescript-eslint/types": "8.37.0", "@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/utils": "8.37.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.37.0", "", {}, "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.37.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.37.0", "@typescript-eslint/tsconfig-utils": "8.37.0", "@typescript-eslint/types": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.37.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/types": "8.37.0", "@typescript-eslint/typescript-estree": "8.37.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.37.0", "", { "dependencies": { "@typescript-eslint/types": "8.37.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w=="], - - "@vscode/test-cli": ["@vscode/test-cli@0.0.11", "", { "dependencies": { "@types/mocha": "^10.0.2", "c8": "^9.1.0", "chokidar": "^3.5.3", "enhanced-resolve": "^5.15.0", "glob": "^10.3.10", "minimatch": "^9.0.3", "mocha": "^11.1.0", "supports-color": "^9.4.0", "yargs": "^17.7.2" }, "bin": { "vscode-test": "out/bin.mjs" } }, "sha512-qO332yvzFqGhBMJrp6TdwbIydiHgCtxXc2Nl6M58mbH/Z+0CyLR76Jzv4YWPEthhrARprzCRJUqzFvTHFhTj7Q=="], - - "@vscode/test-electron": ["@vscode/test-electron@2.5.2", "", { "dependencies": { "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.5", "jszip": "^3.10.1", "ora": "^8.1.0", "semver": "^7.6.2" } }, "sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg=="], - - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], - - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - - "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - - "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], - - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - - "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - - "browser-stdout": ["browser-stdout@1.3.1", "", {}, "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="], - - "c8": ["c8@9.1.0", "", { "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@istanbuljs/schema": "^0.1.3", "find-up": "^5.0.0", "foreground-child": "^3.1.1", "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.1.6", "test-exclude": "^6.0.0", "v8-to-istanbul": "^9.0.0", "yargs": "^17.7.2", "yargs-parser": "^21.1.1" }, "bin": { "c8": "bin/c8.js" } }, "sha512-mBWcT5iqNir1zIkzSPyI3NCR9EZCVI3WUD+AVO17MVWTSFNyUueXE82qTeampNtTr+ilN/5Ua3j24LgbCKjDVg=="], - - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - - "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - - "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], - - "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], - - "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - - "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], - - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - - "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], - - "decamelize": ["decamelize@4.0.0", "", {}, "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="], - - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - - "diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="], - - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], - - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "enhanced-resolve": ["enhanced-resolve@5.18.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ=="], - - "esbuild": ["esbuild@0.25.8", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.8", "@esbuild/android-arm": "0.25.8", "@esbuild/android-arm64": "0.25.8", "@esbuild/android-x64": "0.25.8", "@esbuild/darwin-arm64": "0.25.8", "@esbuild/darwin-x64": "0.25.8", "@esbuild/freebsd-arm64": "0.25.8", "@esbuild/freebsd-x64": "0.25.8", "@esbuild/linux-arm": "0.25.8", "@esbuild/linux-arm64": "0.25.8", "@esbuild/linux-ia32": "0.25.8", "@esbuild/linux-loong64": "0.25.8", "@esbuild/linux-mips64el": "0.25.8", "@esbuild/linux-ppc64": "0.25.8", "@esbuild/linux-riscv64": "0.25.8", "@esbuild/linux-s390x": "0.25.8", "@esbuild/linux-x64": "0.25.8", "@esbuild/netbsd-arm64": "0.25.8", "@esbuild/netbsd-x64": "0.25.8", "@esbuild/openbsd-arm64": "0.25.8", "@esbuild/openbsd-x64": "0.25.8", "@esbuild/openharmony-arm64": "0.25.8", "@esbuild/sunos-x64": "0.25.8", "@esbuild/win32-arm64": "0.25.8", "@esbuild/win32-ia32": "0.25.8", "@esbuild/win32-x64": "0.25.8" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "eslint": ["eslint@9.31.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.0", "@eslint/core": "^0.15.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.31.0", "@eslint/plugin-kit": "^0.3.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ=="], - - "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], - - "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], - - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], - - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - - "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], - - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat": ["flat@5.0.2", "", { "bin": { "flat": "cli.js" } }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], - - "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - - "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - - "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - - "get-east-asian-width": ["get-east-asian-width@1.3.0", "", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="], - - "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - - "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], - - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], - - "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], - - "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], - - "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], - - "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - - "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], - - "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - - "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], - - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - - "is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="], - - "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], - - "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], - - "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], - - "istanbul-reports": ["istanbul-reports@3.1.7", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g=="], - - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - - "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - - "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="], - - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - - "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], - - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - - "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - - "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], - - "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - - "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], - - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - - "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], - - "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - - "mocha": ["mocha@11.7.1", "", { "dependencies": { "browser-stdout": "^1.3.1", "chokidar": "^4.0.1", "debug": "^4.3.5", "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^9.0.5", "ms": "^2.1.3", "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", "workerpool": "^9.2.0", "yargs": "^17.7.2", "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "bin": { "mocha": "bin/mocha.js", "_mocha": "bin/_mocha" } }, "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], - - "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], - - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - - "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], - - "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], - - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - - "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], - - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - - "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], - - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - - "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], - - "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - - "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - - "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], - - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - - "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="], - - "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], - - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - - "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="], - - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], - - "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], - - "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - - "supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="], - - "tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="], - - "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], - - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], - - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - - "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], - - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], - - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - - "v8-to-istanbul": ["v8-to-istanbul@9.3.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" } }, "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA=="], - - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - - "workerpool": ["workerpool@9.3.3", "", {}, "sha512-slxCaKbYjEdFT/o2rH9xS1hf4uRDch1w7Uo+apxhZ+sf/1d9e0ZVkn42kPNGP2dgjIx6YFvSevj0zHvbWe2jdw=="], - - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - - "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - - "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], - - "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - - "yargs-unparser": ["yargs-unparser@2.0.0", "", { "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" } }, "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA=="], - - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@eslint/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], - - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - - "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "eslint/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "log-symbols/is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], - - "mocha/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - - "mocha/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "ora/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="], - - "ora/log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], - - "ora/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], - - "string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - - "test-exclude/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - - "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "eslint/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "mocha/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - - "ora/log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], - - "ora/string-width/emoji-regex": ["emoji-regex@10.4.0", "", {}, "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="], - - "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "test-exclude/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - - "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - } -} diff --git a/sdks/vscode/esbuild.js b/sdks/vscode/esbuild.js deleted file mode 100644 index aa09b4eba81..00000000000 --- a/sdks/vscode/esbuild.js +++ /dev/null @@ -1,54 +0,0 @@ -const esbuild = require("esbuild") - -const production = process.argv.includes("--production") -const watch = process.argv.includes("--watch") - -/** - * @type {import('esbuild').Plugin} - */ -const esbuildProblemMatcherPlugin = { - name: "esbuild-problem-matcher", - - setup(build) { - build.onStart(() => { - console.log("[watch] build started") - }) - build.onEnd((result) => { - result.errors.forEach(({ text, location }) => { - console.error(`✘ [ERROR] ${text}`) - console.error(` ${location.file}:${location.line}:${location.column}:`) - }) - console.log("[watch] build finished") - }) - }, -} - -async function main() { - const ctx = await esbuild.context({ - entryPoints: ["src/extension.ts"], - bundle: true, - format: "cjs", - minify: production, - sourcemap: !production, - sourcesContent: false, - platform: "node", - outfile: "dist/extension.js", - external: ["vscode"], - logLevel: "silent", - plugins: [ - /* add to the end of plugins array */ - esbuildProblemMatcherPlugin, - ], - }) - if (watch) { - await ctx.watch() - } else { - await ctx.rebuild() - await ctx.dispose() - } -} - -main().catch((e) => { - console.error(e) - process.exit(1) -}) diff --git a/sdks/vscode/eslint.config.mjs b/sdks/vscode/eslint.config.mjs deleted file mode 100644 index bcaaf8a9666..00000000000 --- a/sdks/vscode/eslint.config.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import typescriptEslint from "@typescript-eslint/eslint-plugin" -import tsParser from "@typescript-eslint/parser" - -export default [ - { - files: ["**/*.ts"], - }, - { - plugins: { - "@typescript-eslint": typescriptEslint, - }, - - languageOptions: { - parser: tsParser, - ecmaVersion: 2022, - sourceType: "module", - }, - - rules: { - "@typescript-eslint/naming-convention": [ - "warn", - { - selector: "import", - format: ["camelCase", "PascalCase"], - }, - ], - - curly: "warn", - eqeqeq: "warn", - "no-throw-literal": "warn", - semi: "warn", - }, - }, -] diff --git a/sdks/vscode/images/button-dark.svg b/sdks/vscode/images/button-dark.svg deleted file mode 120000 index c0e444a520a..00000000000 --- a/sdks/vscode/images/button-dark.svg +++ /dev/null @@ -1 +0,0 @@ -../../../packages/identity/mark.svg \ No newline at end of file diff --git a/sdks/vscode/images/button-light.svg b/sdks/vscode/images/button-light.svg deleted file mode 120000 index 4120d51f62e..00000000000 --- a/sdks/vscode/images/button-light.svg +++ /dev/null @@ -1 +0,0 @@ -../../../packages/identity/mark-light.svg \ No newline at end of file diff --git a/sdks/vscode/images/icon.png b/sdks/vscode/images/icon.png deleted file mode 120000 index d6bfa6e7caa..00000000000 --- a/sdks/vscode/images/icon.png +++ /dev/null @@ -1 +0,0 @@ -../../../packages/identity/mark-512x512.png \ No newline at end of file diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json deleted file mode 100644 index 2150f0f7147..00000000000 --- a/sdks/vscode/package.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "name": "opencode", - "displayName": "opencode", - "description": "opencode for VS Code", - "version": "7.3.0", - "publisher": "sst-dev", - "repository": { - "type": "git", - "url": "https://github.com/Kilo-Org/kilocode" - }, - "license": "MIT", - "icon": "images/icon.png", - "galleryBanner": { - "color": "#000000", - "theme": "dark" - }, - "engines": { - "vscode": "^1.94.0" - }, - "categories": [ - "Other" - ], - "activationEvents": [], - "main": "./dist/extension.js", - "contributes": { - "commands": [ - { - "command": "opencode.openTerminal", - "title": "Open opencode", - "icon": { - "light": "images/button-dark.svg", - "dark": "images/button-light.svg" - } - }, - { - "command": "opencode.openNewTerminal", - "title": "Open opencode in new tab", - "icon": { - "light": "images/button-dark.svg", - "dark": "images/button-light.svg" - } - }, - { - "command": "opencode.addFilepathToTerminal", - "title": "Add Filepath to Terminal" - } - ], - "menus": { - "editor/title": [ - { - "command": "opencode.openNewTerminal", - "group": "navigation" - } - ] - }, - "keybindings": [ - { - "command": "opencode.openTerminal", - "title": "Run opencode", - "key": "cmd+escape", - "mac": "cmd+escape", - "win": "ctrl+escape", - "linux": "ctrl+escape" - }, - { - "command": "opencode.openNewTerminal", - "title": "Run opencode", - "key": "cmd+shift+escape", - "mac": "cmd+shift+escape", - "win": "ctrl+shift+escape", - "linux": "ctrl+shift+escape" - }, - { - "command": "opencode.addFilepathToTerminal", - "title": "opencode: Insert At-Mentioned", - "key": "cmd+alt+k", - "mac": "cmd+alt+k", - "win": "ctrl+alt+K", - "linux": "ctrl+alt+K" - } - ] - }, - "scripts": { - "vscode:prepublish": "bun run package", - "compile": "bun run check-types && bun run lint && node esbuild.js", - "watch:esbuild": "node esbuild.js --watch", - "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", - "package": "bun run check-types && bun run lint && node esbuild.js --production", - "compile-tests": "tsc -p . --outDir out", - "watch-tests": "tsc -p . -w --outDir out", - "pretest": "bun run compile-tests && bun run compile && bun run lint", - "check-types": "tsc --noEmit", - "lint": "eslint src", - "test": "vscode-test" - }, - "devDependencies": { - "@types/vscode": "^1.94.0", - "@types/mocha": "^10.0.10", - "@types/node": "20.x", - "@typescript-eslint/eslint-plugin": "^8.31.1", - "@typescript-eslint/parser": "^8.31.1", - "eslint": "^9.25.1", - "esbuild": "^0.25.3", - "typescript": "^5.8.3", - "@vscode/test-cli": "^0.0.11", - "@vscode/test-electron": "^2.5.2" - }, - "dependencies": {}, - "peerDependencies": {} -} diff --git a/sdks/vscode/script/publish b/sdks/vscode/script/publish deleted file mode 100755 index bc48f574c2a..00000000000 --- a/sdks/vscode/script/publish +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Get the latest Git tag -latest_tag=$(git tag --sort=committerdate | grep -E '^vscode-v[0-9]+\.[0-9]+\.[0-9]+$' | tail -1) -if [ -z "$latest_tag" ]; then - echo "No tags found" - exit 1 -fi -echo "Latest tag: $latest_tag" -version=$(echo "$latest_tag" | sed 's/^vscode-v//') -echo "Latest version: $version" - -# package-marketplace -vsce package --no-git-tag-version --no-update-package-json --no-dependencies --skip-license -o dist/opencode.vsix "$version" - -# publish-marketplace -vsce publish --packagePath dist/opencode.vsix - -# publish-openvsx -npx ovsx publish dist/opencode.vsix -p "$OPENVSX_TOKEN" diff --git a/sdks/vscode/script/release b/sdks/vscode/script/release deleted file mode 100755 index 28de15fd8d1..00000000000 --- a/sdks/vscode/script/release +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -# Parse command line arguments -minor=false -while [ "$#" -gt 0 ]; do - case "$1" in - --minor) minor=true; shift 1;; - *) echo "Unknown parameter: $1"; exit 1;; - esac -done - -# Get the latest Git tag -git fetch --force --tags -latest_tag=$(git tag --sort=committerdate | grep -E '^vscode-v[0-9]+\.[0-9]+\.[0-9]+$' | tail -1) -if [ -z "$latest_tag" ]; then - echo "No tags found" - exit 1 -fi - -echo "Latest tag: $latest_tag" - -# Split the tag into major, minor, and patch numbers -IFS='.' read -ra VERSION <<< "$latest_tag" - -if [ "$minor" = true ]; then - # Increment the minor version and reset patch to 0 - minor_number=${VERSION[1]} - let "minor_number++" - new_version="${VERSION[0]}.$minor_number.0" -else - # Increment the patch version - patch_number=${VERSION[2]} - let "patch_number++" - new_version="${VERSION[0]}.${VERSION[1]}.$patch_number" -fi - -echo "New version: $new_version" - -# Tag -git tag $new_version -git push --tags \ No newline at end of file diff --git a/sdks/vscode/src/extension.ts b/sdks/vscode/src/extension.ts deleted file mode 100644 index d141420b18a..00000000000 --- a/sdks/vscode/src/extension.ts +++ /dev/null @@ -1,137 +0,0 @@ -// This method is called when your extension is deactivated -export function deactivate() {} - -import * as vscode from "vscode" - -const TERMINAL_NAME = "opencode" - -export function activate(context: vscode.ExtensionContext) { - const openNewTerminalDisposable = vscode.commands.registerCommand("opencode.openNewTerminal", async () => { - await openTerminal() - }) - - const openTerminalDisposable = vscode.commands.registerCommand("opencode.openTerminal", async () => { - // An opencode terminal already exists => focus it - const existingTerminal = vscode.window.terminals.find((t) => t.name === TERMINAL_NAME) - if (existingTerminal) { - existingTerminal.show() - return - } - - await openTerminal() - }) - - let addFilepathDisposable = vscode.commands.registerCommand("opencode.addFilepathToTerminal", async () => { - const fileRef = getActiveFile() - if (!fileRef) { - return - } - - const terminal = vscode.window.activeTerminal - if (!terminal) { - return - } - - if (terminal.name === TERMINAL_NAME) { - // @ts-ignore - const port = terminal.creationOptions.env?.["_EXTENSION_KILO_PORT"] - port ? await appendPrompt(parseInt(port), fileRef) : terminal.sendText(fileRef, false) - terminal.show() - } - }) - - context.subscriptions.push(openNewTerminalDisposable, openTerminalDisposable, addFilepathDisposable) - - async function openTerminal() { - // Create a new terminal in split screen - const port = Math.floor(Math.random() * (65535 - 16384 + 1)) + 16384 - const terminal = vscode.window.createTerminal({ - name: TERMINAL_NAME, - iconPath: { - light: vscode.Uri.file(context.asAbsolutePath("images/button-dark.svg")), - dark: vscode.Uri.file(context.asAbsolutePath("images/button-light.svg")), - }, - location: { - viewColumn: vscode.ViewColumn.Beside, - preserveFocus: false, - }, - env: { - _EXTENSION_KILO_PORT: port.toString(), - KILO_CALLER: "vscode", - }, - }) - - terminal.show() - terminal.sendText(`opencode --port ${port}`) - - const fileRef = getActiveFile() - if (!fileRef) { - return - } - - // Wait for the terminal to be ready - let tries = 10 - let connected = false - do { - await new Promise((resolve) => setTimeout(resolve, 200)) - try { - await fetch(`http://localhost:${port}/app`) - connected = true - break - } catch {} - - tries-- - } while (tries > 0) - - // If connected, append the prompt to the terminal - if (connected) { - await appendPrompt(port, `In ${fileRef}`) - terminal.show() - } - } - - async function appendPrompt(port: number, text: string) { - await fetch(`http://localhost:${port}/tui/append-prompt`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ text }), - }) - } - - function getActiveFile() { - const activeEditor = vscode.window.activeTextEditor - if (!activeEditor) { - return - } - - const document = activeEditor.document - const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri) - if (!workspaceFolder) { - return - } - - // Get the relative path from workspace root - const relativePath = vscode.workspace.asRelativePath(document.uri) - let filepathWithAt = `@${relativePath}` - - // Check if there's a selection and add line numbers - const selection = activeEditor.selection - if (!selection.isEmpty) { - // Convert to 1-based line numbers - const startLine = selection.start.line + 1 - const endLine = selection.end.line + 1 - - if (startLine === endLine) { - // Single line selection - filepathWithAt += `#L${startLine}` - } else { - // Multi-line selection - filepathWithAt += `#L${startLine}-${endLine}` - } - } - - return filepathWithAt - } -} diff --git a/sdks/vscode/sst-env.d.ts b/sdks/vscode/sst-env.d.ts deleted file mode 100644 index f25b9714550..00000000000 --- a/sdks/vscode/sst-env.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* This file is auto-generated by SST. Do not edit. */ -/* tslint:disable */ -/* eslint-disable */ -/* deno-fmt-ignore-file */ -/* biome-ignore-all lint: auto-generated */ - -/// - -import "sst" -export {} diff --git a/sdks/vscode/tsconfig.json b/sdks/vscode/tsconfig.json deleted file mode 100644 index 710f9ede464..00000000000 --- a/sdks/vscode/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "Node16", - "target": "ES2022", - "lib": ["ES2022"], - "sourceMap": true, - "rootDir": "src", - "typeRoots": ["./node_modules/@types"], - "strict": true /* enable all strict type-checking options */, - "skipLibCheck": true - /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - } -} diff --git a/specs/v2/todo.md b/specs/v2/todo.md new file mode 100644 index 00000000000..77c650e55fc --- /dev/null +++ b/specs/v2/todo.md @@ -0,0 +1,59 @@ +# TODO + +ok we need to work towards a launch of v2 so we can get out of this rebuild phase + +## Kill Hono - Kit + +Hono needs to go away so zod can go away. this is almost done + +## New Data Mode - Dax + +This is mostly done. I'm working through modeling subagents, skill invocations +and shell commands. + +## Rework agent loop - Kit? + +I think this needs to be done so we can take advantage of the simpler data +model. It can stop doing all the + +## Rework compaction - Aiden? + +The new agent loop needs to trigger compaction properly + +## Plugin API design - James? + +We need to figure out how we want server plugins to work and what hooks are useful. + +Some ideas: + +- plugins get immer drafts so bad mutations can be thrown away +- plugins get global "opencode" instance like in that post i showed +- opencode instance has stuff like `opencode.session.prompt()` or + `opencode.tool.register({...})` + +## Rework Config - ??? + +We should do another pass on config to clean up any mistakes we made with it and +simplify as much as possible. Old configs should get auto-converted to new + +## Auth - ??? + +I have a basic auth system that can track any kind of auth, not just providers + +## Model Database - ??? + +I have a basic model service that allows for models to be registered dynamically + +## Provider - ??? + +Providers should register as plugins and autoload based on whatever logic they +want / config. They should register models into model database + +## Event - Kit + +I have this v2/event.ts but it needs to be self contained instead of using the +old bus system + +## Everything is hotreloadable - ??? + +Instead of needing to tear down things when something changes every service should emit granular events so services can react to them and reconfigure themselves. Allows frontend to receive these too, eg model.added. also prevents startup from blocking diff --git a/turbo.json b/turbo.json index 90cf038a0c4..c1798ac2a7e 100644 --- a/turbo.json +++ b/turbo.json @@ -10,6 +10,10 @@ "dependsOn": [], "outputs": ["dist/**"] }, + "@kilocode/cli#build": { + "dependsOn": ["@kilocode/sdk#build"], + "outputs": ["dist/**"] + }, "@kilocode/cli#test": { "dependsOn": ["^build"], "outputs": [], @@ -28,6 +32,21 @@ "@kilocode/kilo-jetbrains#build": { "dependsOn": ["@kilocode/cli#build"], "outputs": ["build/distributions/**"] + }, + "@kilocode/kilo-jetbrains#typecheck": { + "outputs": [] + }, + "@kilocode/kilo-jetbrains#test:ci": { + "outputs": [".artifacts/unit/junit.xml"] + }, + "@opencode-ai/ui#test": { + "dependsOn": ["^build"], + "outputs": [] + }, + "@opencode-ai/ui#test:ci": { + "dependsOn": ["^build"], + "outputs": [".artifacts/unit/junit.xml"], + "passThroughEnv": ["*"] } } }