diff --git a/packages/action/examples/patch-pulse-bot.yml b/packages/action/examples/patchpulse.yml
similarity index 99%
rename from packages/action/examples/patch-pulse-bot.yml
rename to packages/action/examples/patchpulse.yml
index 4484fec..6bf3cfd 100644
--- a/packages/action/examples/patch-pulse-bot.yml
+++ b/packages/action/examples/patchpulse.yml
@@ -1,4 +1,4 @@
-# Example: add this file to your repo at .github/workflows/patch-pulse-bot.yml
+# Example: add this file to your repo at .github/workflows/patchpulse.yml
#
# This workflow runs PatchPulse weekly and opens one PR per outdated package (or
# package group). PRs include the version diff, release notes links, a
diff --git a/packages/docs/.astro/content-assets.mjs b/packages/docs/.astro/content-assets.mjs
index 83e3505..2b8b823 100644
--- a/packages/docs/.astro/content-assets.mjs
+++ b/packages/docs/.astro/content-assets.mjs
@@ -1,4 +1 @@
-
-
-export default new Map([]);
-
\ No newline at end of file
+export default new Map();
\ No newline at end of file
diff --git a/packages/docs/.astro/content-modules.mjs b/packages/docs/.astro/content-modules.mjs
index 20158c8..341093e 100644
--- a/packages/docs/.astro/content-modules.mjs
+++ b/packages/docs/.astro/content-modules.mjs
@@ -4,6 +4,7 @@ export default new Map([
["src/content/docs/cli/commands.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcli%2Fcommands.mdx&astroContentModuleFlag=true")],
["src/content/docs/cli/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcli%2Fconfiguration.mdx&astroContentModuleFlag=true")],
["src/content/docs/cli/overview.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcli%2Foverview.mdx&astroContentModuleFlag=true")],
+["src/content/docs/discord-bot.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fdiscord-bot.mdx&astroContentModuleFlag=true")],
["src/content/docs/github-action/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgithub-action%2Fconfiguration.mdx&astroContentModuleFlag=true")],
["src/content/docs/github-action/overview.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgithub-action%2Foverview.mdx&astroContentModuleFlag=true")],
["src/content/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")],
diff --git a/packages/docs/.astro/data-store.json b/packages/docs/.astro/data-store.json
index eca5a24..ddd7875 100644
--- a/packages/docs/.astro/data-store.json
+++ b/packages/docs/.astro/data-store.json
@@ -1 +1 @@
-[["Map",1,2,136,137],"docs",["Map",3,4,37,38,49,50,60,61,71,72,92,93,103,104,114,115,125,126],"404",{"id":3,"data":5,"body":34,"filePath":35,"digest":36,"deferredRender":32},{"title":6,"description":7,"editUrl":8,"head":9,"template":10,"hero":11,"sidebar":31,"pagefind":8,"draft":8},"Page Not Found","The requested docs page could not be found.",false,[],"splash",{"tagline":12,"actions":13},"The page you requested does not exist or may have moved.",[14,21,26],{"text":15,"link":16,"variant":17,"icon":18},"Go Home","/","primary",{"type":19,"name":20},"icon","right-arrow",{"text":22,"link":23,"variant":24,"icon":25},"Read the Introduction","/introduction","minimal",{"type":19,"name":20},{"text":27,"link":28,"variant":24,"icon":29},"Report Broken Link","https://github.com/barrymichaeldoyle/patch-pulse/issues/new?template=bug_report.md&labels=bug&title=Broken%20docs%20link%3A%20&body=I%20reached%20the%20Patch%20Pulse%20docs%20404%20page%20from%20an%20outdated%20or%20broken%20link.%0A%0ABroken%20URL%3A%20%0AReferrer%20(optional)%3A%20%0AWhat%20I%20expected%20to%20find%3A%20",{"type":19,"name":30},"external",{"hidden":32,"attrs":33},true,{},"If you followed an old Patch Pulse docs link, the page may have been renamed as the docs site structure evolved.\n\nUse the navigation or search to find the current page.","src/content/docs/404.mdx","bea4156dc90062f4","cli/commands",{"id":37,"data":39,"body":46,"filePath":47,"digest":48,"deferredRender":32},{"title":40,"description":41,"editUrl":32,"head":42,"template":43,"sidebar":44,"pagefind":32,"draft":8},"Commands & Flags","All CLI flags supported by Patch Pulse.",[],"doc",{"hidden":8,"attrs":45},{},"import { Aside } from '@astrojs/starlight/components';\n\n## Usage\n\n```bash\nnpx patch-pulse [flags]\n```\n\n## Flags\n\n### `--help`, `-h`\n\nPrint usage information and exit.\n\n```bash\nnpx patch-pulse --help\n```\n\n---\n\n### `--version`, `-v`\n\nPrint the current CLI version and exit.\n\n```bash\nnpx patch-pulse --version\n```\n\n---\n\n### `--about`\n\nPrint information about Patch Pulse and exit.\n\n```bash\nnpx patch-pulse --about\n```\n\n---\n\n### `--license`, `-l`\n\nPrint the license and exit.\n\n```bash\nnpx patch-pulse --license\n```\n\n---\n\n### `--interactive`, `-i` / `--no-interactive`\n\nShow an interactive update prompt after the dependency summary.\n\n```bash\nnpx patch-pulse --interactive\nnpx patch-pulse --no-interactive\n```\n\nCLI flags override the [`interactive`](../configuration#interactive) setting in your config file.\n\n---\n\n### `--skip`, `-s`\n\nComma-separated list of package names or glob patterns to skip.\n\n```bash\nnpx patch-pulse --skip \"lodash,@types/*\"\n```\n\nMerged with any `skip` entries in your [config file](../configuration#skip).\n\n---\n\n### `--package-manager`\n\nOverride auto-detected package manager. Accepted values: `npm`, `pnpm`, `yarn`, `bun`.\n\n```bash\nnpx patch-pulse --package-manager pnpm\n```\n\n---\n\n### `--project`\n\nFocus on a single workspace project by path or package name.\n\n```bash\nnpx patch-pulse --project packages/app\nnpx patch-pulse --project my-app\n```\n\n---\n\n### `--expand`\n\nIn a monorepo, print the full dependency list for every workspace — including those that are up to date.\n\n```bash\nnpx patch-pulse --expand\n```\n\n---\n\n### `--hide-clean`\n\nHide workspaces that have no outdated dependencies from the output.\n\n```bash\nnpx patch-pulse --hide-clean\n```\n\n---\n\n### `--json`\n\nOutput results as JSON instead of the human-readable terminal display. Useful for scripts, CI, or editor integrations.\n\n```bash\nnpx patch-pulse --json\n```\n\nWhen running through the root pnpm script, use `pnpm -s` to suppress pnpm's banner before the JSON:\n\n```bash\npnpm -s pp -- --json\n```\n\n---\n\n### `--fail`\n\nExit with code `1` if any outdated packages are found. Use as a CI gate.\n\n```bash\nnpx patch-pulse --fail\nnpx patch-pulse --json --fail\n```\n\n\u003CAside type=\"tip\">\n Combine `--json` and `--fail` for machine-readable output with a non-zero exit\n code when updates are available.\n\u003C/Aside>","src/content/docs/cli/commands.mdx","6fe9e11a9f69c12f","cli/configuration",{"id":49,"data":51,"body":57,"filePath":58,"digest":59,"deferredRender":32},{"title":52,"description":53,"editUrl":32,"head":54,"template":43,"sidebar":55,"pagefind":32,"draft":8},"Configuration","Persistent configuration for the Patch Pulse CLI.",[],{"hidden":8,"attrs":56},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe CLI supports a configuration file for persistent settings. Use `patchpulse.json` in your project root going forward. These filenames are supported:\n\n- `patchpulse.json`\n- `patchpulse.config.json`\n- `.patchpulserc.json`\n- `.patchpulserc`\n\n## Example\n\n```json\n{\n \"skip\": [\"lodash\", \"@types/*\", \"test-*\"],\n \"ignorePaths\": [\"packages/cli/e2e\"],\n \"packageManager\": \"pnpm\",\n \"interactive\": true\n}\n```\n\n## Options\n\n### `skip`\n\nAn array of package names or glob patterns to exclude from version checks.\n\n```json\n{\n \"skip\": [\"lodash\", \"@types/*\", \"test-*\", \"*-dev\"]\n}\n```\n\nSupported pattern syntax:\n\n| Pattern | Matches |\n| ------------ | ------------------------------------ |\n| `\"lodash\"` | Exact package name |\n| `\"@types/*\"` | Any package under the `@types` scope |\n| `\"test-*\"` | Any package starting with `test-` |\n| `\"*-dev\"` | Any package ending with `-dev` |\n\n\u003CAside>\n `--skip` passed on the command line is **merged** with the config file's\n `skip` array — it does not replace it.\n\u003C/Aside>\n\n---\n\n### `ignorePaths`\n\nAn array of directory or file paths to exclude from workspace scanning. Useful for ignoring fixture directories or generated packages.\n\n```json\n{\n \"ignorePaths\": [\"packages/cli/e2e\", \"**/fixtures\", \"packages/*/dist\"]\n}\n```\n\nBoth exact paths and glob patterns are supported.\n\n---\n\n### `includePaths`\n\nAn array of paths to force-include in the workspace scan, even if they would otherwise be excluded (e.g. by `.gitignore`). `ignorePaths` still takes priority.\n\n```json\n{\n \"includePaths\": [\"tools/internal-package\"]\n}\n```\n\n---\n\n### `packageManager`\n\nOverride the auto-detected package manager. Accepted values: `npm`, `pnpm`, `yarn`, `bun`.\n\n```json\n{\n \"packageManager\": \"pnpm\"\n}\n```\n\n---\n\n### `interactive`\n\nEnable the interactive update prompt automatically after every run.\n\n```json\n{\n \"interactive\": true\n}\n```\n\n---\n\n## CLI vs file precedence\n\nCLI flags take precedence over file settings for most options. The `skip` array is an exception — values from both sources are **merged**.\n\n```bash\n# Overrides packageManager and interactive, but merges with file's skip list\nnpx patch-pulse --skip \"react,react-dom\" --package-manager npm --no-interactive\n```","src/content/docs/cli/configuration.mdx","8cd6d19ecf7642b6","cli/overview",{"id":60,"data":62,"body":68,"filePath":69,"digest":70,"deferredRender":32},{"title":63,"description":64,"editUrl":32,"head":65,"template":43,"sidebar":66,"pagefind":32,"draft":8},"CLI Overview","The Patch Pulse command-line tool.",[],{"hidden":8,"attrs":67},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse CLI scans your project for `package.json` files and reports which dependencies have newer versions available on the npm registry.\n\n## Key features\n\n- **Zero runtime dependencies** — nothing extra is installed into your project\n- **Monorepo-aware** — scans all workspaces from the repo root, including pnpm `catalog:` support\n- **Interactive updates** — optionally apply patch, minor, or all updates in one step\n- **CI-friendly** — `--json` output and a `--fail` exit-code gate for pipelines\n- **Configurable** — persistent settings via `patchpulse.json`\n\n## Installation\n\nRun without installing:\n\n```bash\nnpx patch-pulse\n```\n\nOr install globally:\n\n```bash\nnpm install -g patch-pulse\n```\n\n## Basic usage\n\nRun from any project directory:\n\n```bash\nnpx patch-pulse\n```\n\nPatch Pulse will scan every `package.json` it finds (excluding `node_modules`) and display a summary of outdated dependencies grouped by project and dependency type.\n\n\u003CAside>\n `workspace:*` dependencies are ignored automatically. pnpm `catalog:` entries\n are resolved from `pnpm-workspace.yaml`.\n\u003C/Aside>\n\n## Enabling interactive updates\n\nPass `--interactive` (or `-i`) to get a prompt after the summary that lets you apply patch, minor, or all updates in one step:\n\n```bash\nnpx patch-pulse --interactive\n```\n\nYou can also enable this permanently in your [configuration file](../configuration).\n\n## Debugging\n\nTo log npm registry lookup failures and network errors, set the `PATCH_PULSE_DEBUG` environment variable:\n\n```bash\nPATCH_PULSE_DEBUG=1 npx patch-pulse\n```","src/content/docs/cli/overview.mdx","6bd3663aa262e749","index",{"id":71,"data":73,"body":89,"filePath":90,"digest":91,"deferredRender":32},{"title":74,"description":75,"editUrl":32,"head":76,"template":10,"hero":77,"sidebar":87,"pagefind":32,"draft":8},"Patch Pulse","Keep a pulse on your npm dependencies.",[],{"tagline":75,"actions":78},[79,83],{"text":80,"link":81,"variant":17,"icon":82},"Get Started","./introduction",{"type":19,"name":20},{"text":84,"link":85,"variant":24,"icon":86},"View on GitHub","https://github.com/barrymichaeldoyle/patch-pulse",{"type":19,"name":30},{"hidden":8,"attrs":88},{},"import { CardGrid, LinkCard } from '@astrojs/starlight/components';\n\n## Products\n\n\u003CCardGrid>\n \u003CLinkCard\n title=\"CLI\"\n href=\"./cli/overview\"\n description=\"Scan projects and monorepos for outdated npm dependencies.\"\n />\n \u003CLinkCard\n title=\"Slack Bot\"\n href=\"./slack-bot\"\n description=\"Get update notifications in Slack when tracked packages release new versions.\"\n />\n \u003CLinkCard\n title=\"VS Code Extension\"\n href=\"./vscode/overview\"\n description=\"See dependency version status inline in your package.json files.\"\n />\n\u003C/CardGrid>","src/content/docs/index.mdx","d6fa694074a91cba","introduction",{"id":92,"data":94,"body":100,"filePath":101,"digest":102,"deferredRender":32},{"title":95,"description":96,"editUrl":32,"head":97,"template":43,"sidebar":98,"pagefind":32,"draft":8},"Introduction","What is Patch Pulse and what does it offer?",[],{"hidden":8,"attrs":99},{},"Patch Pulse is a suite of tools that help you keep your npm dependencies up to date.\n\n## What's in the ecosystem?\n\n| Tool | Description |\n| --------------------------------------- | ---------------------------------------------------------------------------- |\n| [CLI](../cli/overview) | Zero-dependency command-line tool to scan your project for outdated packages |\n| [VS Code Extension](../vscode/overview) | Inline version information directly in your `package.json` files |\n| [Slack Bot](../slack-bot) | Get notified in Slack when packages you depend on release new versions |\n\n## Core concepts\n\nPatch Pulse checks your dependencies against the npm registry and tells you which packages have newer versions available — breaking them down by **patch**, **minor**, and **major** updates so you can decide what to act on.\n\nIt is **monorepo-aware**: running from the root of a workspace will scan every `package.json` found under the project, with full support for pnpm `catalog:` entries.\n\n## Quick start\n\nThe fastest way to try it is with the CLI — no install required:\n\n```bash\nnpx patch-pulse\n```\n\nSee the [CLI overview](../cli/overview) to dive deeper.","src/content/docs/introduction.mdx","92bb4a870199cf4e","slack-bot",{"id":103,"data":105,"body":111,"filePath":112,"digest":113,"deferredRender":32},{"title":106,"description":107,"editUrl":32,"head":108,"template":43,"sidebar":109,"pagefind":32,"draft":8},"Slack Bot","Get notified in Slack when packages you depend on release new versions.",[],{"hidden":8,"attrs":110},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse Slack Bot notifies your workspace whenever a package you depend on releases a new version — so your team stays informed without having to run the CLI manually.\n\n\u003Ca\n href=\"https://grand-yak-92.convex.site/slack/install\"\n style=\"display: inline-block; margin: 1rem 0 1.5rem;\"\n>\n \u003Cimg\n alt=\"Add to Slack\"\n height=\"40\"\n src=\"https://platform.slack-edge.com/img/add_to_slack.png\"\n srcset=\"https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x\"\n />\n\u003C/a>\n\n\u003CAside type=\"tip\">\n Installation takes about 30 seconds and is free. Patch Pulse needs at least 5\n active workspace installs before Slack will approve it for the official\n Marketplace. Installing now helps the project reach that threshold.\n\u003C/Aside>\n\n## How it works\n\nOnce installed, the bot monitors packages you care about and sends a Slack notification when a new version is published to the npm registry.","src/content/docs/slack-bot.mdx","9fceb38589f68d49","vscode/overview",{"id":114,"data":116,"body":122,"filePath":123,"digest":124,"deferredRender":32},{"title":117,"description":118,"editUrl":32,"head":119,"template":43,"sidebar":120,"pagefind":32,"draft":8},"VS Code Extension Overview","The Patch Pulse VS Code extension.",[],{"hidden":8,"attrs":121},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse VS Code extension shows inline version information for packages in your `package.json` files, so you can see which dependencies are outdated without leaving the editor.\n\n\u003CAside type=\"caution\">\n The extension is currently in early development. Features and settings are\n subject to change.\n\u003C/Aside>\n\n## Features\n\n- **Inline decorations** — version status shown directly next to each dependency in `package.json`\n- **Automatic checks** — versions are checked when a `package.json` file is opened\n- **Manual refresh** — trigger a re-check at any time via the command palette\n\n## Commands\n\nThe following commands are available in the VS Code command palette (`Cmd/Ctrl + Shift + P`):\n\n| Command | Description |\n| --------------------------------------- | -------------------------------------------- |\n| `Patch Pulse: Check Package Versions` | Run a version check on the current workspace |\n| `Patch Pulse: Refresh Package Versions` | Refresh previously checked version data |\n\n## Activation\n\nThe extension activates automatically when:\n\n- A JSON file is opened, or\n- A `package.json` file is detected anywhere in the workspace\n\nSee [Settings](../settings) for configuration options.","src/content/docs/vscode/overview.mdx","32f9cbbe0002dd14","vscode/settings",{"id":125,"data":127,"body":133,"filePath":134,"digest":135,"deferredRender":32},{"title":128,"description":129,"editUrl":32,"head":130,"template":43,"sidebar":131,"pagefind":32,"draft":8},"VS Code Settings","Configuration settings for the Patch Pulse VS Code extension.",[],{"hidden":8,"attrs":132},{},"All settings are available under the `patchPulse` namespace in VS Code's settings UI or `settings.json`.\n\n## Settings\n\n### `patchPulse.enabled`\n\nEnable or disable the Patch Pulse extension entirely.\n\n| | |\n| ----------- | --------- |\n| **Type** | `boolean` |\n| **Default** | `true` |\n\n---\n\n### `patchPulse.checkOnOpen`\n\nAutomatically check package versions when a `package.json` file is opened.\n\n| | |\n| ----------- | --------- |\n| **Type** | `boolean` |\n| **Default** | `true` |\n\n---\n\n### `patchPulse.updateInterval`\n\nHow often (in seconds) Patch Pulse should re-check versions in the background.\n\n| | |\n| ----------- | --------------- |\n| **Type** | `number` |\n| **Default** | `3600` (1 hour) |\n\n## Example `settings.json`\n\n```json\n{\n \"patchPulse.enabled\": true,\n \"patchPulse.checkOnOpen\": true,\n \"patchPulse.updateInterval\": 1800\n}\n```","src/content/docs/vscode/settings.mdx","36e2f25a483bbf1f","meta::meta",["Map",138,139,140,141,142,143],"astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://barrymichaeldoyle.github.io\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"where\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":false,\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[null,null,null],\"rehypePlugins\":[[null],null,[null,{\"themes\":[{\"name\":\"Night Owl No Italics\",\"type\":\"dark\",\"colors\":{\"focusBorder\":\"#122d42\",\"foreground\":\"#d6deeb\",\"disabledForeground\":\"#cccccc80\",\"descriptionForeground\":\"#d6deebb3\",\"errorForeground\":\"#ef5350\",\"icon.foreground\":\"#c5c5c5\",\"contrastActiveBorder\":null,\"contrastBorder\":\"#122d42\",\"textBlockQuote.background\":\"#7f7f7f1a\",\"textBlockQuote.border\":\"#007acc80\",\"textCodeBlock.background\":\"#4f4f4f\",\"textLink.activeForeground\":\"#3794ff\",\"textLink.foreground\":\"#3794ff\",\"textPreformat.foreground\":\"#d7ba7d\",\"textSeparator.foreground\":\"#ffffff2e\",\"editor.background\":\"#23262f\",\"editor.foreground\":\"#d6deeb\",\"editorLineNumber.foreground\":\"#4b6479\",\"editorLineNumber.activeForeground\":\"#c5e4fd\",\"editorActiveLineNumber.foreground\":\"#c6c6c6\",\"editor.selectionBackground\":\"#1d3b53\",\"editor.inactiveSelectionBackground\":\"#7e57c25a\",\"editor.selectionHighlightBackground\":\"#5f7e9779\",\"editorError.foreground\":\"#ef5350\",\"editorWarning.foreground\":\"#b39554\",\"editorInfo.foreground\":\"#3794ff\",\"editorHint.foreground\":\"#eeeeeeb2\",\"problemsErrorIcon.foreground\":\"#ef5350\",\"problemsWarningIcon.foreground\":\"#b39554\",\"problemsInfoIcon.foreground\":\"#3794ff\",\"editor.findMatchBackground\":\"#5f7e9779\",\"editor.findMatchHighlightBackground\":\"#1085bb5d\",\"editor.findRangeHighlightBackground\":\"#3a3d4166\",\"editorLink.activeForeground\":\"#4e94ce\",\"editorLightBulb.foreground\":\"#ffcc00\",\"editorLightBulbAutoFix.foreground\":\"#75beff\",\"diffEditor.insertedTextBackground\":\"#99b76d23\",\"diffEditor.insertedTextBorder\":\"#c5e47833\",\"diffEditor.removedTextBackground\":\"#ef535033\",\"diffEditor.removedTextBorder\":\"#ef53504d\",\"diffEditor.insertedLineBackground\":\"#9bb95533\",\"diffEditor.removedLineBackground\":\"#ff000033\",\"editorStickyScroll.background\":\"#011627\",\"editorStickyScrollHover.background\":\"#2a2d2e\",\"editorInlayHint.background\":\"#5f7e97cc\",\"editorInlayHint.foreground\":\"#ffffff\",\"editorInlayHint.typeBackground\":\"#5f7e97cc\",\"editorInlayHint.typeForeground\":\"#ffffff\",\"editorInlayHint.parameterBackground\":\"#5f7e97cc\",\"editorInlayHint.parameterForeground\":\"#ffffff\",\"editorPane.background\":\"#011627\",\"editorGroup.emptyBackground\":\"#011627\",\"editorGroup.focusedEmptyBorder\":null,\"editorGroupHeader.tabsBackground\":\"var(--sl-color-black)\",\"editorGroupHeader.tabsBorder\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"editorGroupHeader.noTabsBackground\":\"#011627\",\"editorGroupHeader.border\":null,\"editorGroup.border\":\"#011627\",\"editorGroup.dropBackground\":\"#7e57c273\",\"editorGroup.dropIntoPromptForeground\":\"#d6deeb\",\"editorGroup.dropIntoPromptBackground\":\"#021320\",\"editorGroup.dropIntoPromptBorder\":null,\"sideBySideEditor.horizontalBorder\":\"#011627\",\"sideBySideEditor.verticalBorder\":\"#011627\",\"scrollbar.shadow\":\"#010b14\",\"scrollbarSlider.background\":\"#ffffff17\",\"scrollbarSlider.hoverBackground\":\"#ffffff40\",\"scrollbarSlider.activeBackground\":\"#084d8180\",\"panel.background\":\"#011627\",\"panel.border\":\"#5f7e97\",\"panelTitle.activeBorder\":\"#5f7e97\",\"panelTitle.activeForeground\":\"#ffffffcc\",\"panelTitle.inactiveForeground\":\"#d6deeb80\",\"panelSectionHeader.background\":\"#80808051\",\"terminal.background\":\"#011627\",\"widget.shadow\":\"#011627\",\"editorWidget.background\":\"#021320\",\"editorWidget.foreground\":\"#d6deeb\",\"editorWidget.border\":\"#5f7e97\",\"quickInput.background\":\"#021320\",\"quickInput.foreground\":\"#d6deeb\",\"quickInputTitle.background\":\"#ffffff1a\",\"pickerGroup.foreground\":\"#d1aaff\",\"pickerGroup.border\":\"#011627\",\"editor.hoverHighlightBackground\":\"#7e57c25a\",\"editorHoverWidget.background\":\"#011627\",\"editorHoverWidget.foreground\":\"#d6deeb\",\"editorHoverWidget.border\":\"#5f7e97\",\"editorHoverWidget.statusBarBackground\":\"#011a2f\",\"titleBar.activeBackground\":\"var(--sl-color-black)\",\"titleBar.activeForeground\":\"var(--sl-color-text)\",\"titleBar.inactiveBackground\":\"#010e1a\",\"titleBar.inactiveForeground\":\"#eeefff99\",\"titleBar.border\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"toolbar.hoverBackground\":\"#5a5d5e50\",\"toolbar.activeBackground\":\"#63666750\",\"tab.activeBackground\":\"#0b2942\",\"tab.unfocusedActiveBackground\":\"#0b2942\",\"tab.inactiveBackground\":\"#01111d\",\"tab.unfocusedInactiveBackground\":\"#01111d\",\"tab.activeForeground\":\"var(--sl-color-text)\",\"tab.inactiveForeground\":\"#5f7e97\",\"tab.unfocusedActiveForeground\":\"#5f7e97\",\"tab.unfocusedInactiveForeground\":\"#5f7e97\",\"tab.hoverBackground\":null,\"tab.unfocusedHoverBackground\":null,\"tab.hoverForeground\":null,\"tab.unfocusedHoverForeground\":null,\"tab.border\":\"#272b3b\",\"tab.lastPinnedBorder\":\"#585858\",\"tab.activeBorder\":\"transparent\",\"tab.unfocusedActiveBorder\":\"#262a39\",\"tab.activeBorderTop\":\"var(--sl-color-accent-high)\",\"tab.unfocusedActiveBorderTop\":null,\"tab.hoverBorder\":null,\"tab.unfocusedHoverBorder\":null,\"tab.activeModifiedBorder\":\"#3399cc\",\"tab.inactiveModifiedBorder\":\"#3399cc80\",\"tab.unfocusedActiveModifiedBorder\":\"#3399cc80\",\"tab.unfocusedInactiveModifiedBorder\":\"#3399cc40\",\"badge.background\":\"#5f7e97\",\"badge.foreground\":\"#ffffff\",\"button.background\":\"#7e57c2cc\",\"button.foreground\":\"#ffffffcc\",\"button.border\":\"#122d42\",\"button.separator\":\"#ffffff52\",\"button.hoverBackground\":\"#7e57c2\",\"button.secondaryBackground\":\"#3a3d41\",\"button.secondaryForeground\":\"#ffffff\",\"button.secondaryHoverBackground\":\"#46494e\",\"dropdown.background\":\"#011627\",\"dropdown.foreground\":\"#ffffffcc\",\"dropdown.border\":\"#5f7e97\",\"list.activeSelectionBackground\":\"#234d708c\",\"list.activeSelectionForeground\":\"#ffffff\",\"tree.indentGuidesStroke\":\"#585858\",\"input.background\":\"#0b253a\",\"input.foreground\":\"#ffffffcc\",\"input.placeholderForeground\":\"#5f7e97\",\"inputOption.activeBorder\":\"#ffffffcc\",\"inputOption.hoverBackground\":\"#5a5d5e80\",\"inputOption.activeBackground\":\"#122d4266\",\"inputOption.activeForeground\":\"#ffffff\",\"inputValidation.infoBackground\":\"#00589ef2\",\"inputValidation.infoBorder\":\"#64b5f6\",\"inputValidation.warningBackground\":\"#675700f2\",\"inputValidation.warningBorder\":\"#ffca28\",\"inputValidation.errorBackground\":\"#ab0300f2\",\"inputValidation.errorBorder\":\"#ef5350\",\"keybindingLabel.background\":\"#8080802b\",\"keybindingLabel.foreground\":\"#cccccc\",\"keybindingLabel.border\":\"#33333399\",\"keybindingLabel.bottomBorder\":\"#44444499\",\"menu.foreground\":\"#ffffffcc\",\"menu.background\":\"#011627\",\"menu.selectionForeground\":\"#ffffff\",\"menu.selectionBackground\":\"#234d708c\",\"menu.separatorBackground\":\"#606060\",\"editor.snippetTabstopHighlightBackground\":\"#7c7c74c\",\"editor.snippetFinalTabstopHighlightBorder\":\"#525252\",\"terminal.ansiBlack\":\"#011627\",\"terminal.ansiRed\":\"#ef5350\",\"terminal.ansiGreen\":\"#22da6e\",\"terminal.ansiYellow\":\"#c5e478\",\"terminal.ansiBlue\":\"#82aaff\",\"terminal.ansiMagenta\":\"#c792ea\",\"terminal.ansiCyan\":\"#21c7a8\",\"terminal.ansiWhite\":\"#ffffff\",\"terminal.ansiBrightBlack\":\"#575656\",\"terminal.ansiBrightRed\":\"#ef5350\",\"terminal.ansiBrightGreen\":\"#22da6e\",\"terminal.ansiBrightYellow\":\"#ffeb95\",\"terminal.ansiBrightBlue\":\"#82aaff\",\"terminal.ansiBrightMagenta\":\"#c792ea\",\"terminal.ansiBrightCyan\":\"#7fdbca\",\"terminal.ansiBrightWhite\":\"#ffffff\",\"selection.background\":\"#4373c2\",\"input.border\":\"#5f7e97\",\"punctuation.definition.generic.begin.html\":\"#ef5350f2\",\"progress.background\":\"#7e57c2\",\"breadcrumb.foreground\":\"#a599e9\",\"breadcrumb.focusForeground\":\"#ffffff\",\"breadcrumb.activeSelectionForeground\":\"#ffffff\",\"breadcrumbPicker.background\":\"#001122\",\"list.invalidItemForeground\":\"#975f94\",\"list.dropBackground\":\"#011627\",\"list.focusBackground\":\"#010d18\",\"list.focusForeground\":\"#ffffff\",\"list.highlightForeground\":\"#ffffff\",\"list.hoverBackground\":\"#011627\",\"list.hoverForeground\":\"#ffffff\",\"list.inactiveSelectionBackground\":\"#0e293f\",\"list.inactiveSelectionForeground\":\"#5f7e97\",\"activityBar.background\":\"#011627\",\"activityBar.dropBackground\":\"#5f7e97\",\"activityBar.foreground\":\"#5f7e97\",\"activityBar.border\":\"#011627\",\"activityBarBadge.background\":\"#44596b\",\"activityBarBadge.foreground\":\"#ffffff\",\"sideBar.background\":\"#011627\",\"sideBar.foreground\":\"#89a4bb\",\"sideBar.border\":\"#011627\",\"sideBarTitle.foreground\":\"#5f7e97\",\"sideBarSectionHeader.background\":\"#011627\",\"sideBarSectionHeader.foreground\":\"#5f7e97\",\"editorCursor.foreground\":\"#80a4c2\",\"editor.wordHighlightBackground\":\"#f6bbe533\",\"editor.wordHighlightStrongBackground\":\"#e2a2f433\",\"editor.lineHighlightBackground\":\"#0003\",\"editor.rangeHighlightBackground\":\"#7e57c25a\",\"editorIndentGuide.background\":\"#5e81ce52\",\"editorIndentGuide.activeBackground\":\"#7e97ac\",\"editorRuler.foreground\":\"#5e81ce52\",\"editorCodeLens.foreground\":\"#5e82ceb4\",\"editorBracketMatch.background\":\"#5f7e974d\",\"editorOverviewRuler.currentContentForeground\":\"#7e57c2\",\"editorOverviewRuler.incomingContentForeground\":\"#7e57c2\",\"editorOverviewRuler.commonContentForeground\":\"#7e57c2\",\"editorGutter.background\":\"#011627\",\"editorGutter.modifiedBackground\":\"#e2b93d\",\"editorGutter.addedBackground\":\"#9ccc65\",\"editorGutter.deletedBackground\":\"#ef5350\",\"editorSuggestWidget.background\":\"#2c3043\",\"editorSuggestWidget.border\":\"#2b2f40\",\"editorSuggestWidget.foreground\":\"#d6deeb\",\"editorSuggestWidget.highlightForeground\":\"#ffffff\",\"editorSuggestWidget.selectedBackground\":\"#5f7e97\",\"debugExceptionWidget.background\":\"#011627\",\"debugExceptionWidget.border\":\"#5f7e97\",\"editorMarkerNavigation.background\":\"#0b2942\",\"editorMarkerNavigationError.background\":\"#ef5350\",\"editorMarkerNavigationWarning.background\":\"#ffca28\",\"peekView.border\":\"#5f7e97\",\"peekViewEditor.background\":\"#011627\",\"peekViewEditor.matchHighlightBackground\":\"#7e57c25a\",\"peekViewResult.background\":\"#011627\",\"peekViewResult.fileForeground\":\"#5f7e97\",\"peekViewResult.lineForeground\":\"#5f7e97\",\"peekViewResult.matchHighlightBackground\":\"#ffffffcc\",\"peekViewResult.selectionBackground\":\"#2e3250\",\"peekViewResult.selectionForeground\":\"#5f7e97\",\"peekViewTitle.background\":\"#011627\",\"peekViewTitleDescription.foreground\":\"#697098\",\"peekViewTitleLabel.foreground\":\"#5f7e97\",\"merge.currentHeaderBackground\":\"#5f7e97\",\"merge.incomingHeaderBackground\":\"#7e57c25a\",\"statusBar.background\":\"#011627\",\"statusBar.foreground\":\"#5f7e97\",\"statusBar.border\":\"#262a39\",\"statusBar.debuggingBackground\":\"#202431\",\"statusBar.debuggingBorder\":\"#1f2330\",\"statusBar.noFolderBackground\":\"#011627\",\"statusBar.noFolderBorder\":\"#25293a\",\"statusBarItem.activeBackground\":\"#202431\",\"statusBarItem.hoverBackground\":\"#202431\",\"statusBarItem.prominentBackground\":\"#202431\",\"statusBarItem.prominentHoverBackground\":\"#202431\",\"notifications.background\":\"#01111d\",\"notifications.border\":\"#262a39\",\"notificationCenter.border\":\"#262a39\",\"notificationToast.border\":\"#262a39\",\"notifications.foreground\":\"#ffffffcc\",\"notificationLink.foreground\":\"#80cbc4\",\"extensionButton.prominentForeground\":\"#ffffffcc\",\"extensionButton.prominentBackground\":\"#7e57c2cc\",\"extensionButton.prominentHoverBackground\":\"#7e57c2\",\"terminal.selectionBackground\":\"#1b90dd4d\",\"terminalCursor.background\":\"#234d70\",\"debugToolBar.background\":\"#011627\",\"welcomePage.buttonBackground\":\"#011627\",\"welcomePage.buttonHoverBackground\":\"#011627\",\"walkThrough.embeddedEditorBackground\":\"#011627\",\"gitDecoration.modifiedResourceForeground\":\"#a2bffc\",\"gitDecoration.deletedResourceForeground\":\"#ef535090\",\"gitDecoration.untrackedResourceForeground\":\"#c5e478ff\",\"gitDecoration.ignoredResourceForeground\":\"#395a75\",\"gitDecoration.conflictingResourceForeground\":\"#ffeb95cc\",\"source.elm\":\"#5f7e97\",\"string.quoted.single.js\":\"#ffffff\",\"meta.objectliteral.js\":\"#82aaff\"},\"fg\":\"#d6deeb\",\"bg\":\"#23262f\",\"semanticHighlighting\":false,\"settings\":[{\"name\":\"Changed\",\"scope\":[\"markup.changed\",\"meta.diff.header.git\",\"meta.diff.header.from-file\",\"meta.diff.header.to-file\"],\"settings\":{\"foreground\":\"#a2bffc\"}},{\"name\":\"Deleted\",\"scope\":[\"markup.deleted.diff\"],\"settings\":{\"foreground\":\"#f27775fe\"}},{\"name\":\"Inserted\",\"scope\":[\"markup.inserted.diff\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Global settings\",\"settings\":{\"background\":\"#011627\",\"foreground\":\"#d6deeb\"}},{\"name\":\"Comment\",\"scope\":[\"comment\"],\"settings\":{\"foreground\":\"#919f9f\",\"fontStyle\":\"\"}},{\"name\":\"String\",\"scope\":[\"string\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"String Quoted\",\"scope\":[\"string.quoted\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"Support Constant Math\",\"scope\":[\"support.constant.math\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Number\",\"scope\":[\"constant.numeric\",\"constant.character.numeric\"],\"settings\":{\"foreground\":\"#f78c6c\",\"fontStyle\":\"\"}},{\"name\":\"Built-in constant\",\"scope\":[\"constant.language\",\"punctuation.definition.constant\",\"variable.other.constant\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"User-defined constant\",\"scope\":[\"constant.character\",\"constant.other\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Constant Character Escape\",\"scope\":[\"constant.character.escape\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"RegExp String\",\"scope\":[\"string.regexp\",\"string.regexp keyword.other\"],\"settings\":{\"foreground\":\"#5ca7e4\"}},{\"name\":\"Comma in functions\",\"scope\":[\"meta.function punctuation.separator.comma\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"Variable\",\"scope\":[\"variable\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Keyword\",\"scope\":[\"punctuation.accessor\",\"keyword\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Storage\",\"scope\":[\"storage\",\"meta.var.expr\",\"meta.class meta.method.declaration meta.var.expr storage.type.js\",\"storage.type.property.js\",\"storage.type.property.ts\",\"storage.type.property.tsx\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type.function.arrow.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Class name\",\"scope\":[\"entity.name.class\",\"meta.class entity.name.type.class\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Inherited class\",\"scope\":[\"entity.other.inherited-class\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Function name\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Meta Tag\",\"scope\":[\"punctuation.definition.tag\",\"meta.tag\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"HTML Tag names\",\"scope\":[\"entity.name.tag\",\"meta.tag.other.html\",\"meta.tag.other.js\",\"meta.tag.other.tsx\",\"entity.name.tag.tsx\",\"entity.name.tag.js\",\"entity.name.tag\",\"meta.tag.js\",\"meta.tag.tsx\",\"meta.tag.html\"],\"settings\":{\"foreground\":\"#caece6\",\"fontStyle\":\"\"}},{\"name\":\"Tag attribute\",\"scope\":[\"entity.other.attribute-name\"],\"settings\":{\"fontStyle\":\"\",\"foreground\":\"#c5e478\"}},{\"name\":\"Entity Name Tag Custom\",\"scope\":[\"entity.name.tag.custom\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Library (function & constant)\",\"scope\":[\"support.function\",\"support.constant\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Support Constant Property Value meta\",\"scope\":[\"support.constant.meta.property-value\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Library class/type\",\"scope\":[\"support.type\",\"support.class\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Support Variable DOM\",\"scope\":[\"support.variable.dom\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Invalid\",\"scope\":[\"invalid\"],\"settings\":{\"background\":\"#ff2c83\",\"foreground\":\"#ffffff\"}},{\"name\":\"Invalid deprecated\",\"scope\":[\"invalid.deprecated\"],\"settings\":{\"foreground\":\"#ffffff\",\"background\":\"#d3423e\"}},{\"name\":\"Keyword Operator\",\"scope\":[\"keyword.operator\"],\"settings\":{\"foreground\":\"#7fdbca\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Relational\",\"scope\":[\"keyword.operator.relational\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Assignment\",\"scope\":[\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Arithmetic\",\"scope\":[\"keyword.operator.arithmetic\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Bitwise\",\"scope\":[\"keyword.operator.bitwise\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Increment\",\"scope\":[\"keyword.operator.increment\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Ternary\",\"scope\":[\"keyword.operator.ternary\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Double-Slashed Comment\",\"scope\":[\"comment.line.double-slash\"],\"settings\":{\"foreground\":\"#919f9f\"}},{\"name\":\"Object\",\"scope\":[\"object\"],\"settings\":{\"foreground\":\"#cdebf7\"}},{\"name\":\"Null\",\"scope\":[\"constant.language.null\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Meta Brace\",\"scope\":[\"meta.brace\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Meta Delimiter Period\",\"scope\":[\"meta.delimiter.period\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Punctuation Definition String\",\"scope\":[\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Punctuation Definition String Markdown\",\"scope\":[\"punctuation.definition.string.begin.markdown\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Boolean\",\"scope\":[\"constant.language.boolean\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Object Comma\",\"scope\":[\"object.comma\"],\"settings\":{\"foreground\":\"#ffffff\"}},{\"name\":\"Variable Parameter Function\",\"scope\":[\"variable.parameter.function\"],\"settings\":{\"foreground\":\"#7fdbca\",\"fontStyle\":\"\"}},{\"name\":\"Support Type Property Name & entity name tags\",\"scope\":[\"support.type.vendor.property-name\",\"support.constant.vendor.property-value\",\"support.type.property-name\",\"meta.property-list entity.name.tag\"],\"settings\":{\"foreground\":\"#80cbc4\",\"fontStyle\":\"\"}},{\"name\":\"Entity Name tag reference in stylesheets\",\"scope\":[\"meta.property-list entity.name.tag.reference\"],\"settings\":{\"foreground\":\"#57eaf1\"}},{\"name\":\"Constant Other Color RGB Value Punctuation Definition Constant\",\"scope\":[\"constant.other.color.rgb-value punctuation.definition.constant\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Constant Other Color\",\"scope\":[\"constant.other.color\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Keyword Other Unit\",\"scope\":[\"keyword.other.unit\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Meta Selector\",\"scope\":[\"meta.selector\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Entity Other Attribute Name Id\",\"scope\":[\"entity.other.attribute-name.id\"],\"settings\":{\"foreground\":\"#fad430\"}},{\"name\":\"Meta Property Name\",\"scope\":[\"meta.property-name\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Doctypes\",\"scope\":[\"entity.name.tag.doctype\",\"meta.tag.sgml.doctype\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Punctuation Definition Parameters\",\"scope\":[\"punctuation.definition.parameters\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Keyword Control Operator\",\"scope\":[\"keyword.control.operator\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Keyword Operator Logical\",\"scope\":[\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Variable Instances\",\"scope\":[\"variable.instance\",\"variable.other.instance\",\"variable.readwrite.instance\",\"variable.other.readwrite.instance\",\"variable.other.property\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Variable Property Other object property\",\"scope\":[\"variable.other.object.property\"],\"settings\":{\"foreground\":\"#faf39f\",\"fontStyle\":\"\"}},{\"name\":\"Variable Property Other object\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Entity Name Function\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#82aaff\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Comparison, returns, imports, and Keyword Operator Ruby\",\"scope\":[\"keyword.control.conditional.js\",\"keyword.operator.comparison\",\"keyword.control.flow.js\",\"keyword.control.flow.ts\",\"keyword.control.flow.tsx\",\"keyword.control.ruby\",\"keyword.control.def.ruby\",\"keyword.control.loop.js\",\"keyword.control.loop.ts\",\"keyword.control.import.js\",\"keyword.control.import.ts\",\"keyword.control.import.tsx\",\"keyword.control.from.js\",\"keyword.control.from.ts\",\"keyword.control.from.tsx\",\"keyword.control.conditional.js\",\"keyword.control.conditional.ts\",\"keyword.control.switch.js\",\"keyword.control.switch.ts\",\"keyword.operator.instanceof.js\",\"keyword.operator.expression.instanceof.ts\",\"keyword.operator.expression.instanceof.tsx\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Support Constant, `new` keyword, Special Method Keyword, `debugger`, other keywords\",\"scope\":[\"support.constant\",\"keyword.other.special-method\",\"keyword.other.new\",\"keyword.other.debugger\",\"keyword.control\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Support Function\",\"scope\":[\"support.function\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Invalid Broken\",\"scope\":[\"invalid.broken\"],\"settings\":{\"foreground\":\"#989da0\",\"background\":\"#F78C6C\"}},{\"name\":\"Invalid Unimplemented\",\"scope\":[\"invalid.unimplemented\"],\"settings\":{\"background\":\"#8BD649\",\"foreground\":\"#ffffff\"}},{\"name\":\"Invalid Illegal\",\"scope\":[\"invalid.illegal\"],\"settings\":{\"foreground\":\"#ffffff\",\"background\":\"#ec5f67\"}},{\"name\":\"Language Variable\",\"scope\":[\"variable.language\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Support Variable Property\",\"scope\":[\"support.variable.property\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Variable Function\",\"scope\":[\"variable.function\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Variable Interpolation\",\"scope\":[\"variable.interpolation\"],\"settings\":{\"foreground\":\"#ef787f\"}},{\"name\":\"Meta Function Call\",\"scope\":[\"meta.function-call\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Punctuation Section Embedded\",\"scope\":[\"punctuation.section.embedded\"],\"settings\":{\"foreground\":\"#e2817f\"}},{\"name\":\"Punctuation Tweaks\",\"scope\":[\"punctuation.terminator.expression\",\"punctuation.definition.arguments\",\"punctuation.definition.array\",\"punctuation.section.array\",\"meta.array\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"More Punctuation Tweaks\",\"scope\":[\"punctuation.definition.list.begin\",\"punctuation.definition.list.end\",\"punctuation.separator.arguments\",\"punctuation.definition.list\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Template Strings\",\"scope\":[\"string.template meta.template.expression\"],\"settings\":{\"foreground\":\"#e2817f\"}},{\"name\":\"Backticks(``) in Template Strings\",\"scope\":[\"string.template punctuation.definition.string\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Italics\",\"scope\":[\"italic\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"italic\"}},{\"name\":\"Bold\",\"scope\":[\"bold\"],\"settings\":{\"foreground\":\"#c5e478\",\"fontStyle\":\"bold\"}},{\"name\":\"Quote\",\"scope\":[\"quote\"],\"settings\":{\"foreground\":\"#969bb7\",\"fontStyle\":\"\"}},{\"name\":\"Raw Code\",\"scope\":[\"raw\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"CoffeeScript Variable Assignment\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#31e1eb\"}},{\"name\":\"CoffeeScript Parameter Function\",\"scope\":[\"variable.parameter.function.coffee\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"CoffeeScript Assignments\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"C# Readwrite Variables\",\"scope\":[\"variable.other.readwrite.cs\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C# Classes & Storage types\",\"scope\":[\"entity.name.type.class.cs\",\"storage.type.cs\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"C# Namespaces\",\"scope\":[\"entity.name.type.namespace.cs\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"C# Unquoted String Zone\",\"scope\":[\"string.unquoted.preprocessor.message.cs\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C# Region\",\"scope\":[\"punctuation.separator.hash.cs\",\"keyword.preprocessor.region.cs\",\"keyword.preprocessor.endregion.cs\"],\"settings\":{\"foreground\":\"#ffcb8b\",\"fontStyle\":\"bold\"}},{\"name\":\"C# Other Variables\",\"scope\":[\"variable.other.object.cs\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"C# Enum\",\"scope\":[\"entity.name.type.enum.cs\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Dart String\",\"scope\":[\"string.interpolated.single.dart\",\"string.interpolated.double.dart\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Dart Class\",\"scope\":[\"support.class.dart\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Tag names in Stylesheets\",\"scope\":[\"entity.name.tag.css\",\"entity.name.tag.less\",\"entity.name.tag.custom.css\",\"support.constant.property-value.css\"],\"settings\":{\"foreground\":\"#ff6d6d\",\"fontStyle\":\"\"}},{\"name\":\"Wildcard(*) selector in Stylesheets\",\"scope\":[\"entity.name.tag.wildcard.css\",\"entity.name.tag.wildcard.less\",\"entity.name.tag.wildcard.scss\",\"entity.name.tag.wildcard.sass\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"CSS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Attribute Name for CSS\",\"scope\":[\"meta.attribute-selector.css entity.other.attribute-name.attribute\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Elixir Classes\",\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Elixir Functions\",\"scope\":[\"source.elixir entity.name.function\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir Constants\",\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Elixir String Punctuations\",\"scope\":[\"source.elixir punctuation.definition.string\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir\",\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir Binary Punctuations\",\"scope\":[\"source.elixir .punctuation.binary.elixir\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Closure Constant Keyword\",\"scope\":[\"constant.keyword.clojure\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Go Function Calls\",\"scope\":[\"source.go meta.function-call.go\"],\"settings\":{\"foreground\":\"#dddddd\"}},{\"name\":\"Go Keywords\",\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Go Constants e.g. nil, string format (%s, %d, etc.)\",\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"C++ Functions\",\"scope\":[\"entity.name.function.preprocessor.cpp\",\"entity.scope.name.cpp\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"C++ Meta Namespace\",\"scope\":[\"meta.namespace-block.cpp\"],\"settings\":{\"foreground\":\"#e0dec6\"}},{\"name\":\"C++ Language Primitive Storage\",\"scope\":[\"storage.type.language.primitive.cpp\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"C++ Preprocessor Macro\",\"scope\":[\"meta.preprocessor.macro.cpp\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C++ Variable Parameter\",\"scope\":[\"variable.parameter\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Powershell Variables\",\"scope\":[\"variable.other.readwrite.powershell\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Powershell Function\",\"scope\":[\"support.function.powershell\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"ID Attribute Name in HTML\",\"scope\":[\"entity.other.attribute-name.id.html\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"HTML Punctuation Definition Tag\",\"scope\":[\"punctuation.definition.tag.html\"],\"settings\":{\"foreground\":\"#6ae9f0\"}},{\"name\":\"HTML Doctype\",\"scope\":[\"meta.tag.sgml.doctype.html\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Classes\",\"scope\":[\"meta.class entity.name.type.class.js\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"JavaScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.js\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"JavaScript Terminator\",\"scope\":[\"terminator.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Meta Punctuation Definition\",\"scope\":[\"meta.js punctuation.definition.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Entity Names in Code Documentations\",\"scope\":[\"entity.name.type.instance.jsdoc\",\"entity.name.type.instance.phpdoc\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"Other Variables in Code Documentations\",\"scope\":[\"variable.other.jsdoc\",\"variable.other.phpdoc\"],\"settings\":{\"foreground\":\"#78ccf0\"}},{\"name\":\"JavaScript module imports and exports\",\"scope\":[\"variable.other.meta.import.js\",\"meta.import.js variable.other\",\"variable.other.meta.export.js\",\"meta.export.js variable.other\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Variable Parameter Function\",\"scope\":[\"variable.parameter.function.js\"],\"settings\":{\"foreground\":\"#8b96ea\"}},{\"name\":\"JavaScript[React] Variable Other Object\",\"scope\":[\"variable.other.object.js\",\"variable.other.object.jsx\",\"variable.object.property.js\",\"variable.object.property.jsx\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Variables\",\"scope\":[\"variable.js\",\"variable.other.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Entity Name Type\",\"scope\":[\"entity.name.type.js\",\"entity.name.type.module.js\"],\"settings\":{\"foreground\":\"#ffcb8b\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Support Classes\",\"scope\":[\"support.class.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JSON Property Names\",\"scope\":[\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"JSON Support Constants\",\"scope\":[\"support.constant.json\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"JSON Property values (string)\",\"scope\":[\"meta.structure.dictionary.value.json string.quoted.double\"],\"settings\":{\"foreground\":\"#c789d6\"}},{\"name\":\"Strings in JSON values\",\"scope\":[\"string.quoted.double.json punctuation.definition.string.json\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Specific JSON Property values like null\",\"scope\":[\"meta.structure.dictionary.json meta.structure.dictionary.value constant.language\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"JavaScript Other Variable\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Ruby Variables\",\"scope\":[\"variable.other.ruby\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Ruby Class\",\"scope\":[\"entity.name.type.class.ruby\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"Ruby Hashkeys\",\"scope\":[\"constant.language.symbol.hashkey.ruby\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"LESS Tag names\",\"scope\":[\"entity.name.tag.less\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"LESS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Attribute Name for LESS\",\"scope\":[\"meta.attribute-selector.less entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Markdown Headings\",\"scope\":[\"markup.heading.markdown\",\"markup.heading.setext.1.markdown\",\"markup.heading.setext.2.markdown\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown Italics\",\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"italic\"}},{\"name\":\"Markdown Bold\",\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"foreground\":\"#c5e478\",\"fontStyle\":\"bold\"}},{\"name\":\"Markdown Quote + others\",\"scope\":[\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#969bb7\",\"fontStyle\":\"\"}},{\"name\":\"Markdown Raw Code + others\",\"scope\":[\"markup.inline.raw.markdown\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Markdown Links\",\"scope\":[\"markup.underline.link.markdown\",\"markup.underline.link.image.markdown\"],\"settings\":{\"foreground\":\"#ff869a\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Link Title and Description\",\"scope\":[\"string.other.link.title.markdown\",\"string.other.link.description.markdown\"],\"settings\":{\"foreground\":\"#d6deeb\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Punctuation\",\"scope\":[\"punctuation.definition.string.markdown\",\"punctuation.definition.string.begin.markdown\",\"punctuation.definition.string.end.markdown\",\"meta.link.inline.markdown punctuation.definition.string\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown MetaData Punctuation\",\"scope\":[\"punctuation.definition.metadata.markdown\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Markdown List Punctuation\",\"scope\":[\"beginning.punctuation.definition.list.markdown\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown Inline Raw String\",\"scope\":[\"markup.inline.raw.string.markdown\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"PHP Variables\",\"scope\":[\"variable.other.php\"],\"settings\":{\"foreground\":\"#bec5d4\"}},{\"name\":\"Support Classes in PHP\",\"scope\":[\"support.class.php\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Punctuations in PHP function calls\",\"scope\":[\"meta.function-call.php punctuation\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"PHP Global Variables\",\"scope\":[\"variable.other.global.php\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Declaration Punctuation in PHP Global Variables\",\"scope\":[\"variable.other.global.php punctuation.definition.variable\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Language Constants in Python\",\"scope\":[\"constant.language.python\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Python Function Parameter and Arguments\",\"scope\":[\"variable.parameter.function.python\",\"meta.function-call.arguments.python\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Python Function Call\",\"scope\":[\"meta.function-call.python\",\"meta.function-call.generic.python\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"Punctuations in Python\",\"scope\":[\"punctuation.python\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Decorator Functions in Python\",\"scope\":[\"entity.name.function.decorator.python\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Python Language Variable\",\"scope\":[\"source.python variable.language.special\"],\"settings\":{\"foreground\":\"#8eace3\"}},{\"name\":\"Python import control keyword\",\"scope\":[\"keyword.control\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"SCSS Variable\",\"scope\":[\"variable.scss\",\"variable.sass\",\"variable.parameter.url.scss\",\"variable.parameter.url.sass\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#bec5d4\"}},{\"name\":\"Attribute Name for SASS\",\"scope\":[\"meta.attribute-selector.scss entity.other.attribute-name.attribute\",\"meta.attribute-selector.sass entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Tag names in SASS\",\"scope\":[\"entity.name.tag.scss\",\"entity.name.tag.sass\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"SASS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.scss\",\"keyword.other.unit.sass\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"TypeScript[React] Variables and Object Properties\",\"scope\":[\"variable.other.readwrite.alias.ts\",\"variable.other.readwrite.alias.tsx\",\"variable.other.readwrite.ts\",\"variable.other.readwrite.tsx\",\"variable.other.object.ts\",\"variable.other.object.tsx\",\"variable.object.property.ts\",\"variable.object.property.tsx\",\"variable.other.ts\",\"variable.other.tsx\",\"variable.tsx\",\"variable.ts\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript[React] Entity Name Types\",\"scope\":[\"entity.name.type.ts\",\"entity.name.type.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript[React] Node Classes\",\"scope\":[\"support.class.node.ts\",\"support.class.node.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"TypeScript[React] Entity Name Types as Parameters\",\"scope\":[\"meta.type.parameters.ts entity.name.type\",\"meta.type.parameters.tsx entity.name.type\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"TypeScript[React] Import/Export Punctuations\",\"scope\":[\"meta.import.ts punctuation.definition.block\",\"meta.import.tsx punctuation.definition.block\",\"meta.export.ts punctuation.definition.block\",\"meta.export.tsx punctuation.definition.block\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.decorator punctuation.decorator.ts\",\"meta.decorator punctuation.decorator.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.tag.js meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"YAML Entity Name Tags\",\"scope\":[\"entity.name.tag.yaml\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"JavaScript Variable Other ReadWrite\",\"scope\":[\"variable.other.readwrite.js\",\"variable.parameter\"],\"settings\":{\"foreground\":\"#d7dbe0\"}},{\"name\":\"Support Class Component\",\"scope\":[\"support.class.component.js\",\"support.class.component.tsx\"],\"settings\":{\"foreground\":\"#f78c6c\",\"fontStyle\":\"\"}},{\"name\":\"Text nested in React tags\",\"scope\":[\"meta.jsx.children\",\"meta.jsx.children.js\",\"meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript Classes\",\"scope\":[\"meta.class entity.name.type.class.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript Entity Name Type\",\"scope\":[\"entity.name.type.tsx\",\"entity.name.type.module.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript Class Variable Keyword\",\"scope\":[\"meta.class.ts meta.var.expr.ts storage.type.ts\",\"meta.class.tsx meta.var.expr.tsx storage.type.tsx\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"TypeScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.ts\",\"meta.method.declaration storage.type.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"normalize font style of certain components\",\"scope\":[\"meta.property-list.css meta.property-value.css variable.other.less\",\"meta.property-list.scss variable.scss\",\"meta.property-list.sass variable.sass\",\"meta.brace\",\"keyword.operator.operator\",\"keyword.operator.or.regexp\",\"keyword.operator.expression.in\",\"keyword.operator.relational\",\"keyword.operator.assignment\",\"keyword.operator.comparison\",\"keyword.operator.type\",\"keyword.operator\",\"keyword\",\"punctuation.definition.string\",\"punctuation\",\"variable.other.readwrite.js\",\"storage.type\",\"source.css\",\"string.quoted\"],\"settings\":{\"fontStyle\":\"\"}}],\"styleOverrides\":{\"frames\":{\"editorBackground\":\"var(--sl-color-gray-6)\",\"terminalBackground\":\"var(--sl-color-gray-6)\",\"editorActiveTabBackground\":\"var(--sl-color-gray-6)\",\"terminalTitlebarDotsForeground\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"terminalTitlebarDotsOpacity\":\"0.75\",\"inlineButtonForeground\":\"var(--sl-color-text)\",\"frameBoxShadowCssValue\":\"none\"},\"textMarkers\":{\"markBackground\":\"#ffffff17\",\"markBorderColor\":\"#ffffff40\"}}},{\"name\":\"Night Owl Light\",\"type\":\"light\",\"colors\":{\"focusBorder\":\"#93a1a1\",\"foreground\":\"#403f53\",\"disabledForeground\":\"#61616180\",\"descriptionForeground\":\"#403f53\",\"errorForeground\":\"#403f53\",\"icon.foreground\":\"#424242\",\"contrastActiveBorder\":null,\"contrastBorder\":null,\"textBlockQuote.background\":\"#7f7f7f1a\",\"textBlockQuote.border\":\"#007acc80\",\"textCodeBlock.background\":\"#dcdcdc66\",\"textLink.activeForeground\":\"#006ab1\",\"textLink.foreground\":\"#006ab1\",\"textPreformat.foreground\":\"#a31515\",\"textSeparator.foreground\":\"#0000002e\",\"editor.background\":\"#f6f7f9\",\"editor.foreground\":\"#403f53\",\"editorLineNumber.foreground\":\"#90a7b2\",\"editorLineNumber.activeForeground\":\"#403f53\",\"editorActiveLineNumber.foreground\":\"#0b216f\",\"editor.selectionBackground\":\"#e0e0e0\",\"editor.inactiveSelectionBackground\":\"#e0e0e080\",\"editor.selectionHighlightBackground\":\"#339cec33\",\"editorError.foreground\":\"#e64d49\",\"editorWarning.foreground\":\"#daaa01\",\"editorInfo.foreground\":\"#1a85ff\",\"editorHint.foreground\":\"#6c6c6c\",\"problemsErrorIcon.foreground\":\"#e64d49\",\"problemsWarningIcon.foreground\":\"#daaa01\",\"problemsInfoIcon.foreground\":\"#1a85ff\",\"editor.findMatchBackground\":\"#93a1a16c\",\"editor.findMatchHighlightBackground\":\"#93a1a16c\",\"editor.findRangeHighlightBackground\":\"#7497a633\",\"editorLink.activeForeground\":\"#0000ff\",\"editorLightBulb.foreground\":\"#ddb100\",\"editorLightBulbAutoFix.foreground\":\"#007acc\",\"diffEditor.insertedTextBackground\":\"#9ccc2c40\",\"diffEditor.insertedTextBorder\":null,\"diffEditor.removedTextBackground\":\"#ff000033\",\"diffEditor.removedTextBorder\":null,\"diffEditor.insertedLineBackground\":\"#9bb95533\",\"diffEditor.removedLineBackground\":\"#ff000033\",\"editorStickyScroll.background\":\"#fbfbfb\",\"editorStickyScrollHover.background\":\"#f0f0f0\",\"editorInlayHint.background\":\"#2aa29899\",\"editorInlayHint.foreground\":\"#f0f0f0\",\"editorInlayHint.typeBackground\":\"#2aa29899\",\"editorInlayHint.typeForeground\":\"#f0f0f0\",\"editorInlayHint.parameterBackground\":\"#2aa29899\",\"editorInlayHint.parameterForeground\":\"#f0f0f0\",\"editorPane.background\":\"#fbfbfb\",\"editorGroup.emptyBackground\":null,\"editorGroup.focusedEmptyBorder\":null,\"editorGroupHeader.tabsBackground\":\"var(--sl-color-gray-6)\",\"editorGroupHeader.tabsBorder\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"editorGroupHeader.noTabsBackground\":\"#f0f0f0\",\"editorGroupHeader.border\":null,\"editorGroup.border\":\"#f0f0f0\",\"editorGroup.dropBackground\":\"#2677cb2d\",\"editorGroup.dropIntoPromptForeground\":\"#403f53\",\"editorGroup.dropIntoPromptBackground\":\"#f0f0f0\",\"editorGroup.dropIntoPromptBorder\":null,\"sideBySideEditor.horizontalBorder\":\"#f0f0f0\",\"sideBySideEditor.verticalBorder\":\"#f0f0f0\",\"scrollbar.shadow\":\"#cccccc\",\"scrollbarSlider.background\":\"#0000001a\",\"scrollbarSlider.hoverBackground\":\"#00000055\",\"scrollbarSlider.activeBackground\":\"#00000099\",\"panel.background\":\"#f0f0f0\",\"panel.border\":\"#d9d9d9\",\"panelTitle.activeBorder\":\"#424242\",\"panelTitle.activeForeground\":\"#424242\",\"panelTitle.inactiveForeground\":\"#424242bf\",\"panelSectionHeader.background\":\"#80808051\",\"terminal.background\":\"#f6f6f6\",\"widget.shadow\":\"#d9d9d9\",\"editorWidget.background\":\"#f0f0f0\",\"editorWidget.foreground\":\"#403f53\",\"editorWidget.border\":\"#d9d9d9\",\"quickInput.background\":\"#f0f0f0\",\"quickInput.foreground\":\"#403f53\",\"quickInputTitle.background\":\"#0000000f\",\"pickerGroup.foreground\":\"#403f53\",\"pickerGroup.border\":\"#d9d9d9\",\"editor.hoverHighlightBackground\":\"#339cec33\",\"editorHoverWidget.background\":\"#f0f0f0\",\"editorHoverWidget.foreground\":\"#403f53\",\"editorHoverWidget.border\":\"#d9d9d9\",\"editorHoverWidget.statusBarBackground\":\"#e4e4e4\",\"titleBar.activeBackground\":\"var(--sl-color-gray-6)\",\"titleBar.activeForeground\":\"var(--sl-color-text)\",\"titleBar.inactiveBackground\":\"#f0f0f099\",\"titleBar.inactiveForeground\":\"#33333399\",\"titleBar.border\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"toolbar.hoverBackground\":\"#b8b8b850\",\"toolbar.activeBackground\":\"#a6a6a650\",\"tab.activeBackground\":\"#f6f6f6\",\"tab.unfocusedActiveBackground\":\"#f6f6f6\",\"tab.inactiveBackground\":\"#f0f0f0\",\"tab.unfocusedInactiveBackground\":\"#f0f0f0\",\"tab.activeForeground\":\"var(--sl-color-text)\",\"tab.inactiveForeground\":\"#403f53\",\"tab.unfocusedActiveForeground\":\"#403f53b3\",\"tab.unfocusedInactiveForeground\":\"#403f5380\",\"tab.hoverBackground\":null,\"tab.unfocusedHoverBackground\":null,\"tab.hoverForeground\":null,\"tab.unfocusedHoverForeground\":null,\"tab.border\":\"#f0f0f0\",\"tab.lastPinnedBorder\":\"#a9a9a9\",\"tab.activeBorder\":\"transparent\",\"tab.unfocusedActiveBorder\":null,\"tab.activeBorderTop\":\"var(--sl-color-accent)\",\"tab.unfocusedActiveBorderTop\":null,\"tab.hoverBorder\":null,\"tab.unfocusedHoverBorder\":null,\"tab.activeModifiedBorder\":\"#2aa298\",\"tab.inactiveModifiedBorder\":\"#93a1a1\",\"tab.unfocusedActiveModifiedBorder\":\"#93a1a1\",\"tab.unfocusedInactiveModifiedBorder\":\"#93a1a1\",\"badge.background\":\"#2aa298\",\"badge.foreground\":\"#f0f0f0\",\"button.background\":\"#2aa298\",\"button.foreground\":\"#f0f0f0\",\"button.border\":null,\"button.separator\":\"#f0f0f066\",\"button.hoverBackground\":\"#22827a\",\"button.secondaryBackground\":\"#5f6a79\",\"button.secondaryForeground\":\"#ffffff\",\"button.secondaryHoverBackground\":\"#4c5561\",\"dropdown.background\":\"#f0f0f0\",\"dropdown.foreground\":\"#403f53\",\"dropdown.border\":\"#d9d9d9\",\"list.activeSelectionBackground\":\"#d3e8f8\",\"list.activeSelectionForeground\":\"#403f53\",\"tree.indentGuidesStroke\":\"#a9a9a9\",\"input.background\":\"#f0f0f0\",\"input.foreground\":\"#403f53\",\"input.placeholderForeground\":\"#93a1a1\",\"inputOption.activeBorder\":\"#2aa298\",\"inputOption.hoverBackground\":\"#b8b8b850\",\"inputOption.activeBackground\":\"#93a1a133\",\"inputOption.activeForeground\":\"#000000\",\"inputValidation.infoBackground\":\"#f0f0f0\",\"inputValidation.infoBorder\":\"#d0d0d0\",\"inputValidation.warningBackground\":\"#daaa01\",\"inputValidation.warningBorder\":\"#e0af02\",\"inputValidation.errorBackground\":\"#f76e6e\",\"inputValidation.errorBorder\":\"#de3d3b\",\"keybindingLabel.background\":\"#dddddd66\",\"keybindingLabel.foreground\":\"#555555\",\"keybindingLabel.border\":\"#cccccc66\",\"keybindingLabel.bottomBorder\":\"#bbbbbb66\",\"menu.foreground\":\"#403f53\",\"menu.background\":\"#f0f0f0\",\"menu.selectionForeground\":\"#403f53\",\"menu.selectionBackground\":\"#d3e8f8\",\"menu.separatorBackground\":\"#d4d4d4\",\"editor.snippetTabstopHighlightBackground\":\"#0a326433\",\"editor.snippetFinalTabstopHighlightBorder\":\"#0a326480\",\"terminal.ansiBlack\":\"#403f53\",\"terminal.ansiRed\":\"#de3d3b\",\"terminal.ansiGreen\":\"#08916a\",\"terminal.ansiYellow\":\"#e0af02\",\"terminal.ansiBlue\":\"#288ed7\",\"terminal.ansiMagenta\":\"#d6438a\",\"terminal.ansiCyan\":\"#2aa298\",\"terminal.ansiWhite\":\"#f0f0f0\",\"terminal.ansiBrightBlack\":\"#403f53\",\"terminal.ansiBrightRed\":\"#de3d3b\",\"terminal.ansiBrightGreen\":\"#08916a\",\"terminal.ansiBrightYellow\":\"#daaa01\",\"terminal.ansiBrightBlue\":\"#288ed7\",\"terminal.ansiBrightMagenta\":\"#d6438a\",\"terminal.ansiBrightCyan\":\"#2aa298\",\"terminal.ansiBrightWhite\":\"#f0f0f0\",\"selection.background\":\"#7a8181ad\",\"notifications.background\":\"#f0f0f0\",\"notifications.foreground\":\"#403f53\",\"notificationLink.foreground\":\"#994cc3\",\"notifications.border\":\"#cccccc\",\"notificationCenter.border\":\"#cccccc\",\"notificationToast.border\":\"#cccccc\",\"notificationCenterHeader.foreground\":\"#403f53\",\"notificationCenterHeader.background\":\"#f0f0f0\",\"input.border\":\"#d9d9d9\",\"progressBar.background\":\"#2aa298\",\"list.inactiveSelectionBackground\":\"#e0e7ea\",\"list.inactiveSelectionForeground\":\"#403f53\",\"list.focusBackground\":\"#d3e8f8\",\"list.hoverBackground\":\"#d3e8f8\",\"list.focusForeground\":\"#403f53\",\"list.hoverForeground\":\"#403f53\",\"list.highlightForeground\":\"#403f53\",\"list.errorForeground\":\"#e64d49\",\"list.warningForeground\":\"#daaa01\",\"activityBar.background\":\"#f0f0f0\",\"activityBar.foreground\":\"#403f53\",\"activityBar.dropBackground\":\"#d0d0d0\",\"activityBarBadge.background\":\"#403f53\",\"activityBarBadge.foreground\":\"#f0f0f0\",\"activityBar.border\":\"#f0f0f0\",\"sideBar.background\":\"#f0f0f0\",\"sideBar.foreground\":\"#403f53\",\"sideBarTitle.foreground\":\"#403f53\",\"sideBar.border\":\"#f0f0f0\",\"editorGroup.background\":\"#f6f6f6\",\"editorCursor.foreground\":\"#90a7b2\",\"editor.wordHighlightBackground\":\"#339cec33\",\"editor.wordHighlightStrongBackground\":\"#007dd659\",\"editor.lineHighlightBackground\":\"#f0f0f0\",\"editor.rangeHighlightBackground\":\"#7497a633\",\"editorWhitespace.foreground\":\"#d9d9d9\",\"editorIndentGuide.background\":\"#d9d9d9\",\"editorCodeLens.foreground\":\"#403f53\",\"editorBracketMatch.background\":\"#d3e8f8\",\"editorBracketMatch.border\":\"#2aa298\",\"editorError.border\":\"#fbfbfb\",\"editorWarning.border\":\"#daaa01\",\"editorGutter.addedBackground\":\"#49d0c5\",\"editorGutter.modifiedBackground\":\"#6fbef6\",\"editorGutter.deletedBackground\":\"#f76e6e\",\"editorRuler.foreground\":\"#d9d9d9\",\"editorOverviewRuler.errorForeground\":\"#e64d49\",\"editorOverviewRuler.warningForeground\":\"#daaa01\",\"editorSuggestWidget.background\":\"#f0f0f0\",\"editorSuggestWidget.foreground\":\"#403f53\",\"editorSuggestWidget.highlightForeground\":\"#403f53\",\"editorSuggestWidget.selectedBackground\":\"#d3e8f8\",\"editorSuggestWidget.border\":\"#d9d9d9\",\"debugExceptionWidget.background\":\"#f0f0f0\",\"debugExceptionWidget.border\":\"#d9d9d9\",\"editorMarkerNavigation.background\":\"#d0d0d0\",\"editorMarkerNavigationError.background\":\"#f76e6e\",\"editorMarkerNavigationWarning.background\":\"#daaa01\",\"debugToolBar.background\":\"#f0f0f0\",\"extensionButton.prominentBackground\":\"#2aa298\",\"extensionButton.prominentForeground\":\"#f0f0f0\",\"statusBar.background\":\"#f0f0f0\",\"statusBar.border\":\"#f0f0f0\",\"statusBar.debuggingBackground\":\"#f0f0f0\",\"statusBar.debuggingForeground\":\"#403f53\",\"statusBar.foreground\":\"#403f53\",\"statusBar.noFolderBackground\":\"#f0f0f0\",\"statusBar.noFolderForeground\":\"#403f53\",\"peekView.border\":\"#d9d9d9\",\"peekViewEditor.background\":\"#f6f6f6\",\"peekViewEditorGutter.background\":\"#f6f6f6\",\"peekViewEditor.matchHighlightBackground\":\"#49d0c5\",\"peekViewResult.background\":\"#f0f0f0\",\"peekViewResult.fileForeground\":\"#403f53\",\"peekViewResult.lineForeground\":\"#403f53\",\"peekViewResult.matchHighlightBackground\":\"#49d0c5\",\"peekViewResult.selectionBackground\":\"#e0e7ea\",\"peekViewResult.selectionForeground\":\"#403f53\",\"peekViewTitle.background\":\"#f0f0f0\",\"peekViewTitleLabel.foreground\":\"#403f53\",\"peekViewTitleDescription.foreground\":\"#403f53\",\"terminal.foreground\":\"#403f53\"},\"fg\":\"#403f53\",\"bg\":\"#f6f7f9\",\"semanticHighlighting\":false,\"settings\":[{\"name\":\"Changed\",\"scope\":[\"markup.changed\",\"meta.diff.header.git\",\"meta.diff.header.from-file\",\"meta.diff.header.to-file\"],\"settings\":{\"foreground\":\"#556484\"}},{\"name\":\"Deleted\",\"scope\":[\"markup.deleted.diff\"],\"settings\":{\"foreground\":\"#ae3c3afd\"}},{\"name\":\"Inserted\",\"scope\":[\"markup.inserted.diff\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Global settings\",\"settings\":{\"background\":\"#011627\",\"foreground\":\"#403f53\"}},{\"name\":\"Comment\",\"scope\":[\"comment\"],\"settings\":{\"foreground\":\"#5f636f\"}},{\"name\":\"String\",\"scope\":[\"string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"String Quoted\",\"scope\":[\"string.quoted\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Support Constant Math\",\"scope\":[\"support.constant.math\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Number\",\"scope\":[\"constant.numeric\",\"constant.character.numeric\"],\"settings\":{\"foreground\":\"#aa0982\",\"fontStyle\":\"\"}},{\"name\":\"Built-in constant\",\"scope\":[\"constant.language\",\"punctuation.definition.constant\",\"variable.other.constant\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"User-defined constant\",\"scope\":[\"constant.character\",\"constant.other\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Constant Character Escape\",\"scope\":[\"constant.character.escape\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"RegExp String\",\"scope\":[\"string.regexp\",\"string.regexp keyword.other\"],\"settings\":{\"foreground\":\"#3a688f\"}},{\"name\":\"Comma in functions\",\"scope\":[\"meta.function punctuation.separator.comma\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"Variable\",\"scope\":[\"variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Keyword\",\"scope\":[\"punctuation.accessor\",\"keyword\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage\",\"scope\":[\"storage\",\"meta.var.expr\",\"meta.class meta.method.declaration meta.var.expr storage.type.js\",\"storage.type.property.js\",\"storage.type.property.ts\",\"storage.type.property.tsx\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type.function.arrow.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Class name\",\"scope\":[\"entity.name.class\",\"meta.class entity.name.type.class\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Inherited class\",\"scope\":[\"entity.other.inherited-class\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Function name\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Meta Tag\",\"scope\":[\"punctuation.definition.tag\",\"meta.tag\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"HTML Tag names\",\"scope\":[\"entity.name.tag\",\"meta.tag.other.html\",\"meta.tag.other.js\",\"meta.tag.other.tsx\",\"entity.name.tag.tsx\",\"entity.name.tag.js\",\"entity.name.tag\",\"meta.tag.js\",\"meta.tag.tsx\",\"meta.tag.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Tag attribute\",\"scope\":[\"entity.other.attribute-name\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Entity Name Tag Custom\",\"scope\":[\"entity.name.tag.custom\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Library (function & constant)\",\"scope\":[\"support.function\",\"support.constant\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Support Constant Property Value meta\",\"scope\":[\"support.constant.meta.property-value\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Library class/type\",\"scope\":[\"support.type\",\"support.class\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Support Variable DOM\",\"scope\":[\"support.variable.dom\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Invalid\",\"scope\":[\"invalid\"],\"settings\":{\"foreground\":\"#bb2060\"}},{\"name\":\"Invalid deprecated\",\"scope\":[\"invalid.deprecated\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Keyword Operator\",\"scope\":[\"keyword.operator\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Relational\",\"scope\":[\"keyword.operator.relational\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Assignment\",\"scope\":[\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Arithmetic\",\"scope\":[\"keyword.operator.arithmetic\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Bitwise\",\"scope\":[\"keyword.operator.bitwise\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Increment\",\"scope\":[\"keyword.operator.increment\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Ternary\",\"scope\":[\"keyword.operator.ternary\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Double-Slashed Comment\",\"scope\":[\"comment.line.double-slash\"],\"settings\":{\"foreground\":\"#5d6376\"}},{\"name\":\"Object\",\"scope\":[\"object\"],\"settings\":{\"foreground\":\"#58656a\"}},{\"name\":\"Null\",\"scope\":[\"constant.language.null\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Meta Brace\",\"scope\":[\"meta.brace\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Meta Delimiter Period\",\"scope\":[\"meta.delimiter.period\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Punctuation Definition String\",\"scope\":[\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Punctuation Definition String Markdown\",\"scope\":[\"punctuation.definition.string.begin.markdown\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Boolean\",\"scope\":[\"constant.language.boolean\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Object Comma\",\"scope\":[\"object.comma\"],\"settings\":{\"foreground\":\"#646464\"}},{\"name\":\"Variable Parameter Function\",\"scope\":[\"variable.parameter.function\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Support Type Property Name & entity name tags\",\"scope\":[\"support.type.vendor.property-name\",\"support.constant.vendor.property-value\",\"support.type.property-name\",\"meta.property-list entity.name.tag\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Entity Name tag reference in stylesheets\",\"scope\":[\"meta.property-list entity.name.tag.reference\"],\"settings\":{\"foreground\":\"#286d70\"}},{\"name\":\"Constant Other Color RGB Value Punctuation Definition Constant\",\"scope\":[\"constant.other.color.rgb-value punctuation.definition.constant\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Constant Other Color\",\"scope\":[\"constant.other.color\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Keyword Other Unit\",\"scope\":[\"keyword.other.unit\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Meta Selector\",\"scope\":[\"meta.selector\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Entity Other Attribute Name Id\",\"scope\":[\"entity.other.attribute-name.id\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Meta Property Name\",\"scope\":[\"meta.property-name\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Doctypes\",\"scope\":[\"entity.name.tag.doctype\",\"meta.tag.sgml.doctype\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Punctuation Definition Parameters\",\"scope\":[\"punctuation.definition.parameters\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Keyword Control Operator\",\"scope\":[\"keyword.control.operator\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Keyword Operator Logical\",\"scope\":[\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"\"}},{\"name\":\"Variable Instances\",\"scope\":[\"variable.instance\",\"variable.other.instance\",\"variable.readwrite.instance\",\"variable.other.readwrite.instance\",\"variable.other.property\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Variable Property Other object property\",\"scope\":[\"variable.other.object.property\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Variable Property Other object\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Entity Name Function\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Keyword Operator Comparison, imports, returns and Keyword Operator Ruby\",\"scope\":[\"keyword.operator.comparison\",\"keyword.control.flow.js\",\"keyword.control.flow.ts\",\"keyword.control.flow.tsx\",\"keyword.control.ruby\",\"keyword.control.module.ruby\",\"keyword.control.class.ruby\",\"keyword.control.def.ruby\",\"keyword.control.loop.js\",\"keyword.control.loop.ts\",\"keyword.control.import.js\",\"keyword.control.import.ts\",\"keyword.control.import.tsx\",\"keyword.control.from.js\",\"keyword.control.from.ts\",\"keyword.control.from.tsx\",\"keyword.operator.instanceof.js\",\"keyword.operator.expression.instanceof.ts\",\"keyword.operator.expression.instanceof.tsx\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Control Conditional\",\"scope\":[\"keyword.control.conditional.js\",\"keyword.control.conditional.ts\",\"keyword.control.switch.js\",\"keyword.control.switch.ts\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"\"}},{\"name\":\"Support Constant, `new` keyword, Special Method Keyword, `debugger`, other keywords\",\"scope\":[\"support.constant\",\"keyword.other.special-method\",\"keyword.other.new\",\"keyword.other.debugger\",\"keyword.control\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Support Function\",\"scope\":[\"support.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Invalid Broken\",\"scope\":[\"invalid.broken\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Invalid Unimplemented\",\"scope\":[\"invalid.unimplemented\"],\"settings\":{\"foreground\":\"#486e26\"}},{\"name\":\"Invalid Illegal\",\"scope\":[\"invalid.illegal\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Language Variable\",\"scope\":[\"variable.language\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Support Variable Property\",\"scope\":[\"support.variable.property\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Variable Function\",\"scope\":[\"variable.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variable Interpolation\",\"scope\":[\"variable.interpolation\"],\"settings\":{\"foreground\":\"#a64348\"}},{\"name\":\"Meta Function Call\",\"scope\":[\"meta.function-call\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Punctuation Section Embedded\",\"scope\":[\"punctuation.section.embedded\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Punctuation Tweaks\",\"scope\":[\"punctuation.terminator.expression\",\"punctuation.definition.arguments\",\"punctuation.definition.array\",\"punctuation.section.array\",\"meta.array\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"More Punctuation Tweaks\",\"scope\":[\"punctuation.definition.list.begin\",\"punctuation.definition.list.end\",\"punctuation.separator.arguments\",\"punctuation.definition.list\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Template Strings\",\"scope\":[\"string.template meta.template.expression\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Backticks(``) in Template Strings\",\"scope\":[\"string.template punctuation.definition.string\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Italics\",\"scope\":[\"italic\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"italic\"}},{\"name\":\"Bold\",\"scope\":[\"bold\"],\"settings\":{\"foreground\":\"#3b61b0\",\"fontStyle\":\"bold\"}},{\"name\":\"Quote\",\"scope\":[\"quote\"],\"settings\":{\"foreground\":\"#5c6285\"}},{\"name\":\"Raw Code\",\"scope\":[\"raw\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"CoffeeScript Variable Assignment\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#186e73\"}},{\"name\":\"CoffeeScript Parameter Function\",\"scope\":[\"variable.parameter.function.coffee\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"CoffeeScript Assignments\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"C# Readwrite Variables\",\"scope\":[\"variable.other.readwrite.cs\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"C# Classes & Storage types\",\"scope\":[\"entity.name.type.class.cs\",\"storage.type.cs\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"C# Namespaces\",\"scope\":[\"entity.name.type.namespace.cs\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Tag names in Stylesheets\",\"scope\":[\"entity.name.tag.css\",\"entity.name.tag.less\",\"entity.name.tag.custom.css\",\"support.constant.property-value.css\"],\"settings\":{\"foreground\":\"#984e4d\",\"fontStyle\":\"\"}},{\"name\":\"Wildcard(*) selector in Stylesheets\",\"scope\":[\"entity.name.tag.wildcard.css\",\"entity.name.tag.wildcard.less\",\"entity.name.tag.wildcard.scss\",\"entity.name.tag.wildcard.sass\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"CSS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Attribute Name for CSS\",\"scope\":[\"meta.attribute-selector.css entity.other.attribute-name.attribute\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Elixir Classes\",\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Functions\",\"scope\":[\"source.elixir entity.name.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Constants\",\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir String Punctuations\",\"scope\":[\"source.elixir punctuation.definition.string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir\",\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Binary Punctuations\",\"scope\":[\"source.elixir .punctuation.binary.elixir\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Closure Constant Keyword\",\"scope\":[\"constant.keyword.clojure\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Go Function Calls\",\"scope\":[\"source.go meta.function-call.go\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Go Keywords\",\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Go Constants e.g. nil, string format (%s, %d, etc.)\",\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"C++ Functions\",\"scope\":[\"entity.name.function.preprocessor.cpp\",\"entity.scope.name.cpp\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"C++ Meta Namespace\",\"scope\":[\"meta.namespace-block.cpp\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"C++ Language Primitive Storage\",\"scope\":[\"storage.type.language.primitive.cpp\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"C++ Preprocessor Macro\",\"scope\":[\"meta.preprocessor.macro.cpp\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"C++ Variable Parameter\",\"scope\":[\"variable.parameter\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Powershell Variables\",\"scope\":[\"variable.other.readwrite.powershell\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Powershell Function\",\"scope\":[\"support.function.powershell\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"ID Attribute Name in HTML\",\"scope\":[\"entity.other.attribute-name.id.html\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"HTML Punctuation Definition Tag\",\"scope\":[\"punctuation.definition.tag.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"HTML Doctype\",\"scope\":[\"meta.tag.sgml.doctype.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"JavaScript Classes\",\"scope\":[\"meta.class entity.name.type.class.js\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"JavaScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.js\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"JavaScript Terminator\",\"scope\":[\"terminator.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Meta Punctuation Definition\",\"scope\":[\"meta.js punctuation.definition.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Entity Names in Code Documentations\",\"scope\":[\"entity.name.type.instance.jsdoc\",\"entity.name.type.instance.phpdoc\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"Other Variables in Code Documentations\",\"scope\":[\"variable.other.jsdoc\",\"variable.other.phpdoc\"],\"settings\":{\"foreground\":\"#3e697c\"}},{\"name\":\"JavaScript module imports and exports\",\"scope\":[\"variable.other.meta.import.js\",\"meta.import.js variable.other\",\"variable.other.meta.export.js\",\"meta.export.js variable.other\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Variable Parameter Function\",\"scope\":[\"variable.parameter.function.js\"],\"settings\":{\"foreground\":\"#555ea2\"}},{\"name\":\"JavaScript[React] Variable Other Object\",\"scope\":[\"variable.other.object.js\",\"variable.other.object.jsx\",\"variable.object.property.js\",\"variable.object.property.jsx\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Variables\",\"scope\":[\"variable.js\",\"variable.other.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Entity Name Type\",\"scope\":[\"entity.name.type.js\",\"entity.name.type.module.js\"],\"settings\":{\"foreground\":\"#111111\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Support Classes\",\"scope\":[\"support.class.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JSON Property Names\",\"scope\":[\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"JSON Support Constants\",\"scope\":[\"support.constant.json\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"JSON Property values (string)\",\"scope\":[\"meta.structure.dictionary.value.json string.quoted.double\"],\"settings\":{\"foreground\":\"#7c5686\"}},{\"name\":\"Strings in JSON values\",\"scope\":[\"string.quoted.double.json punctuation.definition.string.json\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Specific JSON Property values like null\",\"scope\":[\"meta.structure.dictionary.json meta.structure.dictionary.value constant.language\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"JavaScript Other Variable\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Ruby Variables\",\"scope\":[\"variable.other.ruby\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Ruby Class\",\"scope\":[\"entity.name.type.class.ruby\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Ruby Hashkeys\",\"scope\":[\"constant.language.symbol.hashkey.ruby\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Ruby Symbols\",\"scope\":[\"constant.language.symbol.ruby\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"LESS Tag names\",\"scope\":[\"entity.name.tag.less\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"LESS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Attribute Name for LESS\",\"scope\":[\"meta.attribute-selector.less entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Markdown Headings\",\"scope\":[\"markup.heading.markdown\",\"markup.heading.setext.1.markdown\",\"markup.heading.setext.2.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown Italics\",\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"italic\"}},{\"name\":\"Markdown Bold\",\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\",\"fontStyle\":\"bold\"}},{\"name\":\"Markdown Quote + others\",\"scope\":[\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#5c6285\"}},{\"name\":\"Markdown Raw Code + others\",\"scope\":[\"markup.inline.raw.markdown\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Markdown Links\",\"scope\":[\"markup.underline.link.markdown\",\"markup.underline.link.image.markdown\"],\"settings\":{\"foreground\":\"#954f5a\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Link Title and Description\",\"scope\":[\"string.other.link.title.markdown\",\"string.other.link.description.markdown\"],\"settings\":{\"foreground\":\"#403f53\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Punctuation\",\"scope\":[\"punctuation.definition.string.markdown\",\"punctuation.definition.string.begin.markdown\",\"punctuation.definition.string.end.markdown\",\"meta.link.inline.markdown punctuation.definition.string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown MetaData Punctuation\",\"scope\":[\"punctuation.definition.metadata.markdown\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Markdown List Punctuation\",\"scope\":[\"beginning.punctuation.definition.list.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown Inline Raw String\",\"scope\":[\"markup.inline.raw.string.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"PHP Variables\",\"scope\":[\"variable.other.php\",\"variable.other.property.php\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Support Classes in PHP\",\"scope\":[\"support.class.php\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Punctuations in PHP function calls\",\"scope\":[\"meta.function-call.php punctuation\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"PHP Global Variables\",\"scope\":[\"variable.other.global.php\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Declaration Punctuation in PHP Global Variables\",\"scope\":[\"variable.other.global.php punctuation.definition.variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Language Constants in Python\",\"scope\":[\"constant.language.python\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Python Function Parameter and Arguments\",\"scope\":[\"variable.parameter.function.python\",\"meta.function-call.arguments.python\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Python Function Call\",\"scope\":[\"meta.function-call.python\",\"meta.function-call.generic.python\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Punctuations in Python\",\"scope\":[\"punctuation.python\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Decorator Functions in Python\",\"scope\":[\"entity.name.function.decorator.python\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Python Language Variable\",\"scope\":[\"source.python variable.language.special\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Python import control keyword\",\"scope\":[\"keyword.control\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"SCSS Variable\",\"scope\":[\"variable.scss\",\"variable.sass\",\"variable.parameter.url.scss\",\"variable.parameter.url.sass\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Attribute Name for SASS\",\"scope\":[\"meta.attribute-selector.scss entity.other.attribute-name.attribute\",\"meta.attribute-selector.sass entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Tag names in SASS\",\"scope\":[\"entity.name.tag.scss\",\"entity.name.tag.sass\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"SASS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.scss\",\"keyword.other.unit.sass\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"TypeScript[React] Variables and Object Properties\",\"scope\":[\"variable.other.readwrite.alias.ts\",\"variable.other.readwrite.alias.tsx\",\"variable.other.readwrite.ts\",\"variable.other.readwrite.tsx\",\"variable.other.object.ts\",\"variable.other.object.tsx\",\"variable.object.property.ts\",\"variable.object.property.tsx\",\"variable.other.ts\",\"variable.other.tsx\",\"variable.tsx\",\"variable.ts\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript[React] Entity Name Types\",\"scope\":[\"entity.name.type.ts\",\"entity.name.type.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript[React] Node Classes\",\"scope\":[\"support.class.node.ts\",\"support.class.node.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"TypeScript[React] Entity Name Types as Parameters\",\"scope\":[\"meta.type.parameters.ts entity.name.type\",\"meta.type.parameters.tsx entity.name.type\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"TypeScript[React] Import/Export Punctuations\",\"scope\":[\"meta.import.ts punctuation.definition.block\",\"meta.import.tsx punctuation.definition.block\",\"meta.export.ts punctuation.definition.block\",\"meta.export.tsx punctuation.definition.block\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.decorator punctuation.decorator.ts\",\"meta.decorator punctuation.decorator.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.tag.js meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"YAML Entity Name Tags\",\"scope\":[\"entity.name.tag.yaml\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"JavaScript Variable Other ReadWrite\",\"scope\":[\"variable.other.readwrite.js\",\"variable.parameter\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Support Class Component\",\"scope\":[\"support.class.component.js\",\"support.class.component.tsx\"],\"settings\":{\"foreground\":\"#aa0982\",\"fontStyle\":\"\"}},{\"name\":\"Text nested in React tags\",\"scope\":[\"meta.jsx.children\",\"meta.jsx.children.js\",\"meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript Classes\",\"scope\":[\"meta.class entity.name.type.class.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript Entity Name Type\",\"scope\":[\"entity.name.type.tsx\",\"entity.name.type.module.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript Class Variable Keyword\",\"scope\":[\"meta.class.ts meta.var.expr.ts storage.type.ts\",\"meta.class.tsx meta.var.expr.tsx storage.type.tsx\"],\"settings\":{\"foreground\":\"#76578b\"}},{\"name\":\"TypeScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.ts\",\"meta.method.declaration storage.type.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"normalize font style of certain components\",\"scope\":[\"meta.property-list.css meta.property-value.css variable.other.less\",\"meta.property-list.scss variable.scss\",\"meta.property-list.sass variable.sass\",\"meta.brace\",\"keyword.operator.operator\",\"keyword.operator.or.regexp\",\"keyword.operator.expression.in\",\"keyword.operator.relational\",\"keyword.operator.assignment\",\"keyword.operator.comparison\",\"keyword.operator.type\",\"keyword.operator\",\"keyword\",\"punctuation.definition.string\",\"punctuation\",\"variable.other.readwrite.js\",\"storage.type\",\"source.css\",\"string.quoted\"],\"settings\":{\"fontStyle\":\"\"}}],\"styleOverrides\":{\"frames\":{\"editorBackground\":\"var(--sl-color-gray-7)\",\"terminalBackground\":\"var(--sl-color-gray-7)\",\"editorActiveTabBackground\":\"var(--sl-color-gray-7)\",\"terminalTitlebarDotsForeground\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"terminalTitlebarDotsOpacity\":\"0.75\",\"inlineButtonForeground\":\"var(--sl-color-text)\",\"frameBoxShadowCssValue\":\"none\"},\"textMarkers\":{\"markBackground\":\"#0000001a\",\"markBorderColor\":\"#00000055\"}}}],\"defaultLocale\":\"en\",\"cascadeLayer\":\"starlight.components\",\"styleOverrides\":{\"borderRadius\":\"0px\",\"borderWidth\":\"1px\",\"codePaddingBlock\":\"0.75rem\",\"codePaddingInline\":\"1rem\",\"codeFontFamily\":\"var(--__sl-font-mono)\",\"codeFontSize\":\"var(--sl-text-code)\",\"codeLineHeight\":\"var(--sl-line-height)\",\"uiFontFamily\":\"var(--__sl-font)\",\"textMarkers\":{\"lineDiffIndicatorMarginLeft\":\"0.25rem\",\"defaultChroma\":\"45\",\"backgroundOpacity\":\"60%\"}},\"plugins\":[{\"name\":\"Starlight Plugin\",\"hooks\":{}},{\"name\":\"astro-expressive-code\",\"hooks\":{}}]}]],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":{\"backticks\":true,\"closingQuotes\":{\"double\":\"”\",\"single\":\"’\"},\"dashes\":true,\"ellipses\":true,\"openingQuotes\":{\"double\":\"“\",\"single\":\"‘\"},\"quotes\":true}},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[],\"csp\":false,\"actionBodySizeLimit\":1048576,\"serverIslandBodySizeLimit\":1048576},\"env\":{\"schema\":{},\"validateSecrets\":false},\"prerenderConflictBehavior\":\"warn\",\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"chromeDevtoolsWorkspace\":false,\"svgo\":false,\"rustCompiler\":false,\"queuedRendering\":{\"enabled\":false}},\"legacy\":{\"collectionsBackwardsCompat\":false},\"prefetch\":{\"prefetchAll\":true},\"i18n\":{\"defaultLocale\":\"en\",\"locales\":[\"en\"],\"routing\":{\"prefixDefaultLocale\":false,\"redirectToDefaultLocale\":false,\"fallbackType\":\"redirect\"}}}","astro-version","6.1.5","content-config-digest","28e7bc87492477d9"]
\ No newline at end of file
+[["Map",1,2,169,170],"docs",["Map",3,4,37,38,49,50,60,61,71,72,82,83,93,94,104,105,125,126,136,137,147,148,158,159],"404",{"id":3,"data":5,"body":34,"filePath":35,"digest":36,"deferredRender":32},{"title":6,"description":7,"editUrl":8,"head":9,"template":10,"hero":11,"sidebar":31,"pagefind":8,"draft":8},"Page Not Found","The requested docs page could not be found.",false,[],"splash",{"tagline":12,"actions":13},"The page you requested does not exist or may have moved.",[14,21,26],{"text":15,"link":16,"variant":17,"icon":18},"Go Home","/","primary",{"type":19,"name":20},"icon","right-arrow",{"text":22,"link":23,"variant":24,"icon":25},"Read the Introduction","/introduction","minimal",{"type":19,"name":20},{"text":27,"link":28,"variant":24,"icon":29},"Report Broken Link","https://github.com/barrymichaeldoyle/patch-pulse/issues/new?template=bug_report.md&labels=bug&title=Broken%20docs%20link%3A%20&body=I%20reached%20the%20Patch%20Pulse%20docs%20404%20page%20from%20an%20outdated%20or%20broken%20link.%0A%0ABroken%20URL%3A%20%0AReferrer%20(optional)%3A%20%0AWhat%20I%20expected%20to%20find%3A%20",{"type":19,"name":30},"external",{"hidden":32,"attrs":33},true,{},"If you followed an old Patch Pulse docs link, the page may have been renamed as the docs site structure evolved.\n\nUse the navigation or search to find the current page.","src/content/docs/404.mdx","bea4156dc90062f4","cli/commands",{"id":37,"data":39,"body":46,"filePath":47,"digest":48,"deferredRender":32},{"title":40,"description":41,"editUrl":32,"head":42,"template":43,"sidebar":44,"pagefind":32,"draft":8},"Commands & Flags","All CLI flags supported by Patch Pulse.",[],"doc",{"hidden":8,"attrs":45},{},"import { Aside } from '@astrojs/starlight/components';\n\n## Usage\n\n```bash\nnpx patch-pulse [flags]\n```\n\n## Flags\n\n### `--help`, `-h`\n\nPrint usage information and exit.\n\n```bash\nnpx patch-pulse --help\n```\n\n---\n\n### `--version`, `-v`\n\nPrint the current CLI version and exit.\n\n```bash\nnpx patch-pulse --version\n```\n\n---\n\n### `--about`\n\nPrint information about Patch Pulse and exit.\n\n```bash\nnpx patch-pulse --about\n```\n\n---\n\n### `--license`, `-l`\n\nPrint the license and exit.\n\n```bash\nnpx patch-pulse --license\n```\n\n---\n\n### `--interactive`, `-i` / `--no-interactive`\n\nShow an interactive update prompt after the dependency summary.\n\n```bash\nnpx patch-pulse --interactive\nnpx patch-pulse --no-interactive\n```\n\nCLI flags override the [`interactive`](../configuration#interactive) setting in your config file.\n\n---\n\n### `--skip`, `-s`\n\nComma-separated list of package names or glob patterns to skip.\n\n```bash\nnpx patch-pulse --skip \"lodash,@types/*\"\n```\n\nMerged with any `skip` entries in your [config file](../configuration#skip).\n\n---\n\n### `--package-manager`\n\nOverride auto-detected package manager. Accepted values: `npm`, `pnpm`, `yarn`, `bun`.\n\n```bash\nnpx patch-pulse --package-manager pnpm\n```\n\n---\n\n### `--project`\n\nFocus on a single workspace project by path or package name.\n\n```bash\nnpx patch-pulse --project packages/app\nnpx patch-pulse --project my-app\n```\n\n---\n\n### `--expand`\n\nIn a monorepo, print the full dependency list for every workspace — including those that are up to date.\n\n```bash\nnpx patch-pulse --expand\n```\n\n---\n\n### `--hide-clean`\n\nHide workspaces that have no outdated dependencies from the output.\n\n```bash\nnpx patch-pulse --hide-clean\n```\n\n---\n\n### `--json`\n\nOutput results as JSON instead of the human-readable terminal display. Useful for scripts, CI, or editor integrations.\n\n```bash\nnpx patch-pulse --json\n```\n\nWhen running through the root pnpm script, use `pnpm -s` to suppress pnpm's banner before the JSON:\n\n```bash\npnpm -s pp -- --json\n```\n\n---\n\n### `--fail`\n\nExit with code `1` if any outdated packages are found. Use as a CI gate.\n\n```bash\nnpx patch-pulse --fail\nnpx patch-pulse --json --fail\n```\n\n\u003CAside type=\"tip\">\n Combine `--json` and `--fail` for machine-readable output with a non-zero exit\n code when updates are available.\n\u003C/Aside>","src/content/docs/cli/commands.mdx","6fe9e11a9f69c12f","cli/configuration",{"id":49,"data":51,"body":57,"filePath":58,"digest":59,"deferredRender":32},{"title":52,"description":53,"editUrl":32,"head":54,"template":43,"sidebar":55,"pagefind":32,"draft":8},"Configuration","Persistent configuration for the Patch Pulse CLI.",[],{"hidden":8,"attrs":56},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe CLI supports a configuration file for persistent settings. Use `patchpulse.json` in your project root going forward. These filenames are supported:\n\n- `patchpulse.json`\n- `patchpulse.config.json`\n- `.patchpulserc.json`\n- `.patchpulserc`\n\n## Example\n\n```json\n{\n \"skip\": [\"lodash\", \"@types/*\", \"test-*\"],\n \"ignorePaths\": [\"packages/cli/e2e\"],\n \"packageManager\": \"pnpm\",\n \"interactive\": true\n}\n```\n\n## Options\n\n### `skip`\n\nAn array of package names or glob patterns to exclude from version checks.\n\n```json\n{\n \"skip\": [\"lodash\", \"@types/*\", \"test-*\", \"*-dev\"]\n}\n```\n\nSupported pattern syntax:\n\n| Pattern | Matches |\n| ------------ | ------------------------------------ |\n| `\"lodash\"` | Exact package name |\n| `\"@types/*\"` | Any package under the `@types` scope |\n| `\"test-*\"` | Any package starting with `test-` |\n| `\"*-dev\"` | Any package ending with `-dev` |\n\n\u003CAside>\n `--skip` passed on the command line is **merged** with the config file's\n `skip` array — it does not replace it.\n\u003C/Aside>\n\n---\n\n### `ignorePaths`\n\nAn array of directory or file paths to exclude from workspace scanning. Useful for ignoring fixture directories or generated packages.\n\n```json\n{\n \"ignorePaths\": [\"packages/cli/e2e\", \"**/fixtures\", \"packages/*/dist\"]\n}\n```\n\nBoth exact paths and glob patterns are supported.\n\n---\n\n### `includePaths`\n\nAn array of paths to force-include in the workspace scan, even if they would otherwise be excluded (e.g. by `.gitignore`). `ignorePaths` still takes priority.\n\n```json\n{\n \"includePaths\": [\"tools/internal-package\"]\n}\n```\n\n---\n\n### `packageManager`\n\nOverride the auto-detected package manager. Accepted values: `npm`, `pnpm`, `yarn`, `bun`.\n\n```json\n{\n \"packageManager\": \"pnpm\"\n}\n```\n\n---\n\n### `interactive`\n\nEnable the interactive update prompt automatically after every run.\n\n```json\n{\n \"interactive\": true\n}\n```\n\n---\n\n## CLI vs file precedence\n\nCLI flags take precedence over file settings for most options. The `skip` array is an exception — values from both sources are **merged**.\n\n```bash\n# Overrides packageManager and interactive, but merges with file's skip list\nnpx patch-pulse --skip \"react,react-dom\" --package-manager npm --no-interactive\n```","src/content/docs/cli/configuration.mdx","8cd6d19ecf7642b6","cli/overview",{"id":60,"data":62,"body":68,"filePath":69,"digest":70,"deferredRender":32},{"title":63,"description":64,"editUrl":32,"head":65,"template":43,"sidebar":66,"pagefind":32,"draft":8},"CLI Overview","The Patch Pulse command-line tool.",[],{"hidden":8,"attrs":67},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse CLI scans your project for `package.json` files and reports which dependencies have newer versions available on the npm registry.\n\n## Key features\n\n- **Zero runtime dependencies** — nothing extra is installed into your project\n- **Monorepo-aware** — scans all workspaces from the repo root, including pnpm `catalog:` support\n- **Interactive updates** — optionally apply patch, minor, or all updates in one step\n- **CI-friendly** — `--json` output and a `--fail` exit-code gate for pipelines\n- **Configurable** — persistent settings via `patchpulse.json`\n\n## Installation\n\nRun without installing:\n\n```bash\nnpx patch-pulse\n```\n\nOr install globally:\n\n```bash\nnpm install -g patch-pulse\n```\n\n## Basic usage\n\nRun from any project directory:\n\n```bash\nnpx patch-pulse\n```\n\nPatch Pulse will scan every `package.json` it finds (excluding `node_modules`) and display a summary of outdated dependencies grouped by project and dependency type.\n\n\u003CAside>\n `workspace:*` dependencies are ignored automatically. pnpm `catalog:` entries\n are resolved from `pnpm-workspace.yaml`.\n\u003C/Aside>\n\n## Enabling interactive updates\n\nPass `--interactive` (or `-i`) to get a prompt after the summary that lets you apply patch, minor, or all updates in one step:\n\n```bash\nnpx patch-pulse --interactive\n```\n\nYou can also enable this permanently in your [configuration file](../configuration).\n\n## Debugging\n\nTo log npm registry lookup failures and network errors, set the `PATCH_PULSE_DEBUG` environment variable:\n\n```bash\nPATCH_PULSE_DEBUG=1 npx patch-pulse\n```","src/content/docs/cli/overview.mdx","6bd3663aa262e749","discord-bot",{"id":71,"data":73,"body":79,"filePath":80,"digest":81,"deferredRender":32},{"title":74,"description":75,"editUrl":32,"head":76,"template":43,"sidebar":77,"pagefind":32,"draft":8},"Discord Bot","Get Discord notifications for new package releases in your server channels.",[],{"hidden":8,"attrs":78},{},"import { Aside } from '@astrojs/starlight/components';\nimport AddToDiscordButton from '../../components/AddToDiscordButton.astro';\n\nThe Patch Pulse Discord Bot notifies your server whenever a package you depend on releases a new version.\n\n\u003CAddToDiscordButton href=\"https://grand-yak-92.convex.site/discord/install\" />\n\n\u003CAside type=\"note\">\n Discord currently gets the base release notification flow. GitHub link\n backfill and AI-generated release summaries remain Slack-only for now.\n\u003C/Aside>\n\n## How it works\n\nOnce installed, the bot monitors packages you care about and sends a Discord message when a new version is published to the npm registry.\n\nDiscord tracking is channel-based:\n\n- every subscription targets an explicit channel\n- the same package can be tracked in multiple channels\n- filters can be set to patch, minor, or major updates\n\n## Slash commands\n\nUse these commands in your server:\n\n- `/npmtrack package:react`\n- `/npmtrack package:react channel:#frontend`\n- `/npmtrack package:react filter:minor`\n- `/npmuntrack package:react`\n- `/npmuntrack package:react channel:#frontend`\n- `/npmlist`\n\nCommand responses are ephemeral, while update notifications are posted into the subscribed channel.\n\n## Install and setup\n\nTo add Patch Pulse to your server:\n\n- open [grand-yak-92.convex.site/discord/install](https://grand-yak-92.convex.site/discord/install)\n- choose the target server\n- approve the requested permissions\n\nIf you are self-hosting Patch Pulse rather than using the hosted bot, the Discord app setup and environment configuration live in the notifier package docs, not the public user docs site.\n\n## Slack vs Discord\n\nSlack and Discord support the same core package tracking model, but there are a few operational differences:\n\n- Slack has a workspace default channel; Discord does not\n- Slack receives delayed GitHub link backfill and AI summaries; Discord currently does not\n- Discord commands use typed slash-command options instead of Slack's free-text command parsing","src/content/docs/discord-bot.mdx","84b0b2166b10d66a","github-action/configuration",{"id":82,"data":84,"body":90,"filePath":91,"digest":92,"deferredRender":32},{"title":85,"description":86,"editUrl":32,"head":87,"template":43,"sidebar":88,"pagefind":32,"draft":8},"GitHub Action Configuration","All inputs for the PatchPulse GitHub Action — grouping, ignore lists, auto-merge, PR limits, and more.",[],{"hidden":8,"attrs":89},{},"import { Aside } from '@astrojs/starlight/components';\n\n## Inputs\n\n| Input | Required | Default | Description |\n| ----------------------- | -------- | ------------------- | --------------------------------------------------------------------------------- |\n| `github-token` | Yes | — | GitHub token with `contents: write` and `pull-requests: write` permissions |\n| `update-types` | No | `patch,minor,major` | Comma-separated list of update types to open PRs for |\n| `groups` | No | `{}` | JSON object grouping related packages into a single PR |\n| `ignore` | No | `[]` | JSON array of package names or glob patterns to skip |\n| `max-open-prs` | No | `10` | Maximum open patch-pulse PRs at any time (`0` = unlimited) |\n| `auto-merge` | No | `none` | Auto-merge PRs at or below this level once CI passes: `patch`, `minor`, or `none` |\n| `assignees` | No | `[]` | JSON array of GitHub usernames to assign to opened PRs |\n| `reviewers` | No | `[]` | JSON array of GitHub usernames to request as reviewers |\n| `team-reviewers` | No | `[]` | JSON array of team slugs to request as reviewers |\n| `commit-message-prefix` | No | `chore(deps):` | Prefix used in commit messages and PR titles |\n| `working-directory` | No | `.` | Directory to run patch-pulse in |\n\n---\n\n## Filtering update types\n\nBy default the action opens PRs for all three update types. Narrow it down with `update-types`:\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n update-types: 'minor,major' # patch updates are skipped entirely\n```\n\n---\n\n## Grouping related packages\n\nSome packages are tightly coupled and must always update together. Use `groups` to define these relationships — when at least one package in a group is outdated, all packages in the group are bumped in a single branch and PR.\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n groups: |\n {\n \"tanstack\": [\n \"@tanstack/router\",\n \"@tanstack/start\",\n \"@tanstack/react-query\"\n ],\n \"storybook\": [\n \"storybook\",\n \"@storybook/react\",\n \"@storybook/addon-essentials\"\n ]\n }\n```\n\nThe PR's risk level reflects the **highest** update type across all packages in the group. Packages not listed in any group each get their own branch and PR.\n\n---\n\n## Ignoring packages\n\nUse `ignore` to permanently exclude packages from ever getting a PR. Supports exact names and `*` glob patterns:\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n ignore: '[\"some-internal-package\", \"@types/*\", \"eslint-*\"]'\n```\n\n\u003CAside type=\"note\">\n The ignore list is also respected by the PatchPulse CLI's `skip`\n configuration. Packages skipped in `patchpulse.json` are filtered out before\n the action even sees them.\n\u003C/Aside>\n\n---\n\n## Limiting open PRs\n\nThe `max-open-prs` input prevents your queue from being flooded on a first run or after a long gap. Once the limit is reached, no new PRs are opened until existing ones are merged or closed. Existing patch-pulse PRs are always updated regardless of the limit.\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n max-open-prs: '5' # open at most 5 patch-pulse PRs at a time\n```\n\nSet to `'0'` to disable the limit entirely.\n\n---\n\n## Auto-merge\n\nWhen `auto-merge` is set, the action enables GitHub's native auto-merge on the PR. The PR will squash-merge automatically once **all required status checks pass** — it does not merge immediately.\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n auto-merge: 'patch' # also accepts 'minor' to include minor updates\n```\n\nThe threshold is inclusive: `auto-merge: minor` enables auto-merge for both patch and minor PRs. Major PRs always require manual review.\n\n\u003CAside type=\"caution\">\n Auto-merge must be enabled in your repository settings before the action can\n use it (**Settings → General → Allow auto-merge**). If it is not enabled, the\n action will log a warning and continue without failing.\n\u003C/Aside>\n\n---\n\n## Respecting closed PRs\n\nIf you close a patch-pulse PR without merging (rejecting the update), the action will not re-open it on the next run. To allow a PR to be re-created, delete the `patch-pulse/\u003Cgroup-name>` branch from your repository.\n\n---\n\n## Assignees and reviewers\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n assignees: '[\"alice\"]'\n reviewers: '[\"bob\", \"carol\"]'\n team-reviewers: '[\"my-org/frontend-team\"]'\n```\n\nAll three are applied to every newly opened PR. Failures (e.g. the user isn't a collaborator) are logged as warnings and do not fail the action.\n\n---\n\n## Commit message prefix\n\nIf your project uses a different commit convention, override the prefix:\n\n```yaml\n- uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n commit-message-prefix: 'deps:'\n```\n\nThis affects both the git commit message and the PR title.\n\n---\n\n## Full example\n\n```yaml\nname: PatchPulse Dependency Bot\n\non:\n schedule:\n - cron: '0 8 * * 1' # Every Monday at 08:00 UTC\n workflow_dispatch:\n\njobs:\n patch-pulse:\n runs-on: ubuntu-latest\n permissions:\n contents: write\n pull-requests: write\n\n steps:\n - uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - uses: pnpm/action-setup@v4\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: pnpm\n\n - run: pnpm install --frozen-lockfile\n\n - uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n update-types: 'patch,minor,major'\n groups: |\n {\n \"tanstack\": [\n \"@tanstack/router\",\n \"@tanstack/start\",\n \"@tanstack/react-query\"\n ]\n }\n ignore: '[\"@types/*\"]'\n max-open-prs: '10'\n auto-merge: 'patch'\n assignees: '[\"your-github-username\"]'\n reviewers: '[\"your-github-username\"]'\n```","src/content/docs/github-action/configuration.mdx","4d622951dcb39954","github-action/overview",{"id":93,"data":95,"body":101,"filePath":102,"digest":103,"deferredRender":32},{"title":96,"description":97,"editUrl":32,"head":98,"template":43,"sidebar":99,"pagefind":32,"draft":8},"GitHub Action Overview","Automatically open PRs for outdated npm dependencies on a schedule.",[],{"hidden":8,"attrs":100},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse GitHub Action runs on a schedule, detects outdated dependencies using the Patch Pulse CLI, and opens one pull request per package (or package group) — keeping your dependency updates small, reviewable, and easy to revert.\n\n## Key features\n\n- **One PR per package (or group)** — each update is independently reviewable and revertable\n- **Lockfile updates** — automatically runs your package manager's install after bumping versions, so the lockfile is always in sync\n- **Package grouping** — define groups of related packages (e.g. all `@tanstack/*`) that update together in a single PR\n- **Monorepo-aware** — bumps the package across every workspace it appears in, all in one PR\n- **Range-preserving** — if you pin with `^`, the PR writes `^new-version`; exact pins stay exact\n- **Ignore list** — exclude packages or glob patterns (`@types/*`) from ever getting a PR\n- **PR limit** — caps the number of open patch-pulse PRs so your queue never gets overwhelming\n- **Breaking change risk labels** — every PR includes a risk callout (`NONE` / `LOW` / `HIGH`) based on the update type\n- **Release notes links** — the PR body links directly to GitHub releases for each updated package\n- **Respects closed PRs** — if you close a PR without merging, the action won't re-open it until you delete the branch\n- **Auto-merge** — optionally enable GitHub's native auto-merge so PRs squash-merge automatically once all required CI checks pass\n- **Assignees & reviewers** — configure who gets assigned or requested for review on every opened PR\n- **Configurable commit prefix** — use `chore(deps):`, `deps:`, or whatever fits your project's commit convention\n- **No stale PR pile-up** — one branch per group (`patch-pulse/\u003Cname>`), updated in place each run\n\n## How it works\n\n1. The action runs `npx patch-pulse --json --hide-clean` in your repository\n2. Outdated packages are filtered by your ignore list and grouped\n3. For each group, a branch `patch-pulse/\u003Cgroup-name>` is created from your default branch\n4. Version strings are bumped in every affected `package.json`, preserving the existing range prefix\n5. The package manager's install command runs to update the lockfile\n6. The branch is pushed and a pull request is opened (or the existing one is updated)\n\n## Quick start\n\nAdd the following workflow to your repository at `.github/workflows/patchpulse.yml`:\n\n```yaml\nname: PatchPulse Dependency Bot\n\non:\n schedule:\n - cron: '0 8 * * 1' # Every Monday at 08:00 UTC\n workflow_dispatch:\n\njobs:\n patch-pulse:\n runs-on: ubuntu-latest\n permissions:\n contents: write\n pull-requests: write\n\n steps:\n - uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - uses: pnpm/action-setup@v4 # remove if using npm / yarn\n - uses: actions/setup-node@v4\n with:\n node-version: 22\n cache: pnpm\n\n - run: pnpm install --frozen-lockfile\n\n - uses: barrymichaeldoyle/patch-pulse/packages/action@action/v0\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n```\n\n\u003CAside type=\"tip\">\n Make sure your repository's workflow permissions allow GitHub Actions to\n create pull requests. Go to **Settings → Actions → General → Workflow\n permissions** and enable **Allow GitHub Actions to create and approve pull\n requests**.\n\u003C/Aside>\n\n## Example PR\n\nFor a minor update to a single package the action opens a PR like this:\n\n> **chore(deps): update `zod` 3.22.0 → 3.24.0 (minor)**\n>\n> ### Breaking Change Risk: LOW\n>\n> > [!NOTE]\n> > Minor updates add backwards-compatible features. Review the release notes before merging.\n>\n> | Package | From | To | Type |\n> | ------- | -------- | ------------------------------------------------------------------ | -------- |\n> | `zod` | `3.22.0` | [`3.24.0`](https://github.com/colinhacks/zod/releases/tag/v3.24.0) | 🟡 MINOR |\n>\n> #### Release Notes\n>\n> - [`zod` releases](https://github.com/colinhacks/zod/releases)\n\nSee [Configuration](./configuration) for grouping related packages, filtering update types, and enabling auto-merge.\n\n## Versioning\n\nThe action follows the same tag convention used by `actions/checkout`, `actions/setup-node`, and other official actions:\n\n| Ref | Behaviour |\n| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `@action/v0` | **Recommended.** Moving tag — always the latest `v0.x` release. You get new features and fixes automatically, but breaking changes (a `v1`) are opt-in. |\n| `@action/v0.1.0` | Exact pin — nothing changes until you update the ref yourself. Use this in environments that require full reproducibility. |\n| `@main` | Unreleased HEAD — avoid in production. Useful only for testing unreleased changes. |\n\nA new major tag will only be cut if a change would break existing workflow configurations. Additive changes (new inputs, new behaviour behind a flag) stay in the same major.","src/content/docs/github-action/overview.mdx","b68373e5825b515f","index",{"id":104,"data":106,"body":122,"filePath":123,"digest":124,"deferredRender":32},{"title":107,"description":108,"editUrl":32,"head":109,"template":10,"hero":110,"sidebar":120,"pagefind":32,"draft":8},"Patch Pulse","Keep a pulse on your npm dependencies.",[],{"tagline":108,"actions":111},[112,116],{"text":113,"link":114,"variant":17,"icon":115},"Get Started","./introduction",{"type":19,"name":20},{"text":117,"link":118,"variant":24,"icon":119},"View on GitHub","https://github.com/barrymichaeldoyle/patch-pulse",{"type":19,"name":30},{"hidden":8,"attrs":121},{},"import { CardGrid, LinkCard } from '@astrojs/starlight/components';\n\n## Products\n\n\u003CCardGrid>\n \u003CLinkCard\n title=\"CLI\"\n href=\"./cli/overview\"\n description=\"Scan projects and monorepos for outdated npm dependencies.\"\n />\n \u003CLinkCard\n title=\"GitHub Action\"\n href=\"./github-action/overview\"\n description=\"Automatically open PRs for outdated dependencies on a schedule.\"\n />\n \u003CLinkCard\n title=\"Slack Bot\"\n href=\"./slack-bot\"\n description=\"Get Slack release alerts with GitHub release links and AI-generated summaries for tracked packages.\"\n />\n \u003CLinkCard\n title=\"Discord Bot\"\n href=\"./discord-bot\"\n description=\"Get Discord release alerts in your server channels for the packages you track.\"\n />\n \u003CLinkCard\n title=\"VS Code Extension\"\n href=\"./vscode/overview\"\n description=\"See dependency version status inline in your package.json files.\"\n />\n\u003C/CardGrid>","src/content/docs/index.mdx","967dcb698192c5c4","introduction",{"id":125,"data":127,"body":133,"filePath":134,"digest":135,"deferredRender":32},{"title":128,"description":129,"editUrl":32,"head":130,"template":43,"sidebar":131,"pagefind":32,"draft":8},"Introduction","What is Patch Pulse and what does it offer?",[],{"hidden":8,"attrs":132},{},"Patch Pulse is a suite of tools that help you keep your npm dependencies up to date.\n\n## What's in the ecosystem?\n\n| Tool | Description |\n| ------------------------------------------ | ---------------------------------------------------------------------------- |\n| [CLI](../cli/overview) | Zero-dependency command-line tool to scan your project for outdated packages |\n| [GitHub Action](../github-action/overview) | Automatically open PRs for outdated dependencies on a schedule |\n| [VS Code Extension](../vscode/overview) | Inline version information directly in your `package.json` files |\n| [Slack Bot](../slack-bot) | Get Slack release alerts with GitHub release links and AI summaries |\n| [Discord Bot](../discord-bot) | Get Discord release alerts in your server channels |\n\n## Core concepts\n\nPatch Pulse checks your dependencies against the npm registry and tells you which packages have newer versions available — breaking them down by **patch**, **minor**, and **major** updates so you can decide what to act on.\n\nIt is **monorepo-aware**: running from the root of a workspace will scan every `package.json` found under the project, with full support for pnpm `catalog:` entries.\n\n## Quick start\n\nThe fastest way to try it is with the CLI — no install required:\n\n```bash\nnpx patch-pulse\n```\n\nSee the [CLI overview](../cli/overview) to dive deeper.","src/content/docs/introduction.mdx","f93f63d7747037dd","slack-bot",{"id":136,"data":138,"body":144,"filePath":145,"digest":146,"deferredRender":32},{"title":139,"description":140,"editUrl":32,"head":141,"template":43,"sidebar":142,"pagefind":32,"draft":8},"Slack Bot","Get Slack notifications for new package releases, plus GitHub release links and AI summaries.",[],{"hidden":8,"attrs":143},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse Slack Bot notifies your workspace whenever a package you depend on releases a new version, updates the message with GitHub release links when they are available, and posts an AI-generated summary in the thread when the release evidence is strong enough.\n\n\u003Ca\n href=\"https://grand-yak-92.convex.site/slack/install\"\n style=\"display: inline-block; margin: 1rem 0 1.5rem;\"\n>\n \u003Cimg\n alt=\"Add to Slack\"\n height=\"40\"\n src=\"https://platform.slack-edge.com/img/add_to_slack.png\"\n srcset=\"https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x\"\n />\n\u003C/a>\n\n\u003CAside type=\"tip\">\n Installation takes about 30 seconds and is free. Patch Pulse needs at least 5\n active workspace installs before Slack will approve it for the official\n Marketplace. Installing now helps the project reach that threshold.\n\u003C/Aside>\n\n## How it works\n\nOnce installed, the bot monitors packages you care about and sends a Slack notification when a new version is published to the npm registry.\n\nFor supported releases, Patch Pulse also enriches that notification after the initial post:\n\n- it adds GitHub release links when repository metadata can be resolved\n- it posts a short AI-generated thread summary of what changed when upstream release evidence is strong enough\n\nThat gives your team the version bump, the release source, and a quick readable summary without leaving Slack.\n\nIf you use Discord instead, see the [Discord Bot](../discord-bot) docs.","src/content/docs/slack-bot.mdx","f787701a48dc205c","vscode/overview",{"id":147,"data":149,"body":155,"filePath":156,"digest":157,"deferredRender":32},{"title":150,"description":151,"editUrl":32,"head":152,"template":43,"sidebar":153,"pagefind":32,"draft":8},"VS Code Extension Overview","The Patch Pulse VS Code extension.",[],{"hidden":8,"attrs":154},{},"import { Aside } from '@astrojs/starlight/components';\n\nThe Patch Pulse VS Code extension shows inline version information for packages in your `package.json` files, so you can see which dependencies are outdated without leaving the editor.\n\n\u003CAside type=\"caution\">\n The extension is currently in early development. Features and settings are\n subject to change.\n\u003C/Aside>\n\n## Features\n\n- **Inline decorations** — version status shown directly next to each dependency in `package.json`\n- **Automatic checks** — versions are checked when a `package.json` file is opened\n- **Manual refresh** — trigger a re-check at any time via the command palette\n\n## Commands\n\nThe following commands are available in the VS Code command palette (`Cmd/Ctrl + Shift + P`):\n\n| Command | Description |\n| --------------------------------------- | -------------------------------------------- |\n| `Patch Pulse: Check Package Versions` | Run a version check on the current workspace |\n| `Patch Pulse: Refresh Package Versions` | Refresh previously checked version data |\n\n## Activation\n\nThe extension activates automatically when:\n\n- A JSON file is opened, or\n- A `package.json` file is detected anywhere in the workspace\n\nSee [Settings](../settings) for configuration options.","src/content/docs/vscode/overview.mdx","32f9cbbe0002dd14","vscode/settings",{"id":158,"data":160,"body":166,"filePath":167,"digest":168,"deferredRender":32},{"title":161,"description":162,"editUrl":32,"head":163,"template":43,"sidebar":164,"pagefind":32,"draft":8},"VS Code Settings","Configuration settings for the Patch Pulse VS Code extension.",[],{"hidden":8,"attrs":165},{},"All settings are available under the `patchPulse` namespace in VS Code's settings UI or `settings.json`.\n\n## Settings\n\n### `patchPulse.enabled`\n\nEnable or disable the Patch Pulse extension entirely.\n\n| | |\n| ----------- | --------- |\n| **Type** | `boolean` |\n| **Default** | `true` |\n\n---\n\n### `patchPulse.checkOnOpen`\n\nAutomatically check package versions when a `package.json` file is opened.\n\n| | |\n| ----------- | --------- |\n| **Type** | `boolean` |\n| **Default** | `true` |\n\n---\n\n### `patchPulse.updateInterval`\n\nHow often (in seconds) Patch Pulse should re-check versions in the background.\n\n| | |\n| ----------- | --------------- |\n| **Type** | `number` |\n| **Default** | `3600` (1 hour) |\n\n## Example `settings.json`\n\n```json\n{\n \"patchPulse.enabled\": true,\n \"patchPulse.checkOnOpen\": true,\n \"patchPulse.updateInterval\": 1800\n}\n```","src/content/docs/vscode/settings.mdx","36e2f25a483bbf1f","meta::meta",["Map",171,172,173,174,175,176],"astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://barrymichaeldoyle.github.io\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"where\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":false,\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[null,null,null],\"rehypePlugins\":[[null],null,[null,{\"themes\":[{\"name\":\"Night Owl No Italics\",\"type\":\"dark\",\"colors\":{\"focusBorder\":\"#122d42\",\"foreground\":\"#d6deeb\",\"disabledForeground\":\"#cccccc80\",\"descriptionForeground\":\"#d6deebb3\",\"errorForeground\":\"#ef5350\",\"icon.foreground\":\"#c5c5c5\",\"contrastActiveBorder\":null,\"contrastBorder\":\"#122d42\",\"textBlockQuote.background\":\"#7f7f7f1a\",\"textBlockQuote.border\":\"#007acc80\",\"textCodeBlock.background\":\"#4f4f4f\",\"textLink.activeForeground\":\"#3794ff\",\"textLink.foreground\":\"#3794ff\",\"textPreformat.foreground\":\"#d7ba7d\",\"textSeparator.foreground\":\"#ffffff2e\",\"editor.background\":\"#23262f\",\"editor.foreground\":\"#d6deeb\",\"editorLineNumber.foreground\":\"#4b6479\",\"editorLineNumber.activeForeground\":\"#c5e4fd\",\"editorActiveLineNumber.foreground\":\"#c6c6c6\",\"editor.selectionBackground\":\"#1d3b53\",\"editor.inactiveSelectionBackground\":\"#7e57c25a\",\"editor.selectionHighlightBackground\":\"#5f7e9779\",\"editorError.foreground\":\"#ef5350\",\"editorWarning.foreground\":\"#b39554\",\"editorInfo.foreground\":\"#3794ff\",\"editorHint.foreground\":\"#eeeeeeb2\",\"problemsErrorIcon.foreground\":\"#ef5350\",\"problemsWarningIcon.foreground\":\"#b39554\",\"problemsInfoIcon.foreground\":\"#3794ff\",\"editor.findMatchBackground\":\"#5f7e9779\",\"editor.findMatchHighlightBackground\":\"#1085bb5d\",\"editor.findRangeHighlightBackground\":\"#3a3d4166\",\"editorLink.activeForeground\":\"#4e94ce\",\"editorLightBulb.foreground\":\"#ffcc00\",\"editorLightBulbAutoFix.foreground\":\"#75beff\",\"diffEditor.insertedTextBackground\":\"#99b76d23\",\"diffEditor.insertedTextBorder\":\"#c5e47833\",\"diffEditor.removedTextBackground\":\"#ef535033\",\"diffEditor.removedTextBorder\":\"#ef53504d\",\"diffEditor.insertedLineBackground\":\"#9bb95533\",\"diffEditor.removedLineBackground\":\"#ff000033\",\"editorStickyScroll.background\":\"#011627\",\"editorStickyScrollHover.background\":\"#2a2d2e\",\"editorInlayHint.background\":\"#5f7e97cc\",\"editorInlayHint.foreground\":\"#ffffff\",\"editorInlayHint.typeBackground\":\"#5f7e97cc\",\"editorInlayHint.typeForeground\":\"#ffffff\",\"editorInlayHint.parameterBackground\":\"#5f7e97cc\",\"editorInlayHint.parameterForeground\":\"#ffffff\",\"editorPane.background\":\"#011627\",\"editorGroup.emptyBackground\":\"#011627\",\"editorGroup.focusedEmptyBorder\":null,\"editorGroupHeader.tabsBackground\":\"var(--sl-color-black)\",\"editorGroupHeader.tabsBorder\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"editorGroupHeader.noTabsBackground\":\"#011627\",\"editorGroupHeader.border\":null,\"editorGroup.border\":\"#011627\",\"editorGroup.dropBackground\":\"#7e57c273\",\"editorGroup.dropIntoPromptForeground\":\"#d6deeb\",\"editorGroup.dropIntoPromptBackground\":\"#021320\",\"editorGroup.dropIntoPromptBorder\":null,\"sideBySideEditor.horizontalBorder\":\"#011627\",\"sideBySideEditor.verticalBorder\":\"#011627\",\"scrollbar.shadow\":\"#010b14\",\"scrollbarSlider.background\":\"#ffffff17\",\"scrollbarSlider.hoverBackground\":\"#ffffff40\",\"scrollbarSlider.activeBackground\":\"#084d8180\",\"panel.background\":\"#011627\",\"panel.border\":\"#5f7e97\",\"panelTitle.activeBorder\":\"#5f7e97\",\"panelTitle.activeForeground\":\"#ffffffcc\",\"panelTitle.inactiveForeground\":\"#d6deeb80\",\"panelSectionHeader.background\":\"#80808051\",\"terminal.background\":\"#011627\",\"widget.shadow\":\"#011627\",\"editorWidget.background\":\"#021320\",\"editorWidget.foreground\":\"#d6deeb\",\"editorWidget.border\":\"#5f7e97\",\"quickInput.background\":\"#021320\",\"quickInput.foreground\":\"#d6deeb\",\"quickInputTitle.background\":\"#ffffff1a\",\"pickerGroup.foreground\":\"#d1aaff\",\"pickerGroup.border\":\"#011627\",\"editor.hoverHighlightBackground\":\"#7e57c25a\",\"editorHoverWidget.background\":\"#011627\",\"editorHoverWidget.foreground\":\"#d6deeb\",\"editorHoverWidget.border\":\"#5f7e97\",\"editorHoverWidget.statusBarBackground\":\"#011a2f\",\"titleBar.activeBackground\":\"var(--sl-color-black)\",\"titleBar.activeForeground\":\"var(--sl-color-text)\",\"titleBar.inactiveBackground\":\"#010e1a\",\"titleBar.inactiveForeground\":\"#eeefff99\",\"titleBar.border\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"toolbar.hoverBackground\":\"#5a5d5e50\",\"toolbar.activeBackground\":\"#63666750\",\"tab.activeBackground\":\"#0b2942\",\"tab.unfocusedActiveBackground\":\"#0b2942\",\"tab.inactiveBackground\":\"#01111d\",\"tab.unfocusedInactiveBackground\":\"#01111d\",\"tab.activeForeground\":\"var(--sl-color-text)\",\"tab.inactiveForeground\":\"#5f7e97\",\"tab.unfocusedActiveForeground\":\"#5f7e97\",\"tab.unfocusedInactiveForeground\":\"#5f7e97\",\"tab.hoverBackground\":null,\"tab.unfocusedHoverBackground\":null,\"tab.hoverForeground\":null,\"tab.unfocusedHoverForeground\":null,\"tab.border\":\"#272b3b\",\"tab.lastPinnedBorder\":\"#585858\",\"tab.activeBorder\":\"transparent\",\"tab.unfocusedActiveBorder\":\"#262a39\",\"tab.activeBorderTop\":\"var(--sl-color-accent-high)\",\"tab.unfocusedActiveBorderTop\":null,\"tab.hoverBorder\":null,\"tab.unfocusedHoverBorder\":null,\"tab.activeModifiedBorder\":\"#3399cc\",\"tab.inactiveModifiedBorder\":\"#3399cc80\",\"tab.unfocusedActiveModifiedBorder\":\"#3399cc80\",\"tab.unfocusedInactiveModifiedBorder\":\"#3399cc40\",\"badge.background\":\"#5f7e97\",\"badge.foreground\":\"#ffffff\",\"button.background\":\"#7e57c2cc\",\"button.foreground\":\"#ffffffcc\",\"button.border\":\"#122d42\",\"button.separator\":\"#ffffff52\",\"button.hoverBackground\":\"#7e57c2\",\"button.secondaryBackground\":\"#3a3d41\",\"button.secondaryForeground\":\"#ffffff\",\"button.secondaryHoverBackground\":\"#46494e\",\"dropdown.background\":\"#011627\",\"dropdown.foreground\":\"#ffffffcc\",\"dropdown.border\":\"#5f7e97\",\"list.activeSelectionBackground\":\"#234d708c\",\"list.activeSelectionForeground\":\"#ffffff\",\"tree.indentGuidesStroke\":\"#585858\",\"input.background\":\"#0b253a\",\"input.foreground\":\"#ffffffcc\",\"input.placeholderForeground\":\"#5f7e97\",\"inputOption.activeBorder\":\"#ffffffcc\",\"inputOption.hoverBackground\":\"#5a5d5e80\",\"inputOption.activeBackground\":\"#122d4266\",\"inputOption.activeForeground\":\"#ffffff\",\"inputValidation.infoBackground\":\"#00589ef2\",\"inputValidation.infoBorder\":\"#64b5f6\",\"inputValidation.warningBackground\":\"#675700f2\",\"inputValidation.warningBorder\":\"#ffca28\",\"inputValidation.errorBackground\":\"#ab0300f2\",\"inputValidation.errorBorder\":\"#ef5350\",\"keybindingLabel.background\":\"#8080802b\",\"keybindingLabel.foreground\":\"#cccccc\",\"keybindingLabel.border\":\"#33333399\",\"keybindingLabel.bottomBorder\":\"#44444499\",\"menu.foreground\":\"#ffffffcc\",\"menu.background\":\"#011627\",\"menu.selectionForeground\":\"#ffffff\",\"menu.selectionBackground\":\"#234d708c\",\"menu.separatorBackground\":\"#606060\",\"editor.snippetTabstopHighlightBackground\":\"#7c7c74c\",\"editor.snippetFinalTabstopHighlightBorder\":\"#525252\",\"terminal.ansiBlack\":\"#011627\",\"terminal.ansiRed\":\"#ef5350\",\"terminal.ansiGreen\":\"#22da6e\",\"terminal.ansiYellow\":\"#c5e478\",\"terminal.ansiBlue\":\"#82aaff\",\"terminal.ansiMagenta\":\"#c792ea\",\"terminal.ansiCyan\":\"#21c7a8\",\"terminal.ansiWhite\":\"#ffffff\",\"terminal.ansiBrightBlack\":\"#575656\",\"terminal.ansiBrightRed\":\"#ef5350\",\"terminal.ansiBrightGreen\":\"#22da6e\",\"terminal.ansiBrightYellow\":\"#ffeb95\",\"terminal.ansiBrightBlue\":\"#82aaff\",\"terminal.ansiBrightMagenta\":\"#c792ea\",\"terminal.ansiBrightCyan\":\"#7fdbca\",\"terminal.ansiBrightWhite\":\"#ffffff\",\"selection.background\":\"#4373c2\",\"input.border\":\"#5f7e97\",\"punctuation.definition.generic.begin.html\":\"#ef5350f2\",\"progress.background\":\"#7e57c2\",\"breadcrumb.foreground\":\"#a599e9\",\"breadcrumb.focusForeground\":\"#ffffff\",\"breadcrumb.activeSelectionForeground\":\"#ffffff\",\"breadcrumbPicker.background\":\"#001122\",\"list.invalidItemForeground\":\"#975f94\",\"list.dropBackground\":\"#011627\",\"list.focusBackground\":\"#010d18\",\"list.focusForeground\":\"#ffffff\",\"list.highlightForeground\":\"#ffffff\",\"list.hoverBackground\":\"#011627\",\"list.hoverForeground\":\"#ffffff\",\"list.inactiveSelectionBackground\":\"#0e293f\",\"list.inactiveSelectionForeground\":\"#5f7e97\",\"activityBar.background\":\"#011627\",\"activityBar.dropBackground\":\"#5f7e97\",\"activityBar.foreground\":\"#5f7e97\",\"activityBar.border\":\"#011627\",\"activityBarBadge.background\":\"#44596b\",\"activityBarBadge.foreground\":\"#ffffff\",\"sideBar.background\":\"#011627\",\"sideBar.foreground\":\"#89a4bb\",\"sideBar.border\":\"#011627\",\"sideBarTitle.foreground\":\"#5f7e97\",\"sideBarSectionHeader.background\":\"#011627\",\"sideBarSectionHeader.foreground\":\"#5f7e97\",\"editorCursor.foreground\":\"#80a4c2\",\"editor.wordHighlightBackground\":\"#f6bbe533\",\"editor.wordHighlightStrongBackground\":\"#e2a2f433\",\"editor.lineHighlightBackground\":\"#0003\",\"editor.rangeHighlightBackground\":\"#7e57c25a\",\"editorIndentGuide.background\":\"#5e81ce52\",\"editorIndentGuide.activeBackground\":\"#7e97ac\",\"editorRuler.foreground\":\"#5e81ce52\",\"editorCodeLens.foreground\":\"#5e82ceb4\",\"editorBracketMatch.background\":\"#5f7e974d\",\"editorOverviewRuler.currentContentForeground\":\"#7e57c2\",\"editorOverviewRuler.incomingContentForeground\":\"#7e57c2\",\"editorOverviewRuler.commonContentForeground\":\"#7e57c2\",\"editorGutter.background\":\"#011627\",\"editorGutter.modifiedBackground\":\"#e2b93d\",\"editorGutter.addedBackground\":\"#9ccc65\",\"editorGutter.deletedBackground\":\"#ef5350\",\"editorSuggestWidget.background\":\"#2c3043\",\"editorSuggestWidget.border\":\"#2b2f40\",\"editorSuggestWidget.foreground\":\"#d6deeb\",\"editorSuggestWidget.highlightForeground\":\"#ffffff\",\"editorSuggestWidget.selectedBackground\":\"#5f7e97\",\"debugExceptionWidget.background\":\"#011627\",\"debugExceptionWidget.border\":\"#5f7e97\",\"editorMarkerNavigation.background\":\"#0b2942\",\"editorMarkerNavigationError.background\":\"#ef5350\",\"editorMarkerNavigationWarning.background\":\"#ffca28\",\"peekView.border\":\"#5f7e97\",\"peekViewEditor.background\":\"#011627\",\"peekViewEditor.matchHighlightBackground\":\"#7e57c25a\",\"peekViewResult.background\":\"#011627\",\"peekViewResult.fileForeground\":\"#5f7e97\",\"peekViewResult.lineForeground\":\"#5f7e97\",\"peekViewResult.matchHighlightBackground\":\"#ffffffcc\",\"peekViewResult.selectionBackground\":\"#2e3250\",\"peekViewResult.selectionForeground\":\"#5f7e97\",\"peekViewTitle.background\":\"#011627\",\"peekViewTitleDescription.foreground\":\"#697098\",\"peekViewTitleLabel.foreground\":\"#5f7e97\",\"merge.currentHeaderBackground\":\"#5f7e97\",\"merge.incomingHeaderBackground\":\"#7e57c25a\",\"statusBar.background\":\"#011627\",\"statusBar.foreground\":\"#5f7e97\",\"statusBar.border\":\"#262a39\",\"statusBar.debuggingBackground\":\"#202431\",\"statusBar.debuggingBorder\":\"#1f2330\",\"statusBar.noFolderBackground\":\"#011627\",\"statusBar.noFolderBorder\":\"#25293a\",\"statusBarItem.activeBackground\":\"#202431\",\"statusBarItem.hoverBackground\":\"#202431\",\"statusBarItem.prominentBackground\":\"#202431\",\"statusBarItem.prominentHoverBackground\":\"#202431\",\"notifications.background\":\"#01111d\",\"notifications.border\":\"#262a39\",\"notificationCenter.border\":\"#262a39\",\"notificationToast.border\":\"#262a39\",\"notifications.foreground\":\"#ffffffcc\",\"notificationLink.foreground\":\"#80cbc4\",\"extensionButton.prominentForeground\":\"#ffffffcc\",\"extensionButton.prominentBackground\":\"#7e57c2cc\",\"extensionButton.prominentHoverBackground\":\"#7e57c2\",\"terminal.selectionBackground\":\"#1b90dd4d\",\"terminalCursor.background\":\"#234d70\",\"debugToolBar.background\":\"#011627\",\"welcomePage.buttonBackground\":\"#011627\",\"welcomePage.buttonHoverBackground\":\"#011627\",\"walkThrough.embeddedEditorBackground\":\"#011627\",\"gitDecoration.modifiedResourceForeground\":\"#a2bffc\",\"gitDecoration.deletedResourceForeground\":\"#ef535090\",\"gitDecoration.untrackedResourceForeground\":\"#c5e478ff\",\"gitDecoration.ignoredResourceForeground\":\"#395a75\",\"gitDecoration.conflictingResourceForeground\":\"#ffeb95cc\",\"source.elm\":\"#5f7e97\",\"string.quoted.single.js\":\"#ffffff\",\"meta.objectliteral.js\":\"#82aaff\"},\"fg\":\"#d6deeb\",\"bg\":\"#23262f\",\"semanticHighlighting\":false,\"settings\":[{\"name\":\"Changed\",\"scope\":[\"markup.changed\",\"meta.diff.header.git\",\"meta.diff.header.from-file\",\"meta.diff.header.to-file\"],\"settings\":{\"foreground\":\"#a2bffc\"}},{\"name\":\"Deleted\",\"scope\":[\"markup.deleted.diff\"],\"settings\":{\"foreground\":\"#f27775fe\"}},{\"name\":\"Inserted\",\"scope\":[\"markup.inserted.diff\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Global settings\",\"settings\":{\"background\":\"#011627\",\"foreground\":\"#d6deeb\"}},{\"name\":\"Comment\",\"scope\":[\"comment\"],\"settings\":{\"foreground\":\"#919f9f\",\"fontStyle\":\"\"}},{\"name\":\"String\",\"scope\":[\"string\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"String Quoted\",\"scope\":[\"string.quoted\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"Support Constant Math\",\"scope\":[\"support.constant.math\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Number\",\"scope\":[\"constant.numeric\",\"constant.character.numeric\"],\"settings\":{\"foreground\":\"#f78c6c\",\"fontStyle\":\"\"}},{\"name\":\"Built-in constant\",\"scope\":[\"constant.language\",\"punctuation.definition.constant\",\"variable.other.constant\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"User-defined constant\",\"scope\":[\"constant.character\",\"constant.other\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Constant Character Escape\",\"scope\":[\"constant.character.escape\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"RegExp String\",\"scope\":[\"string.regexp\",\"string.regexp keyword.other\"],\"settings\":{\"foreground\":\"#5ca7e4\"}},{\"name\":\"Comma in functions\",\"scope\":[\"meta.function punctuation.separator.comma\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"Variable\",\"scope\":[\"variable\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Keyword\",\"scope\":[\"punctuation.accessor\",\"keyword\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Storage\",\"scope\":[\"storage\",\"meta.var.expr\",\"meta.class meta.method.declaration meta.var.expr storage.type.js\",\"storage.type.property.js\",\"storage.type.property.ts\",\"storage.type.property.tsx\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type.function.arrow.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Class name\",\"scope\":[\"entity.name.class\",\"meta.class entity.name.type.class\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Inherited class\",\"scope\":[\"entity.other.inherited-class\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Function name\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Meta Tag\",\"scope\":[\"punctuation.definition.tag\",\"meta.tag\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"HTML Tag names\",\"scope\":[\"entity.name.tag\",\"meta.tag.other.html\",\"meta.tag.other.js\",\"meta.tag.other.tsx\",\"entity.name.tag.tsx\",\"entity.name.tag.js\",\"entity.name.tag\",\"meta.tag.js\",\"meta.tag.tsx\",\"meta.tag.html\"],\"settings\":{\"foreground\":\"#caece6\",\"fontStyle\":\"\"}},{\"name\":\"Tag attribute\",\"scope\":[\"entity.other.attribute-name\"],\"settings\":{\"fontStyle\":\"\",\"foreground\":\"#c5e478\"}},{\"name\":\"Entity Name Tag Custom\",\"scope\":[\"entity.name.tag.custom\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Library (function & constant)\",\"scope\":[\"support.function\",\"support.constant\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Support Constant Property Value meta\",\"scope\":[\"support.constant.meta.property-value\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Library class/type\",\"scope\":[\"support.type\",\"support.class\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Support Variable DOM\",\"scope\":[\"support.variable.dom\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Invalid\",\"scope\":[\"invalid\"],\"settings\":{\"background\":\"#ff2c83\",\"foreground\":\"#ffffff\"}},{\"name\":\"Invalid deprecated\",\"scope\":[\"invalid.deprecated\"],\"settings\":{\"foreground\":\"#ffffff\",\"background\":\"#d3423e\"}},{\"name\":\"Keyword Operator\",\"scope\":[\"keyword.operator\"],\"settings\":{\"foreground\":\"#7fdbca\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Relational\",\"scope\":[\"keyword.operator.relational\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Assignment\",\"scope\":[\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Arithmetic\",\"scope\":[\"keyword.operator.arithmetic\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Bitwise\",\"scope\":[\"keyword.operator.bitwise\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Increment\",\"scope\":[\"keyword.operator.increment\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Ternary\",\"scope\":[\"keyword.operator.ternary\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Double-Slashed Comment\",\"scope\":[\"comment.line.double-slash\"],\"settings\":{\"foreground\":\"#919f9f\"}},{\"name\":\"Object\",\"scope\":[\"object\"],\"settings\":{\"foreground\":\"#cdebf7\"}},{\"name\":\"Null\",\"scope\":[\"constant.language.null\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Meta Brace\",\"scope\":[\"meta.brace\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Meta Delimiter Period\",\"scope\":[\"meta.delimiter.period\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Punctuation Definition String\",\"scope\":[\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Punctuation Definition String Markdown\",\"scope\":[\"punctuation.definition.string.begin.markdown\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Boolean\",\"scope\":[\"constant.language.boolean\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Object Comma\",\"scope\":[\"object.comma\"],\"settings\":{\"foreground\":\"#ffffff\"}},{\"name\":\"Variable Parameter Function\",\"scope\":[\"variable.parameter.function\"],\"settings\":{\"foreground\":\"#7fdbca\",\"fontStyle\":\"\"}},{\"name\":\"Support Type Property Name & entity name tags\",\"scope\":[\"support.type.vendor.property-name\",\"support.constant.vendor.property-value\",\"support.type.property-name\",\"meta.property-list entity.name.tag\"],\"settings\":{\"foreground\":\"#80cbc4\",\"fontStyle\":\"\"}},{\"name\":\"Entity Name tag reference in stylesheets\",\"scope\":[\"meta.property-list entity.name.tag.reference\"],\"settings\":{\"foreground\":\"#57eaf1\"}},{\"name\":\"Constant Other Color RGB Value Punctuation Definition Constant\",\"scope\":[\"constant.other.color.rgb-value punctuation.definition.constant\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Constant Other Color\",\"scope\":[\"constant.other.color\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Keyword Other Unit\",\"scope\":[\"keyword.other.unit\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Meta Selector\",\"scope\":[\"meta.selector\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Entity Other Attribute Name Id\",\"scope\":[\"entity.other.attribute-name.id\"],\"settings\":{\"foreground\":\"#fad430\"}},{\"name\":\"Meta Property Name\",\"scope\":[\"meta.property-name\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Doctypes\",\"scope\":[\"entity.name.tag.doctype\",\"meta.tag.sgml.doctype\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Punctuation Definition Parameters\",\"scope\":[\"punctuation.definition.parameters\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Keyword Control Operator\",\"scope\":[\"keyword.control.operator\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Keyword Operator Logical\",\"scope\":[\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Variable Instances\",\"scope\":[\"variable.instance\",\"variable.other.instance\",\"variable.readwrite.instance\",\"variable.other.readwrite.instance\",\"variable.other.property\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Variable Property Other object property\",\"scope\":[\"variable.other.object.property\"],\"settings\":{\"foreground\":\"#faf39f\",\"fontStyle\":\"\"}},{\"name\":\"Variable Property Other object\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Entity Name Function\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#82aaff\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Comparison, returns, imports, and Keyword Operator Ruby\",\"scope\":[\"keyword.control.conditional.js\",\"keyword.operator.comparison\",\"keyword.control.flow.js\",\"keyword.control.flow.ts\",\"keyword.control.flow.tsx\",\"keyword.control.ruby\",\"keyword.control.def.ruby\",\"keyword.control.loop.js\",\"keyword.control.loop.ts\",\"keyword.control.import.js\",\"keyword.control.import.ts\",\"keyword.control.import.tsx\",\"keyword.control.from.js\",\"keyword.control.from.ts\",\"keyword.control.from.tsx\",\"keyword.control.conditional.js\",\"keyword.control.conditional.ts\",\"keyword.control.switch.js\",\"keyword.control.switch.ts\",\"keyword.operator.instanceof.js\",\"keyword.operator.expression.instanceof.ts\",\"keyword.operator.expression.instanceof.tsx\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Support Constant, `new` keyword, Special Method Keyword, `debugger`, other keywords\",\"scope\":[\"support.constant\",\"keyword.other.special-method\",\"keyword.other.new\",\"keyword.other.debugger\",\"keyword.control\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Support Function\",\"scope\":[\"support.function\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Invalid Broken\",\"scope\":[\"invalid.broken\"],\"settings\":{\"foreground\":\"#989da0\",\"background\":\"#F78C6C\"}},{\"name\":\"Invalid Unimplemented\",\"scope\":[\"invalid.unimplemented\"],\"settings\":{\"background\":\"#8BD649\",\"foreground\":\"#ffffff\"}},{\"name\":\"Invalid Illegal\",\"scope\":[\"invalid.illegal\"],\"settings\":{\"foreground\":\"#ffffff\",\"background\":\"#ec5f67\"}},{\"name\":\"Language Variable\",\"scope\":[\"variable.language\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Support Variable Property\",\"scope\":[\"support.variable.property\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Variable Function\",\"scope\":[\"variable.function\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Variable Interpolation\",\"scope\":[\"variable.interpolation\"],\"settings\":{\"foreground\":\"#ef787f\"}},{\"name\":\"Meta Function Call\",\"scope\":[\"meta.function-call\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Punctuation Section Embedded\",\"scope\":[\"punctuation.section.embedded\"],\"settings\":{\"foreground\":\"#e2817f\"}},{\"name\":\"Punctuation Tweaks\",\"scope\":[\"punctuation.terminator.expression\",\"punctuation.definition.arguments\",\"punctuation.definition.array\",\"punctuation.section.array\",\"meta.array\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"More Punctuation Tweaks\",\"scope\":[\"punctuation.definition.list.begin\",\"punctuation.definition.list.end\",\"punctuation.separator.arguments\",\"punctuation.definition.list\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Template Strings\",\"scope\":[\"string.template meta.template.expression\"],\"settings\":{\"foreground\":\"#e2817f\"}},{\"name\":\"Backticks(``) in Template Strings\",\"scope\":[\"string.template punctuation.definition.string\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Italics\",\"scope\":[\"italic\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"italic\"}},{\"name\":\"Bold\",\"scope\":[\"bold\"],\"settings\":{\"foreground\":\"#c5e478\",\"fontStyle\":\"bold\"}},{\"name\":\"Quote\",\"scope\":[\"quote\"],\"settings\":{\"foreground\":\"#969bb7\",\"fontStyle\":\"\"}},{\"name\":\"Raw Code\",\"scope\":[\"raw\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"CoffeeScript Variable Assignment\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#31e1eb\"}},{\"name\":\"CoffeeScript Parameter Function\",\"scope\":[\"variable.parameter.function.coffee\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"CoffeeScript Assignments\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"C# Readwrite Variables\",\"scope\":[\"variable.other.readwrite.cs\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C# Classes & Storage types\",\"scope\":[\"entity.name.type.class.cs\",\"storage.type.cs\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"C# Namespaces\",\"scope\":[\"entity.name.type.namespace.cs\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"C# Unquoted String Zone\",\"scope\":[\"string.unquoted.preprocessor.message.cs\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C# Region\",\"scope\":[\"punctuation.separator.hash.cs\",\"keyword.preprocessor.region.cs\",\"keyword.preprocessor.endregion.cs\"],\"settings\":{\"foreground\":\"#ffcb8b\",\"fontStyle\":\"bold\"}},{\"name\":\"C# Other Variables\",\"scope\":[\"variable.other.object.cs\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"C# Enum\",\"scope\":[\"entity.name.type.enum.cs\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Dart String\",\"scope\":[\"string.interpolated.single.dart\",\"string.interpolated.double.dart\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Dart Class\",\"scope\":[\"support.class.dart\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Tag names in Stylesheets\",\"scope\":[\"entity.name.tag.css\",\"entity.name.tag.less\",\"entity.name.tag.custom.css\",\"support.constant.property-value.css\"],\"settings\":{\"foreground\":\"#ff6d6d\",\"fontStyle\":\"\"}},{\"name\":\"Wildcard(*) selector in Stylesheets\",\"scope\":[\"entity.name.tag.wildcard.css\",\"entity.name.tag.wildcard.less\",\"entity.name.tag.wildcard.scss\",\"entity.name.tag.wildcard.sass\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"CSS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Attribute Name for CSS\",\"scope\":[\"meta.attribute-selector.css entity.other.attribute-name.attribute\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Elixir Classes\",\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Elixir Functions\",\"scope\":[\"source.elixir entity.name.function\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir Constants\",\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Elixir String Punctuations\",\"scope\":[\"source.elixir punctuation.definition.string\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir\",\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir Binary Punctuations\",\"scope\":[\"source.elixir .punctuation.binary.elixir\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Closure Constant Keyword\",\"scope\":[\"constant.keyword.clojure\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Go Function Calls\",\"scope\":[\"source.go meta.function-call.go\"],\"settings\":{\"foreground\":\"#dddddd\"}},{\"name\":\"Go Keywords\",\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Go Constants e.g. nil, string format (%s, %d, etc.)\",\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"C++ Functions\",\"scope\":[\"entity.name.function.preprocessor.cpp\",\"entity.scope.name.cpp\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"C++ Meta Namespace\",\"scope\":[\"meta.namespace-block.cpp\"],\"settings\":{\"foreground\":\"#e0dec6\"}},{\"name\":\"C++ Language Primitive Storage\",\"scope\":[\"storage.type.language.primitive.cpp\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"C++ Preprocessor Macro\",\"scope\":[\"meta.preprocessor.macro.cpp\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C++ Variable Parameter\",\"scope\":[\"variable.parameter\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Powershell Variables\",\"scope\":[\"variable.other.readwrite.powershell\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Powershell Function\",\"scope\":[\"support.function.powershell\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"ID Attribute Name in HTML\",\"scope\":[\"entity.other.attribute-name.id.html\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"HTML Punctuation Definition Tag\",\"scope\":[\"punctuation.definition.tag.html\"],\"settings\":{\"foreground\":\"#6ae9f0\"}},{\"name\":\"HTML Doctype\",\"scope\":[\"meta.tag.sgml.doctype.html\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Classes\",\"scope\":[\"meta.class entity.name.type.class.js\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"JavaScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.js\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"JavaScript Terminator\",\"scope\":[\"terminator.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Meta Punctuation Definition\",\"scope\":[\"meta.js punctuation.definition.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Entity Names in Code Documentations\",\"scope\":[\"entity.name.type.instance.jsdoc\",\"entity.name.type.instance.phpdoc\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"Other Variables in Code Documentations\",\"scope\":[\"variable.other.jsdoc\",\"variable.other.phpdoc\"],\"settings\":{\"foreground\":\"#78ccf0\"}},{\"name\":\"JavaScript module imports and exports\",\"scope\":[\"variable.other.meta.import.js\",\"meta.import.js variable.other\",\"variable.other.meta.export.js\",\"meta.export.js variable.other\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Variable Parameter Function\",\"scope\":[\"variable.parameter.function.js\"],\"settings\":{\"foreground\":\"#8b96ea\"}},{\"name\":\"JavaScript[React] Variable Other Object\",\"scope\":[\"variable.other.object.js\",\"variable.other.object.jsx\",\"variable.object.property.js\",\"variable.object.property.jsx\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Variables\",\"scope\":[\"variable.js\",\"variable.other.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Entity Name Type\",\"scope\":[\"entity.name.type.js\",\"entity.name.type.module.js\"],\"settings\":{\"foreground\":\"#ffcb8b\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Support Classes\",\"scope\":[\"support.class.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JSON Property Names\",\"scope\":[\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"JSON Support Constants\",\"scope\":[\"support.constant.json\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"JSON Property values (string)\",\"scope\":[\"meta.structure.dictionary.value.json string.quoted.double\"],\"settings\":{\"foreground\":\"#c789d6\"}},{\"name\":\"Strings in JSON values\",\"scope\":[\"string.quoted.double.json punctuation.definition.string.json\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Specific JSON Property values like null\",\"scope\":[\"meta.structure.dictionary.json meta.structure.dictionary.value constant.language\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"JavaScript Other Variable\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Ruby Variables\",\"scope\":[\"variable.other.ruby\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Ruby Class\",\"scope\":[\"entity.name.type.class.ruby\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"Ruby Hashkeys\",\"scope\":[\"constant.language.symbol.hashkey.ruby\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"LESS Tag names\",\"scope\":[\"entity.name.tag.less\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"LESS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Attribute Name for LESS\",\"scope\":[\"meta.attribute-selector.less entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Markdown Headings\",\"scope\":[\"markup.heading.markdown\",\"markup.heading.setext.1.markdown\",\"markup.heading.setext.2.markdown\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown Italics\",\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"italic\"}},{\"name\":\"Markdown Bold\",\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"foreground\":\"#c5e478\",\"fontStyle\":\"bold\"}},{\"name\":\"Markdown Quote + others\",\"scope\":[\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#969bb7\",\"fontStyle\":\"\"}},{\"name\":\"Markdown Raw Code + others\",\"scope\":[\"markup.inline.raw.markdown\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Markdown Links\",\"scope\":[\"markup.underline.link.markdown\",\"markup.underline.link.image.markdown\"],\"settings\":{\"foreground\":\"#ff869a\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Link Title and Description\",\"scope\":[\"string.other.link.title.markdown\",\"string.other.link.description.markdown\"],\"settings\":{\"foreground\":\"#d6deeb\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Punctuation\",\"scope\":[\"punctuation.definition.string.markdown\",\"punctuation.definition.string.begin.markdown\",\"punctuation.definition.string.end.markdown\",\"meta.link.inline.markdown punctuation.definition.string\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown MetaData Punctuation\",\"scope\":[\"punctuation.definition.metadata.markdown\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Markdown List Punctuation\",\"scope\":[\"beginning.punctuation.definition.list.markdown\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown Inline Raw String\",\"scope\":[\"markup.inline.raw.string.markdown\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"PHP Variables\",\"scope\":[\"variable.other.php\"],\"settings\":{\"foreground\":\"#bec5d4\"}},{\"name\":\"Support Classes in PHP\",\"scope\":[\"support.class.php\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Punctuations in PHP function calls\",\"scope\":[\"meta.function-call.php punctuation\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"PHP Global Variables\",\"scope\":[\"variable.other.global.php\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Declaration Punctuation in PHP Global Variables\",\"scope\":[\"variable.other.global.php punctuation.definition.variable\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Language Constants in Python\",\"scope\":[\"constant.language.python\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Python Function Parameter and Arguments\",\"scope\":[\"variable.parameter.function.python\",\"meta.function-call.arguments.python\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Python Function Call\",\"scope\":[\"meta.function-call.python\",\"meta.function-call.generic.python\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"Punctuations in Python\",\"scope\":[\"punctuation.python\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Decorator Functions in Python\",\"scope\":[\"entity.name.function.decorator.python\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Python Language Variable\",\"scope\":[\"source.python variable.language.special\"],\"settings\":{\"foreground\":\"#8eace3\"}},{\"name\":\"Python import control keyword\",\"scope\":[\"keyword.control\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"SCSS Variable\",\"scope\":[\"variable.scss\",\"variable.sass\",\"variable.parameter.url.scss\",\"variable.parameter.url.sass\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#bec5d4\"}},{\"name\":\"Attribute Name for SASS\",\"scope\":[\"meta.attribute-selector.scss entity.other.attribute-name.attribute\",\"meta.attribute-selector.sass entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Tag names in SASS\",\"scope\":[\"entity.name.tag.scss\",\"entity.name.tag.sass\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"SASS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.scss\",\"keyword.other.unit.sass\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"TypeScript[React] Variables and Object Properties\",\"scope\":[\"variable.other.readwrite.alias.ts\",\"variable.other.readwrite.alias.tsx\",\"variable.other.readwrite.ts\",\"variable.other.readwrite.tsx\",\"variable.other.object.ts\",\"variable.other.object.tsx\",\"variable.object.property.ts\",\"variable.object.property.tsx\",\"variable.other.ts\",\"variable.other.tsx\",\"variable.tsx\",\"variable.ts\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript[React] Entity Name Types\",\"scope\":[\"entity.name.type.ts\",\"entity.name.type.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript[React] Node Classes\",\"scope\":[\"support.class.node.ts\",\"support.class.node.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"TypeScript[React] Entity Name Types as Parameters\",\"scope\":[\"meta.type.parameters.ts entity.name.type\",\"meta.type.parameters.tsx entity.name.type\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"TypeScript[React] Import/Export Punctuations\",\"scope\":[\"meta.import.ts punctuation.definition.block\",\"meta.import.tsx punctuation.definition.block\",\"meta.export.ts punctuation.definition.block\",\"meta.export.tsx punctuation.definition.block\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.decorator punctuation.decorator.ts\",\"meta.decorator punctuation.decorator.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.tag.js meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"YAML Entity Name Tags\",\"scope\":[\"entity.name.tag.yaml\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"JavaScript Variable Other ReadWrite\",\"scope\":[\"variable.other.readwrite.js\",\"variable.parameter\"],\"settings\":{\"foreground\":\"#d7dbe0\"}},{\"name\":\"Support Class Component\",\"scope\":[\"support.class.component.js\",\"support.class.component.tsx\"],\"settings\":{\"foreground\":\"#f78c6c\",\"fontStyle\":\"\"}},{\"name\":\"Text nested in React tags\",\"scope\":[\"meta.jsx.children\",\"meta.jsx.children.js\",\"meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript Classes\",\"scope\":[\"meta.class entity.name.type.class.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript Entity Name Type\",\"scope\":[\"entity.name.type.tsx\",\"entity.name.type.module.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript Class Variable Keyword\",\"scope\":[\"meta.class.ts meta.var.expr.ts storage.type.ts\",\"meta.class.tsx meta.var.expr.tsx storage.type.tsx\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"TypeScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.ts\",\"meta.method.declaration storage.type.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"normalize font style of certain components\",\"scope\":[\"meta.property-list.css meta.property-value.css variable.other.less\",\"meta.property-list.scss variable.scss\",\"meta.property-list.sass variable.sass\",\"meta.brace\",\"keyword.operator.operator\",\"keyword.operator.or.regexp\",\"keyword.operator.expression.in\",\"keyword.operator.relational\",\"keyword.operator.assignment\",\"keyword.operator.comparison\",\"keyword.operator.type\",\"keyword.operator\",\"keyword\",\"punctuation.definition.string\",\"punctuation\",\"variable.other.readwrite.js\",\"storage.type\",\"source.css\",\"string.quoted\"],\"settings\":{\"fontStyle\":\"\"}}],\"styleOverrides\":{\"frames\":{\"editorBackground\":\"var(--sl-color-gray-6)\",\"terminalBackground\":\"var(--sl-color-gray-6)\",\"editorActiveTabBackground\":\"var(--sl-color-gray-6)\",\"terminalTitlebarDotsForeground\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"terminalTitlebarDotsOpacity\":\"0.75\",\"inlineButtonForeground\":\"var(--sl-color-text)\",\"frameBoxShadowCssValue\":\"none\"},\"textMarkers\":{\"markBackground\":\"#ffffff17\",\"markBorderColor\":\"#ffffff40\"}}},{\"name\":\"Night Owl Light\",\"type\":\"light\",\"colors\":{\"focusBorder\":\"#93a1a1\",\"foreground\":\"#403f53\",\"disabledForeground\":\"#61616180\",\"descriptionForeground\":\"#403f53\",\"errorForeground\":\"#403f53\",\"icon.foreground\":\"#424242\",\"contrastActiveBorder\":null,\"contrastBorder\":null,\"textBlockQuote.background\":\"#7f7f7f1a\",\"textBlockQuote.border\":\"#007acc80\",\"textCodeBlock.background\":\"#dcdcdc66\",\"textLink.activeForeground\":\"#006ab1\",\"textLink.foreground\":\"#006ab1\",\"textPreformat.foreground\":\"#a31515\",\"textSeparator.foreground\":\"#0000002e\",\"editor.background\":\"#f6f7f9\",\"editor.foreground\":\"#403f53\",\"editorLineNumber.foreground\":\"#90a7b2\",\"editorLineNumber.activeForeground\":\"#403f53\",\"editorActiveLineNumber.foreground\":\"#0b216f\",\"editor.selectionBackground\":\"#e0e0e0\",\"editor.inactiveSelectionBackground\":\"#e0e0e080\",\"editor.selectionHighlightBackground\":\"#339cec33\",\"editorError.foreground\":\"#e64d49\",\"editorWarning.foreground\":\"#daaa01\",\"editorInfo.foreground\":\"#1a85ff\",\"editorHint.foreground\":\"#6c6c6c\",\"problemsErrorIcon.foreground\":\"#e64d49\",\"problemsWarningIcon.foreground\":\"#daaa01\",\"problemsInfoIcon.foreground\":\"#1a85ff\",\"editor.findMatchBackground\":\"#93a1a16c\",\"editor.findMatchHighlightBackground\":\"#93a1a16c\",\"editor.findRangeHighlightBackground\":\"#7497a633\",\"editorLink.activeForeground\":\"#0000ff\",\"editorLightBulb.foreground\":\"#ddb100\",\"editorLightBulbAutoFix.foreground\":\"#007acc\",\"diffEditor.insertedTextBackground\":\"#9ccc2c40\",\"diffEditor.insertedTextBorder\":null,\"diffEditor.removedTextBackground\":\"#ff000033\",\"diffEditor.removedTextBorder\":null,\"diffEditor.insertedLineBackground\":\"#9bb95533\",\"diffEditor.removedLineBackground\":\"#ff000033\",\"editorStickyScroll.background\":\"#fbfbfb\",\"editorStickyScrollHover.background\":\"#f0f0f0\",\"editorInlayHint.background\":\"#2aa29899\",\"editorInlayHint.foreground\":\"#f0f0f0\",\"editorInlayHint.typeBackground\":\"#2aa29899\",\"editorInlayHint.typeForeground\":\"#f0f0f0\",\"editorInlayHint.parameterBackground\":\"#2aa29899\",\"editorInlayHint.parameterForeground\":\"#f0f0f0\",\"editorPane.background\":\"#fbfbfb\",\"editorGroup.emptyBackground\":null,\"editorGroup.focusedEmptyBorder\":null,\"editorGroupHeader.tabsBackground\":\"var(--sl-color-gray-6)\",\"editorGroupHeader.tabsBorder\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"editorGroupHeader.noTabsBackground\":\"#f0f0f0\",\"editorGroupHeader.border\":null,\"editorGroup.border\":\"#f0f0f0\",\"editorGroup.dropBackground\":\"#2677cb2d\",\"editorGroup.dropIntoPromptForeground\":\"#403f53\",\"editorGroup.dropIntoPromptBackground\":\"#f0f0f0\",\"editorGroup.dropIntoPromptBorder\":null,\"sideBySideEditor.horizontalBorder\":\"#f0f0f0\",\"sideBySideEditor.verticalBorder\":\"#f0f0f0\",\"scrollbar.shadow\":\"#cccccc\",\"scrollbarSlider.background\":\"#0000001a\",\"scrollbarSlider.hoverBackground\":\"#00000055\",\"scrollbarSlider.activeBackground\":\"#00000099\",\"panel.background\":\"#f0f0f0\",\"panel.border\":\"#d9d9d9\",\"panelTitle.activeBorder\":\"#424242\",\"panelTitle.activeForeground\":\"#424242\",\"panelTitle.inactiveForeground\":\"#424242bf\",\"panelSectionHeader.background\":\"#80808051\",\"terminal.background\":\"#f6f6f6\",\"widget.shadow\":\"#d9d9d9\",\"editorWidget.background\":\"#f0f0f0\",\"editorWidget.foreground\":\"#403f53\",\"editorWidget.border\":\"#d9d9d9\",\"quickInput.background\":\"#f0f0f0\",\"quickInput.foreground\":\"#403f53\",\"quickInputTitle.background\":\"#0000000f\",\"pickerGroup.foreground\":\"#403f53\",\"pickerGroup.border\":\"#d9d9d9\",\"editor.hoverHighlightBackground\":\"#339cec33\",\"editorHoverWidget.background\":\"#f0f0f0\",\"editorHoverWidget.foreground\":\"#403f53\",\"editorHoverWidget.border\":\"#d9d9d9\",\"editorHoverWidget.statusBarBackground\":\"#e4e4e4\",\"titleBar.activeBackground\":\"var(--sl-color-gray-6)\",\"titleBar.activeForeground\":\"var(--sl-color-text)\",\"titleBar.inactiveBackground\":\"#f0f0f099\",\"titleBar.inactiveForeground\":\"#33333399\",\"titleBar.border\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"toolbar.hoverBackground\":\"#b8b8b850\",\"toolbar.activeBackground\":\"#a6a6a650\",\"tab.activeBackground\":\"#f6f6f6\",\"tab.unfocusedActiveBackground\":\"#f6f6f6\",\"tab.inactiveBackground\":\"#f0f0f0\",\"tab.unfocusedInactiveBackground\":\"#f0f0f0\",\"tab.activeForeground\":\"var(--sl-color-text)\",\"tab.inactiveForeground\":\"#403f53\",\"tab.unfocusedActiveForeground\":\"#403f53b3\",\"tab.unfocusedInactiveForeground\":\"#403f5380\",\"tab.hoverBackground\":null,\"tab.unfocusedHoverBackground\":null,\"tab.hoverForeground\":null,\"tab.unfocusedHoverForeground\":null,\"tab.border\":\"#f0f0f0\",\"tab.lastPinnedBorder\":\"#a9a9a9\",\"tab.activeBorder\":\"transparent\",\"tab.unfocusedActiveBorder\":null,\"tab.activeBorderTop\":\"var(--sl-color-accent)\",\"tab.unfocusedActiveBorderTop\":null,\"tab.hoverBorder\":null,\"tab.unfocusedHoverBorder\":null,\"tab.activeModifiedBorder\":\"#2aa298\",\"tab.inactiveModifiedBorder\":\"#93a1a1\",\"tab.unfocusedActiveModifiedBorder\":\"#93a1a1\",\"tab.unfocusedInactiveModifiedBorder\":\"#93a1a1\",\"badge.background\":\"#2aa298\",\"badge.foreground\":\"#f0f0f0\",\"button.background\":\"#2aa298\",\"button.foreground\":\"#f0f0f0\",\"button.border\":null,\"button.separator\":\"#f0f0f066\",\"button.hoverBackground\":\"#22827a\",\"button.secondaryBackground\":\"#5f6a79\",\"button.secondaryForeground\":\"#ffffff\",\"button.secondaryHoverBackground\":\"#4c5561\",\"dropdown.background\":\"#f0f0f0\",\"dropdown.foreground\":\"#403f53\",\"dropdown.border\":\"#d9d9d9\",\"list.activeSelectionBackground\":\"#d3e8f8\",\"list.activeSelectionForeground\":\"#403f53\",\"tree.indentGuidesStroke\":\"#a9a9a9\",\"input.background\":\"#f0f0f0\",\"input.foreground\":\"#403f53\",\"input.placeholderForeground\":\"#93a1a1\",\"inputOption.activeBorder\":\"#2aa298\",\"inputOption.hoverBackground\":\"#b8b8b850\",\"inputOption.activeBackground\":\"#93a1a133\",\"inputOption.activeForeground\":\"#000000\",\"inputValidation.infoBackground\":\"#f0f0f0\",\"inputValidation.infoBorder\":\"#d0d0d0\",\"inputValidation.warningBackground\":\"#daaa01\",\"inputValidation.warningBorder\":\"#e0af02\",\"inputValidation.errorBackground\":\"#f76e6e\",\"inputValidation.errorBorder\":\"#de3d3b\",\"keybindingLabel.background\":\"#dddddd66\",\"keybindingLabel.foreground\":\"#555555\",\"keybindingLabel.border\":\"#cccccc66\",\"keybindingLabel.bottomBorder\":\"#bbbbbb66\",\"menu.foreground\":\"#403f53\",\"menu.background\":\"#f0f0f0\",\"menu.selectionForeground\":\"#403f53\",\"menu.selectionBackground\":\"#d3e8f8\",\"menu.separatorBackground\":\"#d4d4d4\",\"editor.snippetTabstopHighlightBackground\":\"#0a326433\",\"editor.snippetFinalTabstopHighlightBorder\":\"#0a326480\",\"terminal.ansiBlack\":\"#403f53\",\"terminal.ansiRed\":\"#de3d3b\",\"terminal.ansiGreen\":\"#08916a\",\"terminal.ansiYellow\":\"#e0af02\",\"terminal.ansiBlue\":\"#288ed7\",\"terminal.ansiMagenta\":\"#d6438a\",\"terminal.ansiCyan\":\"#2aa298\",\"terminal.ansiWhite\":\"#f0f0f0\",\"terminal.ansiBrightBlack\":\"#403f53\",\"terminal.ansiBrightRed\":\"#de3d3b\",\"terminal.ansiBrightGreen\":\"#08916a\",\"terminal.ansiBrightYellow\":\"#daaa01\",\"terminal.ansiBrightBlue\":\"#288ed7\",\"terminal.ansiBrightMagenta\":\"#d6438a\",\"terminal.ansiBrightCyan\":\"#2aa298\",\"terminal.ansiBrightWhite\":\"#f0f0f0\",\"selection.background\":\"#7a8181ad\",\"notifications.background\":\"#f0f0f0\",\"notifications.foreground\":\"#403f53\",\"notificationLink.foreground\":\"#994cc3\",\"notifications.border\":\"#cccccc\",\"notificationCenter.border\":\"#cccccc\",\"notificationToast.border\":\"#cccccc\",\"notificationCenterHeader.foreground\":\"#403f53\",\"notificationCenterHeader.background\":\"#f0f0f0\",\"input.border\":\"#d9d9d9\",\"progressBar.background\":\"#2aa298\",\"list.inactiveSelectionBackground\":\"#e0e7ea\",\"list.inactiveSelectionForeground\":\"#403f53\",\"list.focusBackground\":\"#d3e8f8\",\"list.hoverBackground\":\"#d3e8f8\",\"list.focusForeground\":\"#403f53\",\"list.hoverForeground\":\"#403f53\",\"list.highlightForeground\":\"#403f53\",\"list.errorForeground\":\"#e64d49\",\"list.warningForeground\":\"#daaa01\",\"activityBar.background\":\"#f0f0f0\",\"activityBar.foreground\":\"#403f53\",\"activityBar.dropBackground\":\"#d0d0d0\",\"activityBarBadge.background\":\"#403f53\",\"activityBarBadge.foreground\":\"#f0f0f0\",\"activityBar.border\":\"#f0f0f0\",\"sideBar.background\":\"#f0f0f0\",\"sideBar.foreground\":\"#403f53\",\"sideBarTitle.foreground\":\"#403f53\",\"sideBar.border\":\"#f0f0f0\",\"editorGroup.background\":\"#f6f6f6\",\"editorCursor.foreground\":\"#90a7b2\",\"editor.wordHighlightBackground\":\"#339cec33\",\"editor.wordHighlightStrongBackground\":\"#007dd659\",\"editor.lineHighlightBackground\":\"#f0f0f0\",\"editor.rangeHighlightBackground\":\"#7497a633\",\"editorWhitespace.foreground\":\"#d9d9d9\",\"editorIndentGuide.background\":\"#d9d9d9\",\"editorCodeLens.foreground\":\"#403f53\",\"editorBracketMatch.background\":\"#d3e8f8\",\"editorBracketMatch.border\":\"#2aa298\",\"editorError.border\":\"#fbfbfb\",\"editorWarning.border\":\"#daaa01\",\"editorGutter.addedBackground\":\"#49d0c5\",\"editorGutter.modifiedBackground\":\"#6fbef6\",\"editorGutter.deletedBackground\":\"#f76e6e\",\"editorRuler.foreground\":\"#d9d9d9\",\"editorOverviewRuler.errorForeground\":\"#e64d49\",\"editorOverviewRuler.warningForeground\":\"#daaa01\",\"editorSuggestWidget.background\":\"#f0f0f0\",\"editorSuggestWidget.foreground\":\"#403f53\",\"editorSuggestWidget.highlightForeground\":\"#403f53\",\"editorSuggestWidget.selectedBackground\":\"#d3e8f8\",\"editorSuggestWidget.border\":\"#d9d9d9\",\"debugExceptionWidget.background\":\"#f0f0f0\",\"debugExceptionWidget.border\":\"#d9d9d9\",\"editorMarkerNavigation.background\":\"#d0d0d0\",\"editorMarkerNavigationError.background\":\"#f76e6e\",\"editorMarkerNavigationWarning.background\":\"#daaa01\",\"debugToolBar.background\":\"#f0f0f0\",\"extensionButton.prominentBackground\":\"#2aa298\",\"extensionButton.prominentForeground\":\"#f0f0f0\",\"statusBar.background\":\"#f0f0f0\",\"statusBar.border\":\"#f0f0f0\",\"statusBar.debuggingBackground\":\"#f0f0f0\",\"statusBar.debuggingForeground\":\"#403f53\",\"statusBar.foreground\":\"#403f53\",\"statusBar.noFolderBackground\":\"#f0f0f0\",\"statusBar.noFolderForeground\":\"#403f53\",\"peekView.border\":\"#d9d9d9\",\"peekViewEditor.background\":\"#f6f6f6\",\"peekViewEditorGutter.background\":\"#f6f6f6\",\"peekViewEditor.matchHighlightBackground\":\"#49d0c5\",\"peekViewResult.background\":\"#f0f0f0\",\"peekViewResult.fileForeground\":\"#403f53\",\"peekViewResult.lineForeground\":\"#403f53\",\"peekViewResult.matchHighlightBackground\":\"#49d0c5\",\"peekViewResult.selectionBackground\":\"#e0e7ea\",\"peekViewResult.selectionForeground\":\"#403f53\",\"peekViewTitle.background\":\"#f0f0f0\",\"peekViewTitleLabel.foreground\":\"#403f53\",\"peekViewTitleDescription.foreground\":\"#403f53\",\"terminal.foreground\":\"#403f53\"},\"fg\":\"#403f53\",\"bg\":\"#f6f7f9\",\"semanticHighlighting\":false,\"settings\":[{\"name\":\"Changed\",\"scope\":[\"markup.changed\",\"meta.diff.header.git\",\"meta.diff.header.from-file\",\"meta.diff.header.to-file\"],\"settings\":{\"foreground\":\"#556484\"}},{\"name\":\"Deleted\",\"scope\":[\"markup.deleted.diff\"],\"settings\":{\"foreground\":\"#ae3c3afd\"}},{\"name\":\"Inserted\",\"scope\":[\"markup.inserted.diff\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Global settings\",\"settings\":{\"background\":\"#011627\",\"foreground\":\"#403f53\"}},{\"name\":\"Comment\",\"scope\":[\"comment\"],\"settings\":{\"foreground\":\"#5f636f\"}},{\"name\":\"String\",\"scope\":[\"string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"String Quoted\",\"scope\":[\"string.quoted\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Support Constant Math\",\"scope\":[\"support.constant.math\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Number\",\"scope\":[\"constant.numeric\",\"constant.character.numeric\"],\"settings\":{\"foreground\":\"#aa0982\",\"fontStyle\":\"\"}},{\"name\":\"Built-in constant\",\"scope\":[\"constant.language\",\"punctuation.definition.constant\",\"variable.other.constant\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"User-defined constant\",\"scope\":[\"constant.character\",\"constant.other\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Constant Character Escape\",\"scope\":[\"constant.character.escape\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"RegExp String\",\"scope\":[\"string.regexp\",\"string.regexp keyword.other\"],\"settings\":{\"foreground\":\"#3a688f\"}},{\"name\":\"Comma in functions\",\"scope\":[\"meta.function punctuation.separator.comma\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"Variable\",\"scope\":[\"variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Keyword\",\"scope\":[\"punctuation.accessor\",\"keyword\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage\",\"scope\":[\"storage\",\"meta.var.expr\",\"meta.class meta.method.declaration meta.var.expr storage.type.js\",\"storage.type.property.js\",\"storage.type.property.ts\",\"storage.type.property.tsx\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type.function.arrow.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Class name\",\"scope\":[\"entity.name.class\",\"meta.class entity.name.type.class\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Inherited class\",\"scope\":[\"entity.other.inherited-class\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Function name\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Meta Tag\",\"scope\":[\"punctuation.definition.tag\",\"meta.tag\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"HTML Tag names\",\"scope\":[\"entity.name.tag\",\"meta.tag.other.html\",\"meta.tag.other.js\",\"meta.tag.other.tsx\",\"entity.name.tag.tsx\",\"entity.name.tag.js\",\"entity.name.tag\",\"meta.tag.js\",\"meta.tag.tsx\",\"meta.tag.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Tag attribute\",\"scope\":[\"entity.other.attribute-name\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Entity Name Tag Custom\",\"scope\":[\"entity.name.tag.custom\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Library (function & constant)\",\"scope\":[\"support.function\",\"support.constant\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Support Constant Property Value meta\",\"scope\":[\"support.constant.meta.property-value\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Library class/type\",\"scope\":[\"support.type\",\"support.class\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Support Variable DOM\",\"scope\":[\"support.variable.dom\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Invalid\",\"scope\":[\"invalid\"],\"settings\":{\"foreground\":\"#bb2060\"}},{\"name\":\"Invalid deprecated\",\"scope\":[\"invalid.deprecated\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Keyword Operator\",\"scope\":[\"keyword.operator\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Relational\",\"scope\":[\"keyword.operator.relational\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Assignment\",\"scope\":[\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Arithmetic\",\"scope\":[\"keyword.operator.arithmetic\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Bitwise\",\"scope\":[\"keyword.operator.bitwise\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Increment\",\"scope\":[\"keyword.operator.increment\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Ternary\",\"scope\":[\"keyword.operator.ternary\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Double-Slashed Comment\",\"scope\":[\"comment.line.double-slash\"],\"settings\":{\"foreground\":\"#5d6376\"}},{\"name\":\"Object\",\"scope\":[\"object\"],\"settings\":{\"foreground\":\"#58656a\"}},{\"name\":\"Null\",\"scope\":[\"constant.language.null\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Meta Brace\",\"scope\":[\"meta.brace\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Meta Delimiter Period\",\"scope\":[\"meta.delimiter.period\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Punctuation Definition String\",\"scope\":[\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Punctuation Definition String Markdown\",\"scope\":[\"punctuation.definition.string.begin.markdown\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Boolean\",\"scope\":[\"constant.language.boolean\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Object Comma\",\"scope\":[\"object.comma\"],\"settings\":{\"foreground\":\"#646464\"}},{\"name\":\"Variable Parameter Function\",\"scope\":[\"variable.parameter.function\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Support Type Property Name & entity name tags\",\"scope\":[\"support.type.vendor.property-name\",\"support.constant.vendor.property-value\",\"support.type.property-name\",\"meta.property-list entity.name.tag\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Entity Name tag reference in stylesheets\",\"scope\":[\"meta.property-list entity.name.tag.reference\"],\"settings\":{\"foreground\":\"#286d70\"}},{\"name\":\"Constant Other Color RGB Value Punctuation Definition Constant\",\"scope\":[\"constant.other.color.rgb-value punctuation.definition.constant\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Constant Other Color\",\"scope\":[\"constant.other.color\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Keyword Other Unit\",\"scope\":[\"keyword.other.unit\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Meta Selector\",\"scope\":[\"meta.selector\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Entity Other Attribute Name Id\",\"scope\":[\"entity.other.attribute-name.id\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Meta Property Name\",\"scope\":[\"meta.property-name\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Doctypes\",\"scope\":[\"entity.name.tag.doctype\",\"meta.tag.sgml.doctype\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Punctuation Definition Parameters\",\"scope\":[\"punctuation.definition.parameters\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Keyword Control Operator\",\"scope\":[\"keyword.control.operator\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Keyword Operator Logical\",\"scope\":[\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"\"}},{\"name\":\"Variable Instances\",\"scope\":[\"variable.instance\",\"variable.other.instance\",\"variable.readwrite.instance\",\"variable.other.readwrite.instance\",\"variable.other.property\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Variable Property Other object property\",\"scope\":[\"variable.other.object.property\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Variable Property Other object\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Entity Name Function\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Keyword Operator Comparison, imports, returns and Keyword Operator Ruby\",\"scope\":[\"keyword.operator.comparison\",\"keyword.control.flow.js\",\"keyword.control.flow.ts\",\"keyword.control.flow.tsx\",\"keyword.control.ruby\",\"keyword.control.module.ruby\",\"keyword.control.class.ruby\",\"keyword.control.def.ruby\",\"keyword.control.loop.js\",\"keyword.control.loop.ts\",\"keyword.control.import.js\",\"keyword.control.import.ts\",\"keyword.control.import.tsx\",\"keyword.control.from.js\",\"keyword.control.from.ts\",\"keyword.control.from.tsx\",\"keyword.operator.instanceof.js\",\"keyword.operator.expression.instanceof.ts\",\"keyword.operator.expression.instanceof.tsx\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Control Conditional\",\"scope\":[\"keyword.control.conditional.js\",\"keyword.control.conditional.ts\",\"keyword.control.switch.js\",\"keyword.control.switch.ts\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"\"}},{\"name\":\"Support Constant, `new` keyword, Special Method Keyword, `debugger`, other keywords\",\"scope\":[\"support.constant\",\"keyword.other.special-method\",\"keyword.other.new\",\"keyword.other.debugger\",\"keyword.control\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Support Function\",\"scope\":[\"support.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Invalid Broken\",\"scope\":[\"invalid.broken\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Invalid Unimplemented\",\"scope\":[\"invalid.unimplemented\"],\"settings\":{\"foreground\":\"#486e26\"}},{\"name\":\"Invalid Illegal\",\"scope\":[\"invalid.illegal\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Language Variable\",\"scope\":[\"variable.language\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Support Variable Property\",\"scope\":[\"support.variable.property\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Variable Function\",\"scope\":[\"variable.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variable Interpolation\",\"scope\":[\"variable.interpolation\"],\"settings\":{\"foreground\":\"#a64348\"}},{\"name\":\"Meta Function Call\",\"scope\":[\"meta.function-call\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Punctuation Section Embedded\",\"scope\":[\"punctuation.section.embedded\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Punctuation Tweaks\",\"scope\":[\"punctuation.terminator.expression\",\"punctuation.definition.arguments\",\"punctuation.definition.array\",\"punctuation.section.array\",\"meta.array\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"More Punctuation Tweaks\",\"scope\":[\"punctuation.definition.list.begin\",\"punctuation.definition.list.end\",\"punctuation.separator.arguments\",\"punctuation.definition.list\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Template Strings\",\"scope\":[\"string.template meta.template.expression\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Backticks(``) in Template Strings\",\"scope\":[\"string.template punctuation.definition.string\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Italics\",\"scope\":[\"italic\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"italic\"}},{\"name\":\"Bold\",\"scope\":[\"bold\"],\"settings\":{\"foreground\":\"#3b61b0\",\"fontStyle\":\"bold\"}},{\"name\":\"Quote\",\"scope\":[\"quote\"],\"settings\":{\"foreground\":\"#5c6285\"}},{\"name\":\"Raw Code\",\"scope\":[\"raw\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"CoffeeScript Variable Assignment\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#186e73\"}},{\"name\":\"CoffeeScript Parameter Function\",\"scope\":[\"variable.parameter.function.coffee\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"CoffeeScript Assignments\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"C# Readwrite Variables\",\"scope\":[\"variable.other.readwrite.cs\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"C# Classes & Storage types\",\"scope\":[\"entity.name.type.class.cs\",\"storage.type.cs\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"C# Namespaces\",\"scope\":[\"entity.name.type.namespace.cs\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Tag names in Stylesheets\",\"scope\":[\"entity.name.tag.css\",\"entity.name.tag.less\",\"entity.name.tag.custom.css\",\"support.constant.property-value.css\"],\"settings\":{\"foreground\":\"#984e4d\",\"fontStyle\":\"\"}},{\"name\":\"Wildcard(*) selector in Stylesheets\",\"scope\":[\"entity.name.tag.wildcard.css\",\"entity.name.tag.wildcard.less\",\"entity.name.tag.wildcard.scss\",\"entity.name.tag.wildcard.sass\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"CSS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Attribute Name for CSS\",\"scope\":[\"meta.attribute-selector.css entity.other.attribute-name.attribute\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Elixir Classes\",\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Functions\",\"scope\":[\"source.elixir entity.name.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Constants\",\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir String Punctuations\",\"scope\":[\"source.elixir punctuation.definition.string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir\",\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Binary Punctuations\",\"scope\":[\"source.elixir .punctuation.binary.elixir\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Closure Constant Keyword\",\"scope\":[\"constant.keyword.clojure\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Go Function Calls\",\"scope\":[\"source.go meta.function-call.go\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Go Keywords\",\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Go Constants e.g. nil, string format (%s, %d, etc.)\",\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"C++ Functions\",\"scope\":[\"entity.name.function.preprocessor.cpp\",\"entity.scope.name.cpp\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"C++ Meta Namespace\",\"scope\":[\"meta.namespace-block.cpp\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"C++ Language Primitive Storage\",\"scope\":[\"storage.type.language.primitive.cpp\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"C++ Preprocessor Macro\",\"scope\":[\"meta.preprocessor.macro.cpp\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"C++ Variable Parameter\",\"scope\":[\"variable.parameter\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Powershell Variables\",\"scope\":[\"variable.other.readwrite.powershell\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Powershell Function\",\"scope\":[\"support.function.powershell\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"ID Attribute Name in HTML\",\"scope\":[\"entity.other.attribute-name.id.html\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"HTML Punctuation Definition Tag\",\"scope\":[\"punctuation.definition.tag.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"HTML Doctype\",\"scope\":[\"meta.tag.sgml.doctype.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"JavaScript Classes\",\"scope\":[\"meta.class entity.name.type.class.js\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"JavaScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.js\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"JavaScript Terminator\",\"scope\":[\"terminator.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Meta Punctuation Definition\",\"scope\":[\"meta.js punctuation.definition.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Entity Names in Code Documentations\",\"scope\":[\"entity.name.type.instance.jsdoc\",\"entity.name.type.instance.phpdoc\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"Other Variables in Code Documentations\",\"scope\":[\"variable.other.jsdoc\",\"variable.other.phpdoc\"],\"settings\":{\"foreground\":\"#3e697c\"}},{\"name\":\"JavaScript module imports and exports\",\"scope\":[\"variable.other.meta.import.js\",\"meta.import.js variable.other\",\"variable.other.meta.export.js\",\"meta.export.js variable.other\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Variable Parameter Function\",\"scope\":[\"variable.parameter.function.js\"],\"settings\":{\"foreground\":\"#555ea2\"}},{\"name\":\"JavaScript[React] Variable Other Object\",\"scope\":[\"variable.other.object.js\",\"variable.other.object.jsx\",\"variable.object.property.js\",\"variable.object.property.jsx\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Variables\",\"scope\":[\"variable.js\",\"variable.other.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Entity Name Type\",\"scope\":[\"entity.name.type.js\",\"entity.name.type.module.js\"],\"settings\":{\"foreground\":\"#111111\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Support Classes\",\"scope\":[\"support.class.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JSON Property Names\",\"scope\":[\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"JSON Support Constants\",\"scope\":[\"support.constant.json\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"JSON Property values (string)\",\"scope\":[\"meta.structure.dictionary.value.json string.quoted.double\"],\"settings\":{\"foreground\":\"#7c5686\"}},{\"name\":\"Strings in JSON values\",\"scope\":[\"string.quoted.double.json punctuation.definition.string.json\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Specific JSON Property values like null\",\"scope\":[\"meta.structure.dictionary.json meta.structure.dictionary.value constant.language\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"JavaScript Other Variable\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Ruby Variables\",\"scope\":[\"variable.other.ruby\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Ruby Class\",\"scope\":[\"entity.name.type.class.ruby\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Ruby Hashkeys\",\"scope\":[\"constant.language.symbol.hashkey.ruby\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Ruby Symbols\",\"scope\":[\"constant.language.symbol.ruby\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"LESS Tag names\",\"scope\":[\"entity.name.tag.less\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"LESS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Attribute Name for LESS\",\"scope\":[\"meta.attribute-selector.less entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Markdown Headings\",\"scope\":[\"markup.heading.markdown\",\"markup.heading.setext.1.markdown\",\"markup.heading.setext.2.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown Italics\",\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"italic\"}},{\"name\":\"Markdown Bold\",\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\",\"fontStyle\":\"bold\"}},{\"name\":\"Markdown Quote + others\",\"scope\":[\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#5c6285\"}},{\"name\":\"Markdown Raw Code + others\",\"scope\":[\"markup.inline.raw.markdown\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Markdown Links\",\"scope\":[\"markup.underline.link.markdown\",\"markup.underline.link.image.markdown\"],\"settings\":{\"foreground\":\"#954f5a\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Link Title and Description\",\"scope\":[\"string.other.link.title.markdown\",\"string.other.link.description.markdown\"],\"settings\":{\"foreground\":\"#403f53\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Punctuation\",\"scope\":[\"punctuation.definition.string.markdown\",\"punctuation.definition.string.begin.markdown\",\"punctuation.definition.string.end.markdown\",\"meta.link.inline.markdown punctuation.definition.string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown MetaData Punctuation\",\"scope\":[\"punctuation.definition.metadata.markdown\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Markdown List Punctuation\",\"scope\":[\"beginning.punctuation.definition.list.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown Inline Raw String\",\"scope\":[\"markup.inline.raw.string.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"PHP Variables\",\"scope\":[\"variable.other.php\",\"variable.other.property.php\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Support Classes in PHP\",\"scope\":[\"support.class.php\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Punctuations in PHP function calls\",\"scope\":[\"meta.function-call.php punctuation\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"PHP Global Variables\",\"scope\":[\"variable.other.global.php\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Declaration Punctuation in PHP Global Variables\",\"scope\":[\"variable.other.global.php punctuation.definition.variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Language Constants in Python\",\"scope\":[\"constant.language.python\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Python Function Parameter and Arguments\",\"scope\":[\"variable.parameter.function.python\",\"meta.function-call.arguments.python\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Python Function Call\",\"scope\":[\"meta.function-call.python\",\"meta.function-call.generic.python\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Punctuations in Python\",\"scope\":[\"punctuation.python\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Decorator Functions in Python\",\"scope\":[\"entity.name.function.decorator.python\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Python Language Variable\",\"scope\":[\"source.python variable.language.special\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Python import control keyword\",\"scope\":[\"keyword.control\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"SCSS Variable\",\"scope\":[\"variable.scss\",\"variable.sass\",\"variable.parameter.url.scss\",\"variable.parameter.url.sass\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Attribute Name for SASS\",\"scope\":[\"meta.attribute-selector.scss entity.other.attribute-name.attribute\",\"meta.attribute-selector.sass entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Tag names in SASS\",\"scope\":[\"entity.name.tag.scss\",\"entity.name.tag.sass\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"SASS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.scss\",\"keyword.other.unit.sass\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"TypeScript[React] Variables and Object Properties\",\"scope\":[\"variable.other.readwrite.alias.ts\",\"variable.other.readwrite.alias.tsx\",\"variable.other.readwrite.ts\",\"variable.other.readwrite.tsx\",\"variable.other.object.ts\",\"variable.other.object.tsx\",\"variable.object.property.ts\",\"variable.object.property.tsx\",\"variable.other.ts\",\"variable.other.tsx\",\"variable.tsx\",\"variable.ts\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript[React] Entity Name Types\",\"scope\":[\"entity.name.type.ts\",\"entity.name.type.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript[React] Node Classes\",\"scope\":[\"support.class.node.ts\",\"support.class.node.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"TypeScript[React] Entity Name Types as Parameters\",\"scope\":[\"meta.type.parameters.ts entity.name.type\",\"meta.type.parameters.tsx entity.name.type\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"TypeScript[React] Import/Export Punctuations\",\"scope\":[\"meta.import.ts punctuation.definition.block\",\"meta.import.tsx punctuation.definition.block\",\"meta.export.ts punctuation.definition.block\",\"meta.export.tsx punctuation.definition.block\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.decorator punctuation.decorator.ts\",\"meta.decorator punctuation.decorator.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.tag.js meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"YAML Entity Name Tags\",\"scope\":[\"entity.name.tag.yaml\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"JavaScript Variable Other ReadWrite\",\"scope\":[\"variable.other.readwrite.js\",\"variable.parameter\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Support Class Component\",\"scope\":[\"support.class.component.js\",\"support.class.component.tsx\"],\"settings\":{\"foreground\":\"#aa0982\",\"fontStyle\":\"\"}},{\"name\":\"Text nested in React tags\",\"scope\":[\"meta.jsx.children\",\"meta.jsx.children.js\",\"meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript Classes\",\"scope\":[\"meta.class entity.name.type.class.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript Entity Name Type\",\"scope\":[\"entity.name.type.tsx\",\"entity.name.type.module.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript Class Variable Keyword\",\"scope\":[\"meta.class.ts meta.var.expr.ts storage.type.ts\",\"meta.class.tsx meta.var.expr.tsx storage.type.tsx\"],\"settings\":{\"foreground\":\"#76578b\"}},{\"name\":\"TypeScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.ts\",\"meta.method.declaration storage.type.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"normalize font style of certain components\",\"scope\":[\"meta.property-list.css meta.property-value.css variable.other.less\",\"meta.property-list.scss variable.scss\",\"meta.property-list.sass variable.sass\",\"meta.brace\",\"keyword.operator.operator\",\"keyword.operator.or.regexp\",\"keyword.operator.expression.in\",\"keyword.operator.relational\",\"keyword.operator.assignment\",\"keyword.operator.comparison\",\"keyword.operator.type\",\"keyword.operator\",\"keyword\",\"punctuation.definition.string\",\"punctuation\",\"variable.other.readwrite.js\",\"storage.type\",\"source.css\",\"string.quoted\"],\"settings\":{\"fontStyle\":\"\"}}],\"styleOverrides\":{\"frames\":{\"editorBackground\":\"var(--sl-color-gray-7)\",\"terminalBackground\":\"var(--sl-color-gray-7)\",\"editorActiveTabBackground\":\"var(--sl-color-gray-7)\",\"terminalTitlebarDotsForeground\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"terminalTitlebarDotsOpacity\":\"0.75\",\"inlineButtonForeground\":\"var(--sl-color-text)\",\"frameBoxShadowCssValue\":\"none\"},\"textMarkers\":{\"markBackground\":\"#0000001a\",\"markBorderColor\":\"#00000055\"}}}],\"defaultLocale\":\"en\",\"cascadeLayer\":\"starlight.components\",\"styleOverrides\":{\"borderRadius\":\"0px\",\"borderWidth\":\"1px\",\"codePaddingBlock\":\"0.75rem\",\"codePaddingInline\":\"1rem\",\"codeFontFamily\":\"var(--__sl-font-mono)\",\"codeFontSize\":\"var(--sl-text-code)\",\"codeLineHeight\":\"var(--sl-line-height)\",\"uiFontFamily\":\"var(--__sl-font)\",\"textMarkers\":{\"lineDiffIndicatorMarginLeft\":\"0.25rem\",\"defaultChroma\":\"45\",\"backgroundOpacity\":\"60%\"}},\"plugins\":[{\"name\":\"Starlight Plugin\",\"hooks\":{}},{\"name\":\"astro-expressive-code\",\"hooks\":{}}]}]],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":{\"backticks\":true,\"closingQuotes\":{\"double\":\"”\",\"single\":\"’\"},\"dashes\":true,\"ellipses\":true,\"openingQuotes\":{\"double\":\"“\",\"single\":\"‘\"},\"quotes\":true}},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[],\"csp\":false,\"actionBodySizeLimit\":1048576,\"serverIslandBodySizeLimit\":1048576},\"env\":{\"schema\":{},\"validateSecrets\":false},\"prerenderConflictBehavior\":\"warn\",\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"chromeDevtoolsWorkspace\":false,\"svgo\":false,\"rustCompiler\":false,\"queuedRendering\":{\"enabled\":false}},\"legacy\":{\"collectionsBackwardsCompat\":false},\"prefetch\":{\"prefetchAll\":true},\"i18n\":{\"defaultLocale\":\"en\",\"locales\":[\"en\"],\"routing\":{\"prefixDefaultLocale\":false,\"redirectToDefaultLocale\":false,\"fallbackType\":\"redirect\"}}}","astro-version","6.1.7","content-config-digest","28e7bc87492477d9"]
\ No newline at end of file
diff --git a/packages/docs/astro.config.mjs b/packages/docs/astro.config.mjs
index 932f7d0..1eaa2cb 100644
--- a/packages/docs/astro.config.mjs
+++ b/packages/docs/astro.config.mjs
@@ -51,6 +51,7 @@ export default defineConfig({
],
},
{ label: 'Slack Bot', link: '/slack-bot' },
+ { label: 'Discord Bot', link: '/discord-bot' },
],
}),
],
diff --git a/packages/docs/src/components/AddToDiscordButton.astro b/packages/docs/src/components/AddToDiscordButton.astro
new file mode 100644
index 0000000..cc9cb15
--- /dev/null
+++ b/packages/docs/src/components/AddToDiscordButton.astro
@@ -0,0 +1,56 @@
+---
+interface Props {
+ href: string;
+}
+
+const { href } = Astro.props;
+---
+
+
+ Add to Discord
+
+
+
diff --git a/packages/docs/src/content/docs/discord-bot.mdx b/packages/docs/src/content/docs/discord-bot.mdx
new file mode 100644
index 0000000..d1659d2
--- /dev/null
+++ b/packages/docs/src/content/docs/discord-bot.mdx
@@ -0,0 +1,57 @@
+---
+title: Discord Bot
+description: Get Discord notifications for new package releases in your server channels.
+---
+
+import { Aside } from '@astrojs/starlight/components';
+import AddToDiscordButton from '../../components/AddToDiscordButton.astro';
+
+The Patch Pulse Discord Bot notifies your server whenever a package you depend on releases a new version.
+
+
+
+
+
+## How it works
+
+Once installed, the bot monitors packages you care about and sends a Discord message when a new version is published to the npm registry.
+
+Discord tracking is channel-based:
+
+- every subscription targets an explicit channel
+- the same package can be tracked in multiple channels
+- filters can be set to patch, minor, or major updates
+
+## Slash commands
+
+Use these commands in your server:
+
+- `/npmtrack package:react`
+- `/npmtrack package:react channel:#frontend`
+- `/npmtrack package:react filter:minor`
+- `/npmuntrack package:react`
+- `/npmuntrack package:react channel:#frontend`
+- `/npmlist`
+
+Command responses are ephemeral, while update notifications are posted into the subscribed channel.
+
+## Install and setup
+
+To add Patch Pulse to your server:
+
+- open [grand-yak-92.convex.site/discord/install](https://grand-yak-92.convex.site/discord/install)
+- choose the target server
+- approve the requested permissions
+
+If you are self-hosting Patch Pulse rather than using the hosted bot, the Discord app setup and environment configuration live in the notifier package docs, not the public user docs site.
+
+## Slack vs Discord
+
+Slack and Discord support the same core package tracking model, but there are a few operational differences:
+
+- Slack has a workspace default channel; Discord does not
+- Slack receives delayed GitHub link backfill and AI summaries; Discord currently does not
+- Discord commands use typed slash-command options instead of Slack's free-text command parsing
diff --git a/packages/docs/src/content/docs/github-action/overview.mdx b/packages/docs/src/content/docs/github-action/overview.mdx
index 185f128..5fd5964 100644
--- a/packages/docs/src/content/docs/github-action/overview.mdx
+++ b/packages/docs/src/content/docs/github-action/overview.mdx
@@ -35,7 +35,7 @@ The Patch Pulse GitHub Action runs on a schedule, detects outdated dependencies
## Quick start
-Add the following workflow to your repository at `.github/workflows/patch-pulse-bot.yml`:
+Add the following workflow to your repository at `.github/workflows/patchpulse.yml`:
```yaml
name: PatchPulse Dependency Bot
diff --git a/packages/docs/src/content/docs/index.mdx b/packages/docs/src/content/docs/index.mdx
index aa2c8e8..97d9ec3 100644
--- a/packages/docs/src/content/docs/index.mdx
+++ b/packages/docs/src/content/docs/index.mdx
@@ -34,6 +34,11 @@ import { CardGrid, LinkCard } from '@astrojs/starlight/components';
href="./slack-bot"
description="Get Slack release alerts with GitHub release links and AI-generated summaries for tracked packages."
/>
+
+[Add to Discord](https://grand-yak-92.convex.site/discord/install)
+
> **Help us reach the Slack Marketplace!** We need at least 5 active workspace installs before Slack will approve PatchPulse for the official Marketplace. If the bot looks useful to you, installing it now is a huge help — it's free and takes about 30 seconds.
This package contains the Convex-powered notifier backend for Patch Pulse.
@@ -9,28 +11,31 @@ This package contains the Convex-powered notifier backend for Patch Pulse.
It currently supports:
- Slack workspace subscriptions
+- Discord server subscriptions
- npm package polling
-- Multi-channel Slack tracking per workspace
+- Multi-channel Slack and Discord tracking
- Delayed GitHub metadata enrichment and AI release summaries
More detailed docs live here:
+- [`docs/discord.md`](./docs/discord.md): Discord install flow, slash commands, and channel behavior
- [`docs/slack.md`](./docs/slack.md): Slack install flow, slash commands, list formatting, and channel behavior
- [`docs/architecture.md`](./docs/architecture.md): schema, polling flow, metadata enrichment, and implementation notes
-- [`docs/deployment.md`](./docs/deployment.md): environment variables, Slack endpoint setup, and deployment checks
-- [`docs/runbook.md`](./docs/runbook.md): troubleshooting common Slack, polling, and `/npmlist` issues
+- [`docs/deployment.md`](./docs/deployment.md): environment variables, Slack and Discord endpoint setup, and deployment checks
+- [`docs/runbook.md`](./docs/runbook.md): troubleshooting common Slack, Discord, polling, and `/npmlist` issues
## What This Package Does
-The notifier stores tracked packages, Slack workspace details, and per-channel subscriptions in Convex.
+The notifier stores tracked packages, subscriber details for Slack workspaces and Discord servers, and per-channel subscriptions in Convex.
An hourly cron checks tracked packages for updates. When a newer version is found:
1. The package record is updated in Convex.
2. GitHub repo metadata is stored on the package when it can be derived from npm metadata.
-3. Matching subscribers are grouped by Slack target channel.
+3. Matching subscribers are grouped by delivery target.
4. Slack notifications are sent to the relevant channel or the workspace default channel.
-5. If upstream metadata is incomplete, Patch Pulse retries later, updates the original post with release links, and adds an AI summary in the thread when the evidence is strong enough.
+5. Discord notifications are sent to the explicit subscribed channel.
+6. If upstream metadata is incomplete, Patch Pulse retries later, updates the original Slack post with release links, and adds an AI summary in the thread when the evidence is strong enough.
## Slack Summary
@@ -50,6 +55,24 @@ Examples:
- `/npmuntrack react #frontend`
- `/npmlist`
+## Discord Summary
+
+Discord tracking is channel-based:
+
+- A Discord server has no default channel.
+- Every subscription targets an explicit channel.
+- A subscription is effectively scoped by `(guild, package, channel)`.
+- `/npmlist` groups subscriptions by channel.
+
+Examples:
+
+- `/npmtrack package:react`
+- `/npmtrack package:react channel:#frontend`
+- `/npmtrack package:react filter:minor`
+- `/npmuntrack package:react`
+- `/npmuntrack package:react channel:#frontend`
+- `/npmlist`
+
## Development
Useful commands from this package directory:
@@ -63,4 +86,4 @@ Useful commands from this package directory:
- `/npmlist` does not perform live npm lookups. It uses stored package metadata so the response stays fast.
- GitHub links in `/npmlist` appear after polling has enriched a package with repo metadata.
- Update notifications can include richer release links because polling already fetches npm manifests during the update check.
-- Patch Pulse uses status reactions on the original Slack post: `⏳` queued/pending, `📝` summary added, `⚠️` no trustworthy release details found after retries, `❌` processing failed.
+- Slack-only enrichment uses status reactions on the original Slack post: `⏳` queued/pending, `📝` summary added, `⚠️` no trustworthy release details found after retries, `❌` processing failed.
diff --git a/packages/notifier-bot/convex/_generated/ai/ai-files.state.json b/packages/notifier-bot/convex/_generated/ai/ai-files.state.json
index 50cbe88..a65f4f2 100644
--- a/packages/notifier-bot/convex/_generated/ai/ai-files.state.json
+++ b/packages/notifier-bot/convex/_generated/ai/ai-files.state.json
@@ -2,8 +2,9 @@
"guidelinesHash": "62d72acb9afcc18f658d88dd772f34b5b1da5fa60ef0402e57a784d97c458e57",
"agentsMdSectionHash": "bbf30bd25ceea0aefd279d62e1cb2b4c207fcb712b69adf26f3d02b296ffc7b2",
"claudeMdHash": "bbf30bd25ceea0aefd279d62e1cb2b4c207fcb712b69adf26f3d02b296ffc7b2",
- "agentSkillsSha": "4de8fba05b0a506661116985649072777049f67b",
+ "agentSkillsSha": "231a67aa8a5b29cc2794cbc8298335a71aaa6d0e",
"installedSkillNames": [
+ "convex",
"convex-create-component",
"convex-migration-helper",
"convex-performance-audit",
diff --git a/packages/notifier-bot/convex/_generated/ai/guidelines.md b/packages/notifier-bot/convex/_generated/ai/guidelines.md
index e3f5132..e41bedd 100644
--- a/packages/notifier-bot/convex/_generated/ai/guidelines.md
+++ b/packages/notifier-bot/convex/_generated/ai/guidelines.md
@@ -7,12 +7,12 @@
- HTTP endpoints are defined in `convex/http.ts` and require an `httpAction` decorator. For example:
```typescript
-import { httpRouter } from 'convex/server';
-import { httpAction } from './_generated/server';
+import { httpRouter } from "convex/server";
+import { httpAction } from "./_generated/server";
const http = httpRouter();
http.route({
- path: '/echo',
- method: 'POST',
+ path: "/echo",
+ method: "POST",
handler: httpAction(async (ctx, req) => {
const body = await req.bytes();
return new Response(body, { status: 200 });
@@ -27,8 +27,8 @@ http.route({
- Below is an example of an array validator:
```typescript
-import { mutation } from './_generated/server';
-import { v } from 'convex/values';
+import { mutation } from "./_generated/server";
+import { v } from "convex/values";
export default mutation({
args: {
@@ -43,18 +43,18 @@ export default mutation({
- Below is an example of a schema with validators that codify a discriminated union type:
```typescript
-import { defineSchema, defineTable } from 'convex/server';
-import { v } from 'convex/values';
+import { defineSchema, defineTable } from "convex/server";
+import { v } from "convex/values";
export default defineSchema({
results: defineTable(
v.union(
v.object({
- kind: v.literal('error'),
+ kind: v.literal("error"),
errorMessage: v.string(),
}),
v.object({
- kind: v.literal('success'),
+ kind: v.literal("success"),
value: v.number(),
}),
),
@@ -123,16 +123,16 @@ export const g = query({
- Define pagination using the following syntax:
```ts
-import { v } from 'convex/values';
-import { query, mutation } from './_generated/server';
-import { paginationOptsValidator } from 'convex/server';
+import { v } from "convex/values";
+import { query, mutation } from "./_generated/server";
+import { paginationOptsValidator } from "convex/server";
export const listWithExtraArg = query({
args: { paginationOpts: paginationOptsValidator, author: v.string() },
handler: async (ctx, args) => {
return await ctx.db
- .query('messages')
- .withIndex('by_author', (q) => q.eq('author', args.author))
- .order('desc')
+ .query("messages")
+ .withIndex("by_author", (q) => q.eq("author", args.author))
+ .order("desc")
.paginate(args.paginationOpts);
},
});
@@ -166,8 +166,8 @@ Note: `paginationOpts` is an object with the following properties:
export default {
providers: [
{
- domain: 'https://your-auth-provider.com',
- applicationID: 'convex',
+ domain: "https://your-auth-provider.com",
+ applicationID: "convex",
},
],
};
@@ -181,7 +181,7 @@ The `domain` must be the issuer URL of the JWT provider. Convex fetches `{domain
- When using an external auth provider with Convex on the client, use `ConvexProviderWithAuth` instead of `ConvexProvider`:
```tsx
-import { ConvexProviderWithAuth, ConvexReactClient } from 'convex/react';
+import { ConvexProviderWithAuth, ConvexReactClient } from "convex/react";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
@@ -204,15 +204,15 @@ The `useAuth` prop must return `{ isLoading, isAuthenticated, fetchAccessToken }
- If you need to define a `Record` make sure that you correctly provide the type of the key and value in the type. For example a validator `v.record(v.id('users'), v.string())` would have the type `Record, string>`. Below is an example of using `Record` with an `Id` type in a query:
```ts
-import { query } from './_generated/server';
-import { Doc, Id } from './_generated/dataModel';
+import { query } from "./_generated/server";
+import { Doc, Id } from "./_generated/dataModel";
export const exampleQuery = query({
- args: { userIds: v.array(v.id('users')) },
+ args: { userIds: v.array(v.id("users")) },
handler: async (ctx, args) => {
- const idToUsername: Record, string> = {};
+ const idToUsername: Record, string> = {};
for (const userId of args.userIds) {
- const user = await ctx.db.get('users', userId);
+ const user = await ctx.db.get("users", userId);
if (user) {
idToUsername[user._id] = user.username;
}
@@ -266,12 +266,12 @@ q.search("body", "hello hi").eq("channel", "#general"),
- Below is an example of the syntax for an action:
```ts
-import { action } from './_generated/server';
+import { action } from "./_generated/server";
export const exampleAction = action({
args: {},
handler: async (ctx, args) => {
- console.log('This action does not return anything');
+ console.log("This action does not return anything");
return null;
},
});
@@ -286,21 +286,21 @@ export const exampleAction = action({
- Define crons by declaring the top-level `crons` object, calling some methods on it, and then exporting it as default. For example,
```ts
-import { cronJobs } from 'convex/server';
-import { internal } from './_generated/api';
-import { internalAction } from './_generated/server';
+import { cronJobs } from "convex/server";
+import { internal } from "./_generated/api";
+import { internalAction } from "./_generated/server";
const empty = internalAction({
args: {},
handler: async (ctx, args) => {
- console.log('empty');
+ console.log("empty");
},
});
const crons = cronJobs();
// Run `internal.crons.empty` every two hours.
-crons.interval('delete inactive users', { hours: 2 }, internal.crons.empty, {});
+crons.interval("delete inactive users", { hours: 2 }, internal.crons.empty, {});
export default crons;
```
@@ -316,18 +316,18 @@ Test files go inside the `convex/` directory. You must pass a module map from `i
```typescript
///
-import { convexTest } from 'convex-test';
-import { expect, test } from 'vitest';
-import { api } from './_generated/api';
-import schema from './schema';
+import { convexTest } from "convex-test";
+import { expect, test } from "vitest";
+import { api } from "./_generated/api";
+import schema from "./schema";
-const modules = import.meta.glob('./**/*.ts');
+const modules = import.meta.glob("./**/*.ts");
-test('some behavior', async () => {
+test("some behavior", async () => {
const t = convexTest(schema, modules);
- await t.mutation(api.messages.send, { body: 'Hi!', author: 'Sarah' });
+ await t.mutation(api.messages.send, { body: "Hi!", author: "Sarah" });
const messages = await t.query(api.messages.list);
- expect(messages).toMatchObject([{ body: 'Hi!', author: 'Sarah' }]);
+ expect(messages).toMatchObject([{ body: "Hi!", author: "Sarah" }]);
});
```
diff --git a/packages/notifier-bot/convex/_generated/api.d.ts b/packages/notifier-bot/convex/_generated/api.d.ts
index 1c01c35..6e935af 100644
--- a/packages/notifier-bot/convex/_generated/api.d.ts
+++ b/packages/notifier-bot/convex/_generated/api.d.ts
@@ -10,6 +10,11 @@
import type * as aiSummary from "../aiSummary.js";
import type * as crons from "../crons.js";
+import type * as discord_api from "../discord/api.js";
+import type * as discord_commands from "../discord/commands.js";
+import type * as discord_format from "../discord/format.js";
+import type * as discord_oauth from "../discord/oauth.js";
+import type * as discord_verify from "../discord/verify.js";
import type * as http from "../http.js";
import type * as packages from "../packages.js";
import type * as polling from "../polling.js";
@@ -36,6 +41,11 @@ import type {
declare const fullApi: ApiFromModules<{
aiSummary: typeof aiSummary;
crons: typeof crons;
+ "discord/api": typeof discord_api;
+ "discord/commands": typeof discord_commands;
+ "discord/format": typeof discord_format;
+ "discord/oauth": typeof discord_oauth;
+ "discord/verify": typeof discord_verify;
http: typeof http;
packages: typeof packages;
polling: typeof polling;
diff --git a/packages/notifier-bot/convex/discord/api.ts b/packages/notifier-bot/convex/discord/api.ts
new file mode 100644
index 0000000..2b6574e
--- /dev/null
+++ b/packages/notifier-bot/convex/discord/api.ts
@@ -0,0 +1,187 @@
+export class DiscordMissingAccessError extends Error {
+ constructor() {
+ super('Bot lacks permission to send messages in this channel');
+ this.name = 'DiscordMissingAccessError';
+ }
+}
+
+function botHeaders(): HeadersInit {
+ const token = process.env.DISCORD_BOT_TOKEN;
+ if (!token) throw new Error('DISCORD_BOT_TOKEN not set');
+ return {
+ 'Content-Type': 'application/json',
+ Authorization: `Bot ${token}`,
+ };
+}
+
+export async function sendChannelMessage(
+ channelId: string,
+ content: string,
+): Promise {
+ const response = await fetch(
+ `https://discord.com/api/v10/channels/${channelId}/messages`,
+ {
+ method: 'POST',
+ headers: botHeaders(),
+ body: JSON.stringify({ content }),
+ },
+ );
+
+ if (!response.ok) {
+ const data = (await response.json().catch(() => ({}))) as { code?: number };
+ if (response.status === 403 || data.code === 50013) {
+ throw new DiscordMissingAccessError();
+ }
+ throw new Error(
+ `Discord sendChannelMessage ${response.status}: ${JSON.stringify(data)}`,
+ );
+ }
+}
+
+export async function editInteractionReply(
+ applicationId: string,
+ interactionToken: string,
+ content: string,
+): Promise {
+ const response = await fetch(
+ `https://discord.com/api/v10/webhooks/${applicationId}/${interactionToken}/messages/@original`,
+ {
+ method: 'PATCH',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ content }),
+ },
+ );
+
+ if (!response.ok) {
+ const text = await response.text();
+ console.error(`Discord editInteractionReply ${response.status}: ${text}`);
+ }
+}
+
+export async function sendFollowUpMessage(
+ applicationId: string,
+ interactionToken: string,
+ content: string,
+): Promise {
+ const EPHEMERAL = 64;
+ const response = await fetch(
+ `https://discord.com/api/v10/webhooks/${applicationId}/${interactionToken}`,
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ content, flags: EPHEMERAL }),
+ },
+ );
+
+ if (!response.ok) {
+ const text = await response.text();
+ console.error(`Discord sendFollowUpMessage ${response.status}: ${text}`);
+ }
+}
+
+export async function getGuildName(
+ guildId: string,
+): Promise {
+ const token = process.env.DISCORD_BOT_TOKEN;
+ if (!token) return undefined;
+
+ const response = await fetch(
+ `https://discord.com/api/v10/guilds/${guildId}`,
+ { headers: { Authorization: `Bot ${token}` } },
+ );
+ if (!response.ok) return undefined;
+ const data = (await response.json()) as { name?: string };
+ return data.name;
+}
+
+export async function getChannelName(
+ channelId: string,
+): Promise {
+ const token = process.env.DISCORD_BOT_TOKEN;
+ if (!token) return undefined;
+
+ const response = await fetch(
+ `https://discord.com/api/v10/channels/${channelId}`,
+ { headers: { Authorization: `Bot ${token}` } },
+ );
+ if (!response.ok) return undefined;
+ const data = (await response.json()) as { name?: string };
+ return data.name;
+}
+
+export async function registerGlobalCommands(
+ applicationId: string,
+): Promise {
+ const commands = [
+ {
+ name: 'npmtrack',
+ description: 'Track an npm package for version updates',
+ options: [
+ {
+ name: 'package',
+ description: 'Package name (e.g. react)',
+ type: 3,
+ required: true,
+ },
+ {
+ name: 'channel',
+ description:
+ 'Channel to post notifications in (defaults to current channel)',
+ type: 7,
+ required: false,
+ },
+ {
+ name: 'filter',
+ description:
+ 'Minimum update type to notify on (default: all updates)',
+ type: 3,
+ required: false,
+ choices: [
+ { name: 'All updates (patch, minor, major)', value: 'patch' },
+ { name: 'Minor and major only', value: 'minor' },
+ { name: 'Major only', value: 'major' },
+ ],
+ },
+ ],
+ },
+ {
+ name: 'npmuntrack',
+ description: 'Stop tracking an npm package',
+ options: [
+ {
+ name: 'package',
+ description: 'Package name to stop tracking',
+ type: 3,
+ required: true,
+ },
+ {
+ name: 'channel',
+ description:
+ 'Channel subscription to remove (defaults to current channel)',
+ type: 7,
+ required: false,
+ },
+ ],
+ },
+ {
+ name: 'npmlist',
+ description: 'List all npm packages tracked in this server',
+ },
+ ];
+
+ const response = await fetch(
+ `https://discord.com/api/v10/applications/${applicationId}/commands`,
+ {
+ method: 'PUT',
+ headers: botHeaders(),
+ body: JSON.stringify(commands),
+ },
+ );
+
+ if (!response.ok) {
+ const text = await response.text();
+ throw new Error(
+ `Discord registerGlobalCommands ${response.status}: ${text}`,
+ );
+ }
+}
diff --git a/packages/notifier-bot/convex/discord/commands.ts b/packages/notifier-bot/convex/discord/commands.ts
new file mode 100644
index 0000000..1193496
--- /dev/null
+++ b/packages/notifier-bot/convex/discord/commands.ts
@@ -0,0 +1,540 @@
+import { v } from 'convex/values';
+import {
+ fetchNpmPackageManifest,
+ getNpmLatestVersion,
+ isVersionOutdated,
+} from '@patch-pulse/shared';
+import { ActionCtx, httpAction, internalAction } from '../_generated/server';
+import { internal } from '../_generated/api';
+import { Id } from '../_generated/dataModel';
+import { extractGitHubRepoUrl } from '../slack/links';
+import { verifyDiscordRequest } from './verify';
+import {
+ editInteractionReply,
+ getChannelName,
+ getGuildName,
+ sendFollowUpMessage,
+} from './api';
+import { formatDiscordPackageLink, formatDiscordVersionText } from './format';
+
+const INTERACTION_TYPE_PING = 1;
+const INTERACTION_TYPE_APPLICATION_COMMAND = 2;
+const RESPONSE_PONG = 1;
+const RESPONSE_DEFERRED_EPHEMERAL = 5;
+const RESPONSE_EPHEMERAL_MESSAGE = 4;
+const EPHEMERAL = 64;
+
+type MinUpdateType = 'patch' | 'minor' | 'major';
+
+function normalizePackageName(name: string): string {
+ return name
+ .replace(/[*_<>]/g, '')
+ .trim()
+ .toLowerCase();
+}
+
+function formatMinUpdateType(t: MinUpdateType | undefined): string | null {
+ if (!t || t === 'patch') return null;
+ return t === 'major' ? '[major only]' : '[minor+]';
+}
+
+function ephemeralText(content: string) {
+ return new Response(
+ JSON.stringify({
+ type: RESPONSE_EPHEMERAL_MESSAGE,
+ data: { content, flags: EPHEMERAL },
+ }),
+ { headers: { 'Content-Type': 'application/json' } },
+ );
+}
+
+function deferredEphemeral() {
+ return new Response(
+ JSON.stringify({
+ type: RESPONSE_DEFERRED_EPHEMERAL,
+ data: { flags: EPHEMERAL },
+ }),
+ { headers: { 'Content-Type': 'application/json' } },
+ );
+}
+
+type DiscordInteractionOption = {
+ name: string;
+ value: string | number | boolean;
+};
+
+type DiscordInteraction = {
+ type: number;
+ application_id: string;
+ token: string;
+ guild_id?: string;
+ channel_id: string;
+ member?: { user?: { id?: string } };
+ user?: { id?: string };
+ data: {
+ name: string;
+ options?: DiscordInteractionOption[];
+ resolved?: { channels?: Record };
+ };
+};
+
+export const discordInteractions = httpAction(async (ctx, request) => {
+ const rawBody = await verifyDiscordRequest(request);
+ if (rawBody === null) return new Response('Unauthorized', { status: 401 });
+
+ const interaction = JSON.parse(rawBody) as DiscordInteraction;
+
+ if (interaction.type === INTERACTION_TYPE_PING) {
+ return new Response(JSON.stringify({ type: RESPONSE_PONG }), {
+ headers: { 'Content-Type': 'application/json' },
+ });
+ }
+
+ if (interaction.type !== INTERACTION_TYPE_APPLICATION_COMMAND) {
+ return new Response('Unknown interaction type', { status: 400 });
+ }
+
+ const { name, options = [], resolved } = interaction.data;
+ const applicationId = interaction.application_id;
+ const interactionToken = interaction.token;
+ const guildId = interaction.guild_id;
+ const channelId = interaction.channel_id;
+ const userId =
+ interaction.member?.user?.id ?? interaction.user?.id ?? 'unknown';
+
+ if (!guildId) {
+ return ephemeralText('⚠️ PatchPulse commands must be used in a server.');
+ }
+
+ function getOption(optName: string): T | undefined {
+ return options.find((o) => o.name === optName)?.value as T | undefined;
+ }
+
+ function resolvedChannelName(id: string): string | undefined {
+ return resolved?.channels?.[id]?.name;
+ }
+
+ switch (name) {
+ case 'npmtrack': {
+ const packageName = getOption('package');
+ if (!packageName) {
+ return ephemeralText('⚠️ Please provide a package name.');
+ }
+
+ const channelOption = getOption('channel');
+ const targetChannelId = channelOption ?? channelId;
+ const targetChannelName = channelOption
+ ? resolvedChannelName(channelOption)
+ : undefined;
+ const filter = (getOption('filter') ?? 'patch') as MinUpdateType;
+
+ await ctx.scheduler.runAfter(
+ 0,
+ internal.discord.commands.processNpmTrack,
+ {
+ packageName,
+ guildId,
+ channelId: targetChannelId,
+ channelName: targetChannelName,
+ userId,
+ minUpdateType: filter,
+ applicationId,
+ interactionToken,
+ },
+ );
+ return deferredEphemeral();
+ }
+
+ case 'npmuntrack': {
+ const packageName = getOption('package');
+ if (!packageName) {
+ return ephemeralText('⚠️ Please provide a package name.');
+ }
+
+ const channelOption = getOption('channel');
+ const targetChannelId = channelOption ?? channelId;
+ const targetChannelName = channelOption
+ ? resolvedChannelName(channelOption)
+ : undefined;
+
+ await ctx.scheduler.runAfter(
+ 0,
+ internal.discord.commands.processNpmUntrack,
+ {
+ packageName,
+ guildId,
+ channelId: targetChannelId,
+ channelName: targetChannelName,
+ userId,
+ applicationId,
+ interactionToken,
+ },
+ );
+ return deferredEphemeral();
+ }
+
+ case 'npmlist': {
+ await ctx.scheduler.runAfter(0, internal.discord.commands.processList, {
+ guildId,
+ userId,
+ applicationId,
+ interactionToken,
+ });
+ return deferredEphemeral();
+ }
+
+ default:
+ return new Response('Unknown command', { status: 400 });
+ }
+});
+
+async function trackPackageForDiscord(
+ ctx: ActionCtx,
+ {
+ subscriberId,
+ packageName,
+ minUpdateType,
+ channelId,
+ channelName,
+ }: {
+ subscriberId: Id<'subscribers'>;
+ packageName: string;
+ minUpdateType: MinUpdateType;
+ channelId: string;
+ channelName?: string;
+ },
+): Promise<
+ | { kind: 'not_found' }
+ | { kind: 'already'; version: string; githubUrl?: string }
+ | { kind: 'updated'; version: string; githubUrl?: string }
+ | {
+ kind: 'tracked';
+ version: string;
+ dbVersion: string;
+ githubUrl?: string;
+ pendingUpdate: boolean;
+ }
+> {
+ const manifest = await fetchNpmPackageManifest(packageName, {
+ userAgent: 'patch-pulse-notifier-bot',
+ }).catch(() => null);
+ const version = getNpmLatestVersion(manifest);
+
+ if (!version) return { kind: 'not_found' };
+
+ const githubUrl = manifest ? extractGitHubRepoUrl(manifest) : undefined;
+
+ const { packageId, dbVersion } = await ctx.runMutation(
+ internal.packages.ensureExists,
+ { name: packageName, version, ecosystem: 'npm', githubRepoUrl: githubUrl },
+ );
+
+ const pendingUpdate = isVersionOutdated({
+ current: dbVersion,
+ latest: version,
+ });
+
+ const existing = await ctx.runQuery(internal.subscriptions.exists, {
+ packageId,
+ subscriberId,
+ channelId,
+ });
+
+ if (existing) {
+ if (existing.minUpdateType !== minUpdateType) {
+ await ctx.runMutation(internal.subscriptions.updateMinUpdateType, {
+ subscriptionId: existing._id,
+ minUpdateType,
+ });
+ return { kind: 'updated', version, githubUrl };
+ }
+ return { kind: 'already', version, githubUrl };
+ }
+
+ await ctx.runMutation(internal.subscriptions.create, {
+ packageId,
+ subscriberId,
+ lastNotifiedVersion: version,
+ minUpdateType,
+ channelId,
+ channelName,
+ });
+
+ return { kind: 'tracked', version, dbVersion, githubUrl, pendingUpdate };
+}
+
+async function ensureDiscordSubscriber(
+ ctx: ActionCtx,
+ guildId: string,
+): Promise> {
+ const existing = await ctx.runQuery(internal.subscribers.getByGuildId, {
+ guildId,
+ });
+ if (existing) return existing._id;
+
+ const guildName =
+ (await getGuildName(guildId).catch(() => undefined)) ?? 'Discord Server';
+
+ return await ctx.runMutation(internal.subscribers.upsertDiscordGuild, {
+ guildId,
+ guildName,
+ });
+}
+
+export const processNpmTrack = internalAction({
+ args: {
+ packageName: v.string(),
+ guildId: v.string(),
+ channelId: v.string(),
+ channelName: v.optional(v.string()),
+ userId: v.string(),
+ minUpdateType: v.union(
+ v.literal('patch'),
+ v.literal('minor'),
+ v.literal('major'),
+ ),
+ applicationId: v.string(),
+ interactionToken: v.string(),
+ },
+ handler: async (ctx, args) => {
+ async function reply(content: string) {
+ try {
+ await editInteractionReply(
+ args.applicationId,
+ args.interactionToken,
+ content,
+ );
+ } catch (err) {
+ console.error('discord processNpmTrack reply failed:', err);
+ }
+ }
+
+ const packageName = normalizePackageName(args.packageName);
+
+ const subscriberId = await ensureDiscordSubscriber(ctx, args.guildId);
+
+ let channelName = args.channelName;
+ if (!channelName) {
+ channelName = await getChannelName(args.channelId).catch(() => undefined);
+ }
+
+ const outcome = await trackPackageForDiscord(ctx, {
+ subscriberId,
+ packageName,
+ minUpdateType: args.minUpdateType,
+ channelId: args.channelId,
+ channelName,
+ });
+
+ const pkgLink = formatDiscordPackageLink(packageName);
+ const channelDisplay = `<#${args.channelId}>`;
+
+ if (outcome.kind === 'not_found') {
+ await reply(`❌ Could not find **\`${packageName}\`** on npm.`);
+ return;
+ }
+
+ const versionText = formatDiscordVersionText(
+ packageName,
+ outcome.version,
+ outcome.githubUrl,
+ );
+ const filterLabel = formatMinUpdateType(args.minUpdateType);
+
+ if (outcome.kind === 'updated') {
+ await reply(
+ `Updated: now tracking ${pkgLink} in ${channelDisplay} with ${filterLabel ?? 'all'} notifications — currently at ${versionText}`,
+ );
+ return;
+ }
+
+ if (outcome.kind === 'already') {
+ await reply(
+ `Already tracking ${pkgLink} in ${channelDisplay} — currently at ${versionText}${filterLabel ? ` ${filterLabel}` : ''}`,
+ );
+ return;
+ }
+
+ const displayVersionText = formatDiscordVersionText(
+ packageName,
+ outcome.dbVersion,
+ outcome.githubUrl,
+ );
+ const updateSuffix = outcome.pendingUpdate
+ ? ` There's already an update available (${displayVersionText} → ${versionText}) — I'll notify you shortly.`
+ : '';
+
+ await reply(
+ `Now tracking ${pkgLink} in ${channelDisplay} — current version ${outcome.pendingUpdate ? displayVersionText : versionText}${filterLabel ? ` ${filterLabel}` : ''}.${updateSuffix || " I'll post updates here when new versions are available."}`,
+ );
+ },
+});
+
+export const processNpmUntrack = internalAction({
+ args: {
+ packageName: v.string(),
+ guildId: v.string(),
+ channelId: v.string(),
+ channelName: v.optional(v.string()),
+ userId: v.string(),
+ applicationId: v.string(),
+ interactionToken: v.string(),
+ },
+ handler: async (ctx, args) => {
+ async function reply(content: string) {
+ try {
+ await editInteractionReply(
+ args.applicationId,
+ args.interactionToken,
+ content,
+ );
+ } catch (err) {
+ console.error('discord processNpmUntrack reply failed:', err);
+ }
+ }
+
+ const packageName = normalizePackageName(args.packageName);
+ const pkgLink = formatDiscordPackageLink(packageName);
+ const channelDisplay = `<#${args.channelId}>`;
+
+ const pkg = await ctx.runQuery(internal.packages.getByName, {
+ name: packageName,
+ });
+ if (!pkg) {
+ await reply(`\`${packageName}\` is not tracked in this server.`);
+ return;
+ }
+
+ const subscriberId = await ensureDiscordSubscriber(ctx, args.guildId);
+
+ const existing = await ctx.runQuery(internal.subscriptions.exists, {
+ packageId: pkg._id,
+ subscriberId,
+ channelId: args.channelId,
+ });
+
+ if (!existing) {
+ await reply(`${pkgLink} is not tracked in ${channelDisplay}.`);
+ return;
+ }
+
+ await ctx.runMutation(internal.subscriptions.remove, {
+ packageId: pkg._id,
+ subscriberId,
+ channelId: args.channelId,
+ });
+
+ await reply(`Stopped tracking ${pkgLink} in ${channelDisplay}.`);
+ },
+});
+
+export const processList = internalAction({
+ args: {
+ guildId: v.string(),
+ userId: v.string(),
+ applicationId: v.string(),
+ interactionToken: v.string(),
+ },
+ handler: async (ctx, args) => {
+ async function reply(content: string) {
+ try {
+ await editInteractionReply(
+ args.applicationId,
+ args.interactionToken,
+ content,
+ );
+ } catch (err) {
+ console.error('discord processList reply failed:', err);
+ }
+ }
+
+ const subscriberId = await ensureDiscordSubscriber(ctx, args.guildId);
+
+ const subscriptions = await ctx.runQuery(
+ internal.subscriptions.getBySubscriber,
+ { subscriberId },
+ );
+
+ const channelSubs = subscriptions.filter((s) => s.channelId);
+
+ if (channelSubs.length === 0) {
+ await reply(
+ "You're not tracking any packages yet. Use `/npmtrack` to get started.",
+ );
+ return;
+ }
+
+ const packageIds = [...new Set(channelSubs.map((s) => s.packageId))];
+ const packages = await ctx.runQuery(internal.packages.getByIds, {
+ ids: packageIds,
+ });
+
+ const grouped = new Map();
+
+ for (const sub of channelSubs) {
+ if (!sub.channelId) continue;
+ const pkg = packages.find((p) => p?._id === sub.packageId);
+ if (!pkg) continue;
+
+ const npmUrl = `https://www.npmjs.com/package/${encodeURIComponent(pkg.name)}`;
+ const versionUrl = pkg.githubRepoUrl
+ ? `${pkg.githubRepoUrl}/releases`
+ : `${npmUrl}/v/${pkg.currentVersion}`;
+ const filterLabel = formatMinUpdateType(
+ sub.minUpdateType as MinUpdateType,
+ );
+ const line =
+ ` • **[\`${pkg.name}\`](<${npmUrl}>)** — ` +
+ `[\`${pkg.currentVersion}\`](<${versionUrl}>)` +
+ `${filterLabel ? ` ${filterLabel}` : ''}`;
+
+ const existing = grouped.get(sub.channelId) ?? {
+ channelId: sub.channelId,
+ lines: [],
+ };
+ existing.lines.push(line);
+ grouped.set(sub.channelId, existing);
+ }
+
+ const uniquePackages = packageIds.length;
+ const header =
+ uniquePackages === channelSubs.length
+ ? `📦 Tracking **${channelSubs.length}** package${channelSubs.length === 1 ? '' : 's'}:`
+ : `📦 Tracking **${uniquePackages}** package${uniquePackages === 1 ? '' : 's'} across **${channelSubs.length}** subscriptions:`;
+
+ const sections = Array.from(grouped.values()).map(
+ ({ channelId, lines }) => `<#${channelId}>\n${lines.join('\n')}`,
+ );
+
+ // Chunk into messages under Discord's 2000-char limit
+ const DISCORD_CHAR_LIMIT = 1800;
+ const chunks: string[][] = [];
+ let current: string[] = [];
+ let currentLen = header.length + 2;
+
+ for (const section of sections) {
+ if (
+ current.length > 0 &&
+ currentLen + section.length + 2 > DISCORD_CHAR_LIMIT
+ ) {
+ chunks.push(current);
+ current = [];
+ currentLen = 0;
+ }
+ current.push(section);
+ currentLen += section.length + 2;
+ }
+ if (current.length > 0) chunks.push(current);
+
+ const [first, ...rest] = chunks;
+ await reply(`${header}\n\n${first.join('\n\n')}`);
+
+ for (const chunk of rest) {
+ await sendFollowUpMessage(
+ args.applicationId,
+ args.interactionToken,
+ chunk.join('\n\n'),
+ );
+ }
+ },
+});
diff --git a/packages/notifier-bot/convex/discord/format.ts b/packages/notifier-bot/convex/discord/format.ts
new file mode 100644
index 0000000..21ec611
--- /dev/null
+++ b/packages/notifier-bot/convex/discord/format.ts
@@ -0,0 +1,73 @@
+import {
+ isVersionOutdated,
+ type UpdateType,
+ type NpmPackageManifest,
+} from '@patch-pulse/shared';
+import { extractGitHubRepoUrl } from '../slack/links';
+
+function buildNpmUrl(packageName: string): string {
+ return `https://www.npmjs.com/package/${encodeURIComponent(packageName)}`;
+}
+
+export function formatDiscordPackageLink(packageName: string): string {
+ return `**[\`${packageName}\`](<${buildNpmUrl(packageName)}>)**`;
+}
+
+export function formatDiscordVersionText(
+ packageName: string,
+ version: string,
+ githubUrl: string | undefined,
+): string {
+ const url = githubUrl
+ ? `${githubUrl}/releases`
+ : `${buildNpmUrl(packageName)}/v/${version}`;
+ return `[\`${version}\`](<${url}>)`;
+}
+
+function getIntermediateVersions(
+ manifest: NpmPackageManifest,
+ fromVersion: string,
+ toVersion: string,
+): string[] {
+ return Object.keys(manifest.versions ?? {})
+ .filter((v) => {
+ if (v.includes('-')) return false;
+ const newerThanFrom = isVersionOutdated({
+ current: fromVersion,
+ latest: v,
+ });
+ const notNewerThanTo = !isVersionOutdated({
+ current: toVersion,
+ latest: v,
+ });
+ return newerThanFrom && notNewerThanTo;
+ })
+ .sort((a, b) => (isVersionOutdated({ current: a, latest: b }) ? -1 : 1))
+ .slice(0, 10);
+}
+
+export function formatUpdateLine(
+ name: string,
+ fromVersion: string,
+ toVersion: string,
+ updateType: UpdateType,
+ manifest: NpmPackageManifest,
+): string {
+ const githubUrl = extractGitHubRepoUrl(manifest);
+
+ const releaseLinks = githubUrl
+ ? getIntermediateVersions(manifest, fromVersion, toVersion).map(
+ (v) => `[\`v${v}\`](<${githubUrl}/releases/tag/v${v}>)`,
+ )
+ : [];
+
+ const suffix =
+ releaseLinks.length > 0 ? `\n ↳ ${releaseLinks.join(' · ')}` : '';
+
+ const packageLink = `**[\`${name}\`](<${buildNpmUrl(name)}>)**`;
+ const toVersionText = githubUrl
+ ? `[\`${toVersion}\`](<${githubUrl}/releases>)`
+ : `\`${toVersion}\``;
+
+ return `• ${packageLink} \`${fromVersion}\` → ${toVersionText} [${updateType}]${suffix}`;
+}
diff --git a/packages/notifier-bot/convex/discord/oauth.ts b/packages/notifier-bot/convex/discord/oauth.ts
new file mode 100644
index 0000000..f1ddc0a
--- /dev/null
+++ b/packages/notifier-bot/convex/discord/oauth.ts
@@ -0,0 +1,57 @@
+import { httpAction } from '../_generated/server';
+import { registerGlobalCommands } from './api';
+
+export const discordInstall = httpAction(async (_ctx, _request) => {
+ const clientId =
+ process.env.DISCORD_CLIENT_ID ?? process.env.DISCORD_APPLICATION_ID;
+
+ if (!clientId) {
+ return new Response('Server misconfiguration', { status: 500 });
+ }
+
+ const authorizeUrl = new URL('https://discord.com/oauth2/authorize');
+ authorizeUrl.searchParams.set('client_id', clientId);
+ authorizeUrl.searchParams.set('scope', 'bot applications.commands');
+ authorizeUrl.searchParams.set('permissions', '3072'); // VIEW_CHANNEL + SEND_MESSAGES
+ authorizeUrl.searchParams.set('integration_type', '0');
+
+ return new Response(null, {
+ status: 302,
+ headers: { Location: authorizeUrl.toString() },
+ });
+});
+
+/** Setup endpoint — call once after deploy to register slash commands globally. */
+export const discordRegisterCommands = httpAction(async (_ctx, request) => {
+ const expectedSecret = process.env.DISCORD_REGISTER_COMMANDS_SECRET;
+ if (!expectedSecret) {
+ return new Response('DISCORD_REGISTER_COMMANDS_SECRET not set', {
+ status: 500,
+ });
+ }
+
+ const providedSecret = request.headers.get('x-patchpulse-secret');
+ if (providedSecret !== expectedSecret) {
+ return new Response('Forbidden', { status: 403 });
+ }
+
+ const applicationId =
+ process.env.DISCORD_APPLICATION_ID ?? process.env.DISCORD_CLIENT_ID;
+ if (!applicationId) {
+ return new Response('DISCORD_APPLICATION_ID or DISCORD_CLIENT_ID not set', {
+ status: 500,
+ });
+ }
+
+ try {
+ await registerGlobalCommands(applicationId);
+ return new Response('Slash commands registered successfully.', {
+ status: 200,
+ });
+ } catch (err) {
+ const message = err instanceof Error ? err.message : String(err);
+ return new Response(`Failed to register commands: ${message}`, {
+ status: 500,
+ });
+ }
+});
diff --git a/packages/notifier-bot/convex/discord/verify.ts b/packages/notifier-bot/convex/discord/verify.ts
new file mode 100644
index 0000000..ab96377
--- /dev/null
+++ b/packages/notifier-bot/convex/discord/verify.ts
@@ -0,0 +1,53 @@
+function hexToBytes(hex: string): ArrayBuffer {
+ const bytes = new Uint8Array(hex.length / 2);
+ for (let i = 0; i < hex.length; i += 2) {
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
+ }
+ return bytes.buffer as ArrayBuffer;
+}
+
+/**
+ * Verifies a Discord interaction request signature using Ed25519.
+ * Returns the raw body string on success, null on failure.
+ *
+ * Discord signs every interaction with Ed25519 using the app's public key.
+ * Message: X-Signature-Timestamp + raw body bytes.
+ *
+ */
+export async function verifyDiscordRequest(
+ request: Request,
+): Promise {
+ const publicKey = process.env.DISCORD_PUBLIC_KEY;
+ const body = await request.text();
+
+ if (!publicKey) {
+ console.error('DISCORD_PUBLIC_KEY not set');
+ return null;
+ }
+
+ const signature = request.headers.get('X-Signature-Ed25519');
+ const timestamp = request.headers.get('X-Signature-Timestamp');
+
+ if (!signature || !timestamp) return null;
+
+ try {
+ const key = await crypto.subtle.importKey(
+ 'raw',
+ hexToBytes(publicKey),
+ { name: 'Ed25519' },
+ false,
+ ['verify'],
+ );
+
+ const isValid = await crypto.subtle.verify(
+ 'Ed25519',
+ key,
+ hexToBytes(signature),
+ new TextEncoder().encode(timestamp + body),
+ );
+
+ return isValid ? body : null;
+ } catch {
+ return null;
+ }
+}
diff --git a/packages/notifier-bot/convex/http.ts b/packages/notifier-bot/convex/http.ts
index b512eec..de15a23 100644
--- a/packages/notifier-bot/convex/http.ts
+++ b/packages/notifier-bot/convex/http.ts
@@ -8,6 +8,8 @@ import {
import { npmTrack, npmUntrack, listPackages, help } from './slack/commands';
import { slackEvents } from './slack/events';
import { slackInteractions } from './slack/interactions';
+import { discordInstall, discordRegisterCommands } from './discord/oauth';
+import { discordInteractions } from './discord/commands';
const http = httpRouter();
@@ -71,4 +73,22 @@ http.route({
handler: slackInteractions,
});
+http.route({
+ path: '/discord/install',
+ method: 'GET',
+ handler: discordInstall,
+});
+
+http.route({
+ path: '/discord/interactions',
+ method: 'POST',
+ handler: discordInteractions,
+});
+
+http.route({
+ path: '/discord/register-commands',
+ method: 'POST',
+ handler: discordRegisterCommands,
+});
+
export default http;
diff --git a/packages/notifier-bot/convex/polling.ts b/packages/notifier-bot/convex/polling.ts
index d990865..9e7d34a 100644
--- a/packages/notifier-bot/convex/polling.ts
+++ b/packages/notifier-bot/convex/polling.ts
@@ -11,12 +11,14 @@ import { internal } from './_generated/api';
import { Id } from './_generated/dataModel';
import { extractGitHubRepoUrl } from './slack/links';
import { formatUpdateLine } from './slack/format';
+import { formatUpdateLine as formatDiscordUpdateLine } from './discord/format';
import {
chatPostMessage,
conversationsFindByName,
PrivateChannelError,
reactionsAdd,
} from './slack/api';
+import { sendChannelMessage, DiscordMissingAccessError } from './discord/api';
const UPDATE_TYPE_RANK: Record = {
patch: 0,
@@ -49,6 +51,8 @@ export const checkForUpdates = internalAction({
};
type DestinationEntry = {
lines: string[];
+ discordLines: string[];
+ packageNames: string[];
stamps: Array<{
subscriptionId: Id<'subscriptions'>;
newVersion: string;
@@ -98,6 +102,13 @@ export const checkForUpdates = internalAction({
updateType,
manifest,
);
+ const discordLine = formatDiscordUpdateLine(
+ pkg.name,
+ pkg.currentVersion,
+ version,
+ updateType,
+ manifest,
+ );
await ctx.runMutation(internal.packages.upsertVersion, {
name: pkg.name,
@@ -130,6 +141,8 @@ export const checkForUpdates = internalAction({
channelMap.get(key) ??
({
lines: [] as string[],
+ discordLines: [] as string[],
+ packageNames: [] as string[],
stamps: [] as Array<{
subscriptionId: Id<'subscriptions'>;
newVersion: string;
@@ -137,6 +150,8 @@ export const checkForUpdates = internalAction({
pendingByLine: new Map(),
} satisfies DestinationEntry);
entry.lines.push(line);
+ entry.discordLines.push(discordLine);
+ entry.packageNames.push(pkg.name);
entry.stamps.push({ subscriptionId: sub._id, newVersion: version });
entry.pendingByLine.set(line, {
name: pkg.name,
@@ -162,6 +177,72 @@ export const checkForUpdates = internalAction({
});
if (!subscriber?.active) continue;
+ if (subscriber.type === 'discord') {
+ for (const [
+ key,
+ { discordLines, stamps, packageNames },
+ ] of channelMap) {
+ if (!key.startsWith('channel:')) continue;
+ const targetChannelId = key.slice('channel:'.length);
+
+ const header =
+ discordLines.length === 1
+ ? `📦 **${packageNames[0] ?? 'package'} update**`
+ : `📦 **${discordLines.length} npm package updates**`;
+
+ const DISCORD_CHAR_LIMIT = 1800;
+ const batches: string[][] = [];
+ let batch: string[] = [];
+ let batchLen = header.length + 2;
+ for (const dl of discordLines) {
+ if (
+ batch.length > 0 &&
+ batchLen + dl.length + 1 > DISCORD_CHAR_LIMIT
+ ) {
+ batches.push(batch);
+ batch = [];
+ batchLen = 0;
+ }
+ batch.push(dl);
+ batchLen += dl.length + 1;
+ }
+ if (batch.length > 0) batches.push(batch);
+
+ let allBatchesSent = true;
+ for (const batchLines of batches) {
+ try {
+ await sendChannelMessage(
+ targetChannelId,
+ `${header}\n\n${batchLines.join('\n')}`,
+ );
+ } catch (error) {
+ allBatchesSent = false;
+ if (error instanceof DiscordMissingAccessError) {
+ console.warn(
+ `Discord: missing access for channel ${targetChannelId}`,
+ );
+ } else {
+ console.error(
+ `Discord: error sending to ${targetChannelId}:`,
+ error,
+ );
+ }
+ break;
+ }
+ }
+
+ if (allBatchesSent && batches.length > 0) {
+ for (const { subscriptionId, newVersion } of stamps) {
+ await ctx.runMutation(
+ internal.subscriptions.updateLastNotifiedVersion,
+ { subscriptionId, version: newVersion },
+ );
+ }
+ }
+ }
+ continue;
+ }
+
const details = await ctx.runQuery(internal.subscribers.getSlackDetails, {
subscriberId,
});
diff --git a/packages/notifier-bot/convex/schema.ts b/packages/notifier-bot/convex/schema.ts
index e09287a..5790f55 100644
--- a/packages/notifier-bot/convex/schema.ts
+++ b/packages/notifier-bot/convex/schema.ts
@@ -16,6 +16,14 @@ export default defineSchema({
active: v.boolean(),
}).index('by_identifier', ['identifier']),
+ discordSubscriberDetails: defineTable({
+ subscriberId: v.id('subscribers'),
+ guildId: v.string(),
+ guildName: v.string(),
+ })
+ .index('by_subscriber', ['subscriberId'])
+ .index('by_guild_id', ['guildId']),
+
slackSubscriberDetails: defineTable({
subscriberId: v.id('subscribers'),
accessToken: v.string(),
diff --git a/packages/notifier-bot/convex/subscribers.ts b/packages/notifier-bot/convex/subscribers.ts
index 8546d6a..b7e726b 100644
--- a/packages/notifier-bot/convex/subscribers.ts
+++ b/packages/notifier-bot/convex/subscribers.ts
@@ -1,6 +1,76 @@
import { v } from 'convex/values';
import { internalMutation, internalQuery } from './_generated/server';
+export const getByGuildId = internalQuery({
+ args: { guildId: v.string() },
+ handler: async (ctx, { guildId }) => {
+ return await ctx.db
+ .query('subscribers')
+ .withIndex('by_identifier', (q) => q.eq('identifier', guildId))
+ .first();
+ },
+});
+
+export const getDiscordDetails = internalQuery({
+ args: { subscriberId: v.id('subscribers') },
+ handler: async (ctx, { subscriberId }) => {
+ return await ctx.db
+ .query('discordSubscriberDetails')
+ .withIndex('by_subscriber', (q) => q.eq('subscriberId', subscriberId))
+ .first();
+ },
+});
+
+export const upsertDiscordGuild = internalMutation({
+ args: {
+ guildId: v.string(),
+ guildName: v.string(),
+ },
+ handler: async (ctx, { guildId, guildName }) => {
+ const existing = await ctx.db
+ .query('subscribers')
+ .withIndex('by_identifier', (q) => q.eq('identifier', guildId))
+ .first();
+
+ if (existing) {
+ if (!existing.active) {
+ await ctx.db.patch(existing._id, { active: true });
+ }
+
+ const details = await ctx.db
+ .query('discordSubscriberDetails')
+ .withIndex('by_subscriber', (q) => q.eq('subscriberId', existing._id))
+ .first();
+
+ if (details) {
+ await ctx.db.patch(details._id, { guildName });
+ } else {
+ await ctx.db.insert('discordSubscriberDetails', {
+ subscriberId: existing._id,
+ guildId,
+ guildName,
+ });
+ }
+
+ return existing._id;
+ }
+
+ const subscriberId = await ctx.db.insert('subscribers', {
+ type: 'discord',
+ identifier: guildId,
+ active: true,
+ });
+
+ await ctx.db.insert('discordSubscriberDetails', {
+ subscriberId,
+ guildId,
+ guildName,
+ });
+
+ return subscriberId;
+ },
+});
+
export const getByTeamId = internalQuery({
args: { teamId: v.string() },
handler: async (ctx, { teamId }) => {
diff --git a/packages/notifier-bot/docs/architecture.md b/packages/notifier-bot/docs/architecture.md
index 23056df..b0def38 100644
--- a/packages/notifier-bot/docs/architecture.md
+++ b/packages/notifier-bot/docs/architecture.md
@@ -12,6 +12,7 @@ Primary tables:
- `packages`
- `subscribers`
+- `discordSubscriberDetails`
- `slackSubscriberDetails`
- `subscriptions`
- `pendingReleaseChecks`
@@ -36,7 +37,19 @@ Important fields:
Stores top-level subscriber identities.
-Today this is mainly Slack workspaces.
+This now includes:
+
+- Slack workspaces
+- Discord guilds
+
+`subscribers.type` determines which detail table and delivery path apply.
+
+### `discordSubscriberDetails`
+
+Stores Discord-specific connection details:
+
+- guild ID
+- guild name
### `slackSubscriberDetails`
@@ -76,7 +89,7 @@ Important fields:
- `retryCount`
- `packages`
-Each package entry tracks two independent concerns:
+These rows are currently Slack-only. Each package entry tracks two independent concerns:
- whether the original Slack line still needs GitHub link backfill
- whether an AI summary for that package is still pending
@@ -98,6 +111,26 @@ Pattern:
This keeps slash commands responsive while still allowing async work.
+### Discord Commands
+
+Defined in:
+
+- [`convex/discord/commands.ts`](../convex/discord/commands.ts)
+- [`convex/discord/oauth.ts`](../convex/discord/oauth.ts)
+
+Pattern:
+
+1. Discord hits `/discord/interactions`.
+2. The HTTP handler verifies the Ed25519 signature.
+3. It immediately returns a deferred ephemeral interaction response.
+4. The real work is scheduled via Convex.
+5. The deferred reply is edited with the final result.
+
+Discord install and command registration also use:
+
+- `GET /discord/install`
+- `POST /discord/register-commands`
+
### Polling
Defined in:
@@ -112,21 +145,22 @@ The poller:
3. determines whether an update is available
4. stores the newest version
5. stores GitHub repo metadata when available
-6. groups matching subscriptions by Slack target channel
-7. sends one notification per `(workspace, channel)` target
-8. adds a pending reaction and queues an enrichment job for the posted Slack message
+6. groups matching subscriptions by subscriber-specific target
+7. sends one notification per target channel
+8. for Slack, adds a pending reaction and queues an enrichment job for the posted message
+9. for Discord, sends the base notification only
## Metadata Enrichment
The notifier uses a two-stage enrichment flow.
-Stage 1 happens during polling:
+Stage 1 happens during polling for both Slack and Discord:
- polling fetches npm metadata anyway
- if a GitHub repo URL can be derived from `repository`, it is normalized and stored on `packages.githubRepoUrl`
- the outgoing Slack message includes the best release links available at send time
-Stage 2 happens in [`convex/releaseChecks.ts`](../convex/releaseChecks.ts):
+Stage 2 happens in [`convex/releaseChecks.ts`](../convex/releaseChecks.ts) for Slack only:
- the notifier retries on a backoff schedule: `1h`, `3h`, `6h`, `12h`, `24h`
- each retry re-fetches npm metadata and structured GitHub evidence
@@ -182,6 +216,7 @@ Test stack:
Recommended places to update docs:
+- user-facing Discord behavior: [`docs/discord.md`](./discord.md)
- user-facing Slack behavior: [`docs/slack.md`](./slack.md)
- internal implementation notes: [`docs/architecture.md`](./architecture.md)
- deployment/configuration: [`docs/deployment.md`](./deployment.md)
diff --git a/packages/notifier-bot/docs/deployment.md b/packages/notifier-bot/docs/deployment.md
index f840b30..3bd4623 100644
--- a/packages/notifier-bot/docs/deployment.md
+++ b/packages/notifier-bot/docs/deployment.md
@@ -9,18 +9,26 @@ The notifier runs on Convex.
Important pieces:
- Convex functions and schema
-- HTTP endpoints for Slack OAuth and slash commands
+- HTTP endpoints for Slack and Discord installs and commands
- an hourly polling cron
## Environment Variables
-Current Slack OAuth flow depends on these environment variables:
+Slack install flow depends on these environment variables:
- `SLACK_CLIENT_ID`
- `SLACK_CLIENT_SECRET`
- `SLACK_REDIRECT_URI`
- `SLACK_SIGNING_SECRET`
+Discord install flow depends on these environment variables:
+
+- `DISCORD_APPLICATION_ID`
+- `DISCORD_CLIENT_ID`
+- `DISCORD_PUBLIC_KEY`
+- `DISCORD_BOT_TOKEN`
+- `DISCORD_REGISTER_COMMANDS_SECRET`
+
AI-powered release summaries additionally support:
- `OPENAI_API_KEY`
@@ -28,9 +36,15 @@ AI-powered release summaries additionally support:
- `OPENAI_SUMMARY_MINI_MODEL` optional override
- `GITHUB_TOKEN` optional, for higher GitHub API rate limits
-These are read in [`convex/slack/oauth.ts`](../convex/slack/oauth.ts).
+These are read in:
+
+- [`convex/slack/oauth.ts`](../convex/slack/oauth.ts)
+- [`convex/discord/oauth.ts`](../convex/discord/oauth.ts)
+- [`convex/discord/commands.ts`](../convex/discord/commands.ts)
+
+If Slack env vars are missing, the Slack OAuth callback returns `500 Server misconfiguration`.
-If any of them are missing, the Slack OAuth callback returns `500 Server misconfiguration`.
+If Discord env vars are missing, the Discord install flow, interaction verification, or command registration will fail.
## Slack HTTP Endpoints
@@ -49,6 +63,19 @@ These routes are intended to be configured in Slack as:
- Slack slash command request URLs: `/slack/npmtrack`, `/slack/npmuntrack`, `/slack/list`, `/slack/help`
- event subscriptions: `/slack/events`
+## Discord HTTP Endpoints
+
+Defined in [`convex/http.ts`](../convex/http.ts):
+
+- `GET /discord/install`
+- `POST /discord/interactions`
+- `POST /discord/register-commands`
+
+These routes are intended to be configured in Discord as:
+
+- Interactions endpoint URL: `/discord/interactions`
+- Optional post-deploy command registration trigger: `/discord/register-commands` with `x-patchpulse-secret`
+
## Polling
The notifier uses an hourly cron defined in [`convex/crons.ts`](../convex/crons.ts):
@@ -61,8 +88,8 @@ This cron:
2. detects updates
3. stores the latest version
4. stores GitHub repo metadata when available
-5. delivers notifications grouped by Slack target channel
-6. queues release enrichment jobs that can backfill links and post thread summaries later
+5. delivers notifications grouped by target channel
+6. queues Slack-only release enrichment jobs that can backfill links and post thread summaries later
## Data Expectations
@@ -71,6 +98,11 @@ Slack installs create:
- a `subscribers` row for the workspace
- a `slackSubscriberDetails` row with bot token and webhook channel details
+Discord servers create subscriber rows lazily on first command use:
+
+- a `subscribers` row for the guild
+- a `discordSubscriberDetails` row with guild identity details
+
Tracked packages create:
- a `packages` row
@@ -82,11 +114,18 @@ Tracked packages create:
- Set `SLACK_CLIENT_SECRET`
- Set `SLACK_SIGNING_SECRET`
- Set `SLACK_REDIRECT_URI`
+- Set `DISCORD_APPLICATION_ID`
+- Set `DISCORD_CLIENT_ID`
+- Set `DISCORD_PUBLIC_KEY`
+- Set `DISCORD_BOT_TOKEN`
+- Set `DISCORD_REGISTER_COMMANDS_SECRET`
- Set `OPENAI_API_KEY` if AI summaries should be enabled
- Optionally set `GITHUB_TOKEN` if you expect heavier GitHub API usage
- Confirm Slack app redirect URL matches `SLACK_REDIRECT_URI`
- Confirm slash command request URLs point to the Convex HTTP endpoints
- Confirm event subscriptions point to `/slack/events`
+- Confirm Discord interactions point to `/discord/interactions`
+- Run `curl -X POST -H "x-patchpulse-secret: $DISCORD_REGISTER_COMMANDS_SECRET" https://grand-yak-92.convex.site/discord/register-commands`
- Confirm the poller cron is deployed
## Post-Deploy Smoke Checks
@@ -99,3 +138,8 @@ Tracked packages create:
- Verify update notifications arrive in the expected channels
- Verify new notifications receive `⏳` while enrichment is pending
- Verify a thread summary appears and the reaction changes to `📝` when evidence is available
+- Install the Discord app into a test server
+- Run `/npmtrack package:react`
+- Run `/npmtrack package:react channel:#releases`
+- Run `/npmlist`
+- Verify the bot replies ephemerally and notifications arrive in the chosen channel
diff --git a/packages/notifier-bot/docs/discord.md b/packages/notifier-bot/docs/discord.md
new file mode 100644
index 0000000..99a9e48
--- /dev/null
+++ b/packages/notifier-bot/docs/discord.md
@@ -0,0 +1,124 @@
+# Discord Bot Guide
+
+This document describes how the Discord bot behaves in the notifier package.
+
+## Server Install
+
+When PatchPulse is added to a Discord server, the install flow grants the bot access to the server and slash commands.
+
+We persist the guild in Convex lazily on the first real command we receive from that server. At that point we record:
+
+- the guild ID as the subscriber identifier
+- the guild name for display purposes
+
+There is no per-guild access token. All Discord API calls use a single shared `DISCORD_BOT_TOKEN` environment variable.
+
+There is no default channel — every subscription must specify an explicit channel.
+
+## Subscription Model
+
+Discord subscriptions are channel-based only.
+
+The same package can be tracked in multiple channels:
+
+- once in `#releases`
+- once in `#frontend`
+
+The effective uniqueness key is `(guild, package, channel)`.
+
+DM subscriptions are not supported for Discord bots.
+
+## Slash Commands
+
+Discord slash commands have typed options — no free-text parsing needed.
+
+### `/npmtrack package:[name] [channel:#channel] [filter:patch|minor|major]`
+
+Tracks a package in a channel.
+
+Behavior:
+
+- `package` is required.
+- `channel` defaults to the channel where the command is run if omitted.
+- `filter` defaults to `patch` (all updates) if omitted.
+- Re-running with a different `filter` updates the threshold in place.
+- The same package can be tracked in multiple channels independently.
+
+Examples:
+
+- `/npmtrack package:react`
+- `/npmtrack package:react channel:#releases`
+- `/npmtrack package:react filter:minor`
+- `/npmtrack package:next channel:#frontend filter:major`
+
+User feedback is ephemeral (only visible to the invoking user).
+
+### `/npmuntrack package:[name] [channel:#channel]`
+
+Stops tracking a package in a channel.
+
+Behavior:
+
+- `channel` defaults to the current channel if omitted.
+- Only the subscription for that specific channel is removed.
+
+### `/npmlist`
+
+Lists all packages tracked in the server, grouped by channel.
+
+Output shape:
+
+```
+📦 Tracking **3** packages across **4** subscriptions:
+
+#releases
+ • **`react`** — [`19.2.5`]()
+ • **`typescript`** — [`6.0.2`]()
+
+#frontend
+ • **`react`** — [`19.2.5`]() [minor+]
+```
+
+## Interaction Flow
+
+Discord sends every slash command as an HTTP POST to `/discord/interactions`.
+
+1. The interaction endpoint verifies the Ed25519 signature.
+2. It immediately responds with a deferred ephemeral acknowledgement (type 5, flags 64).
+3. A background Convex action processes the command.
+4. The background action edits the deferred reply with the final result.
+
+This keeps commands responsive even when npm lookups take a moment.
+
+## Notification Format
+
+Update notifications use Discord markdown:
+
+```
+📦 **react update**
+
+• **[`react`]()** `18.3.1` → [`19.0.0`]() [major]
+ ↳ [`v18.3.2`](<.../releases/tag/v18.3.2>) · [`v18.3.3`](<.../releases/tag/v18.3.3>)
+```
+
+Release note enrichment (AI summaries, thread replies) is currently Slack-only. Discord receives the base notification only.
+
+## Link Behavior
+
+- Package names link to npm.
+- Versions link to GitHub releases when `githubRepoUrl` is known, otherwise plain text.
+- Intermediate version links appear when a GitHub repo is available.
+
+## Setup — One-Time Command Registration
+
+Discord slash commands must be registered globally before they appear in any server.
+
+After deploying:
+
+```
+curl -X POST \
+ -H "x-patchpulse-secret: $DISCORD_REGISTER_COMMANDS_SECRET" \
+ https://grand-yak-92.convex.site/discord/register-commands
+```
+
+This is idempotent and safe to re-run after adding or changing commands.
diff --git a/packages/notifier-bot/docs/runbook.md b/packages/notifier-bot/docs/runbook.md
index 0d1612a..b84249c 100644
--- a/packages/notifier-bot/docs/runbook.md
+++ b/packages/notifier-bot/docs/runbook.md
@@ -2,6 +2,61 @@
This document is for debugging common notifier issues.
+## Discord App Install Fails
+
+Symptoms:
+
+- `/discord/install` redirects, but the guild is not stored
+- Discord OAuth completes, but the success page shows an error
+
+Checks:
+
+- verify `DISCORD_CLIENT_ID`
+- verify `DISCORD_APPLICATION_ID`
+- verify `DISCORD_BOT_TOKEN`
+- inspect logs around [`convex/discord/oauth.ts`](../convex/discord/oauth.ts)
+
+Likely causes:
+
+- missing env vars
+- incorrect install link configuration
+
+## Discord Slash Commands Do Not Appear
+
+Symptoms:
+
+- the bot is installed, but `/npmtrack` and `/npmlist` are unavailable in Discord
+
+Checks:
+
+- run `curl -X POST -H "x-patchpulse-secret: $DISCORD_REGISTER_COMMANDS_SECRET" https://grand-yak-92.convex.site/discord/register-commands`
+- inspect logs around [`convex/discord/oauth.ts`](../convex/discord/oauth.ts)
+- verify `DISCORD_APPLICATION_ID`, `DISCORD_CLIENT_ID`, and `DISCORD_BOT_TOKEN`
+
+Explanation:
+
+- Discord slash commands must be registered before they appear
+- global command registration can take some time to propagate
+
+## Discord Interaction Verification Fails
+
+Symptoms:
+
+- Discord marks the interactions endpoint invalid
+- slash commands fail immediately
+
+Checks:
+
+- verify `DISCORD_PUBLIC_KEY`
+- verify Discord Interactions Endpoint URL points to `/discord/interactions`
+- inspect logs around [`convex/discord/commands.ts`](../convex/discord/commands.ts) and [`convex/discord/verify.ts`](../convex/discord/verify.ts)
+
+Likely causes:
+
+- wrong public key
+- wrong endpoint URL
+- stale deployment
+
## Slack App Install Fails
Symptoms:
@@ -73,6 +128,18 @@ Checks:
- inspect `subscriptions.channelId` and `channelName`
- remember that missing `channelId` means “workspace default channel”
+## Wrong Discord Channel Used
+
+Symptoms:
+
+- notifications go to a different Discord channel than expected
+
+Checks:
+
+- inspect `subscriptions.channelId` and `channelName`
+- remember that Discord has no default channel fallback
+- verify the command was run with the intended `channel` option
+
## `/npmuntrack` Removes Too Much
Expected behavior:
@@ -91,6 +158,7 @@ Checks:
- verify the cron in [`convex/crons.ts`](../convex/crons.ts) is deployed
- inspect logs from [`convex/polling.ts`](../convex/polling.ts)
- verify update threshold filters like `minor` or `major`
+- if the subscriber is Discord, inspect bot API errors for missing channel access
## Release Summary Stays At `⏳`
@@ -144,6 +212,9 @@ Checks:
## Useful Files
- [`convex/http.ts`](../convex/http.ts)
+- [`convex/discord/oauth.ts`](../convex/discord/oauth.ts)
+- [`convex/discord/commands.ts`](../convex/discord/commands.ts)
+- [`convex/discord/verify.ts`](../convex/discord/verify.ts)
- [`convex/slack/oauth.ts`](../convex/slack/oauth.ts)
- [`convex/slack/commands.ts`](../convex/slack/commands.ts)
- [`convex/slack/events.ts`](../convex/slack/events.ts)
diff --git a/packages/notifier-bot/skills-lock.json b/packages/notifier-bot/skills-lock.json
index 9451d83..bf33b96 100644
--- a/packages/notifier-bot/skills-lock.json
+++ b/packages/notifier-bot/skills-lock.json
@@ -1,6 +1,11 @@
{
"version": 1,
"skills": {
+ "convex": {
+ "source": "get-convex/agent-skills",
+ "sourceType": "github",
+ "computedHash": "613ee9955985085d0fca8f96e1fc6d7cfd204dffa203499a1d508b8def76577b"
+ },
"convex-create-component": {
"source": "get-convex/agent-skills",
"sourceType": "github",