IDE extensionIDE extensiontypeInstalls into a development environment (VS Code, Eclipse with ABAP Development Tools, SAP Business Application Studio) and works inside it, rather than as a library you call or a command you run.See every one →What this type is →by a community orgby a community orgoriginPublished by a community organisation, so it outlives any one maintainer.See every one →

abap2UI5 for VS Code

A VS Code extension for abap2UI5 apps: F9 starts the app class in a preview beside the source, Ctrl+F3 activates the class and reloads it, and the abap2UI5 linter runs in the editor while you type.

Developing an abap2UI5 app the plain way means three windows: the editor with the class, a browser with the app, and the activation step between them. This extension puts the app in an editor tab beside the source — F9 launches the class through a local auth proxy that attaches the stored SAP credentials to every request, Ctrl+F3 activates and reloads, and an activation done elsewhere is noticed through the class's ADT metadata on the server. The abap2UI5 linter's property gate runs in process while you type, so a control the targeted UI5 release does not have is a squiggle rather than a blank screen, with quick fixes, waivers the project's CI run honours and a findings view grouped by rule; completion and hover answer for the UI5 API inside the builder chain and for the binding paths the class's own model has. *Preview View (No System)* and *Run Unit Tests (No System)* work with no system at all, and the language half runs in vscode.dev, github.dev and browser-based SAP Business Application Studio. Beside the editor features it registers the project's MCP server for every MCP client in the window and hosts a second server of its own for the configured systems, the credentials and the proxy.

Facts

Last pushLicenceMIT

Where it sits

Lives in
Provides
Editor supportABAPEditor supportcapabilityWorking in source code with the editor helping rather than treating it as text — completion, go-to-definition, inline errors, refactoring and preview.Agent access to your systemsABAPAgent access to your systemscapabilityGiving an AI agent access to the business data, configuration or operations of systems you run through an MCP server. [Serving your application over MCP](capability:mcp-servers) exposes your own service contract; system access reaches the systems behind it, and one implementation may do both. Development assistance belongs to [agent access to your code](capability:agent-code-access).Agent guidanceABAPAgent guidancecapabilityPackaged knowledge you hand a coding agent so it gets a framework right unprompted — skills, rule files, instruction packs. Distinct from agent tooling, which is about building agentic features into your application, and from [agent access to your code](capability:agent-code-access), where the agent reads the real project instead of being handed a file about it.
Part of
abap2UI5abap2UI5artifactOne ABAP class implementing z2ui5_if_app is the whole app: the browser loads a generic UI5 shell once, and every interaction after that is an HTTP roundtrip back into ABAP.
Requires
abap2UI5abap2UI5artifactthe apps it develops: F9 launches an app class against a system running abap2UI5, and the view checks and the systemless preview work on the view that class's builder chain produces
Optional
ABAP remote filesystemABAP remote filesystemartifactthe connection to the system: it opens the ABAP objects and is what the activation step hands over toabap connection

Who is behind it

abap2UI5abap2UI5OrganisationMaintains this
In the atlas: maintains 18
@abap2UI5
oblomov-devoblomov-devPersonMaintains this
In the atlas: maintains 4, contributes to 44
@oblomov-dev
maintainers

Before choosing this

Conditions

PracticalFunctional boundary

The embedded preview needs a system that accepts basic auth: the documentation states that pure SSO or SAML without a basic-auth fallback is not supported, and points at external mode, which opens the app in the normal browser with the existing SAP session. On the web only the language half runs; the preview with its proxy, traffic log and screenshot, Ctrl+F3 activation, the render gate, the workspace-wide check and the MCP servers are desktop-only. The agent app tools send nothing until abap2ui5.agent.enableAppTools is switched on in User settings, because an event they fire runs as the configured user and changes data on the system for real.

PolicySAP API Policy 4.2026a§ 1.1, 1.2, 2.2.2from Agent access to your systemsAn MCP server uses SAP APIs to supply tools, resources or data to an agent.
  • § 1.1 Published APIs. Published APIs are made available for the documented purposes identified by SAP, including integration, extensions and data exchange.
  • § 1.2 Non-Published APIs. Customer and third-party applications must not access non-published APIs except where documentation permits it or SAP otherwise authorizes it.
  • § 2.2.2 AI call sequences and data extraction. Outside SAP-endorsed architectures, data services or expressly identified pathways, the policy prohibits specified agentic API use and systematic or large-scale extraction.

MCP does not replace the API's documented-use boundary. Check that every endpoint is published for the intended use and whether the policy's AI-call or extraction provisions apply to the design.

SAP API Policy 4.2026a →

What it declares

Every artifact

Type
IDE extension
Origin
By a community org
Runtime
Node.js

As an IDE extension

Installs into
VS Code
Distributed through
Visual Studio Marketplace

For agent guidance

Installs into
Claude Code

Connections9

abap2UI5 for VS Code connectionsabap2UI5 for VS CodePROVIDES→ provides3provides stated Hosts an MCP server of its own, beside the project's systemless one, whose tools reach the SAP systems configured in the editor: `list_systems`, `search_apps` for class names from the ADT quick search, `run_app_on_system` for a headless screenshot of the app on the real system, and four app tools that fill fields and fire events over the abap2UI5 JSON protocol, each answer a snapshot of the screen. The app tools run as the configured user and stay off until they are allowed in User settings. abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extension abap2UI5/vscode-extension — README, Agent app tools on the system: https://github.com/abap2ui5/vscode-extension abap2UI5/vscode-extension — README, Agent app tools on the system: https://github.com/abap2ui5/vscode-extensionAgent access to your systemsprovides stated *Add Agent Setup to Workspace* writes the agent-ready files of the project's app-template into an existing project from a copy bundled with the extension: `AGENTS.md` and `CLAUDE.md`, `.claude/settings.json` with four skills, `.mcp.json`, the two linter configurations and a check workflow. A file that is already there is left alone, and `package.json` and `.gitignore` are merged. abap2UI5/vscode-extension — Make your repository agent-ready: https://raw.githubusercontent.com/abap2UI5/vscode-extension/main/media/walkthrough/agentsetup.md abap2UI5/vscode-extension — Make your repository agent-ready: https://raw.githubusercontent.com/abap2UI5/vscode-extension/main/media/walkthrough/agentsetup.mdAgent guidanceprovides stated Brings the abap2UI5 loop into the editor: F9 runs the app class in a preview beside the source, the static view check puts findings in the Problems panel while you type, completion and hover cover the UI5 API and the class's binding paths, and Format Document, Emmet-style abbreviations, Extract to View Method and Convert XML View to Builder Chain work on the builder chain. *Preview View (No System)* renders the view without a system or an activation. abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extension abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extension abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extension abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extension abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extensionEditor supportUSED BY← connected from1connected from derived handing the generated class over: *Open in VS Code* calls `vscode://abap2ui5.abap2ui5/open`, and the extension opens the class as an unsaved `.clas.abap` Through: inverted from its connects edge abap2UI5/layout-editor — README, Also in the editor: https://github.com/abap2ui5/layout-editorabap2UI5 Layout EditorNEEDS→ connects to2connects to stated launching the app and every event roundtrip: the preview's local auth proxy and the agent app tools post to the abap2UI5 endpoint the launch URL names, with the stored SAP credentials attached abap2UI5/vscode-extension — README, Agent app tools on the system: https://github.com/abap2ui5/vscode-extension abap2UI5 — VS Code Extension, Why there is a local proxy: https://abap2ui5.github.io/docs/advanced/vscode.htmlabap2UI5connects to stated noticing an activation and finding apps: it watches the class's ADT metadata on the server, and `search_apps` reads class names from the ADT quick search abap2UI5 — VS Code Extension, Reload on activation: https://abap2ui5.github.io/docs/advanced/vscode.html abap2UI5/vscode-extension — README, Agent app tools on the system: https://github.com/abap2ui5/vscode-extensionADT resources→ needs1needs stated the apps it develops: F9 launches an app class against a system running abap2UI5, and the view checks and the systemless preview work on the view that class's builder chain produces abap2UI5/vscode-extension — README: https://github.com/abap2ui5/vscode-extensionabap2UI5→ optionally needs1optionally needs stated If: the parts that talk to a system are used the connection to the system: it opens the ABAP objects and is what the activation step hands over to abap2UI5 — Tooling: https://abap2ui5.github.io/docs/advanced/tooling.html abap2UI5 — VS Code Extension: https://abap2ui5.github.io/docs/advanced/vscode.htmlABAP remote filesystemifLINEAGE→ part of1part of stated abap2UI5 — Tooling: https://abap2ui5.github.io/docs/advanced/tooling.htmlabap2UI5

README

quoted from abap2UI5/vscode-extension under MIT, read
abap2UI5/vscode-extension/README.mdOn GitHub

abap2UI5 for VS Code

VS Code extension for developing abap2UI5 apps: launch an app with F9, see it right next to the source, and have it reload automatically when you activate the class — without the context switch to the browser. The whole abap2UI5-linter runs in the editor while you type, so a broken view is a squiggle rather than a blank screen.

Works with any system running abap2UI5 (on-premise or cloud). The only thing tying the extension to a system is the launch URL you configure once.

Documentation

→ The extension, in full — F9 and the embedded preview, the auth proxy and why it exists, reload on activation, the view checks and quick fixes, completion and hover for the whole UI5 API, the systemless view preview, the refactorings, the MCP servers, what works in the browser, and every setting.

Installing

Install abap2UI5 from the VS Code Marketplace: Extensions panel (Ctrl/Cmd + Shift + X) → search for abap2UI5 → Install. Through the terminal:

code --install-extension abap2ui5.abap2ui5

On Open VSX for VSCodium, Eclipse Theia, SAP Business Application Studio and friends. Without Marketplace access, every release carries the .vsix — Extensions panel → … menu → Install from VSIX… — or build it yourself, see Packaging below.

Coming from a pre-Marketplace .vsix install? Those builds used the placeholder publisher abap2ui5-local, which makes them a different extension to VS Code — they keep working but never update. Uninstall once (code --uninstall-extension abap2ui5-local.abap2ui5), then install from the Marketplace. Settings are kept; the stored SAP credentials are asked for once again.

On the first F9 the extension asks for the launch URL, with {class} as the placeholder:

https://host:44300/sap/bc/z2ui5?app_start={class}&sap-client=100

What you get

  • F9 runs the app next to the source, and the cursor stays where it was. Ctrl+F3 activates the class through your ABAP tooling and reloads the preview — activations done any other way are noticed on the server too.
  • The preview is more than a browser tab: device widths, themes and languages; runtime errors forwarded into the editor; a click-the-control → jump-to-the-builder-call inspector; the live JSON model; a traffic log with roundtrip timings; headless screenshots; and a pin that carries the model across a reload.
  • Static view checks while you type — the linter's property gate in process, the abap2UI5 rules with it, the render gate on demand. Quick fixes, waivers that CI honours, and a findings view grouping the repository's findings by rule. An open abaplint.jsonc whose abap2UI5 pin is below the release the bundled linter assumes gets a warning on its branch line.
  • The whole UI5 API in completion and hover, plus the binding paths your class's model actually has, and the client-> API with its ABAP signature.
  • Write the view faster: Format Document repairs a chain's indentation, Emmet-style abbreviations expand into one, Extract to View Method splits a long one, and Convert XML View to Builder Chain turns a demo kit sample into ABAP.
  • See the view without a system — Preview View (No System) renders what the class builds, with a device matrix and a compare-with-HEAD mode.
  • Test without a system — Run Unit Tests (No System) runs the app's ABAP Unit tests in the transpiled abap2UI5 backend through mcp-server's abap2ui5-unit, in a terminal, for one class or the whole src/: the editor's counterpart of npm run test:unit in a project from app-template.
  • Migrate a classic report — Migrate Classic Report to abap2UI5 turns a *.prog.abap into an abap-cloud-gui report class with its converter report2cloud, opens the class beside its migration report and puts every statement it refuses into Problems (details).
  • Navigate an app: the view hierarchy in the Outline pane, Go to Definition between an event and its WHEN, F2 renaming every literal an app is wired together with, and a navigation map of the workspace's apps.
  • Open a class from a link: vscode://abap2ui5.abap2ui5/open?code=… or ?src=<raw GitHub URL> opens the class unsaved, ready for F9.
  • Templates: New App from Template is a gallery of linter-clean skeletons; New Project from Template writes a whole app-template project.
  • For AI agents: the abap2UI5 MCP server registered for every MCP client in the window, plus a second, in-extension server holding what only the extension has — the configured systems, the credentials and the proxy (list_systems, search_apps, run_app_on_system), and, once you allow it, the app tools that let an agent operate an app on the system through its JSON protocol. Add Agent Setup to Workspace makes an existing project agent-ready: app-template's AGENTS.md, CLAUDE.md, the four skills, .mcp.json, the two gates and check.yml, from the bundled snapshot - nothing overwritten, package.json and .gitignore merged, the gates pointed at your STARTING_FOLDER, the same files as npm create abap2ui5-app@latest -- --agent-setup. The setup for every agent, the Claude Code plugin among them, is on the AI page of the documentation.
  • Works in the browser — vscode.dev, github.dev and browser-based SAP Business Application Studio get the language half.

Agent app tools on the system

The abap2UI5 System MCP server offers four tools that operate an abap2UI5 app semantically on the active SAP system: an agent fills fields by model path or label and fires events by name, over the same JSON protocol the browser frontend speaks - no browser, no CSS selector, no screenshot. Every answer is an agent snapshot v1: the fields with their values and whether they are editable, the actions with their arguments, the tables, the messages, some static text.

ToolWhat it does
app_listClass names on the system, from the ADT quick search (filter: the start of the name, * as wildcard, default Z; at most 50). A name search: whether a class implements z2ui5_if_app is not checked.
app_startStarts app and answers with its snapshot; optional values become pending edits, max_rows sizes the tables (default 20, max 200).
app_describeThe current snapshot of a session, from memory - nothing is sent.
app_actFills values and fires event (a name or an action id) with args/row, then answers with the new snapshot. Without event the values stay pending, as typing does in the browser.

They are the same tools, with the same input, snapshot and refusals, as the sandbox tools of the abap2UI5 MCP server (see its docs/agent-snapshot.md, at the vendored commit): an event that is not on the screen, a field that is not editable, a choice outside its values is refused with what is allowed, and nothing is sent. The code behind the snapshot is that server's own, vendored into src/vendor/agent/ (see Development). What differs on a real system:

  • They act for real, as the configured user. An event may save, post or delete data. So the tools answer only while abap2ui5.agent.enableAppTools is on - off by default, and settable in your User settings only, never by a workspace. While it is off they stay listed and answer with how to switch them on, without contacting the system.
  • The active system. Like run_app_on_system they work on the system Select System made active, through the auth proxy (the credentials stay there; the requests show in the traffic log). The optional system argument of app_list/app_start must name that system - the tools never switch. A session remembers its system, and app_act refuses it while another system is active.
  • The launch URL must carry the class as a query parameter (…/sap/bc/z2ui5?app_start={class}&sap-client=100): the tools post to that endpoint without the class, as the browser posts to its own page. They handle what a browser would - a CSRF token layer in front of the system, a stateful session's sap-contextid, the system's cookies.
  • app_start also accepts a namespaced class (/ns/cl_app).

Migrating a classic report

Migrate Classic Report to abap2UI5 (Command Palette, or the context menu of a *.prog.abap in the editor and the Explorer) converts a classic report into a class of the abap-cloud-gui addon, which keeps the programming model of a report: the event blocks as methods, write( ), alv( ) and message( ) as calls. The converter is the addon's own report2cloud (tools/report2cloud in that repository), the same one the MCP server's migrate_report tool runs. It is not on npm, so the command runs it from a checkout of the addon:

git clone https://github.com/abap2UI5-addons/abap-cloud-gui
cd abap-cloud-gui && npm ci

and abap2ui5.report2cloud.path pointing at that folder (or the ABAP_CLOUD_GUI_HOME environment variable the MCP server reads). Without one the command says so and offers Configure…; a checkout without its npm ci gets Run npm ci. It runs with VS Code's own Node.js.

  1. It asks for the class name - report2cloud's default, zcl_ + the report name, is preselected - and whether to write next to the report or into another folder; existing files of that class are only replaced after you confirm.
  2. The class (.clas.abap, .clas.xml, the report's local classes as .clas.locals_def/_imp.abap) and <class>.migration.md are written in abapGit format, with the report's text pool when its .prog.xml lies beside it. The class opens with the migration report beside it - the work list of TODOs, the tables and APIs not released on ABAP Cloud with their successors, and what the list does not carry over.
  3. A statement with no counterpart in a browser app (CALL SCREEN, a dynpro module, batch input, SUBMIT, native SQL, ...) is refused: each one is an error in Problems, on the statement in the report, and no class is written. Write Partial Result writes the draft anyway, the refused statements marked in it.
  4. When the new class builds a view of its own, Preview View (No System) and Check Views are offered on it. A plain report class draws its screen through z2ui5_cl_cgui_report and has no view of its own to check.

A namespaced class name (/ns/cl_x) is not offered here - run report2cloud's CLI for those.

Commands

All of them are in the Command Palette (Ctrl/Cmd + Shift + P) under abap2UI5; the few with a key are the ones you reach for while typing. This reference is generated from package.json with npm run commands, and npm run commands:check fails when the two drift apart.

CommandIdKey
Run Appabap2ui5.runf9
Reload Previewabap2ui5.reload
Activate and Reload Previewabap2ui5.activatectrl+f3 / cmd+f3
Run a Recently Launched Appabap2ui5.runRecent
Run an App from the Systemabap2ui5.runFromSystem
Show the Preview in the Panelabap2ui5.previewInPanel
Show the Preview in an Editor Tababap2ui5.previewInTab
Go to the Running Appabap2ui5.revealApp
Set Launch URLabap2ui5.setLaunchUrl
Select Systemabap2ui5.selectSystem
Check System Connectionabap2ui5.checkConnection
Clear Stored SAP Credentialsabap2ui5.resetCredentials
New App from Templateabap2ui5.newApp
New Project from Templateabap2ui5.newProject
Add Agent Setup to Workspaceabap2ui5.addAgentSetup
Take App Screenshotabap2ui5.screenshot
Show Traffic Logabap2ui5.showTraffic
Convert XML View to Builder Chainabap2ui5.convertXml
Show App Navigation Mapabap2ui5.showNavMap
Open Project on GitHubabap2ui5.openHomepage
Check Views (Static)abap2ui5.checkViews
Check All Views in the Workspaceabap2ui5.checkWorkspace
Open the Rule Documentationabap2ui5.openRuleDocs
Expand Abbreviation to a Chainabap2ui5.expandAbbreviation
Extract to View Methodabap2ui5.extractViewMethod
Show Examples for This Controlabap2ui5.showExamples
Fix All View Findings in the Workspaceabap2ui5.fixWorkspace
Rebuild the View-Check Baselineabap2ui5.updateBaseline
Preview View (No System)abap2ui5.previewView
Compare View Preview with HEADabap2ui5.previewDiff
Show Reconstructed XML Viewabap2ui5.showReconstructedXml
Generate Mock Data for This Appabap2ui5.generateMock
Run Unit Tests (No System)abap2ui5.runUnitTests
Migrate Classic Report to abap2UI5abap2ui5.migrateReport
Fix All View Findings in This Fileabap2ui5.fixAll
Install Render Gateabap2ui5.installRenderGate
Refresh the App Listabap2ui5.refreshApps
Run This Appabap2ui5.runApp
Preview This App's Viewabap2ui5.previewApp
Check This App's Viewsabap2ui5.checkApp
Copy the App's Class Nameabap2ui5.copyAppName
Turn a View-Check Rule Offabap2ui5.disableRule
Copy Diagnostics for a Bug Reportabap2ui5.copyDiagnostics
Preview Actionsabap2ui5.previewMenu
Apply the Model Document to the Running Appabap2ui5.applyModel
Update Render Gateabap2ui5.updateRenderGate
Show MCP Statusabap2ui5.showMcpStatus
Add All Findings of This Rule to the Baselineabap2ui5.baselineRule

Settings

Everything lives under the abap2ui5. prefix. The full descriptions (with examples) are in the Settings UI; this reference is generated from package.json with npm run settings, and npm run settings:check fails when the two drift apart.

SettingDefaultDescription
abap2ui5.launchUrlTemplate""URL template used to launch an abap2UI5 app. The {class} placeholder is replaced with the (upper-cased) class name.
abap2ui5.systems[]The systems F9 can launch against. The active one is picked with the command "abap2UI5: Select System" and is remembered per window, so two windows can work against two systems at once. Credentials are stored per host, so switching does not ask again.
abap2ui5.allowUnauthorizedCertstrueAllow the embedded preview's local auth proxy to talk to systems whose TLS certificate cannot be verified - self-signed certificates, private CAs not in the OS trust store, hostname mismatches. SAP development systems typically serve self-signed certificates, which is why this is on by default.
abap2ui5.codeLenstrueShow Run, Activate & reload, Check views and Autofix n findings above the class definition of an abap2UI5 app. The autofix lens appears only while the view check has findings it can correct mechanically.
abap2ui5.openMode"tab"How F9 opens the app.
abap2ui5.reloadOn"activation"When the preview of the shown app class reloads by itself.
abap2ui5.reloadOnSaveReload the preview when the shown app class is saved. (deprecated)
abap2ui5.viewCheck.onSavetrueRun the static view check every time a checkable file is saved: an ABAP class building views with z2ui5_cl_ui5_view_builder, or a raw *.view.xml / *.fragment.xml. Findings appear in the Problems panel. The command "abap2UI5: Check Views (Static)" runs the same check on demand.
abap2ui5.viewCheck.livetrueAlso check while typing, shortly after each pause. Only the bundled property gate runs on a keystroke - it works in-process and needs no I/O; the render gate stays on save and on demand.
abap2ui5.viewCheck.command""Command that runs the abap2UI5-linter CLI for the render gate - the property gate is bundled with the extension and needs no command. Leave empty for the default: a local checkout under abap2ui5.mcp.reposRoot when present (runs with VS Code's own Node.js), otherwise npx --yes github:abap2UI5/linter at the release commit of the linter this extension bundles.
abap2ui5.viewCheck.distribution""Which UI5 distribution the target system serves. SAPUI5 ships libraries OpenUI5 does not (sap.ui.comp, sap.suite.*, sap.ushell, sap.fe, sap.viz, ...), so a SmartTable is fine on SAPUI5 and a guaranteed runtime error on OpenUI5. With openui5 such controls are reported as errors, with sapui5 not at all; left unset, they are hints - the same answer a configless abap2ui5lint run gives.
abap2ui5.viewCheck.minUi5"1.71"The UI5 version to check against - the version your system runs. A control or property introduced after it is reported (it would not exist on your system), and a deprecation is only reported once it is in effect at that version. The metadata itself comes from the bundled snapshot; see the abap2UI5 output channel for the version it was generated from.
abap2ui5.viewCheck.renderfalseAlso run the render gate: the reconstructed view is loaded with a real XMLView.create in headless Chromium. Unlike the bundled property gate this needs the external checker - install it once with "abap2UI5: Install Render Gate" (downloads the checker bundle and Chromium, runs with VS Code's own runtime), or provide your own via abap2ui5.viewCheck.command / abap2ui5.mcp.reposRoot.
abap2ui5.viewCheck.rollingBundlefalseDownload the render gate from the linter's rolling bundle instead of the immutable one published for the release commit of the linter version this extension build bundles.
abap2ui5.viewCheck.allow[]Accepted deviations for the property gate, e.g. sap.m.GenericTile.systemInfo - each entry is passed to the checker as --allow. Merges with the allow list of a workspace's abap2ui5lint.jsonc.
abap2ui5.viewCheck.rules{}Which view-check rules are active, and how loudly. A rule id maps to false to switch it off, to "hint" / "warning" / "error" to change its severity, or to { "severity": …, "exclude": […] }.
abap2ui5.inlineFindings"problems"Show the view check's message at the end of the line it concerns, next to the squiggle. A builder chain is long and the Problems panel is far away, so the message is put where you are already looking.
abap2ui5.inlineSincetrueShow the UI5 version a control or attribute arrived in, at the end of its line - warned when it is above abap2ui5.viewCheck.minUi5. The metadata ships with the extension, so this answers "does my system have this yet?" while you write the line rather than after the check runs.
abap2ui5.inlineDeprecatedtrueShow a control's or attribute's deprecation at the end of its line, with the replacement the UI5 documentation names. Deprecations and abap2ui5.inlineSince share one decoration pass; this switch governs only the deprecation half.
abap2ui5.inlineRoundtripCosttrueShow what each PUBLIC attribute adds to a roundtrip, next to its declaration. abap2UI5 serializes every public attribute into the model on every roundtrip; the size is measured from the class's own literal seeds, or from a <class>.mock.json when there is one.
abap2ui5.renamePreviewtrueShow the refactor preview when F2 renames an event, a control id or a bound attribute, so every occurrence can be seen before it changes.
abap2ui5.previewThemes[]Additional UI5 themes the preview's theme picker offers, merged after the built-in list - for a custom theme deployed on your system.
abap2ui5.previewLanguages[]Additional logon languages the preview's language picker offers, merged after the built-in list - passed to the app as sap-language.
abap2ui5.viewPreview.theme"sap_horizon"The UI5 theme "abap2UI5: Preview View (No System)" renders in. Any theme name the runtime ships, e.g. sap_horizon, sap_horizon_dark, sap_fiori_3, sap_belize.
abap2ui5.viewPreview.viewport"1280x900"The viewport(s) the systemless preview renders at, <width>x<height> in CSS pixels - e.g. 390x844 to see the view the way a phone lays it out. Several, comma-separated, become a device matrix: 390x844,1280x900 renders both in one browser session and shows them side by side. The picture is taken full-page, so a view taller than the viewport is shown whole.
abap2ui5.mcp.enabledtrueOffer the abap2UI5 MCP server to MCP clients in this window (Copilot agent mode and others). The server gives AI agents the abap2UI5 dev loop without an SAP system: capability queries, static view validation, deploy, build, headless run with screenshot.
abap2ui5.mcp.systemtrueAlso offer the abap2UI5 System MCP server: real-system tools hosted by the extension itself - list the configured systems, search classes on the system (ADT quick search), run an app through the auth proxy with a headless screenshot, and - only with abap2ui5.agent.enableAppTools - operate an app through its JSON protocol. Uses the same credentials the preview stores; the run tool needs the render gate's Chromium.
abap2ui5.agent.enableAppToolsfalseAllow the abap2UI5 System MCP server's app tools (app_list, app_start, app_describe, app_act) to operate abap2UI5 apps on the real active system: an AI agent fills fields and fires events through the abap2UI5 JSON protocol, as the configured user - an event runs for real and may save, post or delete data. Off by default; while it is off the tools stay listed and answer with how to allow them, sending nothing. User settings only: a workspace cannot turn it on.
abap2ui5.mcp.command""Command that starts the MCP server. Leave empty for the default: a local checkout under abap2ui5.mcp.reposRoot when present, otherwise npx --yes -p @abap2ui5/mcp-server abap2ui5-mcp.
abap2ui5.mcp.reposRoot""Folder containing the checkouts the MCP server orchestrates (abap2UI5, samples-controls, samples, samples-stack, and optionally linter, mcp-server, abap-cloud-gui). The matching A2UI5_HOME / SAMPLES_CONTROLS_HOME / SAMPLES_HOME / SAMPLES_STACK_HOME / AI_VIEW_CHECK_HOME / ABAP_CLOUD_GUI_HOME environment variables are passed to the server, and local mcp-server / linter checkouts found here are preferred over downloading via npx.
abap2ui5.report2cloud.path""Folder of an abap-cloud-gui checkout (with npm ci done) whose tools/report2cloud converter "abap2UI5: Migrate Classic Report to abap2UI5" runs - report2cloud is not on npm. Leave empty to use the checkout ABAP_CLOUD_GUI_HOME names, the variable the MCP server's migrate_report reads for the same purpose.

Development

npm install
npm run compile      # builds dist/extension.js with esbuild

Open this repository in VS Code and press F5 → a second VS Code window (Extension Development Host) starts with the extension loaded.

Handy while developing: npm run watch rebuilds on every change, npm run lint runs tsc --noEmit plus eslint, and npm test runs the unit suite with node --test — several hundred tests over every vscode-free module (bundled with the same esbuild config the extension ships with), plus the cross-checks: the manifest against the registered commands, the property gate against the linter's own pipeline, the snippets and templates through the bundled linter. The in-host smoke tests (npm run test:web, npm run test:desktop) each download a VS Code build and run in CI.

The agent app tools' snapshot code is mcp-server's, vendored at a recorded commit: npm run agent-vendor -- /path/to/mcp-server [--ref <commit>] copies it into src/vendor/agent/ (and the recorded sessions its tests replay into src/test/fixtures/agent/), and npm run agent-vendor:check -- /path/to/mcp-server fails when the copies drift from that commit. npm test fails on a hand edit of a copy.

Packaging as a .vsix

npm install
npm run vsix

The result is a file such as abap2ui5-<version>.vsix.

vsce is included as a devDependency, so npm run vsix uses the local version. Alternatively install it globally: npm install -g @vscode/vsce.

Every push and pull request builds the same .vsix in CI and attaches it to the run as an artifact — handy for trying out a branch without building it locally.

Releasing

Bump version in package.json, add the matching CHANGELOG.md section, then either

  • run the Release workflow from the Actions tab — it tags the current commit with v<version> and releases it, or

  • tag the commit yourself:

    git tag v<version>
    git push origin v<version>

Either way the workflow builds the .vsix, creates the GitHub release and attaches the file, with the changelog section of that version as the release notes. Tag and package.json have to agree, otherwise the run fails on purpose — and a version that is already released is refused instead of overwritten.

Contributing

This project is English-only. Code, comments, identifiers, commit messages, documentation, and every user-facing string in the extension are written in English — see AGENTS.md for the full conventions.

License

MIT — see LICENSE.

MIT, read

History

Latest

v0.31.0

Other 22

Notes

The bundled linter moves to v0.8.5, and is now taken from its npm release rather than from a commit on its main branch.

  • The extension activates with a third less to load. The project template (300 KB) and the client-> method reference (59 KB) are no longer part of the code every window parses on activation: they ship next to it and are read the first time "New Project from Template", "Add Agent Setup to Workspace" or a client-> completion needs them. The archive library the render-gate installer uses (86 KB) is loaded the first time that installer runs, and the client behind the agent app tools (50 KB) the first time an agent calls one. The activation bundle went from 1.1 MB to 0.62 MB, the vscode.dev bundle from 0.75 MB to 0.39 MB; nothing you can do changed.

  • Less work on every keystroke and save. The property gate runs once per edit: the lightbulb and the lenses asked for the findings of the new text before the live check ran, and the check then ran the same gate over the same text again. Whether a file is one the view check judges is decided once per edit instead of on every keystroke (for a class that is not an app, that decision read the repository config's timestamps each time); the lenses above a class no longer re-evaluate on every diagnostic another extension publishes, only when one of abap2UI5's own findings moved, and the "Run unit tests" lens no longer looks for the test include on every pass; the reconstructed XML preview reuses the reconstruction the editor already has instead of parsing the class a second time. The first scan of a workspace reads its classes twelve at a time instead of one after the other, and the web build (vscode.dev, the browser-based Business Application Studio) registers its features first and reads its 600 KB of data after, concurrently - a command or a view used to wait for the slowest read; a check asked for before the data is in waits for it.

  • A window without ABAP in it no longer scans the workspace on activation. The extension activates for any XML file; the index of app classes (what lets F9, the lenses and the Apps tree recognise a class that inherits z2ui5_if_app) is now built when the first ABAP document shows up, in slices that leave the editor responsive, and a change on disk re-reads that one file instead of everything. The Apps tree is a view of that index, so a save moves one node rather than re-reading the workspace - and a save or an open that changes nothing the tree shows (the usual one) does not re-render it at all - and the text the extension keeps of your classes is validated cheaply when it is old (a stat per file, never a second read of the whole workspace) and let go when it has not been used for a while. A class whose file is deleted, or a file closed after an unsaved rename, leaves the Apps tree at once rather than at the next full rescan.

  • Add Agent Setup to Workspace. A new command makes the project in the open folder ready for an AI agent - most abap2UI5 projects did not start from app-template and have no briefing for one. It adds what npm create abap2ui5-app@latest -- --agent-setup adds, from the copy of app-template bundled with the extension, so it needs no network and works on vscode.dev too: AGENTS.md, CLAUDE.md, .claude/settings.json and the four skills, .mcp.json, abaplint.jsonc and abap2ui5lint.jsonc, .github/workflows/check.yml with the two scripts it runs, and .nvmrc. A file you already have is left as it is; package.json and .gitignore only gain the scripts, devDependencies and patterns you are missing, and every value of yours that differs from the template's is named. The gates are pointed at the folder your .abapgit.xml names as STARTING_FOLDER, and nothing is written into it. A confirmation lists every file first; the abap2UI5 Agent Setup output then says what was done and what to run next (npm install, npm run check) - and how the Claude Code plugin brings the skills and the MCP server without the gates. The Get started walkthrough has a step for it.

  • "New Project from Template" is in step with app-template again: its latest AGENTS.md, abap-check and ui5-check skills, check-pin.mjs and doctor.mjs.

  • The MCP walkthrough step names the abap2UI5 Claude Code plugin as the alternative for Claude Code users, gives the claude mcp add line for the server alone, and says the server is listed in the official MCP Registry from 1.0 on; the README links the documentation's AI page. Hover and completion describe the client API with the core's current wording.

  • The agent app tools follow the abap2UI5 protocol's frontend rules. The vendored agent client is now abap2UI5/mcp-server a4d9f07: a response of another protocol number is refused with both numbers named instead of being shown; an app_act with an event while another is still running waits for it instead of sending the same draft id twice; values set meanwhile are kept; a popup of the previous app closes when another app answers; and the system's error text is shown exactly as sent (a <b> in it stays visible text). The CSRF token handshake and the stateful session id (sap-contextid) are now done by the client itself - the extension's transport through the auth proxy only carries their headers and the system's cookies, so the token is fetched once and the body re-sent once, never twice.

  • The agent app tools take mcp-server's later fixes. The vendored agent client is now abap2UI5/mcp-server 185baed: a binding written as {path: '/A', model: 'other'} is read as the named model's, so a value is no longer written into the app's own model; an unsent edit no longer survives into a view the system displayed anew, and a model push no longer invents table rows for one; a model path through __proto__, constructor or prototype is refused, and an element of that name no longer breaks the screen; a number field takes a number or a decimal string, not whatever Number() makes of a value; an action list that is no list is refused with a sentence instead of "object is not iterable".

  • Migrate Classic Report to abap2UI5. A new command - in the Command Palette and in the context menu of a *.prog.abap - converts a classic ABAP report into an abap-cloud-gui report class with that addon's converter, report2cloud: you name the class and pick the folder, and the class opens beside its migration report (the TODOs, the tables and APIs to replace for ABAP Cloud). A statement that has no counterpart in a browser app - CALL SCREEN, batch input, SUBMIT, native SQL - is reported in Problems on the line it stands on, and Write Partial Result writes the draft with those statements marked. report2cloud is not on npm: point the new setting abap2ui5.report2cloud.path at a checkout of abap2UI5-addons/abap-cloud-gui with npm ci done (or set ABAP_CLOUD_GUI_HOME); the command offers Configure… until you have.

  • AI agents can operate an app on the system - once you allow it. The abap2UI5 System MCP server gets the four app tools of the abap2UI5 MCP server, on your real system: app_list searches class names, app_start starts an app and answers with an agent snapshot (its fields and values, its actions, tables and messages), app_act fills fields and fires an event, app_describe repeats the last snapshot. An agent works by model path, label and event name through the abap2UI5 JSON protocol - no browser, no screenshot - and anything not on the screen is refused with what is. They run through the auth proxy on the active system, as you: an event may save, post or delete data. That is why they do nothing until you set abap2ui5.agent.enableAppTools in your User settings (a workspace cannot); until then they tell the agent how to switch them on. A value help (SelectDialog, TableSelectDialog) is a table of the snapshot, and app_act with row on its confirm picks that row as a click does; the items of a MessagePopover / MessageView are listed as messages.

  • Security:

    • Render gate. Its last-resort npx fallback runs the linter release this extension bundles instead of the linter's current main, and the render gate does not run in an untrusted workspace (Restricted Mode). abap2ui5.viewCheck.render can no longer be switched on by an untrusted workspace's settings.
    • abap2ui5.viewCheck.rollingBundle is read from your user settings only: a repository's .vscode/settings.json can no longer make Install Render Gate download the linter's rolling build instead of the release this extension bundles. Off by default, as before.
    • abap2ui5.allowUnauthorizedCerts is read from your user settings only: a repository's .vscode/settings.json can no longer switch certificate verification for the auth proxy on or off. Its default is unchanged; a value you had set in a workspace's settings no longer applies - set it in your User settings instead.
    • Baseline. The "add … to the baseline" quick fix, Add All Findings of This Rule to the Baseline and Rebuild the View-Check Baseline refuse - with a message saying why - a baseline in abap2ui5lint.jsonc that points outside the workspace folder holding the config, a symbolic link out of it included - and a link to a file that does not exist yet, which writing through would have created wherever it points. They used to overwrite whatever JSON file the config named.
    • Add Agent Setup to Workspace writes nothing through a symbolic link: a project whose .claude (or package.json, or any other file of the setup) is a link has that file skipped and named in the confirmation. A cloned repository carrying .claude -> ~/.claude used to have the template's permission allowlist written into your global Claude Code settings.
  • View check - the editor agrees with CI in more places:

    • Disable directives follow the rules block. A repository that switched unused-directive off, re-graded unknown-directive-rule or excluded a folder from them still saw them in the editor; and a waiver of unused-namespace-declaration on a class the rule does not judge was reported as unused.
    • unused-namespace-declaration is no longer reported (nor its fix offered, which deletes the declaration) on a class that writes the prefix in a part of the view the check cannot reconstruct - CI has been silent about those, because the view needs the declaration.
    • On vscode.dev / in the browser the icon rules (unknown-icon, icon-too-new, icon-removed) report again - the linter's icon list could not be read there - and a baseline written as ./../baseline.json, lint/../baseline.json or an absolute path is found again (only a leading ../ used to be resolved, so the findings it waives were reported).
    • "Fix crlf-line-ending" converts the file now. The linter's fix deletes every \r, and an editor position cannot address the gap between \r and \n - so the quick fix, Fix All and the workspace fix applied empty edits and the warning stayed. They now switch the document's line endings to LF, in the same edit (and undo step) as the other fixes.
    • Quick-fix titles name a line, not a number. For the line-keyed rules (trailing-whitespace, source-line-too-long) the lightbulb said "fix trailing-whitespace on 12" - or, with the next linter release, "on 3", the count of blanks. It now says "on line 12"; a fix over many lines names none.
    • An app class whose view comes from another class is checked, as CI checks it: by the rules that read the class rather than a view - a _bind( ) on a private attribute, an obsolete call, the event wires, the lifecycle dispatcher. The editor used to say "nothing to check". Preview View (No System) and Generate Mock Data for This App still ask for a class that builds its view itself.
    • allClasses and properties in abap2ui5lint.jsonc are honoured. With allClasses, every class is checked - one that builds no view by the source rules, as CI does - and Check All Views in the Workspace reaches it. With properties: false the walk over the view against the UI5 metadata is skipped as in CI (in an XML view, the whole check), and a waiver of one of its rules is no longer reported as unused.
    • An icon in a commented-out control of an XML view is no longer reported - CI reads the view with its comments blanked.
    • The check_view_source tool of the abap2UI5 System MCP server treats an unset abap2ui5.viewCheck.distribution as "not decided", like the editor - it judged as SAPUI5 and so hid the SAPUI5-only-control hint.
    • Ready for the next linter release: rows-hidden-by-visible, enum-bound-to-initial-field, navigation-lost-on-rebuild and the opt-in portable-app (its profile ships with the extension) are judged with the same inputs CI gives them as soon as the bundled linter brings them - the start-path model, whether the class raises the size limit, the pages of a container, the portable profile.
    • Fix All View Findings in the Workspace counts what it fixed in findings, and says separately how many files it changed to LF line endings - it used to add up its edits, a finding fixed in two places twice and each line-ending change as one more "fix".
    • A waiver in an XML view never goes above its XML declaration (nor in front of a byte-order mark). With the root on the declaration's line (a minified or generated view), the "suppress on this line" quick fix wrote its comment in front of <?xml …?> - which every XML parser, UI5's included, refuses, so the whole view stopped loading. The directive now goes right behind the declaration.
  • XML views:

    • Namespaces are read per element, as XML scopes them: an inner <VBox xmlns="sap.ui.layout.form"> re-resolved every unprefixed tag of the view for completion, hover and the colour swatches, a prefix declared in one subtree was offered in another, and a declaration in a comment counted. Namespaces declared with single quotes (xmlns:m='sap.m') are read too, and so is a single-quoted colour value.
    • @since and deprecations inline, as in a builder chain: the UI5 version a control or attribute arrived in, warned above abap2ui5.viewCheck.minUi5, and the deprecation with its replacement.
    • id, class and binding - on nearly every control of a real view, but declared in no control's metadata - are offered and explained, in the XML and in the builder chain alike.
    • Completion offers nothing in front of the first tag (accepting an offer there replaced the root tag's name) or inside a comment (a <word> in the prose was taken for a tag).
    • Convert XML View to Builder Chain puts no line break inside a literal from a CRLF view: a long binding written over several lines is split into && chunks, and the cut could fall between \r and \n, leaving a bare \r that abapGit refuses. Attribute values are read the way an XML parser reads them: each line break and tab a blank, a &#10; still a line break.
  • Rename, navigation and events:

    • F2 on an event renames only the WHEN branches of the class's CASE client->get_event( ) (or client->get( )-event) - it used to rewrite a same-named WHEN 'EDIT' of an unrelated CASE mv_mode. or of a status switch nested in a handler too. Go to Definition, the highlights, the "raised n× in the view" lens and completion in a WHEN follow the same rule. A class without such a CASE keeps the old behaviour.
    • F2, Go to Definition and the highlights on an event answer only on the event's name in _event( ) - positional or val =. In any other literal of the call (arg = \{parameters>/value}`, a t_argrow) F2 offered a rename that then changed nothing, and an argument spelled like an event jumped to that event'sWHEN. The same goes for a WHENvalue no event is spelled like (``WHENOut of StockTHEN`` in aSWITCH, ``WHEN %MSG` ``).
    • F2 on a bound attribute no longer rewrites the word inside a string template's text (|The mv_title is …|), another structure's component embedded in one (|{ ls_row-mv_title }|) or a path into another model: a class with a DATA value or DATA text had arg = \{parameters>/value}`, {source>/text}and{device>/text}renamed along with the attribute, which broke the event parameter or the device binding without a word.|{ mv_title }|` is still renamed.
    • Control ids. a( n = `id` v = |inp_{ lv_i }| ) no longer makes the next attribute's name (value) a declared id - the id is the literal right behind v =, or there is none.
    • Go to Definition and Go to Symbol in Workspace land on the method's name in a class written in lower case: method meth. used to put the cursor on the meth of the keyword.
    • Outline. A very large class (from about 120,000 method calls on) no longer makes the view outline, and with it the breadcrumbs, fail.
  • Preview and systems:

    • Reload on activation. Saving right after the preview reloaded (before the system had answered which version the preview now shows) could reload the preview again on the first poll for an activation that never happened, and clear the not activated badge. The watch now waits for the real activation.
    • Preview theme and language. Switching them changes only the sap-ui-theme / sap-language parameter of the launch URL: the other parameters stay exactly as configured. Every launch used to re-encode the whole query (%20 became +, ~ became %7E, / and : were escaped, a bare ?debug became debug=).
    • Proxy. A page declared as windows-1252 or iso-8859-1 shows its euro signs, dashes and curly quotes the way a browser does, a page in another charset (iso-8859-2, shift_jis, ...) is decoded as that charset instead of as UTF-8, and a page in a charset that cannot be decoded is passed through unchanged instead of being garbled.
    • abap2ui5.systems entries of the wrong type ("name": 100, a url that is not a string, a bare string in the list, an object instead of the list) are skipped like any other malformed entry; they used to make Run App, the system picker and the status bar fail with an error until the setting was fixed by hand.
    • Preview View (No System) shows why a render could not even start (a temporary folder that could not be written, a checker that could not be resolved) in the panel, over the last pictures. It used to keep saying "rendering…" until the next save, with the reason only in the log.
  • Editing, projects and agents:

    • Control Properties view. Removing the last attribute of a chain left its closing ). on a line of its own; the paren now moves up to the line of the call that is the last one ()->tag( \Input` ).`), unless that line ends in a comment. Removing an attribute followed by a blank line no longer takes the blank line with it.
    • Builder-chain abbreviations (Page>content>Button+Input) expand when a text or a value holds a lone parenthesis - Text{1) First}+Button or Input[placeholder="(optional"]+Button used to be refused as "not an abbreviation".
    • Framework-pin warning. A pin kept in a comment of abaplint.jsonc (// "branch": "1.100.0" above the real one, or a dependency commented out) is no longer read as the pin, and a { in a comment no longer hides the dependency it sits in.
    • Add Agent Setup to Workspace says that a package.json holding null, an array or a plain value is not a package manifest, instead of calling it invalid JSON - and no longer plans to add entries to an array-shaped one that it would have written back unchanged.
    • New Project from Template and Add Agent Setup to Workspace keep the package.json name within npm's rules: a folder name longer than 214 characters is cut, and a folder called node_modules or favicon.ico gets abap2ui5-app - npm install refused the names they used to write.
    • Opening a workspace reads its classes once. The app index, the class index the view check uses and the apps tree each scanned the workspace when the window opened, and the three scans ran at the same time - so every class was read three times. They now share one scan (over samples-controls' 644 classes: one read per file instead of three, about half the time).
    • The MCP server finds abap-cloud-gui under the repos root. An abap-cloud-gui checkout under abap2ui5.mcp.reposRoot is now handed to the server as ABAP_CLOUD_GUI_HOME, as the other checkouts are. The server's migrate_report tool runs that addon's converter from a local checkout only, and a server started through npx does not look beside your repos root - so the agent's tool reported the checkout missing while Migrate Classic Report to abap2UI5 found it.
  • Internal: TypeScript 6.0 for the type check (7.x waits for typescript-eslint, whose peer range ends below 6.1), eslint 10.12, esbuild 0.28.2, and @types/node back on the Node 22 line that engines.node names.

  • The view check runs abap2UI5-linter 0.8.5 (from 0.8.3). What that brings to the editor: a builder attribute written as a( v = … n = … ) is reconstructed like a( n = … v = … ) - its value, often a binding, used to be dropped and was missing from every check of the class; and a raw *.view.xml with a duplicate attribute, a mismatched or missing closing tag is reported as malformed-xml instead of passing. The render gate, in its matching bundle, renders a view that uses the framework's z2ui5/model/clipboard module (sap.m.plugins.CopyProvider) instead of failing to create it.

  • The render gate downloads the bundle of exactly that release. The linter publishes its checker bundle per commit, so the extension records the commit each bundled version was published from and fetches that bundle. A build whose bundle is not published says which release it wanted; Update Render Gate and the diagnostics report name the bundled linter version and its commit instead of a bare commit hash.

  • Fixes from a review of the whole extension:

    • Preview and activation. An app's screenshot (and MCP's run_app_on_system) no longer fails its first roundtrip with a 404. Ctrl+F3 whose activation failed no longer reloads and stops watching - the preview keeps its "not activated" badge and reloads once the activation does happen; a reload without an activation command, or after re-entering credentials, keeps the watch too. The watch's reload returns the cursor to where you are, not to where you pressed F9. Set Launch URL edits the active system in place - it used to drop a same-named second system or add a duplicate.
    • Proxy. A connection that breaks mid-download aborts the resource instead of completing it with an error text; a WebSocket the system never answers times out; a page that declares its charset only in <meta> keeps its umlauts; a second Content-Security-Policy keeps all of its directives. A wrong password no longer costs extra failed logons through the UI5-version probe.
    • View check. The read-only side of a git diff is no longer checked (findings showed twice, and Fix All tried to edit it). A change to a base config pulled in through extends is picked up without touching the extending file. Turn off rule writes only the workspace's own rules, and Undo restores them exactly. Add all findings to the baseline writes the file once instead of once per finding. Preview Diff finds the committed version when the workspace folder is below the repository root. A proxy's block page downloaded instead of the render-gate bundle no longer blocks the real bundle afterwards, and two windows installing the gate at once no longer break each other's install.
    • Editing. Extract to View Method no longer breaks the class when a comment sits above the chain. Removing an attribute whose value wraps onto a second line removes all of it. The property editor no longer treats `sap-icon://` && mv_icon as an editable literal. Renaming an attribute (F2) leaves same-named structure components alone. The quick fix for an unhandled event is offered when a handler uses IGNORING CASE or TO UPPER CASE. Hover in an XML view works over the whole attribute name. CLASS-DATA and REF TO attributes no longer get a roundtrip-cost annotation.
    • Apps tree, CodeLens and navigation. Opening a test include no longer makes subclasses of that class lose their CodeLens and their entry in the apps tree, and both update once a newly pulled base class is indexed. The navigation map follows CAST #( … ) and CONV #( … ). Show Examples no longer counts a label aggregation as a use of Label, and a broken catalogue download is retried instead of cached as empty for a day. New Project from Template refuses class names the new project's own abaplint rejects (it expects ZCL_/ZCX_). On Windows the unit tests run in cmd.exe, the shell their command line is quoted for. Convert XML View keeps a warning about an unreadable tag from spilling into the generated ABAP.
    • Preview, model and navigation map. Apply the Model Document to the Running App confirms only what the preview accepted; it used to say "applied" even when no app was loaded or nothing of the model was in the document, and now says why instead. The theme and language pickers in a running preview follow a change to abap2ui5.previewThemes / abap2ui5.previewLanguages without an F9. Show the Preview in an Editor Tab / … in the Panel reads the same in the preview menu as in the Command Palette, and honours an openMode set per workspace folder. The activate badge and the welcome screen say that Ctrl+F3 is bound in ADT documents only - elsewhere the button or the command Activate and Reload Preview does the same. Show App Navigation Map run again while its scan is still going no longer opens a second map. The settings UI showed abap2ui5.reloadOnSave as true by default; it has no default (the effective behaviour is reloadOn: activation). A screenshot's Chromium runs in a throwaway profile that is deleted afterwards, instead of leaving the proxy's session cookie in the user's default profile. Take App Screenshot after the proxy moved to another system (a connection check, an agent's connect) says so instead of photographing a connection-refused page.
    • System and credentials. An agent that retries search_apps or run_app_on_system on a rejected logon no longer re-sends the password to the system on every call - the proxy's stop after a 401 now holds for those two tools as it does for the app tools, so a wrong password costs one failed logon, not a locked user. A 403 from the system (a missing authorization, or the CSRF handshake an agent's first POST gets) is logged and no longer offers Re-enter Credentials, which deleted a password that worked. Check System Connection reports a proxy that could not listen as the proxy's failure, not as an unreachable host.
    • View check. Fix Workspace and Check Workspace no longer apply a file's fixes to a buffer edited while the sweep was reading it - the guard compared the right version against the wrong one. The live check leaves a class under a dot-directory or one the config's ignore prunes alone, as CI does; it used to squiggle it, the sweep then removed the findings as stale, and the next keystroke brought them back. On vscode.dev the workspace sweep skips those files too, reports progress every 25 files rather than per file, and a git pull touching a config and its baselines re-reads them once rather than once per file. A document that can never be checked (a log, a JSON file) no longer costs its whole text per keystroke to find that out.
    • Classes the extension knows about. The class index and the app-class index read every class of the workspace; both stopped at 2000 files and judged a larger workspace against a partial index without saying so. A workspace folder added while a class file was changing is indexed (the file's event used to cancel the folder's rebuild), and a class created on disk during the first scan is in the index when the scan is through.
    • Render gate. For the per-commit bundle URL a changed download is refused even when a published checksum agrees with the new bytes - that checksum sits in the same release, and the digest this machine verified is the anchor. The rolling bundle, which moves by design, still trusts the published checksum.
  • The Workspace Trust text no longer claims that every restricted setting is read from the user settings only. abap2ui5.systems, abap2ui5.launchUrlTemplate and abap2ui5.viewCheck.render are ignored from the workspace in Restricted Mode, and a trusted workspace can set them - a team shares its systems that way. The text now says so; the settings themselves are unchanged.

  • Internal: @abap2ui5/linter is an exact npm devDependency, like in every other repository of the ecosystem, instead of a github: commit pin; the weekly bump follows the latest published version, and a test holds the manifest, the lock and the recorded release commit together.

  1. v0.30.1

    Other 5

    Notes
    • The MCP server starts again without a local checkout. The default command was npx --yes @abap2ui5/mcp-server; since the server's 0.2.0 release the package has two commands, and npx stopped with "could not determine executable to run". The extension now starts npx --yes -p @abap2ui5/mcp-server abap2ui5-mcp, which works for every release.
    • The view check no longer calls a view "rendered" that was not. A checker without its UI5 runtime (@abap2ui5/linter-render) skips the render gate silently and reports a clean result. The extension now reads the report's counters and says that the render half did not run, instead of showing the view as passed.
    • Format Document keeps a file's CRLF line endings. The builder-chain formatter applied the linter's layout fixes verbatim, and those always use \n; on a CRLF file that left the re-indented chain lines with mixed line endings, and on an already-formatted CRLF file it reported edits that stripped the \r off every chain line. The formatter now writes the fixes in the document's own line ending.
    • The view check no longer rewrites a repository's badge file. The render gate and the systemless view preview run over a scratch copy of the buffer, and the checker discovered the repository's abap2ui5lint.jsonc from the working directory - so a config with a badge had that badge overwritten with a one-file verdict on every save, and a config anywhere above the temporary directory could steer the run. Both now pass --no-config; the repository's rules still govern the check, applied by the extension itself.
    • No console windows on Windows. The extension host has no console there, so every command the extension ran - the view check, the unit tests, the gates, and the taskkill that ends one - opened a console window of its own for as long as it ran. They are started hidden.
  2. v0.30.0

    Other 14

    Notes

    The bundled linter moves to v0.8.3, the templates and snippets are brought in line with what that linter teaches, and the snippet set grows by five.

    • The view check knows 23 more rules - the bundled @abap2ui5/linter moves from 0.6.1 to 0.7.0 (its metadata to OpenUI5 1.152.0). Among what the editor now reports live and on save: second-root (a second root element beside the mvc:View, the one chain shape that silently builds a broken view), message-box-removed-parameter, unbound-public-attribute, client-handle-capture (a _bind( ) / _event( ) handle captured into a variable), event-arg-single-row-table, event-arg-default-index, unescaped-text-in-attribute, redundant-serializable, bound-aggregation-without-template and column-cell-count-mismatch. Most of them carry fixes, so they arrive as Quick Fixes and in Autofix too.
    • Fewer false positives - the pin moves on to the linter's v0.8.1 release. handler-without-event counts only the WHENs of a CASE over the event and knows the onClose options and hash_attach_changed; unbound-public-attribute reports the right line after a TYPES BEGIN OF and no longer reports a TYPE REF TO attribute; a literal b = abap_false is read as false; smart-variant-without-init accepts filter_bar_variant_init; frontend-action-as-backend-event ignores a class-local cs_event; missing-on-navigated-branch no longer fires on a sub-app; and the unused-namespace-declaration Quick Fix handles the last declaration of a chain. A disable directive written for one of those is now reported as unused-directive.
    • Obsolete companion controls are errors - the pin moves on to v0.8.2. The new rule obsolete-custom-control reports the eight z2ui5.cc controls abap2UI5 marks obsolete - Timer, Focus, Scrolling, Title, LPTitle, Favicon, Info and History - and names the frontend event or client call that replaces each (a Timer becomes follow_up_action( val = client->cs_event-start_timer … )). It reads a builder chain, an XML view and, on a class still on the frozen z2ui5_cl_xml_view, the old _z2ui5( )->timer( ) helpers, which the editor now reports beside frozen-view-builder exactly as CI does. The render check also knows InputExt, UploadSetExt and SmartMultiInputExt: a view using them renders instead of failing to load the control, and a misspelt attribute on a companion control is reported with a did-you-mean (inputmode → inputMode).
    • A variable typed outside the class no longer breaks the render check - the pin moves on to v0.8.3. A bound attribute whose type the class does not declare (a DDIC type, or one another class owns, such as zcl_x=>ty_t_token) used to reach the render check as an empty string, and a property that is not a string rejected it: the view failed to load in the editor although it runs. It is now left out, and the control keeps its default.
    • The framework-pin warning is live. The linter now ships its compatibility record (@abap2ui5/linter/compat), so an abaplint.jsonc pinned to an abap2UI5 release below what the bundled linter assumes gets the warning on its branch line that 0.29.0 prepared and no pin could trigger. On vscode.dev the enum-key table the linter grew for the eight enums whose key and value differ is now handed on like the other hidden tables, so the web gate judges those values as the desktop does.
    • The gallery templates dispatch the way the app guide does. "Form" and "Popup" lost the check_on_init( ) arm that only repeated the check_on_navigated( ) display (redundant-init-display - init implies navigated); "List" and "Master & detail" keep theirs, because it seeds data. All templates and the z2ui5event snippet dispatch on CASE client->get_event( ). - the spelling the guide and the z2ui5test double use, so a test written from the snippet actually reaches a WHEN branch. "Master & detail" wires its one event argument as arg = ... instead of a one-row t_arg table.
    • Snippets follow the house chain layout. z2ui5app, z2ui5table, z2ui5popup and z2ui5popover had chains Format Document rewrote the moment they were inserted (one call per line, four spaces per level, an end( ) in the column of the element it closes); they now insert what the formatter would produce, z2ui5ele inserts a container with one child closed in the container's column, and every chain snippet leaves the cursor in the column of the control it just built, so the next ->tag( ) is a sibling at the sibling's column. The suite now runs every snippet and template through the linter with chain-house-layout switched on, so the drift cannot come back.
    • Three snippets corrected. z2ui5eventarg inserts get_event_arg( ) (the index is an optional placeholder - the linter's event-arg-default-index reports a spelled-out 1), z2ui5navback inserts the parameterless nav_app_leave( ) the interface documents as the return to the caller, and z2ui5event is the get_event( ) form above.
    • Five new snippets for guide idioms: z2ui5bool (an attribute rendered true/false from an ABAP flag, b = instead of v =), z2ui5list (a List whose row press carries the row's key as a single arg), z2ui5liveevent (an Input whose liveChange round-trips per keystroke with check_queue_last and check_no_busy, so nothing typed is lost and no busy overlay flashes), z2ui5backbutton (showNavButton bound to check_app_prev_stack( ) plus navButtonPress wired to _event_nav_app_leave( )) and z2ui5popupclosewire (a Close button whose follow_up_action( cs_event-popup_close ) tears the popup down without a roundtrip).
    • The bundled client-> reference and the app-template snapshot are regenerated (follow_up_action and _event docs, the template's skills).
    • The view outline and completion follow handle variables. A class written the way the starter template is - DATA(page) = view->ele( \Shell` )->ele( `Page` ), then page->ele( `List` )..., then page->tag( `Button` )- is now read the way the builder and the view check read it: the Button is a child of the Page, not of the List above it. Binding completion at Page level no longer offers the list row's fields (which the check then reported asunknown-binding-path), and page->a( n = `...` )` offers the Page's members.
    • **Completion inside client->_event( \...` ).** The event names the class already handles - its WHENbranches andcheck_on_event( ) tests - come first, then the names its other wires raise; a handler spelled differently (WHEN `SAVE`for asavewire) is named in the entry, so the mismatchevent-without-handler` reports later is avoided at the keystroke.
    • Completion after client->_bind( , _bind_edit( and _bind_path( . Offers the PUBLIC instance attributes of the class - the only data the framework can bind - with tables marked as what an aggregation binds; CONSTANTS and CLASS-DATA, which raise BINDING_ERROR at runtime, are left out. Works for the val = form and in any spelling.
    • Internal: the gate parity test normalises line endings in the linter fixtures it reads, so the Windows CI job no longer fails on the CRLF an autocrlf checkout gives them.
  3. v0.29.0

    Other 8

    Notes

    Four additions around the dev loop: a fix for the most common dead-control finding, mock data from the class, editing the running app's model, and a test skeleton - and "New Project from Template" now writes the template's whole project.

    • The scaffolded CI workflow runs the app's ABAP Unit tests without a system. app-template's check.yml gained a unit job (the abap2UI5/mcp-server action: the framework at the pinned release, its transpiled backend, the tests through the open-abap runtime), and the workflow "New Project from Template" writes carries the same job on the same pin, plus npm run test:unit for the terminal.

    • New command "Run Unit Tests (No System)" (abap2ui5.runUnitTests, in the palette, the editor's abap2UI5 menu and the apps tree, and as a "Run unit tests" lens above a class that has a *.clas.testclasses.abap next to it). It runs the same abap2ui5-unit the scaffolded CI job and npm run test:unit run - the framework at the release the project's abaplint.jsonc pins, its transpiled backend, the tests through the open-abap runtime - in an integrated terminal named "abap2UI5 unit tests", reused from run to run, so the log and the per-method summary arrive live. Invoked on a class (or its test include) only that class runs; from the palette the project's src/ does. An mcp-server checkout under abap2ui5.mcp.reposRoot runs from disk with the same *_HOME variables the MCP registration passes, and an abap2UI5 checkout there is handed over as the framework; without them npx fetches the published package and the runner clones the pinned release into ~/.abap2ui5-mcp - the terminal says so up front, because that first run takes minutes and every later one seconds. The settings that choose the program are the MCP server's restricted ones, and in Restricted Mode the command does not run at all: the tests are the repository's code.

    • "New Project from Template" hands out app-template's named files too. The starter class, its abapGit sidecar and the new ABAP Unit test include (src/<class>.clas.testclasses.abap, a test double for z2ui5_if_client driving main( )), .abapgit.xml and package.devc.xml come out of the app-template snapshot and are renamed the way the template's own template.json describes - the sidecar carries WITH_UNIT_TESTS, the include names the chosen class. The scaffold used to write those files itself and a project from the IDE had no test. Because that test asserts on the template's starter class, the project wizard no longer offers the gallery pick; "New App from Template" keeps it.

    • A warning when the framework pin is older than the linter assumes. The bundled linter now states which abap2UI5 release its rules assume, and the extension compares the "branch" of the abap2UI5 dependency in an open abaplint.jsonc against it: a pin below that minimum gets a warning on the branch line naming the pin, the minimum and the remedy (bump the pin, run npm run check), on open and on save. The abap2UI5 output channel says at activation which release line the bundled linter understands and which UI5 snapshot it carries ("Show MCP Status" repeats the line) - or that the bundled linter ships no such record yet, in which case nothing is compared.

    • Quick fix for event-without-handler: "Add a WHEN branch". The lightbulb on a raised event nothing handles now offers to write the handler branch into the class's CASE client->get_event( ) (or CASE client->get( )-event) - before WHEN OTHERS. when there is one, otherwise before ENDCASE., indented like the neighbouring branches and in their quote and keyword case, with a " handle NAME placeholder line. The name is spelt the way the view raises it, because get_event( ) compares letter for letter. A class without such a CASE gets no offer - where a handler belongs in an IF-shaped dispatcher would be a guess.

    • New command "Generate Mock Data for This App" (abap2ui5.generateMock, in the editor's abap2UI5 menu and the apps tree). It writes the <class>.mock.json that Preview View (No System) and the linter's --screenshot read, from the model shape the linter derives out of the class: a readable sample per string, 0, false, two example rows per table, nested structures filled recursively. It asks before replacing an existing file, opens the result beside the class, and names the roots typed outside the class (a DDIC structure) that it had to leave empty. For a class opened through ADT there is no "beside", so the skeleton opens as an untitled document to save into the workspace.

    • New command "Apply the Model Document to the Running App" (abap2ui5.applyModel, also in Preview Actions). The { } button dumps the running app's model, the pin restores a captured model after a reload

      • this is the direction that was missing: on the dump it opens an editable copy; on that JSON it pushes the values into the running app through the same restore path the pin uses, so a table can be filled or a flag flipped without changing ABAP. Only the class's own model paths travel (matched case-blind, framework state and unknown keys are dropped and named), and the app's class has to be open in the editor for the paths to be known.
    • New snippet z2ui5test: an ABAP Unit skeleton for the *.clas.testclasses.abap include - a ltd_client test double implementing z2ui5_if_client partially (answers check_on_init / check_on_navigated / check_on_event / get_event from attributes, records the displayed view XML and every toast) and a ltcl_app test class with one test that sets an event, runs main( ) and asserts the toast. Like every shipped snippet it is held to the bundled linter.

  4. v0.28.0

    Other 44

    Notes

    A review round: every module read against the linter it ships and against the API contracts it relies on. Bug fixes throughout, no new commands.

    • The bundled property gate reports what the CLI reports, for three more rules. absent-boolean-overrides-default never fired in the editor: the gate handed the linter's ABAP rules the enum-typed fields of a bound table but not the boolean ones whose default is true, so a row that omits iconInset was red in CI and clean here. A class that builds a view and never displays it - or builds its views in helper methods the reconstruction cannot follow - answered "nothing to check" in the editor while CI reported view-never-displayed, the flow rules and the ABAP hygiene rules for it; the ABAP-side rules now run over such a class too, and "nothing to check" is only said when there is indeed no finding. The parity test that holds the gate to the linter's own pipeline covers all three with the linter's own fixtures.

    • The lightbulb offers every fix abap2ui5lint --fix applies. The did-you-mean corrections (a misspelt control, property, aggregation, enum value or event parameter) and the deletion of a json = abap_true on a scalar property were attached by the CLI only - the quick fix, "fix all", the Autofix code lens and "Fix Workspace" saw the finding but no fix, in ABAP and in XML views alike. The parity test now compares the fixes as well, so a fix cannot go missing on one side again.

    • "Suppress on this line" in an XML view now works for an attribute inside a multi-line start tag. The directive was written above the tag's < line, but the linter records the finding on the attribute's own line and reads directives per line - so the comment was placed correctly and suppressed nothing. Such a finding now gets an abap2ui5lint-disable <rule> / abap2ui5lint-enable pair around the whole tag, which the linter honours; a tag on one line keeps disable-next-line. Both are proven against the bundled linter.

    • "Check Workspace", "Fix Workspace" and "Update Baseline" look at exactly the files the CLI collects. The sweep used to take every *.abap that calls the builder - including *.clas.testclasses.abap, *.clas.locals_imp.abap and reports the CLI never looks at - and ignored the config's ignore patterns and dot-directories. A baseline rebuilt from the editor could therefore carry entries CI fails as stale. The sweep now follows the CLI's collection rule (*.clas.abap and view/fragment XML, no node_modules, no dot-entries, the config's ignore honoured, directories included), and the baseline rebuild applies the same rule once more.

    • On vscode.dev, enum-value-too-new fires. The web build's snapshot loader attached the enum table and the UI5 version the way the linter does, but not the per-value @since table the rule reads; the hidden tables are now held to the linter's own loader by a test.

    • On vscode.dev, abap2ui5lint.jsonc is read the way the CLI reads it. The web build parsed the file as plain JSONC: an unknown key or rule id the CLI refuses was accepted, "distribution": "OpenUI5" was not recognised (which turned sapui5-only-control from an error into a hint) and a numeric ui5 stayed a number. The linter's own parseConfig validates and normalises it now. An extends cannot be followed in the browser host and is said so in the output channel instead of being dropped silently.

    • Workspace fixes land on the right character in files with a byte-order mark. The sweep read files from disk with the mark kept, the editor's document has none, so every fix in such a file was one character off. The sweep decodes like the live check does; as a consequence the sweep no longer reports byte-order-mark for a file on disk - the live check never did.

    • abap2ui5.viewCheck.distribution can be left undecided. The setting used to default to sapui5, which silenced sapui5-only-control in every workspace that never thought about the distribution - while a configless abap2ui5lint run reports the control as a hint. The default is now empty, meaning "not decided", and the gate answers as the linter does: a hint, and the cue to write the distribution into abap2ui5lint.jsonc. sapui5 and openui5 behave as before.

    • A repository with render: false no longer hears "view check passed" for a render gate that did not run. The render gate was started regardless of the config, came back with an empty report and read as a pass; it is now not started, and the message says "render gate off by config". A rules['render-error'] entry with exclude patterns is applied against the real file's path (the CLI had matched it against the scratch copy in the temp directory, where it matched nothing), and its severity reaches the Problems panel.

    • A misspelt severity in abap2ui5.viewCheck.rules no longer shows as an error. "some-rule": "critical" is not a severity the linter knows; it used to render every such finding as Error and is shown as Information now.

    • A change to a config named in an extends chain is picked up at once. The repo config's cache watched the mtime of the discovered file only, so an edit to the base config it extends changed nothing in the editor until the extending file was touched; every file in the chain is watched now.

    • Changing a setting or a config file re-checked every open document twice; once is enough.

    • The { } model button works for a namespace class. /UI2/CL_APP starts with a slash, the virtual document's path therefore started with two, and the URI validator refused it - the button threw into the host log and did visibly nothing. The path uses the file-safe stem now; the raw name stays in the header comment.

    • Reloading and revealing an app tab no longer moves it. reveal( ) MOVES a shown panel to the column it is given, and "Beside" is relative to the active group - with three groups every F9 dragged the app tab from group 3 to group 2, and with the tab itself active it opened a fourth. An existing tab is revealed where it is; "Beside" is where a NEW tab opens.

    • Focus returns to the source only when there is one. A start from Recent, the welcome view, the system search or MCP has no editor, and the previous F9's document came back into focus - reopened, even when it had been closed since. Such a start forgets the remembered source, and a closed document is never reopened.

    • The XML preview no longer freezes after a while. VS Code drops a hidden virtual document after some minutes and asks for it again when the tab comes back; the preview read that drop as "tab closed" and stopped following the class for good. The open tabs decide now, and being asked for the content means the preview is open.

    • A theme or language switch keeps the activation watch running. The preview reloads the version the server already has; nothing about the server changed, so a watch waiting behind the "not activated" badge keeps waiting instead of being cancelled.

    • No live token in the output channel, no logon parameters in tooltips. A runtime error UI5 reports quotes the page URL - proxy origin and capability token included - and it went into the channel users paste into issues verbatim; it is redacted like the generated report. The full launch URL in the status-bar tooltip and the toolbar tooltip is shown without sap-user/sap-password.

    • release.yml accepts an annotated tag. The retry check compared the tag OBJECT's hash with the commit and refused a workflow_dispatch retry with "already released from commit"; it reads the peeled ref first.

    • manifest.test.ts checks two more promises: every viewItem == … clause names a contextValue the code sets, and every file the manifest points at - the icons, the walkthrough pages - exists.

    • Removing an attribute in the Control Properties view no longer takes its neighbour with it. When two a( ) calls shared a line, removing the second one cut the whole line - the first attribute included, and in the last line of a chain everything but the closing ).. The edit now cuts exactly the call it was asked to remove, and keeps the chain balanced.

    • "Add attribute" works on the last control of a chain. Its block ends with … ). on the attribute's own line, which the property editor read as "not chain style" and refused - on the final control of every chain, in all five templates. The new line now goes in front of that )., in the chain's own layout. A value continued over && lines keeps its continuation lines together.

    • Renaming a bound attribute writes the binding path the framework derives. abap2UI5 addresses DATA mv_title as {/MV_TITLE} - the name upper-cased - and F2 wrote the new name into the path as typed: {/mv_header}, a path that binds to nothing, which is the silently empty wire the rename exists to prevent. The identifier is written as typed, the path segment upper-cased.

    • F2 refuses a field of a DATA: BEGIN OF … END OF structure. Its binding path is nested ({/MS_DATA/TITLE}), which the rename deliberately leaves alone - so accepting the field renamed its declaration, every same-named TYPES field and ls_other-title, and left the wire behind. The structure itself stays renameable, path included.

    • An abbreviation expanded inside a chain closes the containers it opens. Panel>content>Button expanded mid-chain used to leave Panel and content open, so the line below the cursor - written for the Page - became a child of content. The expansion now ends with the end( ) calls the next line's leading ) completes.

    • F12 on client->view_display( ) no longer jumps to the class's own view_display. Go to Definition looked at the method name alone, and every template declares a method of that name. A call on any receiver other than me-> is left to the ABAP extension.

    • The navigation map follows CAST z2ui5_if_app( NEW zcl_x( ) ) to zcl_x. The first Z-name in the call - the interface the result is cast to - used to be drawn as the target.

    • BEGIN OF ENUM and BEGIN OF MESH declare their type, not a type called ENUM - which is what the roundtrip-cost annotation and F2 read.

    • A class shown in a diff is not a second class. The revision side of a git: diff (and GitLens', the pull-request extensions' and output channels' read-only views) has the ABAP language id too, and entered the source scan as a duplicate: a second row in the apps tree, and an old revision that could shadow the class's inheritance entry. Those schemes are excluded; ADT's and every other virtual scheme keep working.

    • Converting XML reports an unquoted attribute. enabled=true is not XML and was dropped without a word; the conversion now says so, like it does for text content and mismatched tags.

    • Colour swatches follow the builder's ownership rule. An attribute written after end( ) belongs to the container just closed - the rule completion and the view check already applied - not to the last control written above it, so a container's colour property gets its swatch even when the container has children.

    • Extract to View Method accepts a name starting with _, as ABAP does (the framework's own _bind and _event start that way); the input box and the refusal share one rule instead of two copies.

    • The property editor never reads a value across a line break (an ABAP literal ends at the end of its line), and a CLASS … DEFINITION written inside a multi-line string template no longer names the class for the CodeLens, F9 and the inheritance lookup.

    • A system with an IPv6 address works. A launch URL such as https://[fd00::10]:44300/... failed every request with "the hostname does not resolve (DNS)": the brackets of the address travelled into the name lookup. The preview, the ADT lookups and WebSocket upgrades now connect to the address itself.

    • A launch URL typed without its scheme is refused where it is typed. host:44300/sap/bc/z2ui5?app_start={class} parses as a URL - with the scheme host: - so it was accepted, the credentials were stored under the origin "null" ("SAP User for null"), and the launch then failed with "Invalid URL". A template has to be http or https now.

    • A wrong password no longer lets a WebSocket-using app hammer the system. An app that reopens its WebSocket after the system refused the logon sent one failed logon per attempt - the burst that locks an account - and the offer to re-enter the credentials never came, because the refusal was not reported. The upgrade path now trips the same breaker as every other request and reports the 401.

    • WebSocket tunnels are cleaned up when the app gives up first. A client that hung up before the system answered left both ends of the pending upgrade open until the proxy stopped.

    • The proxy is stricter about what it forwards and who may ask. An absolute-form request (GET http://127.0.0.1:<port>/...) used to be forwarded to the system verbatim, token segment included; it is refused. A request authorized only by the proxy's cookie is accepted only from the page the cookie was planted for - a cross-site <img>, iframe or form on another local port is refused, told apart by the browser's own Sec-Fetch-Site. And the Referer of a page loaded through a one-shot screenshot URL is rewritten to the system's origin like every other, instead of carrying the one-shot token on to the system.

    • System cookies scoped to a path work through the proxy. A cookie the system set with Path=/sap/bc/z2ui5 was never sent back, because the proxied requests live under /__abap2ui5/<token>/...; the path is rewritten to /, on pages and on WebSocket handshakes alike. A root-relative redirect (Location: /sap/bc/...) now lands behind the token too, rather than on the cookie alone.

    • The system MCP server ignores browsers. A request carrying an Origin header - a page made it, not an MCP client - is answered 404, and a POST whose body is not declared application/json gets 415, so a cross-site "simple" POST can no longer reach a tool.

    • Screenshots: unique file names, no credentials on the command line. Two shots within one second no longer overwrite each other (the name carries milliseconds and a counter), and a launch URL carrying sap-user or sap-password has them stripped before the page URL is handed to Chromium

      • the proxy injects the credentials anyway.
    • Class descriptions from the system show &, < and quotes correctly in "Run an App from the System"; they arrived entity-escaped (&amp;) and were shown that way.

    • A pasted SAP user is trimmed before it is stored, so a trailing space cannot turn every logon into a failure until the credentials are reset.

    • "Preview View (No System)" survives an empty viewCheck.command. Set to "", the checker start threw instead of reporting that nothing could be started; it is reported like any other failed start now, and a taskkill that cannot start on Windows no longer surfaces as an uncaught error.

  5. v0.27.1

    Other 3

    Notes

    Small fixes, and the linter's newest rules.

    • A new project's npm test runs again. app-template grew a check:all script that chains through its check:pin — a script that reads a file out of the template's own scripts/ directory, which a scaffolded project does not get and which "New Project from Template" therefore does not write. The scaffold copied the chain verbatim, so a new project shipped two scripts (check:all and the test that calls it) that existed and died with "missing script". It now takes the links to a dropped script out of the commands that survive, and drops a command that was nothing else.
    • The bundled view check runs the linter's current rules — thirteen more than the last release. Among them the flow rules that read a method's statement sequence (a popup rebuilt on every roundtrip, a display behind a nav_app_call, the same slot displayed twice), an event raised in a spelling its handler does not have, a library SAP deprecated whole, a DELETE inside the LOOP that reads the table, and the abapGit round-trip family (BOM, CRLF, trailing whitespace, a missing final newline). Eight closed-set rules now name the one candidate a misspelling can only have meant and offer a Quick Fix that writes it.
    • client-> hover and completion match the framework again: the bundled z2ui5_if_client reference is back in sync with the interface, including the documentation message_box_display gained.
  6. v0.27.0

    Other 8

    Notes

    More of the extension in the browser, and a faster editor everywhere.

    • Three more features work on vscode.dev, github.dev and browser-based Business Application Studio: the App Navigation Map, the Control Properties view and the abap2UI5 Findings tree now run in the web host too. The findings tree fills from the web view check; only "Add to the Baseline" stays desktop-only (a baseline is a file on disk) and says so instead of failing.
    • Less work per keystroke. The view check and the Autofix CodeLens now reuse the reconstruction the language features already computed, instead of parsing the class a second time on every pause and every lens pass.
    • "Check All Views in the Workspace" is faster on large repositories: the file reads run concurrently ahead of the checks, and the progress notification updates in batches instead of per file. Results and their order are unchanged.
    • Lower memory footprint in big workspaces: the app-class index (the one behind F9 and the apps tree recognising inherited z2ui5_if_app) keeps two facts per class instead of every class's full source, and the inline roundtrip-cost annotation bounds its mock-file cache.
    • Faster window startup: the extension no longer activates in every window (onStartupFinished). It activates when ABAP or view XML is around — and for MCP clients VS Code activates it on demand through the MCP provider contribution, so agents see the abap2UI5 servers exactly as before.
    • Cleaner packaging: the production build now cleans its output directories first, so a locally built .vsix can no longer ship stale files left behind by earlier dev or test builds.
    • A settings reference in the README, generated from the manifest so it cannot drift, and an accurate description of the test suite.
    • For the ecosystem: the weekly bump workflows can now be fired by the upstream repositories on merge (repository_dispatch), so a new linter rule or template change can reach the editor the same day.
  7. v0.26.0

    Other 11

    Notes

    An audit pass: five reviews over the whole extension produced a list of defects, and this closes it. Most of these you will notice as things that stop going wrong.

    • Credentials stay out of the logs. A launch URL carrying sap-user or sap-password used to reach the "abap2UI5 Traffic" channel — and the traffic an MCP agent can read — in full. Both are redacted now. Screenshots authorize with a token that is retired the moment it is used, instead of one that sat in the browser's command line for the life of the process.
    • Reload on activation survives a wrong password. A single 401 used to switch the activation watch off for the rest of the window, silently: you re-entered your credentials, everything else recovered, and the preview simply never reloaded again until you reopened the window.
    • F9 and the CodeLens follow the branch you switch to. Classes that arrive through git pull or a branch switch are picked up now, so an app that inherits its z2ui5_if_app from a base class stops going quiet after a checkout.
    • The view check no longer overstates itself. "View check passed" is only said when the render gate actually reported; a timeout, a crash or an unreadable report says so. Installing the render gate after a failed start works without reloading the window, and pointing mcp.reposRoot at a local linter checkout is noticed the same way the other settings are.
    • Findings stay honest in the background. Turning a rule off, rebuilding the baseline or pulling a changed abap2ui5lint.jsonc now re-checks every open file, not just the visible ones, so a background tab cannot keep showing findings the repository has waived. On vscode.dev the live check and the workspace sweep finally agree on which files a config excludes, and editing while a workspace check runs no longer wipes the squiggles it just produced.
    • The editor keeps up while you type. The ABAP scan behind completion, hover, CodeLens, colours and the inline annotations runs once per edit instead of six to eight times, and the apps tree stops re-reading the workspace every time you save or click one of its entries. Large classes and large workspaces are where you will feel it.
    • Two new ways to follow a wire. Control ids complete inside set_focus( ), by_id = and control_by_id( ) — the literals where a typo used to fail silently — and putting the cursor on an id or an event name highlights its other end.
    • Renaming an attribute rejects a name that would not compile. F2 used to accept mv-title and rewrite the declaration and every use into ABAP the system refuses.
    • The property editor edits the control you are looking at. An edit sent while the form was moving to another control could land on the wrong one.
    • The wizards say what went wrong. "New App from Template" no longer ends in silence in a read-only editor, and a failed "New Project from Template" names the file it could not write and how much it had created, instead of leaving a half-written folder that the next attempt refuses.
    • Turning the MCP system server off really stops it, including clients that were already connected, and a malformed request from one MCP client no longer takes the rest of a batch down with it.
  8. v0.25.1

    Other 7

    Notes

    A dedicated polish pass: 138 small improvements, none of them a new subsystem, all of them the kind of detail you notice daily.

    • Messages act, not just inform. "Show Log", "Show Problems", "Open Baseline", "Open abap2ui5lint.jsonc" and "Set Launch URL" buttons appear on the messages that used to just point somewhere; the invalid-launch-URL message quotes the offending template; the screenshot toast names the file; proper pluralization everywhere ("1 finding", "3 findings" - never "1 fix(es)"); button labels, picker titles and command titles follow one consistent style, and every command now carries the abap2UI5 category instead of a hand-written title prefix.
    • The preview remembers more. The device width survives closing the preview, "Save As…" starts in the folder you last picked, screenshots are pruned to the newest 20 instead of accumulating forever, and additional logon languages can be added to the language picker (abap2ui5.previewLanguages, the counterpart of previewThemes).
    • Waiting has an exit. The connection check runs as a cancellable notification with a 30-second probe deadline (a cold ICF service is no longer misdiagnosed as a network problem), the render-gate install can be cancelled during the Chromium download and no longer freezes the window while deleting an old install, and a failed system search says so in the picker instead of looking like "no matches".
    • Completion got opinionated. Deprecated controls and members sort below their living siblings, enum values keep their declaration order (Default first) and show their type, WHEN completion shows how often each event is raised, typing ( accepts the highlighted client method and opens signature help, and lo_http_client-&gt; no longer gets abap2UI5 hover - only the real client-&gt; does. Signature help works on continuation lines and highlights the right parameter even when names overlap.
    • Findings read better. All obsolete-API rules render strikethrough, "does nothing" findings render faded, quick-fix titles name what they change ("fix obsolete-binder on _bind_edit"), the findings tree shows per-finding severity icons and opens at the exact column, and the web check sweeps fragment.xml files, names the file in its progress and says when it hit its file cap.
    • The tools speak up. The wizard preselects the name part of zcl_my_app, names every conflicting file and the exact invalid character, and opens the starter class instead of reloading the window; converting a Dialog emits popup_display; the navigation map has hover tooltips, a Refresh button and a truncation note; the MCP tools return count/summary lines an agent can branch on; a new Popup-Close snippet completes the popup round trip.
    • Housekeeping: CI cancels superseded runs and every workflow has a timeout; the generator scripts fail fast on stalled fetches; test:grep runs one slice of the suite; the walkthrough no longer references a 🎯 button that doesn't exist; log redaction also covers Authorization headers.
  9. v0.25.0

    Other 35

    Notes

    The result of a full adversarial review of the extension: over sixty bugs fixed, the per-keystroke hot paths measured and cut down, and a round of features that the existing plumbing had almost finished anyway. The highlights, by surface:

    • The preview's badges now act. The "not activated" badge offers Activate directly (reloading only showed the old version - the exact trap the badge warns about), the runtime-error badge jumps to the source line it already knew about (it used to only write it to the log), and when the activation watch gives up after ten minutes it now says so in the preview instead of leaving the badge promising a reload that will never come. The welcome screen offers to relaunch the last app after a window reload, the screenshot button captures at the preview's current device width (desktop/tablet/phone), and the status-bar entry opens a small menu - Reload, move the preview, open in the browser, screenshot, connection check - instead of only reloading. Custom UI5 themes can be added to the theme picker via the new abap2ui5.previewThemes setting.

    • Two previews could end up running the same app. Changing abap2ui5.openMode in the settings (rather than through "Move Preview") and pressing F9 left the old surface alive: every save reloaded the app twice, and closing the leftover tab killed the status bar for the panel that was still showing the app. F9 now reconciles the surfaces the way the move command always did. A launch canceled at the credentials prompt no longer lands in "Recently launched".

    • The render gate installs reliably again. The rolling bundle (viewCheck.rollingBundle) was uninstallable from the second time on - the "content must never change" integrity check applied to the one URL whose content changes by design. A stalled download no longer disables installing for the rest of the session (it times out, can be cancelled, and says what happened), and the new "Update Render Gate" command shows the installed digest next to the pinned linter commit before refreshing.

    • The proxy fails closed, and two windows stop fighting. During the short window while the proxy shuts down, a request without the token cookie was accepted instead of refused (nothing was forwarded - the credentials were already gone - but the gate is now checked first and fails closed, and both the path token and the cookie are compared timing-safe). The auth cookie is now scoped per proxy port, so two VS Code windows pointed at two systems no longer overwrite each other's cookie and blank each other's preview. Stopping or switching systems no longer waits up to two minutes for a hanging request, a failed port bind no longer leaves a half-started proxy that hands out port: undefined, and WebSocket connections are now forwarded - an app using them found the tunnel dead before.

    • Correct credentials could get locked out. The background UI5-version probe ran without the launch URL's sap-client; on systems whose default client rejects the logon it tripped the proxy's 401 breaker with perfectly valid credentials - breaking the running app, prompting for a re-entry, and counting a real failed logon toward the system's lockout, once per F9. The probe now carries the client and can no longer trip the breaker. "Check System Connection" gained a client-mismatch probe that diagnoses exactly this setup, and its TLS classification now recognises the private-CA error codes (UNABLE_TO_GET_ISSUER_CERT*). Credentials migrated from pre-0.14 installs can be deleted again by "Clear Stored SAP Credentials", and adding a system under an already-used name no longer activates the old one.

    • A cancelled check no longer leaks a browser. On macOS and Linux, killing a running checker killed only the wrapper process - the linter and its Chromium kept running (the Windows path always killed the tree). The whole process group dies now, a closed preview panel kills its render instead of letting Chromium finish for nobody, and checker output with umlauts can no longer be corrupted at a chunk boundary.

    • The editor and CI disagree less. Classes on a frozen view builder are reported as frozen-view-builder in the editor (they were "nothing to check" while CI failed them), rules.*.exclude patterns anchored to the repository root now match in the editor too, the suppress quick fix places its directive on the right line in CRLF files (it could land inside a start tag and break the XML), diagnostics are cleared when a file stops being checkable, workspace-check results no longer land on text that changed during the sweep, and rebuilding the baseline in a repository with nested configs no longer writes entries CI would immediately call stale. A changed baseline file (a git pull) now triggers a re-check on desktop, and the web build reacts to settings changes without waiting for a keystroke.

    • Baselines and fixes with more control. "Fix All in Workspace" and "Extract View" open VS Code's refactor preview instead of applying blind, a rule group in the findings view can be baselined as one action, the suppress quick fix has a "with a reason" variant, the findings status-bar item opens the abap2UI5 findings view rather than the generic Problems panel - and "Check All Views in Workspace" now works on vscode.dev and Business Application Studio too.

    • Apps are recognised the way teams actually write them. INTERFACES: if_something, z2ui5_if_app. - the interface anywhere in a chained declaration - is an app now (only the first position was), and a leading CLASS ... DEFINITION DEFERRED. no longer hides a class's superclass, which silently disabled the inheritance lookup for exactly the base-class pattern it exists for.

    • Completion and hover answer for the right control. An attribute written after )->end( ) belongs to the closed container - the builder and the linter always knew, completion and hover now agree instead of offering the inner control's members and then squiggling the accepted offer. client-> hover and completion stay quiet in comments and string literals, go-to-definition on a binding path no longer lands on a commented-out declaration, DATA: BEGIN OF ... blocks no longer annotate BEGIN and END as roundtrip cost, and a > inside a quoted XML attribute no longer kills completion for the rest of the tag.

    • New language smarts: signature help for client-> methods, completion inside WHEN '...' offering the events the view actually raises, a warning lens on an _event( ) no WHEN branch handles, deprecation as an inline annotation (toggle: abap2ui5.inlineDeprecated), completion for xmlns library values, and the default aggregation marked in member completion. Events raised with a nested VALUE #( ) before the name are now found by F2, go-to-definition and the lenses, and WHEN 'A' OR 'B' branches count all their alternatives.

    • F2 on an attribute stays inside its wires. Renaming title no longer rewrites a same-named component inside {/MT_TAB/TITLE} paths or TYPES blocks (and structure components, whose relative bindings F2 cannot track, are honestly not offered for rename any more). Inspect mode finds the builder call for a control inside an aggregation template instead of the first control in the document, and "Extract View" no longer writes a broken class when methods are declared in a chain or the file holds two classes.

    • Converting XML views got sharper. Event handlers become client->_event( \ON_PRESS` )wires with a TODO instead of dead string literals, lines longer than ABAP's 255-character limit are split with&&(they failed the abapGit import before), entity text like& survives the abbreviation round-trip, and Emmet abbreviations learned groups and counters ((Label+Input)*3, Button$*3). The XML preview follows the cursor (the ABAP side highlights the matching XML line), maps findings to the opening tag instead of sometimes the closing one, and the navigation map draws no arrows for commented-out nav_app_call`s - and its arrows are clickable now, jumping to the call.

    • The example search tells the truth. Commented-out chains no longer count as (or rank) examples, the three remote catalogues are fetched in parallel instead of one after another, the corpus walk no longer freezes the extension host, a remote hit opens read-only in the editor instead of bouncing to github.com, and the day cache revalidates with ETags.

    • The MCP surface grew and locked down. New tools: check_view_source (the bundled view check over agent-supplied source), get_traffic (the proxy's recent roundtrip log), and a viewport parameter plus sap-ui-theme support for run_app_on_system. Turning abap2ui5.mcp.system off now actually stops the running server (a connected client kept its access before), its token is compared timing-safe, the servers are registered even in a window without ABAP files, and the new "Show MCP Status" command says what the registration resolved. Screenshots work for namespaced classes (/UI2/CL_...) and the file name can no longer be steered outside the storage folder.

    • Hardening and housekeeping: releases run the test suite before publishing, abap2ui5.systems and abap2ui5.launchUrlTemplate are restricted in untrusted workspaces (a cloned repository could point F9 - and the credential prompt - at its own host), the apps tree notices files changed by a git pull, the .vsix no longer ships package-lock.json, and the per-keystroke paths (live check, code lens, rename, inline annotations, completion docs) each do their expensive work once per document version instead of once per consumer.

    • The icon rules now judge .view.xml files too. An unknown or too-new sap-icon:// name was reported by CI and not by the editor whenever it sat in a view or fragment XML file rather than in an ABAP class - the icon scan was not reachable from the in-process gate. It is now, so both paths judge the same file the same way.

    • Fewer false positives from the view check. A relative binding path under a slot the class element-binds (cs_event-bind_element) has a context at runtime that no static analysis can see. The linter knows that and accepts the path; the editor did not and squiggled it. It now asks the same question, per view document rather than per class.

    • Two more rules reach the editor: the picker whose bound value has no format, and the enum-typed row field left unset on an insert - the second is a runtime error in UI5's strict validation, which takes the binding update and the view down with it.

    • F9 recognises an app that INHERITS z2ui5_if_app. A shared base class carrying the interface and the lifecycle methods, with each app redefining them, is a common way to keep a team's apps uniform - and the extension recognised none of those apps: it read the interface out of the class in front of it, so F9, the "Run"/"Activate & reload" CodeLens, the abap2UI5 Apps tree and the navigation map all stayed silent on the very classes a developer works in every day. The inheritance chain is now followed, over as many levels as it has, using the classes the window can see (the workspace's files plus everything open, so it works against ADT too). A base class this window cannot see still means "not an app" - the same answer as before, rather than a guess. (#81)

    • The view check works again in the browser. On vscode.dev and browser- based BAS every check threw before it produced anything, and the error was swallowed by design, so the whole feature was silently dead: no squiggles, no Problems entries, no completion metadata - with nothing anywhere saying why.

    • The editor reports the findings CI reports. Five rules never fired in the editor although the linter reports them on the same file: unknown-model, json-bind-on-scalar-property, raw-javascript-to-frontend, and the three structural ones that assert at RUNTIME - excess-shut, duplicate-property and attribute-without-element. The icon rules (unknown-icon, icon-too-new, icon-removed) had never fired in the editor at all, and the configured minimum UI5 version now reaches them, so a repository with a higher floor is judged against its own floor.

    • "Fix All Views in the Workspace" no longer corrupts unsaved files. A class that was open with unsaved changes AND on disk was checked against the version on DISK, and the resulting fixes were then applied to the buffer - so every fix after the first difference landed a few characters off, in the middle of a token. Open files are now checked as they stand, and a file edited while the sweep runs is skipped and reported instead of edited blind. The same mismatch had put the workspace check's squiggles on the wrong lines.

    • Format Document agrees with the linter. It worked the chain layout out for itself and was measurably stricter than chain-house-layout: eight of the 637 builder classes in samples-controls would have been re-indented although the rule calls them correct. It now applies the linter's own layout fixes, so formatting and CI cannot disagree.

    • Redirects from the system reach the preview. A Location header that spelled the host in another case, or its port differently, was not rewritten onto the local proxy - the browser then followed it to the system directly, without the injected credentials, and the preview stayed white.

    • Reload-on-activation survives a system switch. One launch against a system whose /sap/bc/adt is closed used to switch the feature off for every other system too, until the window was reloaded.

    • Fewer wrong answers from the language features. A commented-out argument inside a builder call decided which control completion, hover and the property editor were talking about; a doubled quote ( `its fine``) truncated a value, and rewriting it from the property editor corrupted the literal; a commented-outWHENbranch was where Go-to-Definition landed and what F2 renamed;control_by_id mentioned in a comment made the next literal look like a control id. String templates with embedded expressions (|val { get( 'a|b' ) }|`) no longer swallow the rest of the line.

    • "Show Examples for this Control" finds most of the corpus. It matched only tag( n = \Button` )and not the positionaltag( `Button` )`, which is what the XML converter emits and most of what the sample catalogues contain - so common sap.m controls returned no local hits at all. Hits in samples-stack now link to the branch their file is actually on instead of 404ing.

    • The view preview and the screenshot cannot hang the panel any more. Both run the checker with a timeout and kill the whole process tree, as the view check already did; a Windows path with a space in it (C:\Users\John Smith\...) no longer breaks either of them, nor a viewCheck.command pointing at C:\Program Files\nodejs\node.exe.

    • The render gate verifies what it downloads before extracting or running it, and the extension's second local listener (the System MCP server) now refuses a non-loopback Host exactly as the auth proxy does.

    • The preview's toolbar cannot be spoofed by the app it shows. The embedded app could post the host's own messages and rewrite the class name, the system URL shown under it and the reload target.

    • Desktop-only commands are hidden in the browser. The editor-title play button and F9 appeared on vscode.dev, where those commands do not exist, and answered "command not found".

    • The client-> hover links to the published Client API Reference. The hover shows a method's signature and ABAP Doc, but it was a dead end: no way to read on - the parameter tables, the constants, the neighbouring methods of the same group. Every hover now ends with a "Client API Reference" link to the generated page on the documentation site, deep-linked straight to the method's own heading (client->view_display opens at #view-display), so the full reference is one click from the code.

    • "Show Examples for this Control" works without a single clone. The command used to read only the local checkouts under abap2ui5.mcp.reposRoot - and the beginner most in need of an example is exactly the person who has cloned nothing yet, so they got an empty result. Each sample repository without a local checkout is now answered from the catalogue.json it commits at its root, fetched from GitHub and cached for a day: those hits name whole samples - the ports that demonstrate the control first - and open on github.com at the class. A local checkout stays the primary source and always wins for its repository (it is searched line by line and opens in the editor); a failed fetch quietly falls back to the previous behavior. Only when there is no checkout AND no fetched catalogue does the command say so, offering to open the setting or retry the download.

    • "Check System Connection" diagnoses a white preview. The most common first-run failure is a launch URL that is slightly wrong, and its symptom is the least helpful one possible: an empty white frame. The new command probes the configured system the way F9 would - the same URL expansion, the same stored credentials, the same proxy plumbing - and reports step by step where a launch ends: the URL's shape ({class} placeholder, scheme), the host (DNS, port, TLS certificate, VPN), the HTTP status (401/403 with the system's own words and whether basic auth is offered at all, 404 with the SICF hint and the path that failed), and whether a 200 actually is an abap2UI5 bootstrap page rather than a logon form or something else entirely. Each failing step names its fix; the full stepwise report lands in the abap2UI5 output log. The preview's "taking longer than usual" overlay and the getting-started walkthrough offer the check right where the wall is usually hit.

  10. v0.24.4

    Other 2

    Notes
    • A launch URL without a path loads past its first request. (#60) The preview swaps the system's origin for the local proxy's http://127.0.0.1:<port>/__abap2ui5/<token> prefix. For https://host/sap/bc/z2ui5?app_start=X that leaves the token as a directory; for https://host?app_start=X it left the token as the LAST PATH SEGMENT - which a browser drops when resolving every relative url on the page. The UI5 bootstrap and every module were then asked for as /__abap2ui5/<resource>, token gone, nothing loaded - a white preview whose only trace on the system was the initial GET, with the roundtrip POST never arriving. The frame URL is now rebuilt from the parsed launch URL (pathname is never empty), so the token is always followed by / and survives resolution.

      Rebuilding instead of substring-replacing also fixes a quieter miss: a launch URL that never spells its normalised origin verbatim (an uppercase host, an explicit :443) left replace(origin, proxyOrigin) a no-op, and the iframe loaded the system directly - without the credentials only the proxy can inject.

    • The proxy's own cookie now travels from the framed page. The token cookie that authorizes absolute-path requests (/sap/public/...) was planted SameSite=Lax - but the app page sits in an iframe whose top-level document is the vscode-webview:// origin, so every request it makes counts as cross-site and a Lax cookie stays home. It is SameSite=None; Secure now, the same pair the SAP session cookies are already preserved with, and loopback is a trustworthy origin so Chromium accepts it over plain http.

  11. v0.24.3

    Other 1

    Notes
    • The preview is clickable. Twice now this was answered as a handshake problem, and twice the app kept eating every click. It is not a handshake problem. sap/ui/security/FrameOptions blocks the document the moment it finds itself framed - a capture-phase listener that calls preventDefault( ) on every input event - and lifts that block only from _applyState(bRunnable, bParentUnlocked), which needs BOTH flags. The preview can supply bParentUnlocked and never bRunnable:

      • bRunnable needs a same-origin parent, or an allowlist that matches the parent's origin. Ours is vscode-webview://<id> - not the system's, and in nobody's allowlist.
      • the first message from the parent runs _check( ) before the "parent-unlocked" branch, and _check( ) without an allowlist ends in _callback(false).

      So 0.24.1's answer was correct on the wire and still could not win. The proxy now serves the bootstrap with sap-ui-frameOptions="allow" instead, which is defensible exactly here: frame protection stops a FOREIGN page from framing an SAP app to harvest clicks, and the framing page is this extension, loading a url it built itself over loopback behind a capability token.

  12. v0.24.2

    Other 2

    Notes
    • A rejected logon stops at the first request, and says what the system said. One wrong password used to become one failed logon per resource: the proxy puts the same credentials on every request a UI5 page makes, so a single F9 was observed sending eleven 401s within seconds - two of them in the same second. A system with a lockout policy counts every one of them, so a typo could cost the user their account. The proxy now stops asking after the first 401 and answers the remaining requests itself, until credentials are entered again (which every F9 does). The ADT lookups, which run on a timer rather than on a keystroke, stop with it.
    • "HTTP 401" alone was never a diagnosis. It fits a wrong password, a locked user, an expired one, a client that refuses logons, and a system that does not offer basic auth at all - and the extension had nothing else to offer. The rejection now carries the WWW-Authenticate header (a 401 without one is not asking for a password, and no amount of retyping helps) and the system's own sentence, taken from the rejection page and redacted, both in the log and in the message that offers to re-enter the credentials.
  13. v0.24.1

    Other 2

    Notes
    • The render gate works against a system again. 0.24.0 taught the view check to see documents opened through ADT, and then started its checker in the workspace folder of whatever it was checking. For an ADT document that folder is a repotree-v1 route, not a directory - and spawn answers ENOENT for a working directory that is not there exactly as it does for a missing executable, naming the COMMAND in both messages. So it read as "node could not be started", and the remedy offered was to install the render gate: 275 MB, after which the next check failed the same way and offered again. Four rounds is a gigabyte and no working gate.

      The preview never had this - it runs in a scratch directory - which is why the same class photographed fine while the check refused. committedText already guards the same way; this was the one call site that did not.

    • F9 apps react to clicks - this time against the real protocol. 0.24.0 claimed this and did not deliver it: the answer it posted was an invented JSON envelope with a sentinel field, and sap/ui/security/FrameOptions never sends or reads such a thing. Its wire format is two plain strings, and it drops everything else before looking:

      if (oSource === FrameOptions.__self || oSource == null ||
          typeof sData !== "string" ||
          sData.indexOf("SAPFrameProtection*") === -1) { return; }

      So the app asked with SAPFrameProtection*require-origin, the preview replied with an object nobody parsed, and after ten seconds UI5 logged "waiting for a response from parent window" and blocked the frame - the app rendered and then ignored every click, exactly as before. It answers SAPFrameProtection*parent-unlocked now, which is the reply that unlocks (_applyState(false, true)) rather than parent-origin, which only proves the parent is alive.

  14. v0.24.0

    Other 13

    Notes
    • The scaffold hands out the MCP server's new name. abap2UI5/ai-mcp is abap2UI5/mcp-server, and src/data/app-template.json - the snapshot a new project is written from - still carried the old one, so every project created since the rename got an AGENTS.md pointing at a repository that only exists through GitHub's redirect. Regenerated; the same run picked up two script entries the template had added in the meantime. Nothing in CI compares this snapshot to app-template's main on purpose (this repository's build must not go red when another repository merges), which is exactly the window that let it drift - so AGENTS.md now says that out loud instead of claiming the weekly bump is a check. The remaining ai-mcp strings are the deliberate ones: the directory aliases every existing checkout is still found under, and this file's own history.

    • The MCP server comes from npm now. The fallback when there is no local checkout was npx --yes github:abap2UI5/mcp-server: a clone of whatever main held that minute, plus its install, every cold start. It is npx --yes @abap2ui5/mcp-server since that package exists - an immutable tarball of a tested release, and a much shorter first start. Left unpinned on purpose: the server's compatibility is with the corpora it reads, not with this extension, so a version fixed here would invent a coupling and then need an extension release behind every server release.

    • npm run check. The four commands AGENTS.md has always asked for before pushing, under the name every repository in the ecosystem uses for them.

    • One command that writes the bug report for you. abap2UI5: Copy Diagnostics for a Bug Report collects what a diagnosis actually needs and puts it in your clipboard and in an editor tab: every open ABAP document with its uri scheme, whether the check considers it checkable, whether it builds a view, which config governs it and how many findings it carries - plus the versions, the ABAP extensions installed alongside, the settings you changed, the render gate's state, and the last 400 log lines.

      The scheme is the point. A window can hold a checked-out repository and classes opened straight from a system through ADT at the same time, and almost every difference in behaviour between the two comes down to which of them a document is - invisible in a screenshot, and until now invisible in the log too. The check's own log lines carry it now, along with the config that governed each one.

      Hostnames, credentials in urls, sap-user style parameters and the proxy's own token are removed before you see it; the report opens in a tab so you can read it before pasting rather than taking that on trust. Ports survive, since "which port did it even try" is usually part of the answer.

    • The system server's run_app is now run_app_on_system. Both MCP servers this extension registers live in one window, and the abap2UI5 server (ai-mcp) already had a run_app — a build of the transpiled sandbox, no system involved. This one runs a class on a real system through the auth proxy. One name for the two of them left the agent guessing which it was calling; the name now says.

    • Apps you launch with F9 react to clicks again. A system configured with sap-ui-frameOptions=trusted lets its app run in an iframe only after asking the embedding window for permission. Nothing answered, so UI5 waited ten seconds and then blocked the frame: the app rendered and then ignored every click, with one line in the console to say why. The preview is the window that embedded it — it answers now.

    • The systemless preview can take a picture. Preview View (No System) shipped against a checker option that no published bundle contained, so the render gate installed perfectly and then refused the only thing it was installed for. Reinstalling fetched the same bundle again, which is why the advice to do so was a loop; the message says what actually helps, and the pinned checker is now one that knows the option.

    • Working straight against a system, without a checked-out repository. Six surfaces asked what files exist, which answers nothing when a class is a document opened through ADT rather than a file on disk: the app list and the findings tree stayed empty, the navigation map drew nothing, Check All Views reported "no checkable files", Ctrl+T found no methods, and the preview never found its mock data. All of them now see the open documents too — and the findings tree had been throwing away findings the check was already producing. What cannot be enumerated that way is said out loud rather than reported as an empty workspace.

    • Which view-check rules are active is now a setting. A repository's abap2ui5lint.jsonc could always switch a rule off or move its severity, but that file is the project's shared answer and needs one to exist. abap2ui5.viewCheck.rules says the same thing per person and per workspace: a rule id maps to false, to a severity, or to { severity, exclude }.

      "abap2ui5.viewCheck.rules": {
        "unknown-binding-path": false,
        "control-too-new": "warning"
      }

      The repository still wins for every rule it names — editor and CI disagreeing about the same file is the one thing this must not cause — and the setting decides the rest. Since nobody knows rule ids by heart, the lightbulb on a finding now offers turn off in this workspace, which writes the id for you and offers to undo it.

    • Right-click has an abap2UI5 menu in ABAP classes and view XML: run and activate, the three ways to look at a view, check and fix, and the three editing actions — one entry rather than ten loose ones.

    • Fixes to what the reconstructed XML view points at. Switching to another class made the preview follow it before the re-render landed, and a jump from an XML line during that window used the previous class's offsets against the new source - landing somewhere arbitrary in it. It refuses instead, until the render it belongs to exists. And findings that cannot be recomputed on a half-typed buffer are now cleared rather than left pinned to lines the re-render has already moved.

    • Two things that failed silently now say so. Picking an app from the system search and having nothing happen was a possible outcome: starting it talks to a system, and a refusal had nowhere to land. Same for the property editor, where an edit that did not apply looked exactly like one that did - the field showed the new value and the class still said the old one.

    • Two lists that explain themselves. An empty tree with no explanation is indistinguishable from a broken one. The app list says what it collects and offers the two commands that fill it; the findings tree points at the workspace check. The app list also carries the system search in its title bar — the rest of the app landscape lives there, and looking for it started in the palette — and a tree item can hand you its class name to paste.

  15. v0.23.0

    Other 24

    Notes
    • "New Project from Template" now hands out the real template. The command wrote its own hand-typed copy of abap2UI5/app-template's files, and that copy had drifted: it installed @abap2ui5/linter 0.1.1 while the ecosystem was on 0.2.1, it pinned no framework release at all — so abaplint resolved abap2UI5's moving default branch and a rename over there could turn into a red build in your brand-new project — it left out the chain-house-layout rule the guide tells you a gate applies, and it wrote no AGENTS.md, so an assistant opening the new project found nothing to read.

      A project created from the IDE now gets app-template's own abaplint.jsonc, abap2ui5lint.jsonc, AGENTS.md (the complete app-building guide), .claude/settings.json permission allowlist, .gitattributes, .gitignore and Dependabot config, the pinned versions from its package.json, and a CI workflow running the abap2UI5-linter's own GitHub Action at the same pin the template uses. It is still generated rather than cloned — the command works in vscode.dev, where there is no git — but from a snapshot that is regenerated weekly and gated by the test suite, so it cannot quietly drift again.

    • An opt-in rule your abap2ui5lint.jsonc switches on is now reported in the editor too. chain-house-layout — the builder-chain layout rule abap2UI5/app-template enables — was never produced by the in-editor gate, whatever your config said, so CI flagged a drifted chain and the editor stayed silent about it. That was the last piece of the editor/CI split. The first thing it turns up is in this extension's own gallery: the empty template's chain was laid out flat, and it is now indented per level like the rest.

    • Fixes from a pass over the whole extension. Nothing here is new behaviour; all of it is behaviour that was supposed to work already.

      The preview survives a system that drops a connection. A SAP system resetting the socket while an answer was still arriving took the whole extension host down with it. Loads the preview cancels (every reload cancels a few) now stop the request on the system too, instead of leaving it working on an answer nobody is waiting for. Session cookies from systems configured for cross-site use are no longer dropped, a logon page in a single-byte charset keeps its umlauts, and the proxy's own token stays out of the output channels — it used to ride along in the traffic log, where pasting the log into an issue handed over a working authorized url.

      The render gate cannot pile up any more. It had no time limit and was never killed: on a slow line every save started another one and none of them ever went away. It now gives up after three minutes, or as soon as you have moved on from what it was rendering. On Windows it also works at all when your user name has a space in it — the scratch file arrived as two arguments and the gate answered "no JSON" for good — and viewCheck.command / mcp.command accept a quoted program path.

      Completion, hover and the outline read tag( `Button` ). The positional spelling is what "Convert XML View to Builder Chain" writes and what the samples use, and only half the extension understood it: converted code got no completions, and the outline showed every element as ?.

      F2 rename finds both ends of a wire again. One apostrophe in one comment ("don't") used to hide every control id after it, so the rename went through on one end and left the other pointing at the old name — silently, which is the whole defect the rename exists to prevent. The formatter is no longer fooled by a commented-out )->end( ) either, and F2 on a type name no longer offers to rewrite every TYPE string in the class.

      Checks stop showing what is no longer true. Disabling a rule in abap2ui5lint.jsonc used to leave the quick fix offering findings whose squiggles had already gone. "Check All Views in the Workspace" clears files that were fixed or deleted since the last run, checks each file once instead of twice, and says it was cancelled instead of reporting a whole-workspace result for part of one.

      The app keeps running when you collapse the panel. Ctrl+J used to reload it from scratch, losing the server session and any page it had navigated to. Changing the theme or language no longer leaves the toolbar and the app disagreeing about which url is loaded, and hiding the preview view no longer breaks the next save.

      On vscode.dev, only what actually works is offered. The App Preview, the Apps tree and the Findings tree appeared there with nothing behind them and loaded forever; the web check now also honours viewCheck.live and viewCheck.onSave and notices a baseline file that changed.

      Typing is cheaper. Inline annotations are debounced and no longer repaint when an unrelated extension touches its own diagnostics, completion reads the document once instead of twice, and the member and config lookups behind it are cached — the work per keystroke was several times what it needed to be on a long view.

      Also: the last attribute of a chain can be removed in the property editor, a namespaced class shows up on the navigation map, two systems with the same name can both be selected, resetting credentials reaches systems removed from the settings, and re-running "Install Render Gate" without a network no longer deletes the gate you already had.

    • Three things the editor now says about a line unasked. One decoration pass, three ideas borrowed from the extensions that made them popular, all three fed by data this extension already ships.

      The finding, at the end of its line — the Error Lens idea. A builder chain is forty lines long and the Problems panel is somewhere else; the squiggle is where you are looking and the message was not. abap2ui5.inlineFindings takes problems (the default), all or off; hints are out by default because "worth knowing, never wrong by itself" is a lot of grey text in a long chain.

      The UI5 version something arrived in — the Version Lens idea — warned when it is above your floor. Does my system have this yet? is the permanent abap2UI5 question and the answer has been sitting in the bundled metadata all along, arriving only as a finding once the floor was already crossed.

      What a PUBLIC attribute costs per roundtrip — the Import Cost idea. abap2UI5 serializes every public attribute into the model on every single roundtrip; the size is measured from the class's own seeds or from the <class>.mock.json, and an attribute nothing is known about still says that it is sent. A line that already carries a finding gets neither, because there the defect is what matters.

    • Emmet for builder chains. Page>content>Button*3 expands to the chain that builds it — > child, + sibling, *n repeat, #id, [a=b], {text}. Inside an existing chain the expansion continues it ()->ele( … ), no factory, no view_display( )); outside one it scaffolds the whole statement. > binds tighter than + exactly as in Emmet, so Page>content>Button+Input puts both controls in the content aggregation — the obvious implementation, splitting on + first, makes the Input a sibling of the Page, which reads the same and builds a different view. The chain itself is written by the same emitter Convert XML View uses, so there is one opinion about the house layout rather than two.

    • The apps of this workspace, as a list. Every toolchain extension has one — npm scripts, Docker, Maven, Jest all put the things of the project in a tree with a play button — and abap2UI5 had none: F9 works on the class you happen to have open, and Run a Recently Launched App only knows what this window already ran. Opening a repository with thirty apps in it, nothing said which thirty. The abap2UI5 Apps view lists every class implementing z2ui5_if_app with run, preview and check on the item.

    • F2 shows the refactor preview. The rename crosses from ABAP into view literals on the strength of where a string stands, which is the one refactoring here worth looking at before it happens: every occurrence is listed with its line, and nothing changes until you say so. abap2ui5.renamePreview switches it off for anyone who would rather just rename.

    • A findings view, grouped by rule. The Problems panel lists findings per file, among every other contributor's — which answers "what is wrong in this file". The new abap2UI5 Findings view in the Explorer answers the other question: twelve unknown-binding-path across three classes are ONE decision (fix, waive, baseline), and per file they look like twelve unrelated problems. Rules come worst-severity-first and then by count, so the top of the list is where the next decision is; expanding one lists every occurrence, clicking it opens the line, and the title bar carries the workspace check and the workspace fix. It reads the published diagnostics rather than checking again, so it costs nothing and cannot disagree with the squiggles.

    • Extract to View Method. A view built with the builder is one statement, and a real screen is a long one; abap2UI5's answer is the handle idiom, a helper method taking the builder and returning it, which the linter follows so an extracted section stays reconstructable and checked. Doing it by hand means splitting one statement without breaking its parenthesis balance, inventing the parameter and remembering the declaration in the right section. The command computes all three: the head is captured into a handle (keeping its own name if it has one), the tail becomes result = box->… inside a new method, and the call takes its place. It extracts a tail — a middle section would have to hand the handle back for the rest of the chain to continue from, which is neither the corpus idiom nor readable — and it refuses rather than guesses: a cursor outside a chain, a name already taken and a chain's own first call each come back with a sentence saying why.

    • The preview shows data, several devices, and what changed. Three things that turned the systemless preview from a nice picture into the panel you leave open.

      Preview data. The model behind a picture is derived from what the class seeds literally, so a table filled by a SELECT photographed as No data — which is most real apps, and made the preview least useful exactly where layout matters most. A zcl_app.mock.json next to the class now fills it, merged over the derived model so two lines are enough to fill one table. The caption says which of the two the picture used: an empty table is a correct rendering of a model with no rows, and that has to be distinguishable from a broken binding.

      A device matrix. abap2ui5.viewPreview.viewport takes a list — 390x844,1280x900 — and renders every viewport in ONE browser session, side by side in the panel. The launch and the UI5 boot cost more than the renders, so the second device is nearly free, and responsive layout is precisely what nobody has in their head.

      Before and after. "Preview View - Compare with HEAD" renders the committed version of the file next to the working tree, from the same data. It answers the question no linter can: did my change do what I meant to the view? A file git does not know says so rather than comparing against nothing.

    • The panel tab says what is in it. With the default openMode of tab the app preview goes to an editor tab, so the bottom panel only ever shows the Control Properties form — under a tab labelled just abap2UI5, which named the extension rather than the thing on screen. It is abap2UI5 Control View now. (VS Code capitalises the first letter of a panel title itself, so it renders as Abap2UI5 Control View whatever the manifest says.)

    • Preview the view without a system. An abap2UI5 view exists at runtime and nowhere else, so looking at one has meant a system: activate the class, launch the app, wait for the roundtrip — a long way to go to find out that a column is in the wrong order. "abap2UI5: Preview View (No System)" renders what the class builds and puts the picture beside it. No system, no transport, no activation, no launch URL.

      It is the render gate turned around. That gate has been loading exactly this view in a real browser all along to decide whether it survives creation; the linter can now keep it standing and photograph it instead of throwing it away, and this command is that, wired to a panel: the reconstruction the view check validates, seeded with the model derived from the class's own TYPES/DATA, in the theme (abap2ui5.viewPreview.theme) and viewport (abap2ui5.viewPreview.viewport — 390x844 for a phone) you pick. It re-renders on save, shows every view a class builds, and keeps the last picture up while the next one is taken. Render errors appear above the picture rather than instead of it: a view with one broken binding still comes up, and the half that rendered is the part worth seeing.

      It needs the render gate installed — the same runtime, one click — and it is not the app: nothing round-trips and no event reaches ABAP. That is what F9 is for.

    • F2 renames the strings the app is wired together with. An abap2UI5 app joins its two halves with literals: a control is a( n = idv =TABLE ) in the view and TABLE again in a CONTROL_BY_ID wire; an attribute is mv_title in the class and {/MV_TITLE} in the view. Nothing in ABAP or in UI5 connects those ends — to the compiler a string is a string — so renaming one of them has been a grep, and missing one is silent: a wire that addresses nothing does nothing at runtime, not even a console line, and a binding path that resolves to nothing renders empty. F2 already did this for event names; it now does it for control ids (the id attribute plus CONTROL_BY_ID, SET_FOCUS, SCROLL_TO, SCROLL_INTO_VIEW, KEYBOARD_SET_MODE and popover_display( by_id = … )) and for bound attributes (the ABAP name and every binding path that resolves to it, including the root segment of a path into a table row).

      What makes it safe is that position decides what a literal is, never its text: the setBusy sitting next to the id in the same wire is an argument and stays put, and a name the class does not declare offers no rename at all.

    • The browser build reads the repository's abap2ui5lint.jsonc. It could not before, for a reason that was true of the reading and not of the file: discovery goes through fs, which a browser extension host does not have. So vscode.dev and github.dev checked against the VS Code settings alone and quietly disagreed with CI about the UI5 floor, the distribution, the allow list and every rule severity — the one divergence the web build knowingly kept. The configs are now read through the editor's own filesystem API, the nearest one above a file governs it (what the CLI's upward walk decides, answered against the flat list a workspace search returns), and a baseline the config names is applied too. What a config MEANS is now one piece of code for both builds, because two builds disagreeing about precedence is the same defect in a different place.

    • Examples for the control under the cursor. The bundled UI5 metadata says what sap.m.Table has; it cannot say what a working one looks like in an abap2UI5 class. Three repositories can — samples, samples-controls (416 ports of the official demo kit) and samples-stack — and until now the only thing in this window that could read them was the MCP server, on behalf of an agent. "Show Examples for this Control" asks them the same question with the cursor as the query, and offers the hits richest first: the number of attributes each example configures decides the order, and no single file may fill the list, so one app that happens to use Text forty times is not the whole answer. It reads the catalogues from abap2ui5.mcp.reposRoot, and when none is checked out it says exactly that instead of reporting "nothing found" for a corpus that was never there.

    • The view check has a line in the status bar. Its findings go to the Problems panel, next to whatever the ABAP extension, the XML language server and every other contributor puts there — so "is the file I am looking at clean?" meant opening a panel and reading past other people's entries. The status bar now answers it in place: counts per severity for the active file, the wrench count of what an autofix would correct, the warning or error colour behind it, and a click that opens the list the numbers came from. A clean file says so rather than going blank, because silence is indistinguishable from a check that never ran. It reads the published diagnostics rather than running the gate again, so it changes exactly when the check has something new to say.

    • The fixes and the baseline reach the whole workspace. Two commands that only existed one file at a time, in the cases where a repository is what you are actually working on. "Fix All View Findings in the Workspace" sweeps every checkable file and applies every mechanical correction as one WorkspaceEdit — one undo step, the editor's own refactor preview, unsaved buffers respected instead of overwritten — which is what adopting the linter on an existing repository, or a rule whose autofix arrived after the code did, actually needs. And "Rebuild the View-Check Baseline" writes the baseline file from what the workspace reports right now: the editor's --update-baseline, for the moment when the lightbulb's one-finding waiver is hopeless because there are four hundred of them. It replaces rather than merges (the CLI fails on a stale entry, so a baseline that only grows is one nobody can keep green), asks before it writes, and says so when the config names no baseline — the CLI only honours one the config points at. Both share the check's own sweep, so "what the workspace says" means the same thing in all three.

    • An autofix lens next to the check that finds the work. The class definition already carried Run, Activate & reload and Check views; what it did not carry was the one action that needs no reading at all. Autofix n findings now appears beside them whenever the view check has corrections it can apply mechanically — the obsolete binder method, the missing $ in an event argument, the ABAP boolean written straight into the view — and runs exactly what the palette's Fix All View Findings in This File and source.fixAll.abap2ui5 run. It carries the count and disappears at zero, so it never offers a press that would answer "nothing here can be corrected mechanically", and it follows the findings rather than the keystrokes: a changed setting, an adopted baseline or a finished check updates the number. Findings whose correction would have to guess are not counted — those stay a lightbulb decision on the line itself. Switch the lens row off with abap2ui5.codeLens, as before.

    • The linter pin moves to 0.2.1, and the MCP server gets the two catalogues it grew. The pinned linter stops reading the ELSE of a COND #( ... ) as the end of a lifecycle branch, which is the false positive that kept the sample corpora and the documentation on the longer IF check_on_init( ) OR check_on_navigated( ) dispatcher. The render-gate bundle for that commit is published, so the pinned-bundle path stays exact.

      ai-mcp's examples tool searches three sample repositories now (samples, samples-controls, samples-stack) rather than one, so SAMPLES_HOME and SAMPLES_STACK_HOME are passed from the repos root alongside the two that were already there. A catalogue this extension does not point at is not an error over there — the tool answers from the ones it can read — so a missing variable would have cost a third of the answer silently.

    • The scaffolded configs are now checked by the tools that read them. Every template's SOURCE was already linted, but the files written AROUND it were not: a rule id the linter later renames, or a stray comma in the JSONC, would have turned New Project from Template into a project that fails on its first npm run check — with nothing in this repository noticing. The linter's own loadConfig now parses the generated abap2ui5lint.jsonc, abaplint.jsonc has to parse, and every npm run <x> a generated script chains has to name a script that exists.

    • New Project from Template. New App from Template hands you a class, which is the right thing when you already have a repository — and leaves you with the one artefact the extension cannot check properly when you do not. Without an abap2ui5lint.jsonc the view check falls back to VS Code settings, so the first CI run in that repository disagrees with what the editor had been telling you. The new command scaffolds the whole thing into an empty folder: the class and its abapGit sidecars, abap2ui5lint.jsonc and abaplint.jsonc, a package.json whose npm run check is exactly what the workflow it also writes runs, and a README. Same three templates, same linter, and the config the editor reads is now the config CI reads. It refuses a folder that already looks like a project rather than writing over it. abap2UI5/app-template stays the fuller starting point — the notification links there.

    • The auth proxy only answers its own preview. While a system is connected the extension runs a small proxy on 127.0.0.1 that adds your credentials to every request it forwards, so the app in the preview never sees a logon prompt. It used to add them for any caller: the port is random, but a random port is a scannable port, and a web page you happen to have open can reach loopback too — so anything on your machine could have driven an authenticated session against your SAP system through it, ADT included. Now every url the proxy hands out carries a per-session token, requests without it are answered 404, and a request that arrives under a hostname other than loopback — what a DNS rebinding attempt looks like from this side — is refused outright. Nothing to configure: the preview, Open in Browser and the MCP tools all get the token as part of the address.

    • A hung system no longer hangs the preview. A forwarded request that gets no answer within two minutes is dropped with the proxy's own 502 instead of being held open for as long as the socket lives. Credentials are also cleared when the proxy stops, rather than lingering until the next connect.

    • The abap2UI5 logo, everywhere the extension shows an icon. The generic placeholder is gone: the red abap2UI5 disc is now the Marketplace tile, the icon of the abap2UI5 tab in the bottom panel, and the tab icon of the app preview and the navigation map. The Marketplace tile carries the full logo; the three small icons are 16 and 24 pixels wide, where two lines of wordmark are a smudge, so they carry a short mark — the logo's own a and 2, in the logo's own type, side by side on the disc. The panel tab has them punched out of the disc rather than painted on it, because VS Code tints that icon with the theme colour and keeps only its silhouette.

  16. v0.22.0

    Other 1

    Notes
    • TLS verification is configurable. The auth proxy used to accept any certificate from the system unconditionally; the new setting abap2ui5.allowUnauthorizedCerts makes that a choice. It stays on by default — SAP development systems typically serve self-signed certificates — but if your system presents a properly trusted certificate, turn it off and the proxy verifies the chain on every request, closing the machine-in-the-middle window the default leaves open. The setting description spells out the tradeoff.
  17. v0.21.0

    Other 10

    Notes
    • Traffic log with roundtrip timings. The auth proxy sees every request the embedded app makes; the new abap2UI5 Traffic output channel logs each one with method, status, size and the full roundtrip duration, and the preview toolbar shows the last backend POST's timing as a badge (warning-coloured from 1 s). "Is the backend slow or the UI?" stops being a devtools trip.
    • Take App Screenshot. The running app as a PNG, opened beside the code with Save As… one click away — rendered by the render gate's headless Chromium through the same auth proxy, so no login page and no browser. Command, plus the 📷 button in the preview toolbar.
    • Stateful reload. The 📌 toolbar toggle captures the app's JSON model right before a reload and restores it into the fresh page — only the paths the class itself declares (the same derived model completion already uses), so framework state stays with the fresh load. A popup-deep test state survives the activate-reload loop.
    • Control Properties panel. The builder control under the cursor as an editable form, next to the App Preview: written attributes with enum dropdowns from the UI5 metadata, expression values read-only, an add-row for every member the control accepts but does not set. Every change is an ordinary text edit of the a( ) calls — undo works, the linter re-checks. With Inspect: click the control in the app, adjust it in the form.
    • Colour swatches. A colour written into a colour-typed property (sap.ui.core.CSSColor and friends) gets VS Code's inline swatch and colour picker — in builder chains and raw view XML, on the web too.
    • Convert XML View to Builder Chain. The reverse of the reconstructed XML view: paste a UI5 demo kit sample (selection, document or clipboard) and get the z2ui5_cl_ai_xml chain in the corpus style — Format Document is a no-op on the result, and whatever the builder cannot express becomes a TODO comment instead of a silent drop. Porting starts with paste.
    • New App from Template. The single skeleton grew into a gallery: empty view, list, form, master & detail, popup — pick one, name the class, and it lands at the cursor or as a new document. Every template passes the bundled linter in the test suite, so the gallery cannot teach what the linter reports.
    • App navigation map. "Show App Navigation Map" draws every z2ui5_if_app class in the workspace and each nav_app_call( ) between them as a clickable graph — apps nothing navigates to on the left, unresolved targets dashed. Click a node, land in the class.
    • Fixed: the z2ui5table and z2ui5popup snippets' chains were unbalanced. Their mid-chain )->shut( ) segments closed one parenthesis too many - the linter's reconstruction scan tolerated it, a real system would not have. A mid-chain shut now stays open for the next line's ) (the corpus style), and a new test pins the paren balance of every shipped snippet and template so it cannot regress.
    • The abap2UI5 System MCP server. ai-mcp stays the system-less sandbox; the extension now also offers real-system tools it alone can provide (configured systems, stored credentials, auth proxy): list_systems, search_apps (ADT quick search) and run_app — the app rendered on the system, returned as a screenshot. Hosted in-extension over HTTP on 127.0.0.1, disabled with abap2ui5.mcp.system: false.
  18. v0.20.0

    Other 12

    Notes
    • The client API is known before the fact. client-> completion offers every z2ui5_if_client method, and hovering a call shows its full ABAP signature and documentation - parsed from the interface source and bundled, so popover_display( xml = … by_id = … ) is offered correctly instead of corrected afterwards. Triggered by the > of the arrow.
    • Format Document repairs a builder chain. The chain IS the view hierarchy, so its indentation is structure, not taste: a child one step under its parent, an attribute one step under its element, a shut( ) on the level of the open( ) it closes. Only lines beginning with a builder verb inside a chain are touched - comments, multi-line values and everything else keep their bytes. Verified as a no-op against the canonical corpus style.
    • Baseline support - adopt the linter without fixing everything first. When abap2ui5lint.jsonc names a baseline file, the editor drops exactly the findings CI drops and logs how many. A new quick fix "add to baseline" appends the finding under the cursor to that file (same line-free keys as the CLI's --update-baseline), and the squiggle disappears immediately.
    • Render errors land on their line. The render gate reports message strings, which used to squiggle line 0 of every file. The token the message quotes (a value, a control name) is located in the source and the error is placed there; only a message quoting nothing keeps line 0.
    • More rules run in the editor. The in-process gate now hands the class's own control ids and root fields to the linter, enabling the CONTROL_BY_ID wire checks and relative-binding-without-context - and attaches the undeclared-namespace quick fix for conventional prefixes (xmlns:l, xmlns:core, …), exactly like the CLI.
    • Method navigation for the ABAP file. F12 on a method call jumps to its METHOD implementation in the class, and the workspace symbol search (Ctrl+T) finds method implementations across every *.abap file.
    • abap2ui5lint.jsonc validates while you edit it. The linter's own config schema ships with the extension (contributes.jsonValidation), so an unknown key or a misspelled rule id squiggles in the config file, offline.
    • New snippets. z2ui5main (lifecycle dispatch), z2ui5popup, z2ui5popover, z2ui5toast, z2ui5msgbox, z2ui5navto, z2ui5navback, z2ui5modelupdate, z2ui5eventarg - and every shipped snippet (plus the app template) now has to pass the bundled linter in the test suite, so a snippet can no longer teach what the linter reports.
    • Obsolete client methods are marked. The client-> completion strikes through what the interface's own abapdoc declares obsolete (_bind_edit, nest_view_model_update, nest2_view_model_update), sorts it last, and the hover leads with the warning - the deprecation reaches you while typing, not from the linter afterwards.
    • Warned when the system outruns the metadata. When the detected system UI5 is newer than the bundled snapshot, the output channel says so - a genuinely new control would be reported as unknown, and now the caveat is on record instead of a mystery.
    • Activation covers view files. The extension also activates for XML files and workspaces containing *.view.xml / *.fragment.xml, so raw view checking works without opening an ABAP file first.
    • Fix-on-save, documented. Opt in with "editor.codeActionsOnSave": { "source.fixAll.abap2ui5": "explicit" } - every mechanical fix is applied on save, same as the CLI's --fix.
  19. v0.19.0

    Other 8

    Notes
    • Inspect: click the app, land in the code. The 🎯 button in the preview toolbar starts a one-shot inspect mode: the hovered control is outlined, a click jumps to the open( ) / leaf( ) call that wrote it (Esc cancels). The clicked control's type and parent chain are matched against the reconstructed view, so a row inside a bound list lands on its template - and an id written in the class settles the match outright.
    • The app's model, one click away. The { } button asks the running app for its JSON model and shows it as a document beside the code - the live values next to the statically derived shape completion and hover already know. Every click refreshes the same document. "Why is that field empty?" is now: look.
    • The XML preview follows the editor. One preview, like the Markdown preview: switch to another view-building class and the XML swaps to that class, edit and it re-renders after each pause. A class that builds no views leaves the last reconstruction standing instead of blanking the tab.
    • A binding path jumps to its declaration. Go to Definition on {/MT_TRAVELS/STATUS} lands on the status line of the TYPES BEGIN OF block (or the DATA line for a root path) - the fourth corner of the square: completion offers it, hover judges it, the gate reports it, and now F12 goes there.
    • WHEN branches count their raises. A CodeLens over every WHEN '…' the view actually raises says "raised n× in the view" and peeks the _event( ) calls. A WHEN nothing raises stays unannotated - the CASE may switch over something else entirely.
    • Rename an event everywhere at once. F2 on an event name - in _event( 'GO' ) or on the WHEN 'GO' - renames every raise and the handler together, so the view and the dispatch cannot drift apart.
    • The detected UI5 version stays visible. After the first launch the status bar shows UI5 1.xxx for the active system; clicking it opens the view-check settings.
    • CI proves the web build. npm run test:web activates the web bundle in a real headless browser extension host (@vscode/test-web) and fails the build when a module drags a node builtin into the web graph or the activation throws - the gap the node-based suite could not cover.
  20. v0.18.0

    Other 10

    Notes
    • The reconstructed XML is navigable and honest about problems. The reconstruction records which builder call wrote every node and attribute, so the XML preview now uses it: Go to Definition on any line jumps to its open( ) / leaf( ) / a( ) in the class, and the view check's findings are mirrored onto the XML lines they concern - the structure and what is wrong with it, in one place.
    • Event navigation. Go to Definition on the event name in client->_event( 'GO' ) jumps to the WHEN 'GO' that handles it - and on the WHEN literal it jumps back to every place the view raises the event. Until now that round trip was a text search by hand.
    • The view hierarchy in the Outline. A class building views gets its open( ) / leaf( ) nesting as a labelled tree in the Outline pane (abap2UI5 view), with the id a chain sets shown alongside - a long view method reads as a tree again, and the Outline clicks straight to the builder call.
    • Hover on binding paths. Hovering a {…} path says what the derived model resolves it to - a field, a structure, a table (and that an aggregation binds it), a path under an undeclared DDIC type (accepted unchecked), or missing - the same verdict the gate's unknown-binding-path rule reaches, before it has to.
    • Runtime errors point back at the source. When a forwarded runtime error names a binding path or a quoted identifier that appears in the running class, the output channel adds the file and line right under the error - for local files as a clickable path:line.
    • The system says which UI5 it runs. After the first launch against a system the extension reads its sap-ui-version.json (with the credentials the proxy already holds) and, when version or distribution disagree with the view-check settings, offers once per system to adopt the answer. No more guessing minUi5.
    • "Run an App from the System." A picker backed by the system's ADT quick search: type part of a class name, pick, launch - no need to have the class open or to have run it before. (A name search - whether the class is an app, the launch shows.)
    • Runs in the browser. The extension now ships a web bundle for vscode.dev, github.dev and the browser-based SAP Business Application Studio: completion, hover, binding paths, the in-process property gate, quick-fix-free diagnostics, the reconstructed XML view, outline and event navigation all work there - everything that needs no process and no socket. The embedded preview, ADT integration, render gate and MCP server stay desktop-only, and their commands hide from the palette on the web. One knowing gap: the web check reads the VS Code settings only, not a repository's abap2ui5lint.jsonc.
    • Getting-started walkthrough. VS Code's Welcome page now carries the whole loop - launch URL, F9, Ctrl+F3, view check, reconstructed XML, MCP - as a six-step walkthrough. The Marketplace listing gains the categories Programming Languages and Linters.
    • The linter pin moves by itself. A weekly workflow re-resolves the pinned @abap2ui5/linter commit, runs the full gate over the result and opens a PR - new rules and metadata reach the editor without anyone remembering the bump (AGENTS.md calls it the release lever; now it pulls itself).
  21. v0.17.0

    Other 3

    Notes
    • Runtime errors of the running app reach VS Code. The embedded preview used to swallow them: a thrown error, a failed UI5 assertion, a rejected promise were visible only in the browser devtools — exactly the context switch the preview exists to avoid. The auth proxy now plants a small hook into the app's HTML that forwards window.onerror, unhandled rejections and console.error to the extension: the full text lands in the abap2UI5 output channel, and the preview toolbar counts them in a red badge that clicking opens the log. The count resets with every (re)load. Applies to tab and panel mode — external opens a real browser, which has its own devtools.
    • "Show Reconstructed XML View." abap2UI5 views are strings assembled by builder calls, so what actually reaches XMLView.create was never visible. The linter reconstructs exactly that for its checks; the new command "abap2UI5: Show Reconstructed XML View" opens the same reconstruction as a read-only, syntax-highlighted XML document next to the class — and keeps it following the edits, refreshing shortly after each pause. Debugging a nesting or binding problem stops being "stare at the builder chain".
    • Completion for binding paths. The gate has always reported a path the derived model does not have (unknown-binding-path); now the paths it does have are offered while the binding is written. Typing { in an a( v = … ) literal lists the model's paths — the fields of the enclosing aggregation's row first ({STATUS} inside a list bound to {/TRAVELS}, through nested aggregations too), absolute paths after (/TRAVELS/STATUS walks through the table's row, the way the gate resolves it). Structures the class does not declare (DDIC types) are offered as themselves and never guessed into, named models and expression bindings are left alone — the same lines the gate draws. What is offered is exactly what will not squiggle afterwards.
  22. v0.16.0

    Other 3

    Notes
    • The abap2UI5 panel is no longer a dead end. With the default open mode (tab) F9 opens the app in an editor tab, while the abap2UI5 view in the bottom panel kept showing "press F9, the app opens here" — an instruction that was never going to come true there. The empty state now says where the app actually opens, and names the app once one is running: ZCL_MY_APP is running in an editor tab, with Show it here and Go to the tab.
    • Move the preview without going through the settings. "abap2UI5: Show the Preview in the Panel" and "abap2UI5: Show the Preview in an Editor Tab" switch abap2ui5.openMode and take the running app along, so it changes place instead of having to be launched again. The panel's title bar carries the way back, next to the reload button.
    • "abap2UI5: Go to the Running App" focuses the preview wherever it is.
  23. v0.15.0

    Other 2

    Notes
    • On the VS Code Marketplace. The extension is published as abap2ui5.abap2ui5 — install and update it from the Extensions panel like any other extension. The .vsix attached to every GitHub release stays available for offline installs.
    • The extension ID changed from abap2ui5-local.abap2ui5 to abap2ui5.abap2ui5: the placeholder publisher gave way to the real Marketplace publisher. A previous .vsix install keeps working but is a different extension to VS Code and will not update — uninstall it once (code --uninstall-extension abap2ui5-local.abap2ui5) and install from the Marketplace. Settings are kept (they live in settings.json); the stored SAP credentials are scoped to the extension ID, so they are asked for once again.
  24. v0.14.0

    Other 20

    Notes
    • Completion and hover for every UI5 control and property. The extension already ships the UI5 metadata its view check validates against - a complete API reference sitting next to the bundle. It is now offered while the view is written: control names inside open( ) / leaf( ), the properties, aggregations, associations and events of exactly that control inside the a( ) chained to it, and the accepted values of an enum or boolean property. Hover shows the type, the UI5 version a member appeared in, its deprecation and a link to the UI5 API reference. Raw *.view.xml and *.fragment.xml files get the same. No system, no network, no setup - the knowledge that reported the typo afterwards now prevents it.
    • Quick fixes. The findings whose correction is mechanical carry the correction with them, and the lightbulb now offers it: the obsolete client->_bind_edit( ), a missing $ in an event argument, an ABAP boolean written straight into the view. "Fix all in this file" comes with it, also as source.fixAll.abap2ui5 for editor.codeActionsOnSave.
    • Waive one line, the way CI understands it. Every finding now offers "suppress on this line", which writes the linter's own " abap2ui5lint-disable-next-line <rule> directive above it. The other half of that was a real defect: the editor ignored those directives, so a line deliberately waived for the CLI and the GitHub Action kept squiggling here. It no longer does.
    • The editor reads abap2ui5lint.jsonc. A repository that pins its UI5 floor, its distribution, its allow list or its per-rule severities was checked against those in CI and against the VS Code settings here - the same file could be clean in the editor and red in CI. The repo config now wins wherever it says something, the settings fill in the rest, and the allow lists merge. The output channel names the file the values came from.
    • Checking while you type. The property gate runs in-process, so it no longer waits for a save: findings appear shortly after each pause. The render gate stays on save and on demand. Switch it off with abap2ui5.viewCheck.live.
    • "Check All Views in the Workspace" runs the same gate over every ABAP class and view file in the workspace and fills the Problems panel - the answer to "will the linter gate pass before I push?", which until now only covered whatever happened to be open.
    • Every finding links to its rule. The diagnostic's code is the rule id and points at the published rule reference, so a Ctrl+click explains what the rule means and what the fix looks like. Deprecations are marked as such, so VS Code strikes the member through.
    • More than one system. abap2ui5.systems holds named launch profiles; "abap2UI5: Select System" switches between them and remembers the choice per window, so two windows can work against two systems at once. Credentials are stored per host, so switching does not ask again - and an existing single-system install keeps working untouched.
    • Theme and language in the preview toolbar. Both are ordinary URL parameters of the app, so checking an app in Horizon Dark or in a second logon language is now two clicks instead of a hand-edited URL in the browser.
    • A rejected logon says so. Inside the iframe a 401 was an unhelpful page, and the only cure was finding "Clear Stored SAP Credentials" in the palette. The proxy sees the answer, so the extension now offers to retype the credentials and reloads with them.
    • Run an app without its class open. "abap2UI5: Run a Recently Launched App" lists what this window has launched.
    • Run, Activate & reload and Check views above the class definition. The dev loop was discoverable only through the palette; a CodeLens says it out loud. Switch it off with abap2ui5.codeLens.
    • Fixed: the view check did nothing in a fresh window. The extension declared no activation event, so it only woke up once F9 was pressed or the preview panel was opened - until then, saving an ABAP class produced no diagnostics at all. It now activates for ABAP files.
    • Fixed: F9 did nothing for INTERFACES: z2ui5_if_app. The chained form is just as common as the plain one and was not recognised, so F9 silently toggled a breakpoint instead of launching the app.
    • Fixed: two quick saves lost one check. The checker allowed one run at a time globally and dropped anything arriving while it was busy - with the render gate on, which takes seconds, that was easy to hit. Runs are now tracked per file, and only a newer run for the same file supersedes an older one.
    • The app template and the snippets use z2ui5_cl_ai_xml. They still taught z2ui5_cl_xml_view, which is on its way out of abap2UI5 and which the view check deliberately does not reconstruct - so "Insert App Template" handed out a class the extension's own checker then ignored. Five more snippets come with the change (container, input, table, event dispatch, lint waiver).
    • Internal: the settings that name a program to start (viewCheck.command, mcp.command, mcp.reposRoot) are machine-scoped, so a cloned repository cannot point them somewhere else; the CSP nonce comes from the crypto RNG; the pure helpers moved into vscode-free modules with a node --test suite behind them, which CI now runs; CI and the release build on Node 22, the version the bundled linter asks for.
    • The repository moved from abap2UI5-addons/vscode-extension to abap2UI5/vscode-extension, and the linter's from abap2UI5/abap2UI5-linter to abap2UI5/linter. GitHub redirects the old addresses, so nothing breaks - but the links, the npx fallback and the render-gate download now name the repositories directly.
    • A linter checkout named linter is found again. Both the MCP registration and the view checker probe #abap2ui5.mcp.reposRoot# for a checkout by directory name, and the list only held the two pre-rename names. Cloning the linter under its current name therefore produced a checkout the extension ignored: the render gate silently fell back to npx and the MCP server started without AI_VIEW_CHECK_HOME. linter is now probed first, the old names still work.
    • Internal: the bundled @abap2ui5/linter moved up 19 commits, from the extraction commit to the current linter release. Six new rules come with it (CSS brace escaping in both its forms, frontend-action wire tokens, unresolved and out-of-range event args, dead PUBLIC attributes).
  25. v0.13.0

    Other 4

    Notes
    • Findings land on the right line. Diagnostics used to be placed by searching the file for the first occurrence of a name - in a class with ten buttons, the squiggle sat under the first one no matter which button was broken. The linter now records where every finding came from, so the diagnostic goes exactly there: the second duplicate id, the a( ) call that sets a property twice, the attribute that carries the typo'd value.
    • Three severities instead of two. Findings are now classified by the linter itself: error (the app breaks), warning (it works here, but not necessarily on the UI5 version your system runs) and - new - informational hints for things that are worth knowing but never wrong by themselves, such as an event nothing handles or an icon-only button without a tooltip. They no longer look like defects in the Problems panel.
    • The binding-path checks now run in the editor at all. The property gate was called without the model derived from the class, and the rules that need it stayed silent: a {/TYPO} the model has no path for, and a table or structure bound to a scalar property. Both now show up on save, and inside a bound aggregation a relative {TYPO} is resolved against the row - so a misspelled field in a column template, which otherwise just leaves that column empty forever, is caught while you type it.
    • Two new checks, both of which dump before the app reaches the browser: the same attribute written twice on one control, and a( ) on the bare z2ui5_cl_ai_xml=>factory( ) root with no element to attach it to. z2ui5_cl_ai_xml asserts on both.
  26. v0.11.0

    Other 8

    Notes
    • abap2UI5-specific checks - the defects that stay silent at runtime. A hand-written binding path the model does not have (the field just stays empty), _bind( ) on an event or _event( ) on a property, a value bound to a local variable (lost after the roundtrip, because the instance is serialized and the method stack is not), an event nothing handles, and the obsolete client->_bind_edit( ). No UI5 tooling can see these - they live in the relationship between the ABAP class and the view it builds. Also caught: an ABAP boolean written straight into the view - it arrives as 'X'/' ', and since UI5 reads any non-empty string as true, visible = abap_false makes the control visible. Wrap it in z2ui5_cl_ai_xml=>as_bool( ).
    • Deprecated properties and duplicate aggregations. Deprecation was only checked on control level; it now applies per property too, with the same target-version rule. And opening the same aggregation twice under one control - where the second tag silently replaces the first - is reported as an error.
    • Three more silent failures caught: a view built but never displayed (an empty page, no error), a Table bound to rows but given no columns, and a table or structure bound to a scalar property.
    • More view checks: a duplicate id (a runtime error), a namespace prefix used but never declared, unbalanced braces in {= … } expression bindings, and two unambiguous accessibility defects (icon-only button without a tooltip, image without alt).
    • SAPUI5 or OpenUI5 (abap2ui5.viewCheck.distribution). SAPUI5 ships libraries OpenUI5 does not - sap.ui.comp (Smart controls), sap.suite.*, sap.ushell, sap.fe, sap.viz - so a SmartTable is perfectly fine on SAPUI5 and a guaranteed runtime error on OpenUI5. Set it to what your system serves; with openui5 those controls are reported as errors instead of being skipped silently.
    • The target UI5 version now governs deprecations too (abap2ui5.viewCheck.minUi5). A control deprecated as of 1.149 is no longer flagged for a 1.71 target - only from the version its deprecation takes effect. The output channel logs the target version and the version the bundled metadata came from.
    • Self-installing render gate. "abap2UI5: Install Render Gate" downloads the self-contained checker bundle (published by abap2UI5-linter's CI) and Chromium into the extension's storage and runs both with VS Code's own runtime - the render gate no longer needs node, npm or any PATH setup on the machine. The command is also offered directly from the warning when the gate is enabled but missing, and installing enables abap2ui5.viewCheck.render.
    • Fix: no more "view check passed" on files that only quote builder code (e.g. a log file embedding class source). Checkability now requires an ABAP source actually calling z2ui5_cl_ai_xml=>factory (or a *.view.xml), and when nothing can be reconstructed the check says so instead of claiming a pass.
  27. v0.10.0

    Other 3

    Notes
    • Static view checks in the editor. Saving an ABAP class that builds views with z2ui5_cl_ai_xml (or a raw *.view.xml / *.fragment.xml) now runs the abap2UI5-linter gates and shows the findings in the Problems panel: controls that do not exist in UI5 at all (sap.m.Shell2 - a typo, shown as an error), controls or properties newer than your UI5 floor (default 1.71), and deprecated controls. The property gate and its UI5 metadata snapshot are bundled with the extension - zero setup, instant, works offline, on documents from the ABAP remote filesystem (adt scheme) and on unsaved buffers. Optionally (abap2ui5.viewCheck.render) the external abap2UI5-linter (formerly ai-view-check) CLI adds real render errors from a headless XMLView.create. On demand: "abap2UI5: Check Views (Static)". Configure the floor, accepted deviations and the render-gate command under abap2ui5.viewCheck.*.
    • The abap2UI5 MCP server, offered to every MCP client in the window. The extension registers the ai-mcp server as an MCP server definition provider, so Copilot agent mode (and any other MCP client in VS Code) can use the abap2UI5 dev loop without an SAP system: capability queries, static view validation, deploy into the sandbox, transpiled build, headless run returning page errors and a screenshot. Point abap2ui5.mcp.reposRoot at the folder holding the abap2UI5, ai-demokit (and optionally abap2UI5-linter, ai-mcp) checkouts; disable with abap2ui5.mcp.enabled.
    • The minimum VS Code version moved from 1.85 to 1.101 (June 2025) - the first release with the stable MCP server definition API.
  28. v0.9.3

    Other 4

    Notes
    • Fix: every button press in the embedded preview could fail with "CSRF validation failed - cross-origin POST rejected". The embedded app talks to the local auth proxy on 127.0.0.1, so the browser sent that as Origin/Referer while the forwarded request carried the SAP host — a mismatch that origin-validating CSRF checks reject on every POST. The proxy now rewrites both headers to the system's own origin, so the roundtrips look same-origin to the server again.
    • Fix: the activation watch only ever started for adt: documents. Any other way of editing a server-backed source never got the automatic reload after activation. The watch now starts on every save of the shown class — the server knows whether an inactive version exists, whatever the file's URI scheme is. (Sources that never reach a server simply never show up as inactive, so nothing reloads there either.)
    • Fix: an activation right after the save was missed. The watch used to wait for the class to show up as inactive before an active answer would count as the activation. Activating directly — where the save is part of the activation — can be finished on a fast system before the watch ever looks, so there was nothing inactive to see and the watch waited for a flip it had already missed; only a slow save-then-activate cycle ever reloaded. The watch now also remembers the change timestamp of the class the preview shows: active with a newer change timestamp is a finished activation, no matter how fast it went. (Sources that never reach the server keep their timestamp, so purely local saves still reload nothing.) The first look at the server also moved from 2.5 seconds after the save to a quarter of a second, with checks every 1.5 seconds after that.
    • New output channel abap2UI5 (View → Output): the activation watch says what it is doing there — started, class inactive, active again → reload, or the reason it stops (ADT unreachable, timeout). When an automatic reload does not happen, this is the place that says why.
  29. v0.9.1

    Other 4

    Notes

    Reloading after activation now actually happens — however you activate (#5).

    • Activations are detected on the server. 0.9.0 only reloaded on its own Ctrl+F3; activating with the ABAP remote filesystem's own button or shortcut went unnoticed, because VS Code has no event for it. Now, while the preview shows the not activated badge, the extension watches the class on the server (its ADT metadata, fetched with the credentials it already holds for the preview) and reloads as soon as the inactive version is gone — no matter whether the activation came from Ctrl+F3, the ABAP extension's own UI or even Eclipse. Needs the source to be opened from a system (scheme adt) and the ADT services answering on the launch-URL host; where they do not, the watch stops silently and the badge stays until you reload.
    • Fix: Ctrl+F3 (and the ⚡ button) could stay dead for a whole session. They were gated on a "an ABAP extension with an activate command is installed" flag computed once at startup — when this extension happened to activate before the ABAP extension had registered its commands, the flag stayed false and the key silently did nothing. The gate is now simply "the file was opened from an ABAP system" (scheme adt), which implies working ABAP tooling and cannot go stale.
    • The not activated badge is now clickable — it reloads the preview right there (showing the still-active version, as the tooltip says).
    • Ctrl+F3 now hands the exact document to abapfs.activate instead of relying on its active-editor fallback.
  30. v0.9.0

    Other 3

    Notes

    The preview now reloads when you activate, not when you save (#5).

    • No more pointless reload on save. Saving an ABAP class does not change what the server runs — the activation does. A save of the shown class no longer reloads the preview; it marks it with a small not activated badge in the toolbar instead, so it is clear why the app still shows the old version.
    • New command abap2UI5: Activate and Reload Preview on Ctrl+F3 (Cmd+F3 on macOS, the activation key from SAP GUI) and as a ⚡ button in the editor toolbar: it saves the class, hands the activation to the ABAP extension you already use (ABAP remote filesystem) and reloads the preview afterwards. The key is only taken over for objects opened from a system while such an extension is installed — everywhere else Ctrl+F3 keeps its usual VS Code meaning.
    • New setting abap2ui5.reloadOn with activation (default), save and never. It replaces abap2ui5.reloadOnSave, which is deprecated but still honoured while the new setting is unset — false behaves like never, true like save.
  31. v0.8.0

    Other 11

    Notes

    A visual pass over everything the extension shows.

    • New preview toolbar with the class name, the system URL, a status dot (loading / ready) and buttons for reload and "open externally". It follows your colour theme instead of bringing its own colours.
    • Device widths: switch the preview between desktop, tablet (834px) and phone (414px) to check a responsive app without leaving the editor. The choice is remembered per preview.
    • Loading state: a spinner and "Starting ZCL_…" instead of a white area. If the app takes longer than 12 seconds, the preview offers Reload and Open externally right there.
    • Welcome screen in the preview panel: the three steps to a running app, plus buttons for the launch URL, the app template and the project page.
    • Status bar entry while an app is running — shows the class, click reloads.
    • Run button in the editor toolbar for ABAP files, next to the usual actions.
    • New commands: abap2UI5: Reload Preview (also in the preview panel's title bar) and abap2UI5: Set Launch URL, which validates the URL and the {class} placeholder before saving it.
    • Save toast: reloading after a save says so in the preview, so a slow round trip is not mistaken for nothing happening.
    • Extension icon, tab icon and panel icon reworked.
    • The .vsix is now a download. Every release attaches the packaged extension to its GitHub release, so installing no longer means cloning and building. Every push and pull request also builds one as a CI artifact.
    • Internal: the webview HTML moved to src/webview.ts and the inline scripts now run under a CSP nonce instead of unsafe-inline.
  32. v0.7.0

    Other 2

    Notes
    • The project is now English-only. README, changelog, code comments and every user-facing string (command titles, settings descriptions, input prompts, error messages, the webview placeholder) were translated from German to English. The convention is written down in AGENTS.md so it stays that way.
    • Command titles changed accordingly, e.g. "abap2UI5: App starten (F9)" → abap2UI5: Run App (F9). Command IDs, setting keys and behaviour are unchanged, so your settings.json and any custom keybindings keep working.
  33. v0.6.0

    Other 3

    Notes
    • Renamed: the extension is now simply abap2UI5 instead of "abap2UI5 Demokit Helper". It was never tied to the demokit — the name only came from the repository it originally lived in. It now has its own repository: https://github.com/abap2UI5-addons/vscode-extension.
    • README reworked: describes the extension as a general tool for abap2UI5 development, with tables for settings and commands.
    • Command IDs unified under the abap2ui5. prefix: abap2ui5-demokit.newApp → abap2ui5.newApp, abap2ui5-demokit.openDemokit → abap2ui5.openHomepage. The latter has always opened the abap2UI5 repository, and its title now says so.

    When updating: the rename changes the extension ID from abap2ui5-local.abap2ui5-demokit to abap2ui5-local.abap2ui5. VS Code therefore treats the new .vsix as a separate extension — uninstall the old one once: code --uninstall-extension abap2ui5-local.abap2ui5-demokit. Your settings (abap2ui5.*) survive, they live in settings.json and not on the extension ID. The SAP credentials in the SecretStorage do hang off the ID, so they are asked for once more on the first F9 after the update.

  34. v0.5.0

    Other 1

    Notes
    • Auto-reload on activation: saving/activating the app class shown in the tab reloads the embedded browser automatically — no F9 needed. Can be turned off with abap2ui5.reloadOnSave (default: on).
  35. v0.4.2

    Other 1

    Notes
    • Fix: after F9 the cursor really does stay in the source. The loading UI5 app pulls focus asynchronously — the extension now catches that for a short time window (onDidChangeViewState) and hands focus back to the code.
  36. v0.4.1

    Other 1

    Notes
    • After a launch or reload, F9 returns focus to the source — the cursor stays where it was and you can keep typing right away.
  37. v0.4.0

    Other 1

    Notes
    • F9 now reliably refreshes the existing tab/panel (reloading the app) instead of opening a new one. For a different class the existing tab switches to the new app. The reload runs as a message to the iframe.
  38. v0.3.1

    Other 1

    Notes
    • Fix: blank/white app in the tab — the proxy now strips X-Frame-Options and the CSP directive frame-ancestors from the SAP responses, so the browser allows embedding in the iframe.
  39. v0.3.0

    Other 5

    Notes
    • Embedded app with login through a local auth proxy: F9 shows the app in an editor tab (or panel) and the proxy injects the SAP credentials — no more 401.
    • abap2ui5.openMode extended: tab (the new default), panel, external
    • Credentials are asked for once and kept in the SecretStorage
    • New command: "abap2UI5: Clear Stored SAP Credentials"
    • The proxy forwards UI5 resources, cookies, CSRF and redirects transparently; self-signed HTTPS certificates are accepted
  40. v0.2.0

    Other 2

    Notes
    • New setting abap2ui5.openMode (external | panel), default external
      • external: F9 opens the app in the normal browser (uses the SAP session/SSO)
      • panel: embedded in the panel (only without interactive login, otherwise 401)
    • URL normalization: duplicate slashes in the path are removed
  41. v0.1.0

    Other 4

    Notes
    • F9 launches a z2ui5_if_app class in the embedded browser panel at the bottom
    • New setting abap2ui5.launchUrlTemplate (placeholder {class})
    • Panel view "abap2UI5 / App Preview" with an "Open externally" fallback
    • F9 on non-app ABAP files keeps the normal breakpoint behaviour
  42. v0.0.1

    Other 4

    Notes
    • First version
    • Command: "abap2UI5: Insert New App Template"
    • Command: "abap2UI5: Open Demokit in Browser" (renamed in 0.6.0)
    • Snippets: z2ui5app, z2ui5button

Others providing47

Editor support
  1. abap-adt-apiJS/TS client for the ADT resources of an ABAP system
  2. abap2UI5 PlaygroundIn-browser ABAP editor beside the abap2UI5 app it builds
  3. vscode-tabl-ddicVS Code syntax highlighting for .tabl.ddic table definitions
  4. HammerNative macOS code editor for ABAP and CDS
  5. @arc-mcp/adt-lsTypeScript SDK over SAP's headless adt-ls language server
  6. abapthemesThree colour themes for ABAP source in ADT for Eclipse
  7. Cloud ALM Link for ADTEclipse plugin linking ABAP transports to SAP Cloud ALM features
  8. ABAP Call HierarchyEclipse plugin showing the call hierarchy of ABAP members
  9. abap-call-hierarchyADT backend for the ABAP Call Hierarchy Eclipse plugin
  10. abap-tags-backendADT backend for the ABAP Tags Eclipse plugin
  11. ABAP TagsEclipse plugin for tagging ABAP repository objects
  12. BellaEclipse plugin bringing Claude into ABAP Development Tools
  13. ABAP Syntax HighlightingVS Code syntax highlighting for .abap files
  14. abapfs_extensionsABAP objects enabling ADT updates on systems older than 7.51
  15. ABAP remote filesystemVS Code extension editing ABAP systems over ADT as a filesystem
  16. ABAP Development Tools for EclipseSAP's Eclipse plugins for ABAP development over ADT
  17. ABAP Development Tools for VS CodeSAP's ABAP tools in VS Code for editing, debugging, ATC and transports
  18. my-ide-actionsCollection of ABAP Development Tools IDE Actions
Agent access to your systems
  1. @abap2ui5/mcp-serverMCP server for the abap2UI5 check, deploy and run loop
  2. abapsmithABAP MCP server over ADT with a local journal that can undo writes
  3. btp-sap-odata-to-mcp-serverExposes S/4HANA or ECC OData services as MCP tools
  4. midasol/sap-mcp-serverPython MCP server for SAP Gateway OData operations
  5. odata_mcp_goGo binary bridging any OData v2 or v4 service to MCP
  6. odata_mcpPython bridge generating MCP tools from OData v2 metadata
  7. sap-mcp-serverReads SAP ECC and S/4HANA for an agent over Gateway OData and RFC, with a Node bridge that speaks the RFC protocol without the proprietary SAP NetWeaver RFC SDK.
  8. Skybuffer AI MCP serverABAP add-on serving business data and transactions as MCP tools
  9. sap-security-mcpRead-only security analysis MCP server for SAP audits and SoD review
  10. KlystronMCP server in ABAP inside the application server, with agent skills
  11. pyrfc-mcpMCP server calling RFC-enabled function modules behind an allowlist
Agent guidance
  1. sap-basis-opsRunbook skills for Basis operations at the OS and database layer
  2. abap-offstack-aunitAgent skill for off-stack ABAP Unit tests and an abaplint gate
  3. ARC-1 SkillsTwenty-two agent skills shipped with arc-1
  4. sapskillsAgent skills for Clean ABAP, ADT in VS Code and guardrails
  5. SuperClaude for SAPClaude Code plugin with an ABAP MCP server and write guards
  6. claude-abap-devFive ABAP workflows for Claude Code on existing MCP servers
  7. DanKromp/skillOverflowCollection of 41 agent skills, 37 for SAP development tasks
  8. sap-ai-dev-toolkitMCP proxy pinning an agent's ABAP tools to one SAP system
  9. sapcli Claude Code PluginAgents and skills that drive sapcli instead of ADT
  10. sap-odata-explorerRust CLI and desktop app for exploring SAP OData services
  11. abap-skillsSeventeen agent skills for ABAP development
  12. ABAP remote filesystemVS Code extension editing ABAP systems over ADT as a filesystem
  13. WerkbankLocal desktop workspace for AI conversations with SAP connectors
  14. claude-abap-skillsClaude Code plugins with Clean ABAP rules and templates
  15. SAP Power for KiroSAP skills for the Kiro IDE
  16. SAP Developers MCPHosted MCP server of developers.sap.com tutorials and missions
  17. secondsky/sap-skillsForty SAP development plugins for coding agents
  18. claude-sap-kitClaude Code plugin adding Custom_* tools to arc-1
  19. rap-skillsRAP skills delivered branch-per-target for each deployment
  20. KlystronMCP server in ABAP inside the application server, with agent skills

Details

Sources3
GitHub APIdiscovered herechecked
github.com/abap2UI5/vscode-extensiontree, pushes, contributors, CIchecked
README.mdquoted, and what the entry declareschecked

Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.

Compatibility and provenance
runtimesnode
discovered viaGitHub API
first seen in the atlas
ecosystem and domainabap, developer-experience
History in the atlas1
  1. First seen.
For your agent
Ref
artifact:abap2ui5-vscode-extension
JSON
/artifacts/abap2ui5-vscode-extension.json
MCP
Connecting an agent