VS Code Marketplace / bchelkowski.kopytko v1.13.1

Kopytko VS Code Extension

A full-featured BrightScript language server extension for VS Code. IntelliSense, diagnostics, go-to-definition, call hierarchy, formatting, debugging, and Roku device management — all in one.

IntelliSense

Context-aware completions covering every BrightScript built-in, user-defined functions, local variables, type annotations, ro* component constructors, and Kopytko module exports.

  • Built-in functions and keywords from the BrightScript stdlib
  • User functions from current file, @imports, XML siblings, and /source/
  • Local variables, parameters, and for-loop variables
  • CreateObject("...") — SceneGraph component name completions
  • Type inference: member completions after CreateObject() or typed params
  • m.top field completions from XML interface and parent SG components
  • @import / @mock path auto-complete with package-resolution
  • Kopytko module exports — auto-inserts @import on selection
  • Test framework completions: expect(), mockFunction(), test globals

IntelliSense completion popup

Completion popup showing BrightScript built-ins, user functions, and type-inferred members

→ site/public/screenshots/intellisense-completion-popup.png

Hover documentation

Hover card on a built-in function showing its signature, description, and return type

→ site/public/screenshots/hover-documentation.png

Navigation

Navigate your codebase with precision — from go-to-definition on @import paths to workspace-wide call hierarchy and SceneGraph type hierarchy. All navigation respects the @import graph and XML sibling relationships.

Go-to-Definition
@import paths, user functions, /source/ functions
Find All References
Workspace-wide with Shift+F12
Call Hierarchy
Incoming and outgoing calls (Shift+Alt+H)
Type Hierarchy
SceneGraph extends chains, super and sub components
Outline / Symbols
Functions, subs, and AA methods with params
Workspace Symbols
Fuzzy search across all .brs files (Ctrl+T)
Document Links
Clickable @import paths
Folding Ranges
CST-driven folds for functions and @import groups
Selection Range
Smart expand/shrink (Shift+Alt+→)

Go-to-definition on import

Definition peek popup on an @import path, jumping to the imported .brs file

→ site/public/screenshots/go-to-definition-on-import.png

Call hierarchy panel

Incoming calls panel showing which functions call the selected function

→ site/public/screenshots/call-hierarchy-panel.png

Diagnostics & Quick Fixes

BrightScript diagnostics

BrightScript file with multiple diagnostic squiggles: undefined function, missing type annotation, unused import

→ site/public/screenshots/brightscript-diagnostics.png

Quick fix menu

Light-bulb quick-fix menu with options: Add missing import, Remove unused parameter, Add type annotation

→ site/public/screenshots/quick-fix-menu.png

Real-time diagnostics powered by the kopytko-linter engine. 32 rules reported as you type, with code actions for auto-fixable issues.

error
identifier/undefined-function

Highlights calls to undeclared functions

error
identifier/undefined-variable

Variable used before assignment

error
import/unresolved

@import path cannot be found on disk

warning
import/unused

Imported file never referenced

warning
type/missing-return-type

Missing as Type on function declaration

error
callback/undefined-observer-callback

observeFieldScoped() callback not found

… and 19 more rules. Full rule list →

One of them is project-wide rather than per-file: component/duplicate-name warns on both XML files when two of them declare the same SceneGraph component. Component names are global to the channel, so the second declaration silently overrides the first. The editor reports it as you save; kopytko-lint reports it in CI.

Kopytko imports & test framework

First-class support for the @import / @mock annotation system used by the Kopytko Framework. Import chains are resolved transitively across packages with full IntelliSense at each step.

' @import /components/VideoPlayer.brs
' @import /utils/analytics.brs
' @mock  /components/VideoPlayer.brs  ' test mode only

sub init()
  ' completions, hover, go-to-definition all work
  m.player = createVideoPlayer()
  m.player.observeFieldScoped("state", "onStateChanged")
end sub

Test files (*/_tests/**/*.test.brs) get enriched completions for the Kopytko Unit Testing Framework: expect() matchers, mockFunction(), and test globals with documentation.

' Type "it" + Tab for a test case snippet:
it("should initialize correctly", sub()
  m.player = VideoPlayer()
  expect(m.player.isReady).toBe(true)
end sub)

' Type "expect" for matcher completions:
expect(result).toBe(42)
expect(result).toEqual({ id: 1 })
expect(m.mock).toHaveBeenCalled()

Formatting

The extension embeds the kopytko-formatter engine. Format a file with Shift+Alt+F, or enable format-on-save. All 49 formatting options and casing settings are configurable from .vscode/settings.json.

✓ 49 formatting rules

✓ 10 independent casing dimensions

✓ Preserves @import order or sorts alphabetically

✓ Format-on-save support

✓ Respects readOnlyPaths — skips generated files

Format-on-save

GIF showing a BrightScript file being formatted on save — inconsistent whitespace and casing normalized automatically

→ site/public/screenshots/format-on-save.png

Rename symbol

Press F2 on any function name or local variable to rename it across all usages. Function renames propagate workspace-wide through the @import graph. Local variable renames are confined to the declaring scope.

Roku device discovery

Automatic SSDP-based discovery keeps your sidebar populated with every Roku device on the network. Device health is verified via ECP on each scan, and the list updates on network change or sleep/wake.

Auto-discovery
SSDP M-SEARCH + passive NOTIFY listener
Favorites
Persist important devices across restarts
Manual entry
Add devices by IP when SSDP is unavailable
Secure passwords
Stored in OS keychain via VS Code SecretStorage
Registry viewer
Read device registry sections via ECP
.kopytkorc env
Per-device environment selection

Device sidebar

Roku Devices sidebar tree showing two discovered devices: one online (green indicator) with model/firmware info, one offline (gray)

→ site/public/screenshots/device-sidebar.png

Integrated debugger

Debugger breakpoint hit

VS Code debugger paused at a breakpoint in a .brs file. Variables panel shows typed locals. Call stack shows SceneGraph threads.

→ site/public/screenshots/debugger-breakpoint-hit.png

Debug variables panel

Variables panel with expandable roAssociativeArray container, showing fields including nested objects with virtual $children and $count

→ site/public/screenshots/debug-variables-panel.png

Implements the Roku Socket Debug Protocol 3.3.0 over TCP port 8081. Deploy your channel with Ctrl+Shift+F5, then debug with F5.

  • Static, conditional, and hit-count breakpoints
  • Exception breakpoints (caught and uncaught)
  • Multi-thread inspection: main, render, and task threads
  • Step over / into / out, and pause
  • Typed variable inspection with expandable containers
  • Virtual variables: $children, $parent, $count on roSGNodes
  • Hover-to-evaluate expressions
  • Debug console REPL with EXECUTE command
  • Compile errors surfaced as VS Code diagnostics
  • Program output via IO channel
  • Protocol-state aware: breakpoints toggled while the channel runs are replayed on the next stop, so the device is never sent a command it would answer with a connection reset
  • Wire-level protocol tracing via kopytko.debug.trace for diagnosing dropped sessions
.vscode/launch.json
// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "brightscript",
      "request": "launch",
      "name": "Debug on Roku",

      // host and password are OPTIONAL.
      // When omitted they are taken from the active device in the sidebar.
      // "host": "192.168.1.100",
      // "password": "rokudev",

      "rootDir": "${workspaceFolder}",

      // env selects a .kopytkorc environment key ("dev", "staging", ...).
      // Optional — taken from the active device's environment selection if omitted.
      // "env": "dev",

      "stopOnEntry": false
    }
  ]
}

Device Manager

A dedicated sidebar container — drag it to the right-hand Secondary Side Bar to keep it next to your code — with two views: Remote Control (the on-screen remote, then three expanded-by-default disclosures: Saved Text entries, Device actions, then a Secret screens reference) and a RASP automation-script library compatible with Roku's official Remote Tool.

  • Remote laid out like a physical Roku remote — click for keypress, hold ≥1 s for keydown/keyup (scrubbing works)
  • Text field types on the device keyboard — ordered, sequential Lit_ keypresses, UTF-8 safe
  • Keyboard remote mode — arrows/Enter/Escape drive the device from anywhere; status-bar indicator, Ctrl+K exits
  • Device actions — expanded by default, labeled rows for web-admin actions: screenshot, upload, package, rekey, software update, restart, delete channel
  • Secret screens — expanded-by-default reference list (not buttons) for 5 Roku key sequences: enable dev mode, channel info, screenshots & ads, reset & update, clear cache; typed on your physical remote
  • Saved Text entries: text and credentials types with a Send button per field; passwords in the OS keychain, never in settings or the webview
  • Custom labels on Saved Text (type doubles as an implicit label) and Scripts, with Filter and Sort-by-label dropdowns
  • RASP script editor tab — live validation, snippet toolbar, per-step run progress with cancel
  • Record remote — button presses and sent text write themselves into the open script editor, like Roku’s own tool
  • Full RASP runner: press, text, pause, launch, loops, reusable blocks, wait_for_player_state, validate_streaming
  • Import/export .rasp files — scripts round-trip with the Roku Remote Tool

Device Manager sidebar

Secondary sidebar with a Roku-style remote control (D-pad, media keys, text field), expanded Saved Text entries with Send buttons, an expanded Device actions list of labeled rows, an expanded Secret screens reference list, and a script list with run progress

→ site/public/screenshots/device-manager-sidebar.png

Kopytko Diagnostics (Runtime Telemetry)

A bottom-panel recorder that captures live runtime telemetry from the running channel into replayable per-session NDJSON files, charted live with D3. Every chart and table is individually toggleable — data is only polled while something visible needs it.

  • Memory chart — total/anon/file/shared/swap MB with FG/BG limit lines (chanperf)
  • CPU chart — total/user/sys % (chanperf)
  • SceneGraph Nodes chart — stacked by node type, top 8 + Other (sgnodes counts)
  • Objects chart — BrightScript object counts stacked by type via ECP app-object-counts (hidden by default)
  • Texture memory chart with max reference line (r2d2_bitmaps)
  • Node / Object / Rendezvous / Texture tables — the Objects table splits roSGNode rows per component subtype
  • Rendezvous + framework-beacon markers overlaid on every chart
  • App foreground/background shading + live state badge
  • Record any channel sharing the sideloaded dev key, with past-session replay

Kopytko Diagnostics panel

Bottom panel with live D3 charts: Memory, CPU, stacked SceneGraph Nodes and Objects charts, navigator strip, and node/object/rendezvous tables below

→ site/public/screenshots/kopytko-diagnostics-panel.png

Network Inspector

A Charles-style HTTP inspector for a running channel — an intercepting proxy the device's traffic is redirected through, showing every request and response grouped by origin and path with per-request metrics. The clever part: it sees HTTPS backends decrypted without installing any CA on the Roku. The device stays on plaintext HTTP, the proxy bridges to HTTPS upstream, and response bodies are rewritten https://http:// so the app keeps talking HTTP.

  • Pure-Node proxy — no external tools, no mitmproxy, no certificates
  • One master toggle (off by default): flip on to start the proxy and apply the OS traffic redirect; flip off to fully revert
  • Fully automatic transparent redirect on all three platforms out of the box — a scoped iptables chain (Linux), pf anchor (macOS), or a bundled WinDivert companion (Windows, zero setup) redirecting all of the device's traffic by source IP under one elevated prompt; teardown never touches your other firewall rules and reverts on close/crash, and the Windows companion also self-terminates if VS Code disappears without saying goodbye
  • Live-editable rewrite rules — built-in https→http and wss→ws plus your own find/replace, scoped by host and path, applied without restart
  • Rewrite excludes — opt specific host+path combinations out of ALL rewriting, even the built-ins, for a response that must reach the device byte-for-byte
  • Per-host upstream scheme (https / http / auto); gzip/deflate/br decoded, Set-Cookie Secure stripped, redirects downgraded
  • Requests grouped by origin, detail pane with headers, bodies and original-vs-rewritten view, filter, and Export HAR
  • A detail pane that remembers your place — only Overview opens by default, the sections you expand stay expanded as you step between requests, and the pane scrolls back to the section you were focused on; right-click any key/value row (headers, query params, cookies, JSON-tree nodes) to copy the key, the value, or both — tree nodes copy their whole subtree as JSON
  • Every capture session is saved to a timestamped folder on disk (manifest + flows.ndjson + full body files), so oversized bodies are never shown cut off — a warning links to the complete, formatted body in a new editor tab, and replays of truncated requests send the full on-disk bytes
  • Per-request timing waterfall — blocked / DNS / connect / TLS / send / wait / receive as a stacked bar and table, keep-alive-aware, with the same real phases written to HAR
  • Workflow tools — copy URL / copy as cURL / copy body, one-click replay through the proxy (with confirmation for state-changing methods), pause recording without dropping the redirect, timestamps, and status/method filter chips
  • Map-local, latency-injection, header and block rules (block aborts a matched request so you can test error handling); image response preview + hex; parsed query-param and cookie views; and a search across every captured request that jumps straight to the flow
  • Streaming pass-through — Server-Sent Events and chunked no-length responses forward chunk-by-chunk instead of buffering, so a live stream never hangs the device
  • In-flight rows — a request appears the instant it arrives with a live elapsed-time counter and inspectable request headers, then updates in place when it completes, so long-polls, streams, slow endpoints and breakpoint-paused requests are visible while they run
  • Compare any two captured requests — a line-level diff of summary, headers and bodies to spot exactly what changed between them
  • Breakpoints — pause a matched request or response mid-flight, edit its method/status/headers/body live, then continue or abort (with an auto-continue timeout so nothing hangs)
  • Built to stay fast under load — frame-batched incremental list updates, a dual entry-count + byte-budget memory cap, and pooled upstream connections (no per-request TLS handshake to origins)

The dev machine must be the device's gateway (macOS Internet Sharing, a Linux gateway, or Windows ICS). On 64-bit Windows there's nothing to install — the extension bundles a working WinDivert driver and drives it via an elevated companion process (window hidden, everything logged for auditability). kopytko.network.winDivertDir exists only to override that with a different build, or on architectures the bundled driver doesn't cover — it's machine-scoped, so it can't be pushed onto a team via a shared workspace settings.json.

Network Inspector panel

Editor tab with a capture toggle, a request list grouped by origin with method/status/duration/size columns, a detail pane showing request and response headers and JSON body, and a rewrite-rules editor

→ site/public/screenshots/network-inspector-panel.png

Kopytko Console

An interactive terminal for the Roku debug consoles, in its own bottom-panel tab beside Terminal and Problems. It replaces reaching for an external telnet client — which Windows doesn't ship at all — with a real terminal that knows which commands each port accepts and colours the output by severity, so the crash stands out from the wall of log lines. Works identically on Windows, macOS and Linux.

  • Both interactive ports, connected at once — 8085 (BrightScript runtime: live print output, beacons, and the BrightScript Debugger> prompt when execution stops) and 8080 (SceneGraph debug server: chanperf, sgnodes, sgperf, r2d2_bitmaps, free); the dropdown switches the view, not the connection
  • Follows the device you picked in the Roku Devices sidebar — no second device selector to fall out of sync, just the active device and a dot showing the console connection
  • Completion for every documented command with descriptions, argument hints and subcommands — an empty line lists the whole port catalog, so you never have to guess a first letter, and Tab walks sgnodes all|roots|counts, sgperf start|clear|report|stop and the rest with no round-trip to the device
  • Commands seen only in the device's own help output are labelled undocumented, and destructive ones (genkey, remove_plugin) need an explicit confirmation before they are sent
  • Severity colouring drawn from the theme's own terminal palette — errors, warnings, framework beacons, debugger frames and XML replies each read differently, in light, dark and high-contrast alike
  • Clickable pkg:/components/Foo.brs(40) references that open the file at the line, resolving through Kopytko packages in node_modules too
  • Live filter — plain text or /regex/ — plus severity chips, narrowing what you see without touching what is captured
  • Per-port command history, save-buffer-to-file, and optional append-as-it-arrives logging so a crash still leaves a complete record on disk
  • Device output is sanitised before display, so an escape sequence in a print statement can't repaint your terminal

Only the two ports that carry an interactive command surface on current Roku OS are offered — 8089–8093 were retired in Roku OS 7.5+. Port 8085 accepts a single consumer at a time, so the console tells you when another telnet or debug session is holding it rather than retrying in silence; it also replays the channel's log from launch when you connect, and (verified on firmware 15.2.4) only accepts typed commands once execution has stopped at a debugger prompt.

Kopytko Console panel

Bottom panel tab with a port dropdown, connect button, active-device label with a green status dot, and a filter box above a terminal showing colour-coded Roku log output — red errors, yellow warnings, cyan beacons — with a completion popup listing bt, bsc, bscs and brkd with descriptions

→ site/public/screenshots/kopytko-console-panel.png

Deep Linking

Exercise your channel's deep links without hand-crafting curl commands. An editor-tab panel lists every channel installed on the active device — icons included — and lets you fire a contentId plus any key-value parameters at it via ECP Launch (POST /launch, starts or relaunches the channel) or Input (POST /input, delivered to the running channel as an roInput event — no relaunch).

  • Channel grid with icons from the device (ECP /query/apps + /query/icon)
  • contentId field + free-form key-value parameters, with mediaType value suggestions
  • Launch and Input send modes with clear semantics for each
  • Named parameter sets — save, reuse, edit, and delete; persisted per workspace
  • Custom labels on saved sets, plus Filter (multi-select) and Sort-by-label dropdowns
  • Follows the active device; warns when a preset’s channel is not installed

Deep Linking panel

Editor tab with a channel grid (icons), a contentId + parameters form with Launch and Send Input buttons, and a saved parameter sets list

→ site/public/screenshots/deep-linking-panel.png

SceneGraph Tree

An editor-tab panel that fetches a live SceneGraph node collection from the active Roku device — All (/query/sgnodes/all), Roots (/query/sgnodes/roots), or UI (/query/app-ui, the rendered tree of the foreground app) — and shows it as a formatted, syntax-colored XML document (default) or a D3 icicle chart.

  • Three node collections: every created node, only un-parented roots, or exactly what the screen is rendering
  • XML view: formatted and colorized, with a right-click Copy XML / Copy Selection menu and a Ctrl/Cmd+F find widget
  • Chart view: click a node to focus its subtree, double-click to go back up, hover for an attribute tooltip
  • The chosen view sticks while you switch collections; Refresh re-queries the device without reopening the tab
  • Edit mode (UI + XML): edit the document in place and push field changes to the running app through an injected RALE TrackerTask — validated as you type, applied with Ctrl+Enter, every target verified before writing

SceneGraph Tree

Editor tab showing a formatted XML view of the live SceneGraph node tree, with All/Roots/UI collection buttons and an XML/Chart view toggle in the toolbar

→ site/public/screenshots/scenegraph-tree.png

Kopytko Perfetto (App Tracing)

Live Roku app tracing — right inside VS Code. Click Start and the extension deploys your channel with run_as_process=1, connects to the device's Perfetto WebSocket stream, and feeds the native binary trace into an embedded ui.perfetto.dev viewer. The trace refreshes live every few seconds.

No more record → export → import → guess. See flame charts, counter tracks, heap graphs, and rendezvous spans updating as you navigate your app. Sessions are saved as .perfetto-trace files and can be replayed later.

  • Requires Roku firmware 15.2+
  • Mutual exclusion with the Diagnostics panel — only one panel holds the device at a time
  • Heap snapshot capture with one click
  • Past-session replay from the dropdown

Using it

  1. Click Start to deploy and begin tracing
  2. Watch flame charts, counters, and rendezvous spans stream live in the embedded viewer
  3. Take a heap snapshot at any point with one click
  4. Click Stop to save the session as a .perfetto-trace file
  5. Replay any past session from the dropdown

Roku Pay Web Services

Call Roku Pay's cloud API (apipub.roku.com) from an editor tab — no device needed. Every transaction-service endpoint (validate, cancel, refund, billing cycle, service credit) plus the four subscription-recovery test transitions (in-grace, on-hold, passively cancel, recover), each rendered as a typed form with a live URL preview and a full response viewer.

  • Named credential profiles — the partner API key lives in the OS keychain, never in settings, logs, or the webview
  • Endpoint-driven forms: typed fields (text, number, checkbox, date), required markers, endpoint descriptions and rate-limit warnings
  • Accept header switch — pretty-printed JSON or raw XML responses, with embedded /Date(ms)/ tokens humanized to readable timestamps
  • Full response viewer: status, duration, headers, request and response bodies
  • Persistent request/response history (last 200) with per-entry delete and clear-all — the API key is always masked as ****
  • Subscription-recovery testing per Roku’s guide: walk a test subscription through in-grace → on-hold → cancel → recover

Roku Pay Web Services panel

Editor tab with a credential profile picker, an endpoint dropdown with a generated form and masked URL preview, a response viewer with status and JSON body, and a request history list

→ site/public/screenshots/roku-pay-web-services-panel.png

.kopytkorc configuration

The extension reads .kopytkorc for per-project environment definitions. The JSON schema is validated inline — hover over keys to see descriptions, and you'll get diagnostics for unknown or mistyped fields.

Each environment key maps to a manifest path and optional plugin list. The active environment is selected per device from the sidebar context menu, or set via the env field in launch.json.

.kopytkorc
// .kopytkorc
{
  "baseManifest": "app/manifest",
  "sourceDir": "app",
  "archivePath": "/dist/my_app_${args.env}.zip",

  "environments": {
    "dev": {
      "manifest": "app/manifests/dev.manifest",
      "plugins": ["dev-tools-plugin"]
    },
    "staging": {
      "manifest": "app/manifests/staging.manifest"
    },
    "production": {
      "manifest": "app/manifests/prod.manifest",
      "plugins": ["minify-plugin"]
    }
  }
}

Commands

Command Keybinding Description
Upload to device Ctrl+Shift+F5 Build and upload the channel package to the active Roku
Debug device F5 Deploy with remotedebug=1 and start the debug session
Refresh devices Trigger a new SSDP scan
Select device Set the active Roku from the discovered list
Unset active device Clear the active device selection
Add device Add a device manually by IP address
Set password Store device password in the OS keychain
Clear password Remove the stored password for a device
Copy IP address Copy the device IP address to the clipboard
Copy to clipboard Copy selected text or device info to the clipboard
Set environment Choose a .kopytkorc environment for a device
Open device portal Open the Roku web dashboard in a browser
Read registry View device registry sections in a virtual document
Remove device Remove a manually-added or stale device from the list
Open Console Open the Kopytko Console panel — an interactive terminal for the Roku debug consoles
Connect Console Connect the console to the selected device and port
Disconnect Console Close the console connection for the selected port
Clear Console Empty the console buffer without disconnecting
Save Console Output Write the console buffer to a .log file in the workspace
Select Console Port Switch between port 8085 (BrightScript runtime) and 8080 (SceneGraph debug server)
Show Console Commands Browse every documented command for the selected port as a searchable list
Open SceneGraph Tree Fetch a node collection (sgnodes all/roots or app-ui) and show it as formatted XML or an icicle chart; Edit mode pushes field changes to the running app via RALE TrackerTask
Open Deep Linking Launch channels with contentId / roInput deep-link parameters
Open Device Manager Reveal the Remote Control view (remote, device actions, saved text)
Open Roku Pay Web Services Call Roku Pay cloud endpoints with saved credential profiles and a request history
Toggle Remote Control Keyboard Mode Ctrl+K (exit) Drive the Roku with the keyboard — arrows, Enter, Escape, media keys
New Device Script Open the RASP automation-script editor tab
Add / Remove favorite Persist a device across restarts
Start / Stop Diagnostics Session Start or stop a runtime telemetry recording session
Open Kopytko Perfetto Open the Perfetto app-tracing tab
Start / Stop Perfetto Tracing Session Deploy and begin, or end, a live Perfetto trace
Capture Heap Snapshot (Perfetto) Trigger a heap snapshot during an active Perfetto session
Open Network Inspector Open the HTTP capture tab — requests grouped by origin with rewrite rules
Toggle Network Capture Start/stop the capture proxy and the OS traffic redirect
Clear Network Capture Empty the captured request list

Settings reference

Setting Type Default Description
kopytko.languageServer.enabled boolean true Enable the Kopytko language server.
kopytko.languageServer.trace enum "off" Trace LSP communication for debugging.
kopytko.debug.trace enum "off" Trace the Roku debug protocol (port 8081) to the Kopytko output channel. Use when a debug session disconnects or the channel freezes on resume.
kopytko.imports.resolveModules boolean true Resolve @import annotations from installed Kopytko NPM modules.
kopytko.imports.sourceDir string "app" Root source directory for resolving internal @import paths (matches .kopytkorc sourceDir).
kopytko.imports.generatedPaths array [] Glob patterns for `@import` paths that are generated during the build process and do not exist as source files on disk (e.g. by a Kopytko plugin or code-generation tool). Unresolved imports matching these patterns are shown as informational hints instead of warnings, so the developer is aware of the situation without it being flagged as an error. **Supported wildcards:** `*` matches any characters except `/`; `**` matches any characters including `/`. **Examples:** - `/components/generated/**` - `**/auto-generated/*.brs`
kopytko.imports.generatedModules array [] Declarations for `@import` paths that are generated during the build process and whose function names should be known to the language server. Each entry has a `path` glob pattern and a `functions` list. When a file imports a path matching `path`, the listed functions are added to the known function scope — so they are not flagged as undefined — and the import itself is shown as an informational hint rather than an unresolved warning. Use this when a plugin or code-generation tool creates `.brs` files that are not present as source files on disk but will exist at build time. **Example:** ```json [ { "path": "/components/generated/PluginApi.brs", "functions": ["PluginInit", "PluginGetData"] } ] ```
kopytko.imports.siblingPatterns array [] Groups of file name patterns whose `.brs` files share import scope for the `import/unused` diagnostic check. Files in the same group are always loaded together by the same XML component, so an `@import` in one file is considered used if any file in the group references one of its exported functions. **Pattern syntax:** each pattern may contain a single `*` wildcard; files with the same wildcard value in the same directory are considered siblings. **Example** — Kopytko component/template pairs: ```json [ ["*.component.brs", "*.template.brs"], ["*.view.brs", "*.template.brs"] ] ``` With this config, if `Foo.component.brs` imports `helperFn` and only `Foo.template.brs` calls it, the import is not flagged as unused.
kopytko.readOnlyPaths array [] Glob patterns for files that the extension should treat as read-only. Acts as a shared fallback — applies to both formatting and linting unless overridden by `kopytko.format.readOnlyPaths` or `kopytko.lint.readOnlyPaths`. **Supported wildcards:** `*` matches any characters except `/`; `**` matches any characters including `/`. **Examples:** ```json [ "**/node_modules/**", "**/generated/**", "**/vendor/*.brs" ] ```
kopytko.format.readOnlyPaths array [] Glob patterns for files that the formatter should skip. When set, overrides `kopytko.readOnlyPaths` for formatting. When empty, falls back to `kopytko.readOnlyPaths`.
kopytko.lint.readOnlyPaths array [] Glob patterns for files that the linter should skip. When set, overrides `kopytko.readOnlyPaths` for linting. When empty, falls back to `kopytko.readOnlyPaths`.
kopytko.lint.rules.type/missing-return-type enum "warning" Warn when a function is missing an 'as Type' return type annotation.
kopytko.lint.rules.type/missing-param-type enum "warning" Warn when a function parameter is missing an 'as Type' annotation.
kopytko.lint.rules.component/duplicate-name enum "warning" Warn when two XML files declare the same SceneGraph component name. Component names are global to the channel, so the declaration that loads last silently wins. Build pipelines that copy the source tree into an output directory will report every component as a duplicate — exclude the copy with `kopytko.lint.readOnlyPaths` (e.g. `**/out/**`).
kopytko.casing.builtin enum "preserve" Casing applied to BrightScript built-in function names when a completion is inserted.
kopytko.casing.keyword enum "preserve" Casing applied to BrightScript keywords when a completion is inserted. Acts as fallback for type, literal, and operator casing when those are not set.
kopytko.casing.type enum "preserve" Casing for BrightScript type names (`boolean`, `integer`, `string`, `void`, …). Falls back to `kopytko.casing.keyword` when not set.
kopytko.casing.literal enum "preserve" Casing for literal values (`true`, `false`, `invalid`). Falls back to `kopytko.casing.keyword` when not set.
kopytko.casing.logicOperator enum "preserve" Casing for logic operators (`and`, `or`, `not`). Falls back to `kopytko.casing.keyword` when not set.
kopytko.casing.mathOperator enum "preserve" Casing for math operators (`mod`). Falls back to `kopytko.casing.keyword` when not set.
kopytko.casing.method enum "preserve" Casing applied to component method names when a completion is inserted.
kopytko.casing.userFunction enum "preserve" Casing applied to user-defined function/sub names in completions and formatting.
kopytko.casing.userMethod enum "preserve" Casing applied to user-defined associative array method names in completions.
kopytko.casing.exact object {} Per-identifier casing overrides applied after all other casing rules. Keys are identifier names (case-insensitive), values are the exact output string. **Example:** ```json { "invalid": "Invalid", "getglobalaa": "GetGlobalAA" } ```
kopytko.format.indentSize integer 4 Number of spaces per indentation level used by the BrightScript formatter.
kopytko.format.useTabs boolean false Use tabs instead of spaces for indentation.
kopytko.format.lineEnding enum "auto" Line ending style. 'auto' preserves the document's existing endings.
kopytko.format.trimTrailingWhitespace boolean true Remove trailing whitespace from lines.
kopytko.format.insertFinalNewline boolean true Ensure the file ends with a newline.
kopytko.format.maxEmptyLines integer 2 Maximum consecutive blank lines allowed. 0 = no limit.
kopytko.format.emptyLinesBetweenFunctions integer 1 Number of blank lines to enforce between top-level function/sub declarations.
kopytko.format.emptyLinesBetweenMethods integer 1 Number of blank lines between AA method definitions inside a builder function.
kopytko.format.emptyLinesAtBlockBoundaries enum "preserve" Blank lines at the start/end of blocks: 'strip' removes them, 'enforce' adds one.
kopytko.format.endKeywordStyle enum "preserve" Compound end-keyword style: `spaced` = `end if`, `compact` = `endif`. Applies to endif, endfunction, endsub, endwhile, endfor, endtry.
kopytko.format.thenStyle enum "preserve" Controls 'then' on if-lines.
kopytko.format.functionVsSubForVoid enum "preserve" Controls function vs sub for void procedures. ```brightscript ' "sub": converts function foo() as Void → sub foo() ' "function": converts sub foo() → function foo() as Void ' "allow-void": preserves both sub foo() and function foo() as Void ```
kopytko.format.spaceBeforeNamedFunctionParens boolean false Space before `(` in named function/sub definitions. ```brightscript ' true: function doWork () ' false: function doWork() ```
kopytko.format.spaceBeforeAnonymousFunctionParens boolean false Space before `(` in anonymous function expressions. ```brightscript ' true: m.handler = function () ' false: m.handler = function() ```
kopytko.format.spaceBeforeCallParens boolean false Space before `(` in function calls. ```brightscript ' true: doWork () ' false: doWork() ```
kopytko.format.spaceInsideParens enum "never" Spaces inside '()' in calls and definitions.
kopytko.format.paramAlignmentStyle enum "preserve" Multi-line parameter alignment style.
kopytko.format.maxLineLength integer 120 Max line length before the formatter wraps long strings. `0` = no limit.
kopytko.format.wrapLongStrings enum "preserve" How to break long string literals. - `plus`: break with `+` concatenation - `array-join`: break with `[..., ...].join("")`
kopytko.format.associativeArrayBracketSpacing boolean true Spaces inside `{}`: `{ key: value }` (true) vs `{key: value}` (false).
kopytko.format.associativeArrayCommaSpacing enum "preserve" Spaces around commas separating key-value pairs in inline associative arrays `{}`. Only applies to commas on the same line as `{` and `}` — multi-line AAs are not affected.
kopytko.format.trailingComma enum "never" Trailing comma after the last item in multi-line arrays and associative arrays.
kopytko.format.arrayCommaStyle enum "preserve" Comma separators in multi-line arrays. BrightScript allows omitting commas when items are on separate lines. ```brightscript ' "always": arr = [ 1, 2, 3, ] ' "never": arr = [ 1 2 3 ] ```
kopytko.format.associativeArrayCommaStyle enum "preserve" Comma separators in multi-line associative arrays. BrightScript allows omitting commas when entries are on separate lines. ```brightscript ' "always": obj = { name: "foo", value: 42, } ' "never": obj = { name: "foo" value: 42 } ```
kopytko.format.associativeArraySingleLineThreshold integer 0 Max number of keys before forcing an AA to multi-line. 0 = no limit.
kopytko.format.arraySplitOpenBracket boolean false When `true`, splits `[{` onto separate lines in multi-item arrays for better readability. ```brightscript ' true: return [ { name: "Component", }, otherItem() ] ' false: return [{ name: "Component", }, otherItem() ] ```
kopytko.format.spaceAroundOperators boolean true Spaces around binary operators (+, -, *, /, <>, and, or, mod).
kopytko.format.spaceAroundAssignment boolean true Spaces around = in assignments.
kopytko.format.unarySpacing boolean true Space after unary 'not'.
kopytko.format.commentStyle enum "preserve" Normalize comment markers: `'` or `rem`, or preserve existing.
kopytko.format.spaceAfterCommentMarker boolean true Enforce space after `'` or `rem`: `' comment` vs `'comment`.
kopytko.format.commentWidth integer 0 Max comment line length. 0 = no limit.
kopytko.format.sortImports boolean false Sort @import statements alphabetically (module name first, then path).
kopytko.format.emptyLineAfterImports boolean false Insert blank line after the last @import line, before code starts.
kopytko.format.emptyLineAfterFunctionOpen boolean false Insert empty line after function/sub opening line.
kopytko.format.emptyLineBeforeFunctionClose boolean false Insert empty line before end function/sub.
kopytko.format.emptyLineBeforeReturn string | boolean false Empty line before `return` statements. `not-alone` skips the empty line when `return` is the only statement in its block (e.g. a guard clause like `if x then return`).
kopytko.format.emptyLineBeforeComment boolean false Enforce empty line before stand-alone comment blocks.
kopytko.format.parenthesisIfCase enum "preserve" Wrap if-condition in parentheses: 'always' adds them, 'never' removes them.
kopytko.format.elseOnNewLine boolean true Place 'else' on its own line.
kopytko.format.forLoopSpacing boolean true Enforce spaces around 'to' and 'step' in for loops.
kopytko.format.printStatement enum "preserve" Flag or remove print debug statements.
kopytko.format.lineCommentPosition enum "preserve" Move trailing comments: 'above' puts them on the line above.
kopytko.format.stringConcatStyle enum "preserve" Normalize string concatenation style. ```brightscript ' "plus": result = "hello" + " " + "world" ' "array-join": result = ["hello", " ", "world"].join("") ```
kopytko.format.observeFieldStyle enum "preserve" Enforce `observeFieldScoped` over `observeField`. Using non-scoped `observeField` can cause memory leaks. ```brightscript ' "always-scoped": converts observeField → observeFieldScoped ```
kopytko.format.mPrefixStyle enum "preserve" Normalize `m`-prefix field access style. ```brightscript ' "dot": m.fieldName m.top.visible ' "bracket": m["fieldName"] m.top["visible"] ```
kopytko.format.alignAssignments boolean false Align `=` signs in consecutive assignment lines. ```brightscript ' true: name = "app" version = "1.0" count = 42 ' false: name = "app" version = "1.0" count = 42 ```
kopytko.format.fieldAccessConsistency enum "preserve" Field access consistency on nodes. ```brightscript ' "dot": prefers dot notation m.top.visible = true value = m.top.id ' "method": prefers getField/setField m.top.setField("visible", true) value = m.top.getField("id") ```
kopytko.format.verifySyntax boolean true Verify that formatted output re-parses to an equivalent AST before applying it, catching formatter bugs. Disable only to debug or skip that safety check.
kopytko.deviceDiscovery.enabled boolean true Enable automatic Roku device discovery via SSDP.
kopytko.deviceDiscovery.scanTimeout number 5000 Timeout in milliseconds for active SSDP device scans.
kopytko.deviceDiscovery.showNotifications boolean true Show notification messages when devices come online or go offline.
kopytko.console.defaultPort enum 8085 Debug console port the Kopytko Console selects when it opens.
kopytko.console.autoConnect boolean false Connect to the active device automatically when the Kopytko Console panel opens.
kopytko.console.maxLines number 20000 Maximum number of output lines kept per console port. Older lines are dropped from the buffer.
kopytko.console.reconnect boolean true Reconnect automatically (with backoff) when the console connection drops.
kopytko.console.colorize boolean true Colour console output by severity — errors, warnings, beacons, rendezvous logs, and debugger frames.
kopytko.console.logToFile boolean false Append every console line to a log file as it arrives, in addition to the in-memory buffer.
kopytko.console.outputDir string "debug" Folder (relative to the workspace root, or absolute) where console logs and saved output are written.
kopytko.console.historySize number 200 Number of submitted commands remembered per console port for history recall.
kopytko.diagnostics.outputDir string "debug" Folder (relative to the workspace root, or absolute) where diagnostics sessions are saved. Each session gets its own timestamped subfolder.
kopytko.diagnostics.maxLivePoints number 3600 Maximum number of samples kept in memory per stream for the live view. Older points are dropped from the live charts but remain on disk.
kopytko.diagnostics.debugConsolePort number 8080 TCP port of the Roku SceneGraph debug server used for chanperf / sgnodes / texture metrics.
kopytko.diagnostics.collectors.memCpu.enabled boolean true Collect per-channel CPU and memory usage (chanperf).
kopytko.diagnostics.collectors.memCpu.intervalMs number 1000 Polling interval in milliseconds for per-channel CPU/memory.
kopytko.diagnostics.collectors.nodeCounts.enabled boolean true Collect SceneGraph node counts by type (sgnodes counts).
kopytko.diagnostics.collectors.nodeCounts.intervalMs number 2000 Polling interval in milliseconds for node counts.
kopytko.diagnostics.collectors.objectCounts.enabled boolean true Collect BrightScript object counts by type via ECP /query/app-object-counts. Only polled while the Objects chart or table is visible in the panel (both hidden by default).
kopytko.diagnostics.collectors.objectCounts.intervalMs number 2000 Polling interval in milliseconds for object counts.
kopytko.diagnostics.collectors.rendezvous.enabled boolean true Collect render-thread rendezvous via ECP.
kopytko.diagnostics.collectors.rendezvous.intervalMs number 1000 Polling interval in milliseconds for rendezvous events.
kopytko.diagnostics.collectors.systemMem.enabled boolean false Collect device-wide memory (free). Off by default; per-channel memory is usually more useful.
kopytko.diagnostics.collectors.systemMem.intervalMs number 5000 Polling interval in milliseconds for device-wide memory.
kopytko.diagnostics.collectors.textures.enabled boolean true Collect GPU texture/bitmap memory (r2d2_bitmaps). Enabled by default; the Textures chart/table only shows when selected in the Charts/Tables dropdowns.
kopytko.diagnostics.collectors.textures.intervalMs number 5000 Polling interval in milliseconds for texture memory.
kopytko.diagnostics.collectors.appState.enabled boolean true Track app foreground/background state via ECP /query/app-state, shown as background shading on the charts. Requires "Control by mobile apps" enabled on the device — degrades to no shading (not an error) when unavailable.
kopytko.diagnostics.collectors.appState.intervalMs number 2000 Polling interval in milliseconds for app state.
kopytko.diagnostics.collectors.fwBeacon.enabled boolean true Track framework beacon markers (AppLaunch/AppResume/VODStart Initiate/Complete) via ECP /fwbeacons. Enabled by default, including the Beacons checkbox.
kopytko.diagnostics.collectors.fwBeacon.intervalMs number 1000 Polling interval in milliseconds for framework beacon events.
kopytko.diagnostics.defaultVisibleCharts array ["memory","cpu","nodes"] Charts shown by default when the diagnostics panel opens. The corresponding data is only collected while at least one visible chart or table needs it.
kopytko.diagnostics.defaultVisibleTables array ["nodes","rendezvous"] Tables shown by default when the diagnostics panel opens.
kopytko.diagnostics.memoryLimits.backgroundMB number 100 Reference line on the Memory chart for Roku's published background-app DRAM guidance. Not device-reported (unlike the foreground limit, which comes from chanperf) — Roku publishes this as a fixed recommendation that may change between OS versions, hence configurable here.
kopytko.deviceManager.holdThresholdMs number 1000 Remote Control: how long (ms) a button must be held before a press becomes a keydown/keyup hold instead of a single keypress.
kopytko.deviceManager.runner.pollIntervalMs number 500 Script runner: how often (ms) to poll the device for wait_for_player_state / validate_streaming / launch completion.
kopytko.deviceManager.runner.waitTimeoutSec number 30 Script runner: how long (seconds) wait_for_player_state and validate_streaming wait for the expected player state before failing the step.
kopytko.perfetto.ecpPort number 8060 ECP port used for Perfetto tracing control and the WebSocket connection.
kopytko.perfetto.refreshIntervalMs number 3000 How often (in milliseconds) the live buffer is pushed to the Perfetto UI iframe.
kopytko.perfetto.startCommand string "" Build and deploy command for Perfetto sessions. Defaults to `npx kopytko start` when empty.
kopytko.network.proxyPort number 8888 Local port the Network Inspector capture proxy listens on. Device traffic is redirected here.
kopytko.network.redirectPorts array [80] Device-side ports whose traffic is transparently redirected into the capture proxy (HTTP only).
kopytko.network.maxEntries number 5000 Maximum number of captured requests kept in memory before the oldest are dropped.
kopytko.network.maxBufferBytes number 52428800 Approximate memory budget in bytes for the captured-flow buffer (retained bodies + header overhead). Oldest requests are evicted when exceeded. 0 disables the byte cap; kopytko.network.maxEntries still applies.
kopytko.network.upstreamKeepAlive boolean true Reuse upstream connections (HTTP keep-alive) between the capture proxy and origin servers, avoiding a fresh TCP/TLS handshake per request. The device-side connection is always closed per request. Disable if an origin misbehaves with connection reuse.
kopytko.network.filterToActiveDevice boolean true Only show traffic originating from the active Roku device's IP (hides the dev machine's own traffic).
kopytko.network.maxBodyBytes number 262144 Maximum bytes of each request/response body retained in memory for inline display and HAR export. The full body is always forwarded to the device, and is persisted uncapped to the capture session folder (see kopytko.network.outputDir) for the “Open full body in editor” action.
kopytko.network.outputDir string "debug" Folder (relative to the workspace root, or absolute) where Network Inspector capture sessions are saved — flow metadata plus full request/response bodies. Each capture session gets its own timestamped subfolder.
kopytko.network.defaultUpstreamScheme enum "https" Scheme the proxy uses to reach an origin when the device called it over HTTP. `https` bridges the plaintext device call to a secure upstream connection.
kopytko.network.winDivertDir string "" Windows only, and usually unnecessary — this extension bundles a working WinDivert driver for 64-bit Windows. Only set this to override it with a different WinDivert build/version, or on a non-x64 architecture the bundled driver doesn't cover. A local driver path is inherently per-machine, so this can only be set in User Settings, never in a workspace/team settings.json.
kopytko.network.rewriteRules array [] Body rewrite rules applied to text request/response bodies. Each item: { enabled, direction: 'response'|'request', hostPattern?, pathPattern?, contentTypePattern?, find, replace, isRegex? }. When empty, the built-in `https://` → `http://` and `wss://` → `ws://` response rules are used.
kopytko.network.rewriteExcludeRules array [] Opt specific host+path combinations out of ALL body rewriting (every enabled rewrite rule, both directions) — for a response that must reach the device byte-for-byte even though a broad rule like the built-in https→http one would otherwise match it. Each item: { enabled?, hostPattern?, pathPattern? }.
kopytko.network.upstreamSchemes array [] Per-host upstream scheme overrides. Each item: { hostPattern, scheme: 'https'|'http'|'auto' }.
kopytko.network.mapLocalRules array [] Serve a local file or inline body instead of contacting the upstream when host/path match. Each item: { enabled?, hostPattern, pathPattern?, filePath?, body?, contentType?, status? }. filePath wins over body; a rule with neither is ignored.
kopytko.network.latencyRules array [] Delay matched responses by delayMs before sending them to the device — simulate slow backends. Each item: { enabled?, hostPattern, pathPattern?, delayMs }.
kopytko.network.headerRules array [] Add/set/remove request or response headers for matched hosts. Each item: { enabled?, direction: 'request'|'response', hostPattern?, op: 'set'|'add'|'remove', name, value? }. Proxy-managed headers (content-length, transfer-encoding, connection, host) cannot be changed.
kopytko.network.blockRules array [] Abort matched requests before they reach the upstream — the device sees a connection reset, for testing the channel's network-error handling. Each item: { enabled?, hostPattern, pathPattern? }.
kopytko.network.breakpointRules array [] Pause matched requests and/or responses so you can edit them live before continuing. Each item: { enabled?, hostPattern, pathPattern?, onRequest?, onResponse? }.
kopytko.network.breakpointTimeoutMs number 30000 How long a breakpoint pause waits for you to act before auto-continuing the request/response unmodified, so a forgotten breakpoint can't hang the device.