sap-abap-mcp 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,318 @@
1
+ # SAP ABAP MCP
2
+
3
+ An MCP server for **ABAP development on any on-premise SAP system**. Once
4
+ configured, an MCP-aware client — GitHub Copilot Chat, Claude Code, Claude
5
+ Desktop, Cursor — can read tables, search the repository, read source code,
6
+ and (when not in read-only mode) create or update ABAP programs and classes
7
+ through the ADT (ABAP Development Tools) REST API.
8
+
9
+ Distributed two ways from the **same** repository:
10
+
11
+ - **npm package** [`sap-abap-mcp`](https://www.npmjs.com/package/sap-abap-mcp)
12
+ — for Claude Desktop, Claude Code, Cursor, or any other standalone MCP
13
+ client. Runs over stdio, configured via environment variables.
14
+ - **VS Code extension** (`.vsix` in Releases) — for GitHub Copilot Chat /
15
+ Cursor inside VS Code 1.99+. Includes a connect wizard, OS-keychain
16
+ password storage, and a status bar item.
17
+
18
+ The VS Code extension auto-registers the npm-based config into Claude Code
19
+ and Claude Desktop on first run, so you don't need to maintain two configs.
20
+
21
+ ## Features
22
+
23
+ | Tool | Mode | What it does |
24
+ | ---------------------- | ----- | --------------------------------------------------------------- |
25
+ | `sap_ping` | read | Test the ADT connection. |
26
+ | `sap_sql` | read | Run an ABAP-SQL `SELECT` on any table. |
27
+ | `sap_table_info` | read | DDIC structure of a table. |
28
+ | `sap_read_object` | read | Read source of PROG / CLAS / INTF / FUGR / DDLS. |
29
+ | `sap_search_objects` | read | Repository search with type filter. |
30
+ | `sap_list_package` | read | List all objects in an ABAP package. |
31
+ | `sap_syntax_check` | read | Run the ADT syntax/semantic check. |
32
+ | `sap_deploy_program` | write | Create or update an ABAP report. Idempotent. |
33
+ | `sap_deploy_class` | write | Create or update an ABAP class. |
34
+ | `sap_activate` | write | Activate one object. |
35
+ | `sap_delete_object` | write | Delete an object. |
36
+ | `sap_run_abap` | write | Run an ABAP snippet via `if_oo_adt_classrun`. |
37
+
38
+ Toggle **SAP ABAP: Toggle Read-Only Mode** to hide all write tools from
39
+ Copilot.
40
+
41
+ ## Requirements
42
+
43
+ **Shared (both install paths):**
44
+
45
+ - An on-premise SAP NetWeaver / S/4HANA system with the ADT service path
46
+ `/sap/bc/adt` active (SICF) and HTTPS enabled (SMICM)
47
+ - A development user with `S_DEVELOP` (or equivalent) authorizations
48
+ - Network reachability to the SAP host (VPN if it's an internal IP)
49
+
50
+ **Path A (standalone, npm):** Node.js 18+ on the machine running your MCP
51
+ client (Claude Desktop, Claude Code, Cursor). `npx` ships with Node.
52
+
53
+ **Path B (VS Code extension):** VS Code 1.99+ (native MCP support landed in
54
+ that release). Node.js is bundled with VS Code; no separate install
55
+ needed.
56
+
57
+ ## Install
58
+
59
+ Pick the path that matches your client. They aren't mutually exclusive —
60
+ the npm package and the VS Code extension run the same MCP server and can
61
+ coexist on one machine.
62
+
63
+ ### A. Standalone (Claude Desktop / Claude Code / Cursor)
64
+
65
+ No VS Code required. Add the server to your client's MCP config — npm
66
+ resolves the binary on first spawn.
67
+
68
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`
69
+ (macOS), `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "sap-abap": {
75
+ "command": "npx",
76
+ "args": ["-y", "sap-abap-mcp"],
77
+ "env": {
78
+ "SAP_HOST": "https://sap.example.com:44300",
79
+ "SAP_CLIENT": "100",
80
+ "SAP_USER": "DEVUSER",
81
+ "SAP_PASSWORD": "<password>",
82
+ "SAP_LANG": "EN",
83
+ "SAP_VERIFY_SSL": "false",
84
+ "SAP_READONLY": "false",
85
+ "SAP_TIMEOUT": "30"
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ Then **fully quit** Claude Desktop (Cmd+Q on macOS, not just close the
93
+ window) and reopen.
94
+
95
+ **Claude Code (CLI)** — register once:
96
+
97
+ ```bash
98
+ claude mcp add sap-abap -- npx -y sap-abap-mcp
99
+ ```
100
+
101
+ Set the `SAP_*` env vars in `~/.claude.json` or your shell profile.
102
+
103
+ If `npx` isn't on your client's PATH (common when launching Claude Desktop
104
+ from the macOS Dock), substitute the absolute path:
105
+ `/opt/homebrew/bin/npx` on Apple Silicon, `/usr/local/bin/npx` on Intel
106
+ macOS or Linux.
107
+
108
+ **Why `npx -y`:** the package is resolved by npm at every spawn (cached
109
+ after the first run, ~100 KB compressed tarball, no native deps). Future
110
+ versions ship automatically — your config never points at a stale
111
+ `.vscode/extensions/...mcp-server.js` path.
112
+
113
+ ### B. VS Code extension
114
+
115
+ For GitHub Copilot Chat or Cursor running inside VS Code 1.99+.
116
+
117
+ ```bash
118
+ curl -L -o /tmp/sap-abap-mcp.vsix \
119
+ https://github.com/Lomtech/sap-abap-vscode-mcp/releases/latest/download/sap-abap-mcp.vsix
120
+ code --install-extension /tmp/sap-abap-mcp.vsix
121
+ ```
122
+
123
+ Or manually from
124
+ [Releases](https://github.com/Lomtech/sap-abap-vscode-mcp/releases/latest):
125
+ download the `.vsix`, then in VS Code `Cmd+Shift+P` → **Extensions: Install
126
+ from VSIX...** → pick the file.
127
+
128
+ After install: `Cmd+Shift+P` → **SAP ABAP: Connect to System**. The wizard
129
+ stores the password in OS keychain and offers to register the MCP server
130
+ with any detected Claude Code / Claude Desktop installation (using the
131
+ npx-based config above, so the registration survives extension upgrades).
132
+
133
+ ### Updating
134
+
135
+ - **npm package**: nothing to do — `npx` picks up new versions
136
+ automatically.
137
+ - **VS Code extension**: download the new `.vsix` and reinstall. The
138
+ extension auto-rewrites any pre-0.4.0 Claude configs to the npx shape on
139
+ next activation.
140
+
141
+ ## Quick start
142
+
143
+ **Standalone (Path A):**
144
+
145
+ 1. Drop the JSON block into your client's config (see [Install A](#a-standalone-claude-desktop--claude-code--cursor)) with your SAP credentials.
146
+ 2. Fully quit and restart the client.
147
+ 3. Ask: *"Ping my SAP system."* — should return the mandant and T000 description.
148
+
149
+ **VS Code (Path B):**
150
+
151
+ 1. Install the `.vsix` (see [Install B](#b-vs-code-extension)).
152
+ 2. `Cmd+Shift+P` → **SAP ABAP: Connect to System**.
153
+ 3. Enter host, client, user, password. Password lands in OS keychain via
154
+ VS Code's `SecretStorage` API — never plain text.
155
+ 4. Reload Copilot Chat. The MCP tools appear under the "SAP ABAP MCP"
156
+ provider.
157
+ 5. Ask Copilot: *"Ping my SAP system."*
158
+
159
+ ## VS Code extension commands
160
+
161
+ All available from the command palette (`⇧⌘P` / `Ctrl+Shift+P`) — these
162
+ apply only to Path B (the VS Code extension):
163
+
164
+ - **SAP ABAP: Connect to System...** — Run the 4-step setup wizard.
165
+ - **SAP ABAP: Test Connection** — Verify creds work without leaving VS Code.
166
+ - **SAP ABAP: Toggle Read-Only Mode** — Hide/show write tools.
167
+ - **SAP ABAP: Show Connection Status** — Open a read-only summary view.
168
+ - **SAP ABAP: Register MCP with Claude Code & Desktop** — Push the
169
+ npx-based config into detected Claude clients without re-running the
170
+ full wizard.
171
+ - **SAP ABAP: Disconnect (clear credentials)** — Remove host, user, and
172
+ password from settings + keychain.
173
+
174
+ A status-bar item on the right shows the current connection at a glance
175
+ (`$(database) SAP: user@host` or `[RO]` when read-only is on).
176
+
177
+ ## Configuration
178
+
179
+ The server reads its config from environment variables — the same set
180
+ regardless of install path:
181
+
182
+ | Variable | Required | Default | Notes |
183
+ | ----------------- | -------- | ------- | -------------------------------------------------------------- |
184
+ | `SAP_HOST` | yes | — | Full ADT base URL, e.g. `https://sap.example.com:44300`. HTTPS.|
185
+ | `SAP_CLIENT` | no | `100` | Mandant. |
186
+ | `SAP_USER` | yes | — | ABAP user name. |
187
+ | `SAP_PASSWORD` | yes | — | ABAP password. |
188
+ | `SAP_LANG` | no | `EN` | Logon language. |
189
+ | `SAP_VERIFY_SSL` | no | `false` | Set `true` only if your system has a trusted cert chain. |
190
+ | `SAP_READONLY` | no | `false` | When `true`, write tools are hidden. Recommended for prod. |
191
+ | `SAP_TIMEOUT` | no | `30` | HTTP timeout in seconds. |
192
+
193
+ **Path A (standalone):** set them in the `env` block of your client's
194
+ MCP config (Claude Desktop JSON, `~/.claude.json`, etc.).
195
+
196
+ **Path B (VS Code):** edit `sapAbapMcp.*` settings via Settings UI; the
197
+ extension translates them into the env vars above when spawning the
198
+ subprocess. Sensitive values (`password`) live in OS keychain via
199
+ `SecretStorage`, not `settings.json`.
200
+
201
+ | VS Code setting | Maps to env var |
202
+ | ------------------------ | -------------------- |
203
+ | `sapAbapMcp.host` | `SAP_HOST` |
204
+ | `sapAbapMcp.client` | `SAP_CLIENT` |
205
+ | `sapAbapMcp.user` | `SAP_USER` |
206
+ | `sapAbapMcp.language` | `SAP_LANG` |
207
+ | `sapAbapMcp.verifySsl` | `SAP_VERIFY_SSL` |
208
+ | `sapAbapMcp.readOnly` | `SAP_READONLY` |
209
+ | `sapAbapMcp.timeout` | `SAP_TIMEOUT` |
210
+ | _(keychain)_ | `SAP_PASSWORD` |
211
+
212
+ ## Security notes
213
+
214
+ - **Path A stores the password in plain text** inside the Claude Desktop /
215
+ Claude Code JSON config. There is no keychain integration for those
216
+ clients. Tighten file permissions:
217
+ `chmod 600 ~/Library/Application\ Support/Claude/claude_desktop_config.json`.
218
+ - **Path B uses the OS keychain** (macOS Keychain / Windows Credential
219
+ Manager / Linux libsecret) via VS Code's `SecretStorage` API. Password
220
+ never lands in `settings.json`.
221
+ - In both paths the MCP server subprocess receives credentials via env
222
+ vars at spawn time. They are not logged.
223
+ - `sap_sql` rejects any statement that isn't a `SELECT` / `WITH`.
224
+ - Write tools can be globally disabled by setting `SAP_READONLY=true`
225
+ (Path A) or toggling `sapAbapMcp.readOnly` (Path B).
226
+ - TLS verification defaults to **off** because most on-prem SAP systems
227
+ use self-signed certs. Set `SAP_VERIFY_SSL=true` only with a trusted
228
+ cert chain.
229
+ - **Always test against a development or sandbox system first.** Create /
230
+ update / delete on production SAP development objects is irreversible
231
+ without a transport-request rollback.
232
+
233
+ ## Server-side prerequisites (one-time, Basis admin)
234
+
235
+ | Check | Where |
236
+ | ------------------------------------------- | ------------------------------------------- |
237
+ | SICF service `/sap/bc/adt` active | Transaction `SICF`, activate with sub-nodes |
238
+ | HTTPS service running | Transaction `SMICM` → Goto → Services |
239
+ | User has `S_DEVELOP` | Transaction `SU01` |
240
+
241
+ ## Troubleshooting
242
+
243
+ | Symptom | Likely cause |
244
+ | -------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
245
+ | Tools don't appear in Claude Desktop after JSON edit | Didn't fully quit Claude Desktop (Cmd+Q on macOS). Closing the window isn't enough. |
246
+ | `spawn npx ENOENT` in Claude Desktop logs | `npx` not on the GUI app's PATH. Use absolute path: `/opt/homebrew/bin/npx` (or wherever). |
247
+ | First spawn hangs ~30s | npx is fetching the package. Cached after this, subsequent starts are instant. |
248
+ | `sap-abap-mcp: missing environment variables: SAP_HOST…` | `env` block in your client config missing required vars. |
249
+ | Status bar shows "not configured" (Path B) | Run **SAP ABAP: Connect to System**. |
250
+ | `Connection timed out` | VPN not connected, or wrong host/port. |
251
+ | `HTTP 401` | Wrong user/password, or user is locked. |
252
+ | `HTTP 403 CSRF token validation failed` | Using HTTP instead of HTTPS. |
253
+ | `HTTP 403 Service cannot be reached` | SICF `/sap/bc/adt` not active. |
254
+ | Tools don't appear in Copilot Chat | Reload window after first configuration. |
255
+ | Warning: "VS Code 1.99+ is required" | Update VS Code; MCP API isn't available yet. |
256
+
257
+ ## Development
258
+
259
+ ```bash
260
+ git clone https://github.com/Lomtech/sap-abap-vscode-mcp.git
261
+ cd sap-abap-vscode-mcp
262
+ npm install
263
+ npm run typecheck # tsc -p . --noEmit
264
+ npm run compile # esbuild → out/extension.js + out/mcp-server.js
265
+ npm run package # vsce package → .vsix
266
+ npm test # tests/smoke.mjs against live SAP (skips without SAP_HOST)
267
+ ```
268
+
269
+ To run the extension in a development window: press `F5` inside VS Code with
270
+ this folder open. A new Extension Host window opens with the extension
271
+ loaded.
272
+
273
+ ### Releasing
274
+
275
+ The same artifact stream produces two distributions:
276
+
277
+ | Artifact | Distribution | Trigger |
278
+ | --- | --- | --- |
279
+ | `out/mcp-server.js` (bundled) | npm: `sap-abap-mcp` | `npm publish` |
280
+ | `sap-abap-mcp-<version>.vsix` | GitHub Release asset | `npm run package` + `gh release create` |
281
+
282
+ `package.json` `files` is a single allowlist consumed by **both** vsce
283
+ (for the .vsix) and npm (for the tarball). It includes `out/extension.js`
284
+ + `out/mcp-server.js` + CHANGELOG + LICENSE; everything else (tests, src,
285
+ build config) stays in the repo for source-code consumers. npm auto-adds
286
+ README and package.json on top. vsce demands one strategy at a time —
287
+ either `.vscodeignore` *or* `files` — so `.vscodeignore` is intentionally
288
+ absent.
289
+
290
+ `out/extension.js` ships to npm as dead weight (~70 KB) but is harmless:
291
+ the npm `bin` field points at `out/mcp-server.js`, and nothing in
292
+ `extension.js` is ever loaded outside VS Code.
293
+
294
+ To cut a release:
295
+
296
+ 1. Bump `version` in `package.json` and add a `CHANGELOG.md` entry.
297
+ 2. `npm run compile && npm run package` — produces the .vsix.
298
+ 3. `git commit -am "vX.Y.Z: …" && git tag vX.Y.Z && git push --tags`.
299
+ 4. `gh release create vX.Y.Z sap-abap-mcp-X.Y.Z.vsix --generate-notes`.
300
+ 5. `npm publish` — pushes the same `out/mcp-server.js` to npm.
301
+
302
+ ## Why this exists
303
+
304
+ ABAP developers are increasingly using VS Code (SAP themselves are shipping
305
+ "ABAP Development Tools for VS Code" in 2026). This server fills the gap
306
+ left by SAP's official tooling for *AI-assisted* ABAP work: it gives any
307
+ MCP-aware client — Claude Desktop, Claude Code, Copilot Chat, Cursor —
308
+ direct, structured access to your SAP system's repository, source code, and
309
+ development surface.
310
+
311
+ It is intentionally **generic**: no business logic, no system-specific
312
+ hostnames or users, no customer code. Point it at your system, get to work.
313
+
314
+ ## License
315
+
316
+ Apache 2.0. Drop a copy of the standard Apache 2.0 text into `LICENSE` in
317
+ this folder. (Not included here to keep the repo free of vendored license
318
+ boilerplate.)
@@ -0,0 +1,46 @@
1
+ "use strict";var At=Object.create;var Q=Object.defineProperty;var Pt=Object.getOwnPropertyDescriptor;var Tt=Object.getOwnPropertyNames;var Nt=Object.getPrototypeOf,vt=Object.prototype.hasOwnProperty;var xt=(t,e)=>()=>(t&&(e=t(t=0)),e);var v=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Se=(t,e)=>{for(var s in e)Q(t,s,{get:e[s],enumerable:!0})},Ae=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Tt(e))!vt.call(t,r)&&r!==s&&Q(t,r,{get:()=>e[r],enumerable:!(n=Pt(e,r))||n.enumerable});return t};var R=(t,e,s)=>(s=t!=null?At(Nt(t)):{},Ae(e||!t||!t.__esModule?Q(s,"default",{value:t,enumerable:!0}):s,t)),kt=t=>Ae(Q({},"__esModule",{value:!0}),t);var G=v($=>{"use strict";var Pe=":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD",$t=Pe+"\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040",Te="["+Pe+"]["+$t+"]*",Rt=new RegExp("^"+Te+"$"),Ot=function(t,e){let s=[],n=e.exec(t);for(;n;){let r=[];r.startIndex=e.lastIndex-n[0].length;let i=n.length;for(let o=0;o<i;o++)r.push(n[o]);s.push(r),n=e.exec(t)}return s},It=function(t){let e=Rt.exec(t);return!(e===null||typeof e>"u")};$.isExist=function(t){return typeof t<"u"};$.isEmptyObject=function(t){return Object.keys(t).length===0};$.merge=function(t,e,s){if(e){let n=Object.keys(e),r=n.length;for(let i=0;i<r;i++)s==="strict"?t[n[i]]=[e[n[i]]]:t[n[i]]=e[n[i]]}};$.getValue=function(t){return $.isExist(t)?t:""};var _t=["hasOwnProperty","toString","valueOf","__defineGetter__","__defineSetter__","__lookupGetter__","__lookupSetter__"],Mt=["__proto__","constructor","prototype"];$.isName=It;$.getAllMatches=Ot;$.nameRegexp=Te;$.DANGEROUS_PROPERTY_NAMES=_t;$.criticalProperties=Mt});var re=v($e=>{"use strict";var ne=G(),Lt={allowBooleanAttributes:!1,unpairedTags:[]};$e.validate=function(t,e){e=Object.assign({},Lt,e);let s=[],n=!1,r=!1;t[0]==="\uFEFF"&&(t=t.substr(1));for(let i=0;i<t.length;i++)if(t[i]==="<"&&t[i+1]==="?"){if(i+=2,i=ve(t,i),i.err)return i}else if(t[i]==="<"){let o=i;if(i++,t[i]==="!"){i=xe(t,i);continue}else{let c=!1;t[i]==="/"&&(c=!0,i++);let a="";for(;i<t.length&&t[i]!==">"&&t[i]!==" "&&t[i]!==" "&&t[i]!==`
2
+ `&&t[i]!=="\r";i++)a+=t[i];if(a=a.trim(),a[a.length-1]==="/"&&(a=a.substring(0,a.length-1),i--),!Ht(a)){let u;return a.trim().length===0?u="Invalid space after '<'.":u="Tag '"+a+"' is an invalid name.",w("InvalidTag",u,P(t,i))}let d=Bt(t,i);if(d===!1)return w("InvalidAttr","Attributes for '"+a+"' have open quote.",P(t,i));let l=d.value;if(i=d.index,l[l.length-1]==="/"){let u=i-l.length;l=l.substring(0,l.length-1);let f=ke(l,e);if(f===!0)n=!0;else return w(f.err.code,f.err.msg,P(t,u+f.err.line))}else if(c)if(d.tagClosed){if(l.trim().length>0)return w("InvalidTag","Closing tag '"+a+"' can't have attributes or invalid starting.",P(t,o));if(s.length===0)return w("InvalidTag","Closing tag '"+a+"' has not been opened.",P(t,o));{let u=s.pop();if(a!==u.tagName){let f=P(t,u.tagStartPos);return w("InvalidTag","Expected closing tag '"+u.tagName+"' (opened in line "+f.line+", col "+f.col+") instead of closing tag '"+a+"'.",P(t,o))}s.length==0&&(r=!0)}}else return w("InvalidTag","Closing tag '"+a+"' doesn't have proper closing.",P(t,i));else{let u=ke(l,e);if(u!==!0)return w(u.err.code,u.err.msg,P(t,i-l.length+u.err.line));if(r===!0)return w("InvalidXml","Multiple possible root nodes found.",P(t,i));e.unpairedTags.indexOf(a)!==-1||s.push({tagName:a,tagStartPos:o}),n=!0}for(i++;i<t.length;i++)if(t[i]==="<")if(t[i+1]==="!"){i++,i=xe(t,i);continue}else if(t[i+1]==="?"){if(i=ve(t,++i),i.err)return i}else break;else if(t[i]==="&"){let u=Gt(t,i);if(u==-1)return w("InvalidChar","char '&' is not expected.",P(t,i));i=u}else if(r===!0&&!Ne(t[i]))return w("InvalidXml","Extra text at the end",P(t,i));t[i]==="<"&&i--}}else{if(Ne(t[i]))continue;return w("InvalidChar","char '"+t[i]+"' is not expected.",P(t,i))}if(n){if(s.length==1)return w("InvalidTag","Unclosed tag '"+s[0].tagName+"'.",P(t,s[0].tagStartPos));if(s.length>0)return w("InvalidXml","Invalid '"+JSON.stringify(s.map(i=>i.tagName),null,4).replace(/\r?\n/g,"")+"' found.",{line:1,col:1})}else return w("InvalidXml","Start tag expected.",1);return!0};function Ne(t){return t===" "||t===" "||t===`
3
+ `||t==="\r"}function ve(t,e){let s=e;for(;e<t.length;e++)if(t[e]=="?"||t[e]==" "){let n=t.substr(s,e-s);if(e>5&&n==="xml")return w("InvalidXml","XML declaration allowed only at the start of the document.",P(t,e));if(t[e]=="?"&&t[e+1]==">"){e++;break}else continue}return e}function xe(t,e){if(t.length>e+5&&t[e+1]==="-"&&t[e+2]==="-"){for(e+=3;e<t.length;e++)if(t[e]==="-"&&t[e+1]==="-"&&t[e+2]===">"){e+=2;break}}else if(t.length>e+8&&t[e+1]==="D"&&t[e+2]==="O"&&t[e+3]==="C"&&t[e+4]==="T"&&t[e+5]==="Y"&&t[e+6]==="P"&&t[e+7]==="E"){let s=1;for(e+=8;e<t.length;e++)if(t[e]==="<")s++;else if(t[e]===">"&&(s--,s===0))break}else if(t.length>e+9&&t[e+1]==="["&&t[e+2]==="C"&&t[e+3]==="D"&&t[e+4]==="A"&&t[e+5]==="T"&&t[e+6]==="A"&&t[e+7]==="["){for(e+=8;e<t.length;e++)if(t[e]==="]"&&t[e+1]==="]"&&t[e+2]===">"){e+=2;break}}return e}var Ut='"',qt="'";function Bt(t,e){let s="",n="",r=!1;for(;e<t.length;e++){if(t[e]===Ut||t[e]===qt)n===""?n=t[e]:n!==t[e]||(n="");else if(t[e]===">"&&n===""){r=!0;break}s+=t[e]}return n!==""?!1:{value:s,index:e,tagClosed:r}}var Vt=new RegExp(`(\\s*)([^\\s=]+)(\\s*=)?(\\s*(['"])(([\\s\\S])*?)\\5)?`,"g");function ke(t,e){let s=ne.getAllMatches(t,Vt),n={};for(let r=0;r<s.length;r++){if(s[r][1].length===0)return w("InvalidAttr","Attribute '"+s[r][2]+"' has no space in starting.",Y(s[r]));if(s[r][3]!==void 0&&s[r][4]===void 0)return w("InvalidAttr","Attribute '"+s[r][2]+"' is without value.",Y(s[r]));if(s[r][3]===void 0&&!e.allowBooleanAttributes)return w("InvalidAttr","boolean attribute '"+s[r][2]+"' is not allowed.",Y(s[r]));let i=s[r][2];if(!Yt(i))return w("InvalidAttr","Attribute '"+i+"' is an invalid name.",Y(s[r]));if(!n.hasOwnProperty(i))n[i]=1;else return w("InvalidAttr","Attribute '"+i+"' is repeated.",Y(s[r]))}return!0}function Ft(t,e){let s=/\d/;for(t[e]==="x"&&(e++,s=/[\da-fA-F]/);e<t.length;e++){if(t[e]===";")return e;if(!t[e].match(s))break}return-1}function Gt(t,e){if(e++,t[e]===";")return-1;if(t[e]==="#")return e++,Ft(t,e);let s=0;for(;e<t.length;e++,s++)if(!(t[e].match(/\w/)&&s<20)){if(t[e]===";")break;return-1}return e}function w(t,e,s){return{err:{code:t,msg:e,line:s.line||s,col:s.col}}}function Yt(t){return ne.isName(t)}function Ht(t){return ne.isName(t)}function P(t,e){let s=t.substring(0,e).split(/\r?\n/);return{line:s.length,col:s[s.length-1].length+1}}function Y(t){return t.startIndex+t[1].length}});var Me=v(ie=>{var{DANGEROUS_PROPERTY_NAMES:Re,criticalProperties:Xt}=G(),Oe=t=>Re.includes(t)?"__"+t:t,Ie={preserveOrder:!1,attributeNamePrefix:"@_",attributesGroupName:!1,textNodeName:"#text",ignoreAttributes:!0,removeNSPrefix:!1,allowBooleanAttributes:!1,parseTagValue:!0,parseAttributeValue:!1,trimValues:!0,cdataPropName:!1,numberParseOptions:{hex:!0,leadingZeros:!0,eNotation:!0},tagValueProcessor:function(t,e){return e},attributeValueProcessor:function(t,e){return e},stopNodes:[],alwaysCreateTextNode:!1,isArray:()=>!1,commentPropName:!1,unpairedTags:[],processEntities:!0,htmlEntities:!1,ignoreDeclaration:!1,ignorePiTags:!1,transformTagName:!1,transformAttributeName:!1,updateTag:function(t,e,s){return t},captureMetaData:!1,maxNestedTags:100,strictReservedNames:!0,onDangerousProperty:Oe};function jt(t,e){if(typeof t!="string")return;let s=t.toLowerCase();if(Re.some(n=>s===n.toLowerCase()))throw new Error(`[SECURITY] Invalid ${e}: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`);if(Xt.some(n=>s===n.toLowerCase()))throw new Error(`[SECURITY] Invalid ${e}: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`)}function _e(t){return typeof t=="boolean"?{enabled:t,maxEntitySize:1e4,maxExpansionDepth:10,maxTotalExpansions:1e3,maxExpandedLength:1e5,allowedTags:null,tagFilter:null}:typeof t=="object"&&t!==null?{enabled:t.enabled!==!1,maxEntitySize:Math.max(1,t.maxEntitySize??1e4),maxExpansionDepth:Math.max(1,t.maxExpansionDepth??1e4),maxTotalExpansions:Math.max(1,t.maxTotalExpansions??1/0),maxExpandedLength:Math.max(1,t.maxExpandedLength??1e5),maxEntityCount:Math.max(1,t.maxEntityCount??1e3),allowedTags:t.allowedTags??null,tagFilter:t.tagFilter??null}:_e(!0)}var Wt=function(t){let e=Object.assign({},Ie,t),s=[{value:e.attributeNamePrefix,name:"attributeNamePrefix"},{value:e.attributesGroupName,name:"attributesGroupName"},{value:e.textNodeName,name:"textNodeName"},{value:e.cdataPropName,name:"cdataPropName"},{value:e.commentPropName,name:"commentPropName"}];for(let{value:n,name:r}of s)n&&jt(n,r);return e.onDangerousProperty===null&&(e.onDangerousProperty=Oe),e.processEntities=_e(e.processEntities),e};ie.buildOptions=Wt;ie.defaultOptions=Ie});var Ue=v((fn,Le)=>{"use strict";var oe=class{constructor(e){this.tagname=e,this.child=[],this[":@"]={}}add(e,s){e==="__proto__"&&(e="#__proto__"),this.child.push({[e]:s})}addChild(e){e.tagname==="__proto__"&&(e.tagname="#__proto__"),e[":@"]&&Object.keys(e[":@"]).length>0?this.child.push({[e.tagname]:e.child,":@":e[":@"]}):this.child.push({[e.tagname]:e.child})}};Le.exports=oe});var Ve=v((gn,Be)=>{var qe=G(),ae=class{constructor(e){this.suppressValidationErr=!e,this.options=e||{}}readDocType(e,s){let n=Object.create(null),r=0;if(e[s+3]==="O"&&e[s+4]==="C"&&e[s+5]==="T"&&e[s+6]==="Y"&&e[s+7]==="P"&&e[s+8]==="E"){s=s+9;let i=1,o=!1,c=!1,a="";for(;s<e.length;s++)if(e[s]==="<"&&!c){if(o&&M(e,"!ENTITY",s)){s+=7;let d,l;if([d,l,s]=this.readEntityExp(e,s+1,this.suppressValidationErr),l.indexOf("&")===-1){if(this.options.enabled!==!1&&this.options.maxEntityCount!=null&&r>=this.options.maxEntityCount)throw new Error(`Entity count (${r+1}) exceeds maximum allowed (${this.options.maxEntityCount})`);let u=d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");n[d]={regx:RegExp(`&${u};`,"g"),val:l},r++}}else if(o&&M(e,"!ELEMENT",s)){s+=8;let{index:d}=this.readElementExp(e,s+1);s=d}else if(o&&M(e,"!ATTLIST",s))s+=8;else if(o&&M(e,"!NOTATION",s)){s+=9;let{index:d}=this.readNotationExp(e,s+1,this.suppressValidationErr);s=d}else if(M(e,"!--",s))c=!0;else throw new Error("Invalid DOCTYPE");i++,a=""}else if(e[s]===">"){if(c?e[s-1]==="-"&&e[s-2]==="-"&&(c=!1,i--):i--,i===0)break}else e[s]==="["?o=!0:a+=e[s];if(i!==0)throw new Error("Unclosed DOCTYPE")}else throw new Error("Invalid Tag instead of DOCTYPE");return{entities:n,i:s}}readEntityExp(e,s){s=T(e,s);let n="";for(;s<e.length&&!/\s/.test(e[s])&&e[s]!=='"'&&e[s]!=="'";)n+=e[s],s++;if(H(n),s=T(e,s),!this.suppressValidationErr){if(e.substring(s,s+6).toUpperCase()==="SYSTEM")throw new Error("External entities are not supported");if(e[s]==="%")throw new Error("Parameter entities are not supported")}let r="";if([s,r]=this.readIdentifierVal(e,s,"entity"),this.options.enabled!==!1&&this.options.maxEntitySize!=null&&r.length>this.options.maxEntitySize)throw new Error(`Entity "${n}" size (${r.length}) exceeds maximum allowed size (${this.options.maxEntitySize})`);return s--,[n,r,s]}readNotationExp(e,s){s=T(e,s);let n="";for(;s<e.length&&!/\s/.test(e[s]);)n+=e[s],s++;!this.suppressValidationErr&&H(n),s=T(e,s);let r=e.substring(s,s+6).toUpperCase();if(!this.suppressValidationErr&&r!=="SYSTEM"&&r!=="PUBLIC")throw new Error(`Expected SYSTEM or PUBLIC, found "${r}"`);s+=r.length,s=T(e,s);let i=null,o=null;if(r==="PUBLIC")[s,i]=this.readIdentifierVal(e,s,"publicIdentifier"),s=T(e,s),(e[s]==='"'||e[s]==="'")&&([s,o]=this.readIdentifierVal(e,s,"systemIdentifier"));else if(r==="SYSTEM"&&([s,o]=this.readIdentifierVal(e,s,"systemIdentifier"),!this.suppressValidationErr&&!o))throw new Error("Missing mandatory system identifier for SYSTEM notation");return{notationName:n,publicIdentifier:i,systemIdentifier:o,index:--s}}readIdentifierVal(e,s,n){let r="",i=e[s];if(i!=='"'&&i!=="'")throw new Error(`Expected quoted string, found "${i}"`);for(s++;s<e.length&&e[s]!==i;)r+=e[s],s++;if(e[s]!==i)throw new Error(`Unterminated ${n} value`);return s++,[s,r]}readElementExp(e,s){s=T(e,s);let n="";for(;s<e.length&&!/\s/.test(e[s]);)n+=e[s],s++;if(!this.suppressValidationErr&&!qe.isName(n))throw new Error(`Invalid element name: "${n}"`);s=T(e,s);let r="";if(e[s]==="E"&&M(e,"MPTY",s))s+=4;else if(e[s]==="A"&&M(e,"NY",s))s+=2;else if(e[s]==="("){for(s++;s<e.length&&e[s]!==")";)r+=e[s],s++;if(e[s]!==")")throw new Error("Unterminated content model")}else if(!this.suppressValidationErr)throw new Error(`Invalid Element Expression, found "${e[s]}"`);return{elementName:n,contentModel:r.trim(),index:s}}readAttlistExp(e,s){s=T(e,s);let n="";for(;s<e.length&&!/\s/.test(e[s]);)n+=e[s],s++;H(n),s=T(e,s);let r="";for(;s<e.length&&!/\s/.test(e[s]);)r+=e[s],s++;if(!H(r))throw new Error(`Invalid attribute name: "${r}"`);s=T(e,s);let i="";if(e.substring(s,s+8).toUpperCase()==="NOTATION"){if(i="NOTATION",s+=8,s=T(e,s),e[s]!=="(")throw new Error(`Expected '(', found "${e[s]}"`);s++;let c=[];for(;s<e.length&&e[s]!==")";){let a="";for(;s<e.length&&e[s]!=="|"&&e[s]!==")";)a+=e[s],s++;if(a=a.trim(),!H(a))throw new Error(`Invalid notation name: "${a}"`);c.push(a),e[s]==="|"&&(s++,s=T(e,s))}if(e[s]!==")")throw new Error("Unterminated list of notations");s++,i+=" ("+c.join("|")+")"}else{for(;s<e.length&&!/\s/.test(e[s]);)i+=e[s],s++;let c=["CDATA","ID","IDREF","IDREFS","ENTITY","ENTITIES","NMTOKEN","NMTOKENS"];if(!this.suppressValidationErr&&!c.includes(i.toUpperCase()))throw new Error(`Invalid attribute type: "${i}"`)}s=T(e,s);let o="";return e.substring(s,s+8).toUpperCase()==="#REQUIRED"?(o="#REQUIRED",s+=8):e.substring(s,s+7).toUpperCase()==="#IMPLIED"?(o="#IMPLIED",s+=7):[s,o]=this.readIdentifierVal(e,s,"ATTLIST"),{elementName:n,attributeName:r,attributeType:i,defaultValue:o,index:s}}},T=(t,e)=>{for(;e<t.length&&/\s/.test(t[e]);)e++;return e};function M(t,e,s){for(let n=0;n<e.length;n++)if(e[n]!==t[s+n+1])return!1;return!0}function H(t){if(qe.isName(t))return t;throw new Error(`Invalid entity name ${t}`)}Be.exports=ae});var Ge=v((hn,Fe)=>{var Kt=/^[-+]?0x[a-fA-F0-9]+$/,zt=/^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/,Jt={hex:!0,leadingZeros:!0,decimalPoint:".",eNotation:!0};function Qt(t,e={}){if(e=Object.assign({},Jt,e),!t||typeof t!="string")return t;let s=t.trim();if(e.skipLike!==void 0&&e.skipLike.test(s))return t;if(t==="0")return 0;if(e.hex&&Kt.test(s))return Dt(s,16);if(s.search(/[eE]/)!==-1){let n=s.match(/^([-\+])?(0*)([0-9]*(\.[0-9]*)?[eE][-\+]?[0-9]+)$/);if(n){if(e.leadingZeros)s=(n[1]||"")+n[3];else if(!(n[2]==="0"&&n[3][0]==="."))return t;return e.eNotation?Number(s):t}else return t}else{let n=zt.exec(s);if(n){let r=n[1],i=n[2],o=Zt(n[3]);if(!e.leadingZeros&&i.length>0&&r&&s[2]!==".")return t;if(!e.leadingZeros&&i.length>0&&!r&&s[1]!==".")return t;if(e.leadingZeros&&i===t)return 0;{let c=Number(s),a=""+c;return a.search(/[eE]/)!==-1?e.eNotation?c:t:s.indexOf(".")!==-1?a==="0"&&o===""||a===o||r&&a==="-"+o?c:t:i?o===a||r+o===a?c:t:s===a||s===r+a?c:t}}else return t}}function Zt(t){return t&&t.indexOf(".")!==-1&&(t=t.replace(/0+$/,""),t==="."?t="0":t[0]==="."?t="0"+t:t[t.length-1]==="."&&(t=t.substr(0,t.length-1))),t}function Dt(t,e){if(parseInt)return parseInt(t,e);if(Number.parseInt)return Number.parseInt(t,e);if(window&&window.parseInt)return window.parseInt(t,e);throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")}Fe.exports=Qt});var ce=v((mn,Ye)=>{function es(t){return typeof t=="function"?t:Array.isArray(t)?e=>{for(let s of t)if(typeof s=="string"&&e===s||s instanceof RegExp&&s.test(e))return!0}:()=>!1}Ye.exports=es});var je=v((wn,Xe)=>{"use strict";var Z=G(),B=Ue(),ts=Ve(),ss=Ge(),ns=ce(),de=class{constructor(e){if(this.options=e,this.currentNode=null,this.tagsNodeStack=[],this.docTypeEntities={},this.lastEntities={apos:{regex:/&(apos|#39|#x27);/g,val:"'"},gt:{regex:/&(gt|#62|#x3E);/g,val:">"},lt:{regex:/&(lt|#60|#x3C);/g,val:"<"},quot:{regex:/&(quot|#34|#x22);/g,val:'"'}},this.ampEntity={regex:/&(amp|#38|#x26);/g,val:"&"},this.htmlEntities={space:{regex:/&(nbsp|#160);/g,val:" "},cent:{regex:/&(cent|#162);/g,val:"\xA2"},pound:{regex:/&(pound|#163);/g,val:"\xA3"},yen:{regex:/&(yen|#165);/g,val:"\xA5"},euro:{regex:/&(euro|#8364);/g,val:"\u20AC"},copyright:{regex:/&(copy|#169);/g,val:"\xA9"},reg:{regex:/&(reg|#174);/g,val:"\xAE"},inr:{regex:/&(inr|#8377);/g,val:"\u20B9"},num_dec:{regex:/&#([0-9]{1,7});/g,val:(s,n)=>He(n,10,"&#")},num_hex:{regex:/&#x([0-9a-fA-F]{1,6});/g,val:(s,n)=>He(n,16,"&#x")}},this.addExternalEntities=rs,this.parseXml=ds,this.parseTextData=is,this.resolveNameSpace=os,this.buildAttributesMap=cs,this.isItStopNode=fs,this.replaceEntitiesValue=ls,this.readStopNodeData=hs,this.saveTextToParentTag=ps,this.addChild=us,this.ignoreAttributesFn=ns(this.options.ignoreAttributes),this.entityExpansionCount=0,this.currentExpandedLength=0,this.options.stopNodes&&this.options.stopNodes.length>0){this.stopNodesExact=new Set,this.stopNodesWildcard=new Set;for(let s=0;s<this.options.stopNodes.length;s++){let n=this.options.stopNodes[s];typeof n=="string"&&(n.startsWith("*.")?this.stopNodesWildcard.add(n.substring(2)):this.stopNodesExact.add(n))}}}};function rs(t){let e=Object.keys(t);for(let s=0;s<e.length;s++){let n=e[s],r=n.replace(/[.\-+*:]/g,"\\.");this.lastEntities[n]={regex:new RegExp("&"+r+";","g"),val:t[n]}}}function is(t,e,s,n,r,i,o){if(t!==void 0&&(this.options.trimValues&&!n&&(t=t.trim()),t.length>0)){o||(t=this.replaceEntitiesValue(t,e,s));let c=this.options.tagValueProcessor(e,t,s,r,i);return c==null?t:typeof c!=typeof t||c!==t?c:this.options.trimValues?le(t,this.options.parseTagValue,this.options.numberParseOptions):t.trim()===t?le(t,this.options.parseTagValue,this.options.numberParseOptions):t}}function os(t){if(this.options.removeNSPrefix){let e=t.split(":"),s=t.charAt(0)==="/"?"/":"";if(e[0]==="xmlns")return"";e.length===2&&(t=s+e[1])}return t}var as=new RegExp(`([^\\s=]+)\\s*(=\\s*(['"])([\\s\\S]*?)\\3)?`,"gm");function cs(t,e,s){if(this.options.ignoreAttributes!==!0&&typeof t=="string"){let n=Z.getAllMatches(t,as),r=n.length,i={};for(let o=0;o<r;o++){let c=this.resolveNameSpace(n[o][1]);if(this.ignoreAttributesFn(c,e))continue;let a=n[o][4],d=this.options.attributeNamePrefix+c;if(c.length)if(this.options.transformAttributeName&&(d=this.options.transformAttributeName(d)),d=ms(d,this.options),a!==void 0){this.options.trimValues&&(a=a.trim()),a=this.replaceEntitiesValue(a,s,e);let l=this.options.attributeValueProcessor(c,a,e);l==null?i[d]=a:typeof l!=typeof a||l!==a?i[d]=l:i[d]=le(a,this.options.parseAttributeValue,this.options.numberParseOptions)}else this.options.allowBooleanAttributes&&(i[d]=!0)}if(!Object.keys(i).length)return;if(this.options.attributesGroupName){let o={};return o[this.options.attributesGroupName]=i,o}return i}}var ds=function(t){t=t.replace(/\r\n?/g,`
4
+ `);let e=new B("!xml"),s=e,n="",r="";this.entityExpansionCount=0,this.currentExpandedLength=0;let i=new ts(this.options.processEntities);for(let o=0;o<t.length;o++)if(t[o]==="<")if(t[o+1]==="/"){let a=L(t,">",o,"Closing Tag is not closed."),d=t.substring(o+2,a).trim();if(this.options.removeNSPrefix){let f=d.indexOf(":");f!==-1&&(d=d.substr(f+1))}this.options.transformTagName&&(d=this.options.transformTagName(d)),s&&(n=this.saveTextToParentTag(n,s,r));let l=r.substring(r.lastIndexOf(".")+1);if(d&&this.options.unpairedTags.indexOf(d)!==-1)throw new Error(`Unpaired tag can not be used as closing tag: </${d}>`);let u=0;l&&this.options.unpairedTags.indexOf(l)!==-1?(u=r.lastIndexOf(".",r.lastIndexOf(".")-1),this.tagsNodeStack.pop()):u=r.lastIndexOf("."),r=r.substring(0,u),s=this.tagsNodeStack.pop(),n="",o=a}else if(t[o+1]==="?"){let a=ue(t,o,!1,"?>");if(!a)throw new Error("Pi Tag is not closed.");if(n=this.saveTextToParentTag(n,s,r),!(this.options.ignoreDeclaration&&a.tagName==="?xml"||this.options.ignorePiTags)){let d=new B(a.tagName);d.add(this.options.textNodeName,""),a.tagName!==a.tagExp&&a.attrExpPresent&&(d[":@"]=this.buildAttributesMap(a.tagExp,r,a.tagName)),this.addChild(s,d,r,o)}o=a.closeIndex+1}else if(t.substr(o+1,3)==="!--"){let a=L(t,"-->",o+4,"Comment is not closed.");if(this.options.commentPropName){let d=t.substring(o+4,a-2);n=this.saveTextToParentTag(n,s,r),s.add(this.options.commentPropName,[{[this.options.textNodeName]:d}])}o=a}else if(t.substr(o+1,2)==="!D"){let a=i.readDocType(t,o);this.docTypeEntities=a.entities,o=a.i}else if(t.substr(o+1,2)==="!["){let a=L(t,"]]>",o,"CDATA is not closed.")-2,d=t.substring(o+9,a);n=this.saveTextToParentTag(n,s,r);let l=this.parseTextData(d,s.tagname,r,!0,!1,!0,!0);l==null&&(l=""),this.options.cdataPropName?s.add(this.options.cdataPropName,[{[this.options.textNodeName]:d}]):s.add(this.options.textNodeName,l),o=a+2}else{let a=ue(t,o,this.options.removeNSPrefix),d=a.tagName,l=a.rawTagName,u=a.tagExp,f=a.attrExpPresent,m=a.closeIndex;if(this.options.transformTagName){let h=this.options.transformTagName(d);u===d&&(u=h),d=h}if(this.options.strictReservedNames&&(d===this.options.commentPropName||d===this.options.cdataPropName||d===this.options.textNodeName||d===this.options.attributesGroupName))throw new Error(`Invalid tag name: ${d}`);s&&n&&s.tagname!=="!xml"&&(n=this.saveTextToParentTag(n,s,r,!1));let g=s;g&&this.options.unpairedTags.indexOf(g.tagname)!==-1&&(s=this.tagsNodeStack.pop(),r=r.substring(0,r.lastIndexOf("."))),d!==e.tagname&&(r+=r?"."+d:d);let y=o;if(this.isItStopNode(this.stopNodesExact,this.stopNodesWildcard,r,d)){let h="";if(u.length>0&&u.lastIndexOf("/")===u.length-1)d[d.length-1]==="/"?(d=d.substr(0,d.length-1),r=r.substr(0,r.length-1),u=d):u=u.substr(0,u.length-1),o=a.closeIndex;else if(this.options.unpairedTags.indexOf(d)!==-1)o=a.closeIndex;else{let S=this.readStopNodeData(t,l,m+1);if(!S)throw new Error(`Unexpected end of ${l}`);o=S.i,h=S.tagContent}let b=new B(d);d!==u&&f&&(b[":@"]=this.buildAttributesMap(u,r,d)),h&&(h=this.parseTextData(h,d,r,!0,f,!0,!0)),r=r.substr(0,r.lastIndexOf(".")),b.add(this.options.textNodeName,h),this.addChild(s,b,r,y)}else{if(u.length>0&&u.lastIndexOf("/")===u.length-1){if(d[d.length-1]==="/"?(d=d.substr(0,d.length-1),r=r.substr(0,r.length-1),u=d):u=u.substr(0,u.length-1),this.options.transformTagName){let b=this.options.transformTagName(d);u===d&&(u=b),d=b}let h=new B(d);d!==u&&f&&(h[":@"]=this.buildAttributesMap(u,r,d)),this.addChild(s,h,r,y),r=r.substr(0,r.lastIndexOf("."))}else if(this.options.unpairedTags.indexOf(d)!==-1){let h=new B(d);d!==u&&f&&(h[":@"]=this.buildAttributesMap(u,r)),this.addChild(s,h,r,y),r=r.substr(0,r.lastIndexOf(".")),o=a.closeIndex;continue}else{let h=new B(d);if(this.tagsNodeStack.length>this.options.maxNestedTags)throw new Error("Maximum nested tags exceeded");this.tagsNodeStack.push(s),d!==u&&f&&(h[":@"]=this.buildAttributesMap(u,r,d)),this.addChild(s,h,r),s=h}n="",o=m}}else n+=t[o];return e.child};function us(t,e,s,n){this.options.captureMetaData||(n=void 0);let r=this.options.updateTag(e.tagname,s,e[":@"]);r===!1||(typeof r=="string"&&(e.tagname=r),t.addChild(e,n))}var ls=function(t,e,s){if(t.indexOf("&")===-1)return t;let n=this.options.processEntities;if(!n.enabled||n.allowedTags&&!n.allowedTags.includes(e)||n.tagFilter&&!n.tagFilter(e,s))return t;for(let r in this.docTypeEntities){let i=this.docTypeEntities[r],o=t.match(i.regx);if(o){if(this.entityExpansionCount+=o.length,n.maxTotalExpansions&&this.entityExpansionCount>n.maxTotalExpansions)throw new Error(`Entity expansion limit exceeded: ${this.entityExpansionCount} > ${n.maxTotalExpansions}`);let c=t.length;if(t=t.replace(i.regx,i.val),n.maxExpandedLength&&(this.currentExpandedLength+=t.length-c,this.currentExpandedLength>n.maxExpandedLength))throw new Error(`Total expanded content size exceeded: ${this.currentExpandedLength} > ${n.maxExpandedLength}`)}}if(t.indexOf("&")===-1)return t;for(let r of Object.keys(this.lastEntities)){let i=this.lastEntities[r],o=t.match(i.regex);if(o&&(this.entityExpansionCount+=o.length,n.maxTotalExpansions&&this.entityExpansionCount>n.maxTotalExpansions))throw new Error(`Entity expansion limit exceeded: ${this.entityExpansionCount} > ${n.maxTotalExpansions}`);t=t.replace(i.regex,i.val)}if(t.indexOf("&")===-1)return t;if(this.options.htmlEntities)for(let r of Object.keys(this.htmlEntities)){let i=this.htmlEntities[r],o=t.match(i.regex);if(o&&(this.entityExpansionCount+=o.length,n.maxTotalExpansions&&this.entityExpansionCount>n.maxTotalExpansions))throw new Error(`Entity expansion limit exceeded: ${this.entityExpansionCount} > ${n.maxTotalExpansions}`);t=t.replace(i.regex,i.val)}return t=t.replace(this.ampEntity.regex,this.ampEntity.val),t};function ps(t,e,s,n){return t&&(n===void 0&&(n=e.child.length===0),t=this.parseTextData(t,e.tagname,s,!1,e[":@"]?Object.keys(e[":@"]).length!==0:!1,n),t!==void 0&&t!==""&&e.add(this.options.textNodeName,t),t=""),t}function fs(t,e,s,n){return!!(e&&e.has(n)||t&&t.has(s))}function gs(t,e,s=">"){let n,r="";for(let i=e;i<t.length;i++){let o=t[i];if(n)o===n&&(n="");else if(o==='"'||o==="'")n=o;else if(o===s[0])if(s[1]){if(t[i+1]===s[1])return{data:r,index:i}}else return{data:r,index:i};else o===" "&&(o=" ");r+=o}}function L(t,e,s,n){let r=t.indexOf(e,s);if(r===-1)throw new Error(n);return r+e.length-1}function ue(t,e,s,n=">"){let r=gs(t,e+1,n);if(!r)return;let i=r.data,o=r.index,c=i.search(/\s/),a=i,d=!0;c!==-1&&(a=i.substring(0,c),i=i.substring(c+1).trimStart());let l=a;if(s){let u=a.indexOf(":");u!==-1&&(a=a.substr(u+1),d=a!==r.data.substr(u+1))}return{tagName:a,tagExp:i,closeIndex:o,attrExpPresent:d,rawTagName:l}}function hs(t,e,s){let n=s,r=1;for(;s<t.length;s++)if(t[s]==="<")if(t[s+1]==="/"){let i=L(t,">",s,`${e} is not closed`);if(t.substring(s+2,i).trim()===e&&(r--,r===0))return{tagContent:t.substring(n,s),i};s=i}else if(t[s+1]==="?")s=L(t,"?>",s+1,"StopNode is not closed.");else if(t.substr(s+1,3)==="!--")s=L(t,"-->",s+3,"StopNode is not closed.");else if(t.substr(s+1,2)==="![")s=L(t,"]]>",s,"StopNode is not closed.")-2;else{let i=ue(t,s,">");i&&((i&&i.tagName)===e&&i.tagExp[i.tagExp.length-1]!=="/"&&r++,s=i.closeIndex)}}function le(t,e,s){if(e&&typeof t=="string"){let n=t.trim();return n==="true"?!0:n==="false"?!1:ss(t,s)}else return Z.isExist(t)?t:""}function He(t,e,s){let n=Number.parseInt(t,e);return n>=0&&n<=1114111?String.fromCodePoint(n):s+t+";"}function ms(t,e){if(Z.criticalProperties.includes(t))throw new Error(`[SECURITY] Invalid name: "${t}" is a reserved JavaScript keyword that could cause prototype pollution`);return Z.DANGEROUS_PROPERTY_NAMES.includes(t)?e.onDangerousProperty(t):t}Xe.exports=de});var ze=v(Ke=>{"use strict";function ws(t,e){return We(t,e)}function We(t,e,s){let n,r={};for(let i=0;i<t.length;i++){let o=t[i],c=ys(o),a="";if(s===void 0?a=c:a=s+"."+c,c===e.textNodeName)n===void 0?n=o[c]:n+=""+o[c];else{if(c===void 0)continue;if(o[c]){let d=We(o[c],e,a),l=bs(d,e);o[":@"]?Es(d,o[":@"],a,e):Object.keys(d).length===1&&d[e.textNodeName]!==void 0&&!e.alwaysCreateTextNode?d=d[e.textNodeName]:Object.keys(d).length===0&&(e.alwaysCreateTextNode?d[e.textNodeName]="":d=""),r[c]!==void 0&&r.hasOwnProperty(c)?(Array.isArray(r[c])||(r[c]=[r[c]]),r[c].push(d)):e.isArray(c,a,l)?r[c]=[d]:r[c]=d}}}return typeof n=="string"?n.length>0&&(r[e.textNodeName]=n):n!==void 0&&(r[e.textNodeName]=n),r}function ys(t){let e=Object.keys(t);for(let s=0;s<e.length;s++){let n=e[s];if(n!==":@")return n}}function Es(t,e,s,n){if(e){let r=Object.keys(e),i=r.length;for(let o=0;o<i;o++){let c=r[o];n.isArray(c,s+"."+c,!0,!0)?t[c]=[e[c]]:t[c]=e[c]}}}function bs(t,e){let{textNodeName:s}=e,n=Object.keys(t).length;return!!(n===0||n===1&&(t[s]||typeof t[s]=="boolean"||t[s]===0))}Ke.prettify=ws});var Qe=v((En,Je)=>{var{buildOptions:Cs}=Me(),Ss=je(),{prettify:As}=ze(),Ps=re(),pe=class{constructor(e){this.externalEntities={},this.options=Cs(e)}parse(e,s){if(typeof e!="string")if(e.toString)e=e.toString();else throw new Error("XML data is accepted in String or Bytes[] form.");if(s){s===!0&&(s={});let i=Ps.validate(e,s);if(i!==!0)throw Error(`${i.err.msg}:${i.err.line}:${i.err.col}`)}let n=new Ss(this.options);n.addExternalEntities(this.externalEntities);let r=n.parseXml(e);return this.options.preserveOrder||r===void 0?r:As(r,this.options)}addEntity(e,s){if(s.indexOf("&")!==-1)throw new Error("Entity value can't have '&'");if(e.indexOf("&")!==-1||e.indexOf(";")!==-1)throw new Error("An entity must be set without '&' and ';'. Eg. use '#xD' for '&#xD;'");if(s==="&")throw new Error("An entity with value '&' is not permitted");this.externalEntities[e]=s}};Je.exports=pe});var tt=v((bn,et)=>{function Ts(t,e){let s="";return e.format&&e.indentBy.length>0&&(s=`
5
+ `),De(t,e,"",s)}function De(t,e,s,n){let r="",i=!1;if(!Array.isArray(t)){if(t!=null){let o=t.toString();return o=fe(o,e),o}return""}for(let o=0;o<t.length;o++){let c=t[o],a=Ns(c);if(a===void 0)continue;let d="";if(s.length===0?d=a:d=`${s}.${a}`,a===e.textNodeName){let g=c[a];vs(d,e)||(g=e.tagValueProcessor(a,g),g=fe(g,e)),i&&(r+=n),r+=g,i=!1;continue}else if(a===e.cdataPropName){i&&(r+=n),r+=`<![CDATA[${c[a][0][e.textNodeName]}]]>`,i=!1;continue}else if(a===e.commentPropName){r+=n+`<!--${c[a][0][e.textNodeName]}-->`,i=!0;continue}else if(a[0]==="?"){let g=Ze(c[":@"],e),y=a==="?xml"?"":n,h=c[a][0][e.textNodeName];h=h.length!==0?" "+h:"",r+=y+`<${a}${h}${g}?>`,i=!0;continue}let l=n;l!==""&&(l+=e.indentBy);let u=Ze(c[":@"],e),f=n+`<${a}${u}`,m=De(c[a],e,d,l);e.unpairedTags.indexOf(a)!==-1?e.suppressUnpairedNode?r+=f+">":r+=f+"/>":(!m||m.length===0)&&e.suppressEmptyNode?r+=f+"/>":m&&m.endsWith(">")?r+=f+`>${m}${n}</${a}>`:(r+=f+">",m&&n!==""&&(m.includes("/>")||m.includes("</"))?r+=n+e.indentBy+m+n:r+=m,r+=`</${a}>`),i=!0}return r}function Ns(t){let e=Object.keys(t);for(let s=0;s<e.length;s++){let n=e[s];if(Object.prototype.hasOwnProperty.call(t,n)&&n!==":@")return n}}function Ze(t,e){let s="";if(t&&!e.ignoreAttributes)for(let n in t){if(!Object.prototype.hasOwnProperty.call(t,n))continue;let r=e.attributeValueProcessor(n,t[n]);r=fe(r,e),r===!0&&e.suppressBooleanAttributes?s+=` ${n.substr(e.attributeNamePrefix.length)}`:s+=` ${n.substr(e.attributeNamePrefix.length)}="${r}"`}return s}function vs(t,e){t=t.substr(0,t.length-e.textNodeName.length-1);let s=t.substr(t.lastIndexOf(".")+1);for(let n in e.stopNodes)if(e.stopNodes[n]===t||e.stopNodes[n]==="*."+s)return!0;return!1}function fe(t,e){if(t&&t.length>0&&e.processEntities)for(let s=0;s<e.entities.length;s++){let n=e.entities[s];t=t.replace(n.regex,n.val)}return t}et.exports=Ts});var nt=v((Cn,st)=>{"use strict";var xs=tt(),ks=ce(),$s={attributeNamePrefix:"@_",attributesGroupName:!1,textNodeName:"#text",ignoreAttributes:!0,cdataPropName:!1,format:!1,indentBy:" ",suppressEmptyNode:!1,suppressUnpairedNode:!0,suppressBooleanAttributes:!0,tagValueProcessor:function(t,e){return e},attributeValueProcessor:function(t,e){return e},preserveOrder:!1,commentPropName:!1,unpairedTags:[],entities:[{regex:new RegExp("&","g"),val:"&amp;"},{regex:new RegExp(">","g"),val:"&gt;"},{regex:new RegExp("<","g"),val:"&lt;"},{regex:new RegExp("'","g"),val:"&apos;"},{regex:new RegExp('"',"g"),val:"&quot;"}],processEntities:!0,stopNodes:[],oneListGroup:!1};function I(t){this.options=Object.assign({},$s,t),this.options.ignoreAttributes===!0||this.options.attributesGroupName?this.isAttribute=function(){return!1}:(this.ignoreAttributesFn=ks(this.options.ignoreAttributes),this.attrPrefixLen=this.options.attributeNamePrefix.length,this.isAttribute=Is),this.processTextOrObjNode=Rs,this.options.format?(this.indentate=Os,this.tagEndChar=`>
6
+ `,this.newLine=`
7
+ `):(this.indentate=function(){return""},this.tagEndChar=">",this.newLine="")}I.prototype.build=function(t){return this.options.preserveOrder?xs(t,this.options):(Array.isArray(t)&&this.options.arrayNodeName&&this.options.arrayNodeName.length>1&&(t={[this.options.arrayNodeName]:t}),this.j2x(t,0,[]).val)};I.prototype.j2x=function(t,e,s){let n="",r="",i=s.join(".");for(let o in t)if(Object.prototype.hasOwnProperty.call(t,o))if(typeof t[o]>"u")this.isAttribute(o)&&(r+="");else if(t[o]===null)this.isAttribute(o)||o===this.options.cdataPropName?r+="":o[0]==="?"?r+=this.indentate(e)+"<"+o+"?"+this.tagEndChar:r+=this.indentate(e)+"<"+o+"/"+this.tagEndChar;else if(t[o]instanceof Date)r+=this.buildTextValNode(t[o],o,"",e);else if(typeof t[o]!="object"){let c=this.isAttribute(o);if(c&&!this.ignoreAttributesFn(c,i))n+=this.buildAttrPairStr(c,""+t[o]);else if(!c)if(o===this.options.textNodeName){let a=this.options.tagValueProcessor(o,""+t[o]);r+=this.replaceEntitiesValue(a)}else r+=this.buildTextValNode(t[o],o,"",e)}else if(Array.isArray(t[o])){let c=t[o].length,a="",d="";for(let l=0;l<c;l++){let u=t[o][l];if(!(typeof u>"u"))if(u===null)o[0]==="?"?r+=this.indentate(e)+"<"+o+"?"+this.tagEndChar:r+=this.indentate(e)+"<"+o+"/"+this.tagEndChar;else if(typeof u=="object")if(this.options.oneListGroup){let f=this.j2x(u,e+1,s.concat(o));a+=f.val,this.options.attributesGroupName&&u.hasOwnProperty(this.options.attributesGroupName)&&(d+=f.attrStr)}else a+=this.processTextOrObjNode(u,o,e,s);else if(this.options.oneListGroup){let f=this.options.tagValueProcessor(o,u);f=this.replaceEntitiesValue(f),a+=f}else a+=this.buildTextValNode(u,o,"",e)}this.options.oneListGroup&&(a=this.buildObjectNode(a,o,d,e)),r+=a}else if(this.options.attributesGroupName&&o===this.options.attributesGroupName){let c=Object.keys(t[o]),a=c.length;for(let d=0;d<a;d++)n+=this.buildAttrPairStr(c[d],""+t[o][c[d]])}else r+=this.processTextOrObjNode(t[o],o,e,s);return{attrStr:n,val:r}};I.prototype.buildAttrPairStr=function(t,e){return e=this.options.attributeValueProcessor(t,""+e),e=this.replaceEntitiesValue(e),this.options.suppressBooleanAttributes&&e==="true"?" "+t:" "+t+'="'+e+'"'};function Rs(t,e,s,n){let r=this.j2x(t,s+1,n.concat(e));return t[this.options.textNodeName]!==void 0&&Object.keys(t).length===1?this.buildTextValNode(t[this.options.textNodeName],e,r.attrStr,s):this.buildObjectNode(r.val,e,r.attrStr,s)}I.prototype.buildObjectNode=function(t,e,s,n){if(t==="")return e[0]==="?"?this.indentate(n)+"<"+e+s+"?"+this.tagEndChar:this.indentate(n)+"<"+e+s+this.closeTag(e)+this.tagEndChar;{let r="</"+e+this.tagEndChar,i="";return e[0]==="?"&&(i="?",r=""),(s||s==="")&&t.indexOf("<")===-1?this.indentate(n)+"<"+e+s+i+">"+t+r:this.options.commentPropName!==!1&&e===this.options.commentPropName&&i.length===0?this.indentate(n)+`<!--${t}-->`+this.newLine:this.indentate(n)+"<"+e+s+i+this.tagEndChar+t+this.indentate(n)+r}};I.prototype.closeTag=function(t){let e="";return this.options.unpairedTags.indexOf(t)!==-1?this.options.suppressUnpairedNode||(e="/"):this.options.suppressEmptyNode?e="/":e=`></${t}`,e};I.prototype.buildTextValNode=function(t,e,s,n){if(this.options.cdataPropName!==!1&&e===this.options.cdataPropName)return this.indentate(n)+`<![CDATA[${t}]]>`+this.newLine;if(this.options.commentPropName!==!1&&e===this.options.commentPropName)return this.indentate(n)+`<!--${t}-->`+this.newLine;if(e[0]==="?")return this.indentate(n)+"<"+e+s+"?"+this.tagEndChar;{let r=this.options.tagValueProcessor(e,t);return r=this.replaceEntitiesValue(r),r===""?this.indentate(n)+"<"+e+s+this.closeTag(e)+this.tagEndChar:this.indentate(n)+"<"+e+s+">"+r+"</"+e+this.tagEndChar}};I.prototype.replaceEntitiesValue=function(t){if(t&&t.length>0&&this.options.processEntities)for(let e=0;e<this.options.entities.length;e++){let s=this.options.entities[e];t=t.replace(s.regex,s.val)}return t};function Os(t){return this.options.indentBy.repeat(t)}function Is(t){return t.startsWith(this.options.attributeNamePrefix)&&t!==this.options.textNodeName?t.substr(this.attrPrefixLen):!1}st.exports=I});var it=v((Sn,rt)=>{"use strict";var _s=re(),Ms=Qe(),Ls=nt();rt.exports={XMLParser:Ms,XMLValidator:_s,XMLBuilder:Ls}});var wt={};Se(wt,{claudeCodeUserConfigPath:()=>W,claudeDesktopConfigPath:()=>K,detectClaudeInstallations:()=>z,isStaleEntry:()=>he,isStaleVsCodeHelperCommand:()=>zs,probeSapAbapRegistration:()=>we,removeFromClaude:()=>me,syncToClaude:()=>se});function Ws(t){try{let n=process.env.SHELL||"/bin/zsh",r=(0,ft.execSync)(`${n} -lc 'command -v ${t}'`,{encoding:"utf-8",timeout:4e3}).trim();if(r&&r.startsWith("/"))return r}catch{}let e=process.platform==="win32"?`${t}.cmd`:t,s=process.platform==="win32"?[`C:\\Program Files\\nodejs\\${e}`,`${process.env.APPDATA||""}\\npm\\${e}`]:[`/opt/homebrew/bin/${t}`,`/usr/local/bin/${t}`,`/usr/bin/${t}`];for(let n of s)try{if(gt.existsSync(n))return n}catch{}return t}function Ks(t){return{type:"stdio",command:Ws("npx"),args:["-y",js],env:{SAP_HOST:t.host,SAP_CLIENT:t.client,SAP_USER:t.user,SAP_PASSWORD:t.password,SAP_LANG:t.lang,SAP_VERIFY_SSL:String(t.verifySsl),SAP_READONLY:String(t.readonly),SAP_TIMEOUT:String(Math.floor(t.timeoutMs/1e3))}}}function he(t){let e=t.command;return!(!e||/(^|[\\/])npx(\.cmd)?$/.test(e))}function zs(t){return t?t.includes("Code Helper (Plugin)")||t.includes("Visual Studio Code.app"):!1}function W(){return q.join(ge.homedir(),".claude.json")}function K(){let t=ge.homedir();return process.platform==="darwin"?q.join(t,"Library/Application Support/Claude/claude_desktop_config.json"):process.platform==="win32"?q.join(t,"AppData/Roaming/Claude/claude_desktop_config.json"):q.join(t,".config/Claude/claude_desktop_config.json")}async function ht(t){try{let e=await x.readFile(t,"utf-8");return e.trim()?JSON.parse(e):{}}catch(e){if(e.code==="ENOENT")return{};throw e}}async function mt(t,e){await x.mkdir(q.dirname(t),{recursive:!0});let s=t+".tmp-"+Date.now();await x.writeFile(s,JSON.stringify(e,null,2)+`
8
+ `,{mode:384}),await x.rename(s,t)}async function pt(t,e){let s=await ht(t),n=s.mcpServers??{},r=j in n;return n[j]=e,s.mcpServers=n,await mt(t,s),{existed:r}}async function Js(t){let e;try{e=await ht(t)}catch{return!1}let s=e.mcpServers;return!s||!(j in s)?!1:(delete s[j],e.mcpServers=s,await mt(t,e),!0)}async function se(t,e){let s={written:[],skipped:[],errors:[]},n=Ks(t);if(e.claudeCodeUser){let r=W();try{let{existed:i}=await pt(r,n);s.written.push(`Claude Code (${i?"updated":"added"}): ${r}`)}catch(i){s.errors.push({target:"Claude Code (user)",message:i instanceof Error?i.message:String(i)})}}else s.skipped.push("Claude Code (user)");if(e.claudeDesktop){let r=K();try{let{existed:i}=await pt(r,n);s.written.push(`Claude Desktop (${i?"updated":"added"}): ${r}`)}catch(i){s.errors.push({target:"Claude Desktop",message:i instanceof Error?i.message:String(i)})}}else s.skipped.push("Claude Desktop");return s}async function me(){let t={written:[],skipped:[],errors:[]};for(let[e,s]of[["Claude Code (user)",W()],["Claude Desktop",K()]])try{await Js(s)?t.written.push(`Removed from ${e}: ${s}`):t.skipped.push(`${e} (no entry to remove)`)}catch(n){t.errors.push({target:e,message:n instanceof Error?n.message:String(n)})}return t}async function z(){let t=await Promise.all([x.access(W()).then(()=>!0,()=>!1),x.access(K()).then(()=>!0,()=>!1)]);return{claudeCodeUser:t[0],claudeDesktop:t[1]}}async function we(){let t=async n=>{try{await x.access(n)}catch{return{exists:!1,configured:!1}}try{let r=await x.readFile(n,"utf-8"),i=JSON.parse(r);return{exists:!0,configured:!!(i.mcpServers&&j in i.mcpServers)}}catch{return{exists:!0,configured:!1}}},[e,s]=await Promise.all([t(W()),t(K())]);return{claudeCodeUser:e,claudeDesktop:s}}var ft,x,gt,ge,q,j,js,ye=xt(()=>{"use strict";ft=require("node:child_process"),x=R(require("node:fs/promises")),gt=R(require("node:fs")),ge=R(require("node:os")),q=R(require("node:path")),j="sap-abap",js="sap-abap-mcp"});var cn={};Se(cn,{activate:()=>Zs,deactivate:()=>tn});module.exports=kt(cn);var yt=R(require("node:path")),p=R(require("vscode"));var Us=R(require("node:https")),qs=R(require("node:http")),dt=require("node:url"),ut=R(it()),C=class extends Error{constructor(s,n,r){super(s);this.status=n;this.body=r;this.name="ADTError"}status;body};var Bs="http://www.sap.com/adt/programs/programs",Vs="http://www.sap.com/adt/oo/classes",U="http://www.sap.com/adt/core",Fs={DDLS:{path:"ddic/ddl/sources",ct:"application/vnd.sap.adt.ddlSource+xml",nsPrefix:"ddls",nsUri:"http://www.sap.com/adt/ddic/ddlsources",root:"ddlSource",nameInUrl:"upper",extraAttrs:""},BDEF:{path:"bo/behaviordefinitions",ct:"application/vnd.sap.adt.blues.v1+xml",nsPrefix:"blue",nsUri:"http://www.sap.com/wbobj/blue",root:"blueSource",nameInUrl:"lower",extraAttrs:""},SRVD:{path:"ddic/srvd/sources",ct:"application/vnd.sap.adt.ddic.srvd.v1+xml",nsPrefix:"srvd",nsUri:"http://www.sap.com/adt/ddic/srvdsources",root:"srvdSource",nameInUrl:"upper",extraAttrs:' srvd:srvdSourceType="S" adtcore:type="SRVD/SRV"'}},ot={ODATA_V4_UI:["ODATA","V4","1"],ODATA_V4_WEBAPI:["ODATA","V4","0"],ODATA_V2_UI:["ODATA","V2","1"],ODATA_V2_WEBAPI:["ODATA","V2","0"],INA:["INA","","0"],SQL:["SQL","","1"]},lt=new ut.XMLParser({ignoreAttributes:!1,attributeNamePrefix:"@_",removeNSPrefix:!0,parseAttributeValue:!1,parseTagValue:!1,trimValues:!0}),X=class{constructor(e){this.settings=e;this.base=`${e.host.replace(/\/$/,"")}/sap/bc/adt`}settings;base;cookies=new Map;async request(e){let s=new dt.URL(this.base+e.path);for(let[a,d]of Object.entries(e.query||{}))s.searchParams.set(a,d);let n=s.protocol==="https:",i={Authorization:`Basic ${Buffer.from(`${this.settings.user}:${this.settings.password}`).toString("base64")}`,"sap-client":this.settings.client,"Accept-Language":this.settings.lang,...e.headers||{}};this.cookies.size>0&&(i.Cookie=[...this.cookies.entries()].map(([a,d])=>`${a}=${d}`).join("; "));let o=n?Us:qs,c={method:e.method||"GET",hostname:s.hostname,port:s.port||(n?443:80),path:s.pathname+s.search,headers:i,timeout:this.settings.timeoutMs};return n&&(c.rejectUnauthorized=this.settings.verifySsl),new Promise((a,d)=>{let l=o.request(c,u=>{let f=u.headers["set-cookie"];if(f)for(let g of f){let[y]=g.split(";"),h=y.indexOf("=");h>0&&this.cookies.set(y.slice(0,h).trim(),y.slice(h+1).trim())}let m=[];u.on("data",g=>m.push(g)),u.on("end",()=>a({status:u.statusCode||0,headers:u.headers,text:Buffer.concat(m).toString("utf-8")}))});l.on("error",d),l.on("timeout",()=>{l.destroy(new Error(`Request timed out after ${this.settings.timeoutMs}ms`))}),e.body&&l.write(e.body),l.end()})}async csrf(){let s=(await this.request({method:"GET",path:"/discovery",headers:{"x-csrf-token":"Fetch"}})).headers["x-csrf-token"];return typeof s=="string"?s:""}ensureOk(e,s){if(e.status>=400)throw new C(`${s} failed: HTTP ${e.status}`,e.status,e.text.slice(0,2e3))}async testConnection(){try{let e=/^\d{1,3}$/.test(this.settings.client)?this.settings.client:"000",s=`SELECT MANDT, MTEXT FROM T000 WHERE MANDT = '${e}'`,n=await this.sqlQueryRaw(s,1),r=ct(n.text);return r.length>0?{status:"ok",client:r[0].MANDT||e,description:r[0].MTEXT||"",host:this.settings.host}:{status:"warning",message:`Connected, but client '${e}' was not found in T000. Verify the SAP_CLIENT setting.`,client:e,host:this.settings.host,diagnostic:{rawXml:n.text.slice(0,4e3),httpStatus:n.status}}}catch(e){let s=e;return{status:"error",message:s.message||String(e),diagnostic:{rawXml:s.body,httpStatus:s.status}}}}async sqlQueryRaw(e,s=100){if(!at(e))throw new C("Only SELECT statements are allowed.");let n=await this.csrf(),r=await this.request({method:"POST",path:"/datapreview/freestyle",query:{rowNumber:String(s)},headers:{Accept:"application/vnd.sap.adt.datapreview.table.v1+xml","Content-Type":"text/plain","x-csrf-token":n},body:e});return this.ensureOk(r,"SQL query"),r}async sqlQuery(e,s=100){if(!at(e))throw new C("Only SELECT statements are allowed via sqlQuery. Use the ABAP tools for write operations.");let n=await this.csrf(),r=await this.request({method:"POST",path:"/datapreview/freestyle",query:{rowNumber:String(s)},headers:{Accept:"application/vnd.sap.adt.datapreview.table.v1+xml","Content-Type":"text/plain","x-csrf-token":n},body:e});return this.ensureOk(r,"SQL query"),ct(r.text)}async readSource(e,s){let n=await this.request({method:"GET",path:D(e,s),headers:{Accept:"text/plain"}});return this.ensureOk(n,`Read ${e} ${s}`),n.text}async searchObjects(e,s="",n=50){let r={operation:"quickSearch",query:e,maxResults:String(n)};s&&(r.objectType=s);let i=await this.request({method:"GET",path:"/repository/informationsystem/search",query:r,headers:{Accept:"application/xml"}});return this.ensureOk(i,"Object search"),Ys(i.text)}async listPackage(e){let s=await this.csrf(),n=await this.request({method:"POST",path:"/repository/nodestructure",query:{parent_name:e,parent_tech_name:e},headers:{Accept:"application/vnd.sap.as+xml","x-csrf-token":s,"Content-Length":"0"},body:""});return this.ensureOk(n,`List package ${e}`),Hs(n.text)}async tableInfo(e){let s=`SELECT FIELDNAME, KEYFLAG, ROLLNAME, DATATYPE, LENG, DECIMALS, POSITION FROM DD03L WHERE TABNAME = '${e.toUpperCase()}' AND AS4LOCAL = 'A' ORDER BY POSITION`,n=await this.sqlQuery(s,500);return{table:e.toUpperCase(),fields:n,field_count:n.length}}async syntaxCheck(e,s){let n=await this.csrf(),r=`/sap/bc/adt${D(e,s)}`,i=`<?xml version="1.0" encoding="UTF-8"?><chkrun:checkObjectList xmlns:adtcore="${U}" xmlns:chkrun="http://www.sap.com/adt/checkrun"><chkrun:checkObject adtcore:uri="${r}" adtcore:version="active"/></chkrun:checkObjectList>`,o=await this.request({method:"POST",path:"/checkruns",query:{reporters:"abapCheckRun"},headers:{"Content-Type":"application/vnd.sap.adt.checkobjects+xml",Accept:"application/vnd.sap.adt.checkmessages+xml","x-csrf-token":n},body:i});return this.ensureOk(o,`Syntax check ${e} ${s}`),Xs(o.text)}async createProgram(e,s,n="",r="$TMP",i=""){let o=await this.csrf(),c=`<?xml version="1.0" encoding="UTF-8"?><pgm:abapProgram xmlns:pgm="${Bs}" xmlns:adtcore="${U}" adtcore:name="${e}" adtcore:type="PROG/P" adtcore:description="${te(n)}" pgm:lockedByEditor="false" pgm:programType="executableProgram"><adtcore:packageRef adtcore:name="${r}"/></pgm:abapProgram>`,a={};i&&(a.corrNr=i);let d=await this.request({method:"POST",path:"/programs/programs",query:a,headers:{"Content-Type":"application/vnd.sap.adt.programs.programs+xml","x-csrf-token":o},body:c});return this.ensureOk(d,`Create program ${e}`),this.putSource("PROG",e,s,i)}async deployProgram(e,s,n="",r="$TMP",i="",o=!0){let c=!1,a;try{await this.readSource("PROG",e),a=await this.putSource("PROG",e,s,i)}catch(d){if(d instanceof C&&d.status===404)a=await this.createProgram(e,s,n,r,i),c=!0;else throw d}return a.created=c,o&&(a.activation=await this.activate("PROG",e)),a}async createClass(e,s,n="",r="$TMP",i=""){let o=await this.csrf(),c=`<?xml version="1.0" encoding="UTF-8"?><class:abapClass xmlns:class="${Vs}" xmlns:adtcore="${U}" adtcore:name="${e}" adtcore:type="CLAS/OC" adtcore:description="${te(n)}" class:final="true" class:visibility="public"><adtcore:packageRef adtcore:name="${r}"/></class:abapClass>`,a={};i&&(a.corrNr=i);let d=await this.request({method:"POST",path:"/oo/classes",query:a,headers:{"Content-Type":"application/vnd.sap.adt.oo.classes.v3+xml","x-csrf-token":o},body:c});return this.ensureOk(d,`Create class ${e}`),this.putSource("CLAS",e,s,i)}async deployClass(e,s,n="",r="$TMP",i="",o=!0){let c=!1,a;try{await this.readSource("CLAS",e),a=await this.putSource("CLAS",e,s,i)}catch(d){if(d instanceof C&&d.status===404)a=await this.createClass(e,s,n,r,i),c=!0;else throw d}return a.created=c,o&&(a.activation=await this.activate("CLAS",e)),a}async putSource(e,s,n,r=""){let i=await this.csrf(),o=await this.request({method:"GET",path:D(e,s),headers:{"x-csrf-token":i}}),c=o.headers.etag||o.headers.etag||"",a={};r&&(a.corrNr=r);let d=await this.acquireLock(e,s,i);d&&(a.lockHandle=d);try{let l={"Content-Type":"text/plain; charset=utf-8",Accept:"text/plain","x-csrf-token":i};c&&(l["If-Match"]=c);let u=await this.request({method:"PUT",path:D(e,s),query:a,headers:l,body:Buffer.from(n,"utf-8")});return this.ensureOk(u,`Upload source ${e} ${s}`),{ok:!0,status:u.status}}finally{d&&await this.releaseLock(e,s,i,d)}}async acquireLock(e,s,n){let r=await this.request({method:"POST",path:ee(e,s),query:{_action:"LOCK",accessMode:"MODIFY"},headers:{"x-csrf-token":n,"X-sap-adt-sessiontype":"stateful",Accept:"application/vnd.sap.as+xml;dataname=com.sap.adt.lock.Result"}});if(r.status>=400)return null;let i=r.text.match(/<LOCK_HANDLE[^>]*>([^<]+)<\/LOCK_HANDLE>/i);return i?i[1]:null}async releaseLock(e,s,n,r){try{await this.request({method:"POST",path:ee(e,s),query:{_action:"UNLOCK",lockHandle:r},headers:{"x-csrf-token":n,"X-sap-adt-sessiontype":"stateful"}})}catch{}}async activate(e,s){let n=await this.csrf(),r=`/sap/bc/adt${ee(e,s)}`,i=`<?xml version="1.0" encoding="UTF-8"?><adtcore:objectReferences xmlns:adtcore="${U}"><adtcore:objectReference adtcore:uri="${r}" adtcore:name="${s}"/></adtcore:objectReferences>`,o=await this.request({method:"POST",path:"/activation",query:{method:"activate",preauditRequested:"true"},headers:{"Content-Type":"application/xml",Accept:"application/xml","x-csrf-token":n},body:i});return this.ensureOk(o,`Activate ${e} ${s}`),{ok:!o.text.includes("<chkl:messages")||!o.text.includes('type="E"'),status:o.status,body:o.text.slice(0,1500)}}async deleteObject(e,s,n=""){let r=await this.csrf(),i={};n&&(i.corrNr=n);let o=await this.acquireLock(e,s,r);o&&(i.lockHandle=o);try{let c=await this.request({method:"DELETE",path:ee(e,s),query:i,headers:{"x-csrf-token":r,"X-sap-adt-sessiontype":"stateful"}});return c.status===404?{ok:!0,status:404,message:"Already absent"}:(this.ensureOk(c,`Delete ${e} ${s}`),{ok:!0,status:c.status})}finally{o&&await this.releaseLock(e,s,r,o)}}async createTable(e,s,n="",r="$TMP",i=!0){e=e.toUpperCase(),i&&!s.some(g=>g.name.toUpperCase()==="MANDT")&&(s=[{name:"MANDT",type:"CLNT",length:3,key:!0,rollname:"MANDT"},...s]);let o=n.slice(0,60).replaceAll("'","''"),c=r.replace(/'/g,"''"),a=["DATA: ls_dd02v TYPE dd02v,"," ls_dd09l TYPE dd09l,"," lt_dd03p TYPE STANDARD TABLE OF dd03p,"," ls_dd03p TYPE dd03p,"," ls_tadir TYPE tadir.","","ls_tadir-pgmid = 'R3TR'.","ls_tadir-object = 'TABL'.",`ls_tadir-obj_name = '${e}'.`,`ls_tadir-devclass = '${c}'.`,"ls_tadir-srcsystem = sy-sysid.","ls_tadir-author = sy-uname.","ls_tadir-masterlang = sy-langu.","MODIFY tadir FROM ls_tadir.","","",`ls_dd02v-tabname = '${e}'.`,"ls_dd02v-tabclass = 'TRANSP'.","ls_dd02v-mainflag = 'X'.","ls_dd02v-contflag = 'A'.","ls_dd02v-as4user = sy-uname.",`ls_dd02v-ddtext = '${o}'.`,"",`ls_dd09l-tabname = '${e}'.`,"ls_dd09l-as4user = sy-uname.","ls_dd09l-tabkat = '0'.","ls_dd09l-tabart = 'APPL0'.","ls_dd09l-bufallow = 'N'.","ls_dd09l-pufferung = ' '.","ls_dd09l-schfeldanz = '0'.","ls_dd09l-protokoll = ' '.",""];s.forEach((g,y)=>{let h=y+1,b=g.name.toUpperCase(),S=g.type.toUpperCase(),k=g.length,N=!!g.key,F=g.notnull??N,A=(g.rollname||"").toUpperCase(),_=(g.ref_table||(g.ref_field?e:"")).toUpperCase(),be=(g.ref_field||"").toUpperCase(),Ce=(g.description||"").slice(0,60).replaceAll("'","''");a.push("CLEAR ls_dd03p."),a.push(`ls_dd03p-tabname = '${e}'.`),a.push(`ls_dd03p-fieldname = '${b}'.`),a.push(`ls_dd03p-position = '${String(h).padStart(4,"0")}'.`),N&&a.push("ls_dd03p-keyflag = 'X'."),F&&a.push("ls_dd03p-notnull = 'X'."),A&&a.push(`ls_dd03p-rollname = '${A}'.`),a.push(`ls_dd03p-datatype = '${S}'.`),a.push(`ls_dd03p-leng = '${String(k).padStart(6,"0")}'.`),g.decimals!==void 0&&a.push(`ls_dd03p-decimals = '${String(g.decimals).padStart(6,"0")}'.`),be&&(a.push(`ls_dd03p-reftable = '${_}'.`),a.push(`ls_dd03p-reffield = '${be}'.`)),Ce&&a.push(`ls_dd03p-ddtext = '${Ce}'.`),a.push("APPEND ls_dd03p TO lt_dd03p."),a.push("")}),a.push("CALL FUNCTION 'DDIF_TABL_PUT'",` EXPORTING name = '${e}'`," dd02v_wa = ls_dd02v"," dd09l_wa = ls_dd09l"," TABLES dd03p_tab = lt_dd03p"," EXCEPTIONS OTHERS = 99.","out->write( |PUT subrc=| && |{ sy-subrc }| ).","COMMIT WORK.");let d=a.join(`
9
+ `),l=await this.runAbap(d,120);if(!l.ok)return{ok:!1,step:"put",name:e,put:l};let u=await this.activate("TABL",e),f=`UPDATE dd02l SET as4local = 'A' WHERE tabname = '${e}'.
10
+ COMMIT WORK.
11
+ out->write( sy-dbcnt ).`,m=await this.runAbap(f);return{ok:u.ok===!0,name:e,put:l,activation:u,as4local_fix:m.output||""}}async deployDdls(e,s,n="",r="$TMP",i="",o=!0){return this.deployRap("DDLS",e,s,n,r,i,o)}async deployBdef(e,s,n="",r="$TMP",i="",o=!0){return this.deployRap("BDEF",e,s,n,r,i,o)}async deploySrvd(e,s,n="",r="$TMP",i="",o=!0){return this.deployRap("SRVD",e,s,n,r,i,o)}async deployRap(e,s,n,r,i,o,c){let a=Fs[e];s=s.toUpperCase();let d=a.nameInUrl==="upper"?s:s.toLowerCase(),l=`/${a.path}`,u=`${l}/${d}`,f=`${u}/source/main`,m=await this.csrf(),g=await this.request({method:"GET",path:u,headers:{Accept:a.ct}}),y=g.status===200?"updated":"created";if(g.status!==200){let S=`<?xml version="1.0" encoding="UTF-8"?>
12
+ <${a.nsPrefix}:${a.root} xmlns:${a.nsPrefix}="${a.nsUri}" xmlns:adtcore="${U}" adtcore:name="${s}" adtcore:description="${te(r)}"${a.extraAttrs}><adtcore:packageRef adtcore:name="${i}"/></${a.nsPrefix}:${a.root}>`,k={};o&&(k.corrNr=o);let N=await this.request({method:"POST",path:l,query:k,headers:{"Content-Type":a.ct,Accept:a.ct,"x-csrf-token":m},body:S});if(N.status!==200&&N.status!==201)throw new C(`Create ${e} ${s} failed: HTTP ${N.status}`,N.status,N.text.slice(0,1500))}let h=await this.acquireLockUrl(u,m);if(!h)throw new C(`Lock acquire failed for ${e} ${s}`);try{let S={lockHandle:h};o&&(S.corrNr=o);let k=await this.request({method:"PUT",path:f,query:S,headers:{"Content-Type":"text/plain; charset=utf-8","x-csrf-token":m},body:Buffer.from(n,"utf-8")});if(k.status!==200&&k.status!==204)throw new C(`Upload ${e} ${s} source failed: HTTP ${k.status}`,k.status,k.text.slice(0,1500))}finally{await this.releaseLockUrl(u,m,h)}let b={ok:!0,name:s,action:y,object_type:e};if(c){let S=await this.activateUrl(e,s,u);b.activation=S,b.ok=S.ok===!0}return b}async deploySrvb(e,s,n="",r="$TMP",i="ODATA_V4_UI",o="",c=!0){let a=ot[i.toUpperCase()];if(!a)throw new C(`Unknown binding_type '${i}'. Choose from: ${Object.keys(ot).join(", ")}`);let[d,l,u]=a;e=e.toUpperCase(),s=s.toUpperCase();let f="/businessservices/bindings",m=`${f}/${e.toLowerCase()}`,g="application/vnd.sap.adt.businessservices.servicebinding.v2+xml",y=l?` srvb:version="${l}"`:"",h=`<?xml version="1.0" encoding="UTF-8"?>
13
+ <srvb:serviceBinding xmlns:srvb="http://www.sap.com/adt/ddic/ServiceBindings"
14
+ xmlns:adtcore="${U}"
15
+ srvb:contract="C2"
16
+ adtcore:name="${e}"
17
+ adtcore:description="${te(n)}"
18
+ adtcore:type="SRVB/SVB">
19
+ <adtcore:packageRef adtcore:name="${r}"/>
20
+ <srvb:services srvb:name="${e}">
21
+ <srvb:content srvb:version="0001" srvb:releaseState="NOT_RELEASED">
22
+ <srvb:serviceDefinition adtcore:uri="/sap/bc/adt/ddic/srvd/sources/${s.toLowerCase()}" adtcore:type="SRVD/SRV" adtcore:name="${s}"/>
23
+ </srvb:content>
24
+ </srvb:services>
25
+ <srvb:binding srvb:type="${d}"${y} srvb:category="${u}">
26
+ <srvb:implementation adtcore:name="${e}"/>
27
+ </srvb:binding>
28
+ </srvb:serviceBinding>`,b=await this.csrf(),S=await this.request({method:"GET",path:m,headers:{Accept:g}}),k=S.status===200?"updated":"created",N={};if(o&&(N.corrNr=o),S.status===200){let A=await this.acquireLockUrl(m,b);if(!A)throw new C(`Lock failed for SRVB ${e}`);try{N.lockHandle=A;let _=await this.request({method:"PUT",path:m,query:N,headers:{"Content-Type":g,Accept:g,"x-csrf-token":b},body:h});if(_.status!==200&&_.status!==204)throw new C(`Update SRVB ${e} failed: HTTP ${_.status}`,_.status,_.text.slice(0,1500))}finally{await this.releaseLockUrl(m,b,A)}}else{let A=await this.request({method:"POST",path:f,query:N,headers:{"Content-Type":g,Accept:g,"x-csrf-token":b},body:h});if(A.status!==200&&A.status!==201)throw new C(`Create SRVB ${e} failed: HTTP ${A.status}`,A.status,A.text.slice(0,1500))}let F={ok:!0,name:e,action:k,binding_type:i.toUpperCase(),object_type:"SRVB",note:"Activated but not published \u2014 publish from Eclipse / VS Code ADT."};if(c){let A=await this.activateUrl("SRVB",e,m);F.activation=A,F.ok=A.ok===!0}return F}async acquireLockUrl(e,s){let n=await this.request({method:"POST",path:e,query:{_action:"LOCK",accessMode:"MODIFY"},headers:{"x-csrf-token":s,"X-sap-adt-sessiontype":"stateful",Accept:"application/vnd.sap.as+xml;dataname=com.sap.adt.lock.Result"}});if(n.status>=400)return null;let r=n.text.match(/<LOCK_HANDLE[^>]*>([^<]+)<\/LOCK_HANDLE>/i);return r?r[1]:null}async releaseLockUrl(e,s,n){try{await this.request({method:"POST",path:e,query:{_action:"UNLOCK",lockHandle:n},headers:{"x-csrf-token":s,"X-sap-adt-sessiontype":"stateful"}})}catch{}}async activateUrl(e,s,n){let r=await this.csrf(),i=`/sap/bc/adt${n}`,o=`<?xml version="1.0" encoding="UTF-8"?><adtcore:objectReferences xmlns:adtcore="${U}"><adtcore:objectReference adtcore:uri="${i}" adtcore:name="${s}"/></adtcore:objectReferences>`,c=await this.request({method:"POST",path:"/activation",query:{method:"activate",preauditRequested:"true"},headers:{"Content-Type":"application/xml",Accept:"application/xml","x-csrf-token":r},body:o});if(c.status>=400)throw new C(`Activate ${e} ${s} failed: HTTP ${c.status}`,c.status,c.text.slice(0,1500));return{ok:!c.text.includes("<chkl:messages")||!c.text.includes('type="E"'),status:c.status,body:c.text.slice(0,1500)}}async runAbap(e,s=60){let r=`ZCL_MCP_RUN_${String(Date.now()).slice(-7)}`,i=e.split(`
29
+ `).map(c=>c.trim()?" "+c:c).join(`
30
+ `),o=`CLASS ${r} DEFINITION PUBLIC FINAL CREATE PUBLIC.
31
+ PUBLIC SECTION.
32
+ INTERFACES if_oo_adt_classrun.
33
+ ENDCLASS.
34
+ CLASS ${r} IMPLEMENTATION.
35
+ METHOD if_oo_adt_classrun~main.
36
+ TRY.
37
+ ${i}
38
+ CATCH cx_root INTO DATA(lx).
39
+ out->write( |ERROR: { lx->get_text( ) }| ).
40
+ ENDTRY.
41
+ ENDMETHOD.
42
+ ENDCLASS.`;try{await this.deployClass(r,o,"Transient classrun");let c=await this.classrun(r,s*1e3);return{ok:!c.startsWith("[HTTP")&&!c.includes("Error:"),output:c.trim()}}finally{try{await this.deleteObject("CLAS",r)}catch{}}}async classrun(e,s){this.cookies.clear();let n=await this.request({method:"GET",path:"/datapreview/freestyle",headers:{"x-csrf-token":"Fetch",Accept:"application/vnd.sap.adt.datapreview.table.v1+xml"}}),r=n.headers["x-csrf-token"]||n.headers["X-CSRF-Token"]||"",i=this.settings.timeoutMs;this.settings.timeoutMs=Math.max(s,i);try{let o=await this.request({method:"POST",path:`/oo/classrun/${e.toUpperCase()}`,headers:{Accept:"text/plain","x-csrf-token":r}});return o.status>=400?`[HTTP ${o.status}] ${o.text.slice(0,1e3)}`:o.text}finally{this.settings.timeoutMs=i}}};function D(t,e){let s=t.toUpperCase(),n=encodeURIComponent(e);switch(s){case"PROG":return`/programs/programs/${n}/source/main`;case"CLAS":return`/oo/classes/${n}/source/main`;case"INTF":return`/oo/interfaces/${n}/source/main`;case"FUGR":return`/functions/groups/${n}/source/main`;case"DDLS":return`/ddic/ddl/sources/${n}/source/main`;default:throw new C(`Unsupported object type for source: ${t}`)}}function ee(t,e){let s=t.toUpperCase(),n=encodeURIComponent(e);switch(s){case"PROG":return`/programs/programs/${n}`;case"CLAS":return`/oo/classes/${n}`;case"INTF":return`/oo/interfaces/${n}`;case"FUGR":return`/functions/groups/${n}`;case"DDLS":return`/ddic/ddl/sources/${n}`;case"TABL":return`/ddic/tables/${n}`;case"TRAN":return`/transactions/${n}`;default:throw new C(`Unsupported object type: ${t}`)}}function te(t){return t.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&apos;")}function at(t){let e=t.trim().replace(/^\(+/,"").trimStart().toUpperCase();if(!e.startsWith("SELECT")&&!e.startsWith("WITH"))return!1;let s=["INSERT ","UPDATE ","DELETE ","MODIFY ","DROP ","ALTER ","TRUNCATE ","CREATE "],n=t.toUpperCase();return!s.some(r=>n.includes(r))}function ct(t){let e=lt.parse(t),n=(e.tableData??e).columns;if(!n)return[];let r=Array.isArray(n)?n:[n],i=[];for(let a of r){let d=a.metadata,l=Gs(d,"name"),f=a.dataSet?.data,g=(f===void 0?[]:Array.isArray(f)?f:[f]).map(y=>typeof y=="string"?y:y==null?"":String(y));i.push({name:l,values:g})}if(i.length===0)return[];let o=Math.max(0,...i.map(a=>a.values.length)),c=[];for(let a=0;a<o;a++){let d={};for(let{name:l,values:u}of i)l&&(d[l]=u[a]??"");c.push(d)}return c}function Gs(t,e){if(!t)return"";for(let s of Object.keys(t))if(s===`@_${e}`||s.endsWith(`:${e}`)||s===e){let n=t[s];if(typeof n=="string")return n;if(n!=null)return String(n)}return""}function Ys(t){let s=lt.parse(t).objectReferences?.objectReference;return s?(Array.isArray(s)?s:[s]).map(r=>({name:r["@_name"]||"",type:r["@_type"]||"",description:r["@_description"]||"",package:r["@_packageName"]||"",uri:r["@_uri"]||""})):[]}function Hs(t){let e=[],s=/<SEU_ADT_REPOSITORY_OBJ_NODE>([\s\S]*?)<\/SEU_ADT_REPOSITORY_OBJ_NODE>/g,n;for(;(n=s.exec(t))!==null;){let r=n[1],i=c=>{let a=new RegExp(`<${c}>([^<]*)</${c}>`).exec(r);return a?a[1]:""},o=i("OBJECT_NAME");o&&e.push({name:o,type:i("OBJECT_TYPE"),tech_name:i("TECH_NAME"),uri:i("OBJECT_URI"),description:i("DESCRIPTION")})}return e}function Xs(t){let e=[],s=/<\w*:?checkMessage\b([^/]*?)\/>/gi,n;for(;(n=s.exec(t))!==null;){let o=n[1];e.push({type:/\btype="([^"]+)"/.exec(o)?.[1]||"",text:/\bshortText="([^"]+)"/.exec(o)?.[1]||"",line:parseInt(/\bline="([^"]+)"/.exec(o)?.[1]||"0",10),uri:/\buri="([^"]+)"/.exec(o)?.[1]||""})}let r=e.filter(o=>o.type==="E"),i=e.filter(o=>o.type==="W");return{ok:r.length===0,errors:r,warnings:i,messages:e}}ye();var Ee="sapAbapMcp.password",Qs="sapAbapMcp.provider",V;function E(t){V&&V.appendLine(`[${new Date().toISOString()}] ${t}`)}function Zs(t){V=p.window.createOutputChannel("SAP ABAP MCP");let e=new p.EventEmitter,s=p.window.createStatusBarItem(p.StatusBarAlignment.Right,100);s.command="sapAbapMcp.showStatus",t.subscriptions.push(V,s,e),J(t,s);let n=p.lm;if(n&&typeof n.registerMcpServerDefinitionProvider=="function"){let r={onDidChangeMcpServerDefinitions:e.event,provideMcpServerDefinitions:async()=>{let i=await O(t);if(!i.host||!i.user||!i.password)return[];let o=t.asAbsolutePath(yt.join("out","mcp-server.js"));return[{label:`SAP ABAP MCP (${i.host})`,command:process.execPath,args:[o],env:{SAP_HOST:i.host,SAP_CLIENT:i.client,SAP_USER:i.user,SAP_PASSWORD:i.password,SAP_LANG:i.lang,SAP_VERIFY_SSL:String(i.verifySsl),SAP_READONLY:String(i.readonly),SAP_TIMEOUT:String(Math.floor(i.timeoutMs/1e3))}}]}};t.subscriptions.push(n.registerMcpServerDefinitionProvider(Qs,r))}else p.window.showWarningMessage("SAP ABAP MCP: VS Code 1.99+ is required for native MCP support. The extension is installed but the server provider is inactive.");t.subscriptions.push(p.commands.registerCommand("sapAbapMcp.connect",async()=>{await sn(t),e.fire(),await J(t,s)}),p.commands.registerCommand("sapAbapMcp.testConnection",async()=>{await nn(t)}),p.commands.registerCommand("sapAbapMcp.disconnect",async()=>{if(await p.window.showWarningMessage("Clear all SAP ABAP MCP credentials and remove the MCP server entry from Claude Code / Desktop configs?",{modal:!0},"Clear")==="Clear"){await t.secrets.delete(Ee);let i=p.workspace.getConfiguration("sapAbapMcp");for(let c of["host","client","user","language"])await i.update(c,void 0,p.ConfigurationTarget.Global);let o=await me();Ct(o),e.fire(),await J(t,s),p.window.showInformationMessage("SAP ABAP MCP credentials cleared.")}}),p.commands.registerCommand("sapAbapMcp.syncToClaude",async()=>{let r=await z();if(!r.claudeCodeUser&&!r.claudeDesktop){p.window.showInformationMessage("Neither Claude Code (~/.claude.json) nor Claude Desktop config found on this machine.");return}await Et(t,!0)}),p.commands.registerCommand("sapAbapMcp.toggleReadOnly",async()=>{let r=p.workspace.getConfiguration("sapAbapMcp"),i=r.get("readOnly",!1);await r.update("readOnly",!i,p.ConfigurationTarget.Global),e.fire(),await J(t,s),p.window.showInformationMessage(`SAP ABAP MCP: Read-only mode ${i?"OFF":"ON"}. Reload Copilot Chat for the change to take effect.`)}),p.commands.registerCommand("sapAbapMcp.showStatus",async()=>{await rn(t)})),t.subscriptions.push(p.workspace.onDidChangeConfiguration(r=>{r.affectsConfiguration("sapAbapMcp")&&(e.fire(),J(t,s))})),an(t),en(t),Ds(t)}async function Ds(t){let e="sapAbapMcp.migrationNudgeHandled";if(t.globalState.get(e,!1)){E("migration nudge: skip (already handled)");return}try{let s=await O(t);if(!s.host||!s.user||!s.password){E("migration nudge: skip (not configured)");return}let n=await we();E(`migration nudge probe: cc(exists=${n.claudeCodeUser.exists},configured=${n.claudeCodeUser.configured}) cd(exists=${n.claudeDesktop.exists},configured=${n.claudeDesktop.configured})`);let r={claudeCodeUser:n.claudeCodeUser.exists&&!n.claudeCodeUser.configured,claudeDesktop:n.claudeDesktop.exists&&!n.claudeDesktop.configured};if((n.claudeCodeUser.exists&&n.claudeCodeUser.configured||n.claudeDesktop.exists&&n.claudeDesktop.configured)&&!r.claudeCodeUser&&!r.claudeDesktop){E("migration nudge: all detected clients already configured \u2014 suppressing nudge"),await t.globalState.update(e,!0);return}if(!n.claudeCodeUser.exists&&!n.claudeDesktop.exists){E("migration nudge: no Claude installations detected \u2014 re-check next start");return}let i=[];r.claudeCodeUser&&i.push("Claude Code"),r.claudeDesktop&&i.push("Claude Desktop"),E(`migration nudge: showing toast for ${i.join(" + ")}`);let o=await p.window.showInformationMessage(`SAP ABAP MCP can register itself with ${i.join(" and ")} so the tools work there too. Sync now?`,"Sync now","Later","Don't ask again");E(`migration nudge: user chose '${o??"(dismissed)"}'`),o==="Sync now"?(await bt(t,r),await t.globalState.update(e,!0)):o==="Don't ask again"&&await t.globalState.update(e,!0)}catch(s){E(`migration nudge failed: ${s instanceof Error?s.message:String(s)}`)}}async function en(t){try{let e=await O(t);if(!e.host||!e.user||!e.password)return;let s=await z();if(!s.claudeCodeUser&&!s.claudeDesktop)return;let n=await import("node:fs/promises"),{claudeCodeUserConfigPath:r,claudeDesktopConfigPath:i}=await Promise.resolve().then(()=>(ye(),wt)),o={claudeCodeUser:!1,claudeDesktop:!1};for(let[c,a]of[["claudeCodeUser",r()],["claudeDesktop",i()]])try{let d=await n.readFile(a,"utf-8"),u=JSON.parse(d).mcpServers?.["sap-abap"];if(!u)continue;he(u)&&(o[c]=!0,E(`stale entry in ${a}: ${u.command} ${(u.args??[]).join(" ")} \u2192 npx -y sap-abap-mcp`))}catch{}if(o.claudeCodeUser||o.claudeDesktop){let c=await se(e,o);for(let a of c.written)E(`auto-refresh: ${a}`)}}catch(e){E(`refresh check failed: ${e instanceof Error?e.message:String(e)}`)}}function tn(){}async function O(t){let e=p.workspace.getConfiguration("sapAbapMcp"),s=await t.secrets.get(Ee)??"";return{host:(e.get("host")??"").trim(),client:(e.get("client")??"100").trim(),user:(e.get("user")??"").trim(),password:s,lang:(e.get("language")??"EN").trim(),verifySsl:e.get("verifySsl")??!1,readonly:e.get("readOnly")??!1,timeoutMs:(e.get("timeout")??30)*1e3}}async function sn(t){let e=p.workspace.getConfiguration("sapAbapMcp"),s=await p.window.showInputBox({title:"SAP ABAP MCP \u2014 Step 1/4: Host",prompt:"Base URL of your SAP system (use HTTPS)",value:e.get("host")||"",placeHolder:"https://sap.example.com:44300",ignoreFocusOut:!0,validateInput:c=>c.trim()?/^https?:\/\//i.test(c.trim())?null:"Must start with http:// or https://":"Required"});if(!s)return;let n=await p.window.showInputBox({title:"SAP ABAP MCP \u2014 Step 2/4: Client",prompt:"SAP client / mandant",value:e.get("client")||"100",ignoreFocusOut:!0,validateInput:c=>/^\d{1,3}$/.test(c.trim())?null:"Must be 1-3 digits"});if(!n)return;let r=await p.window.showInputBox({title:"SAP ABAP MCP \u2014 Step 3/4: User",prompt:"ABAP user name",value:e.get("user")||"",ignoreFocusOut:!0,validateInput:c=>c.trim()?null:"Required"});if(!r)return;let i=await p.window.showInputBox({title:"SAP ABAP MCP \u2014 Step 4/4: Password",prompt:"Stored in OS keychain via VS Code SecretStorage. Never logged.",password:!0,ignoreFocusOut:!0,validateInput:c=>c?null:"Required"});if(i===void 0)return;await e.update("host",s.trim(),p.ConfigurationTarget.Global),await e.update("client",n.trim(),p.ConfigurationTarget.Global),await e.update("user",r.trim(),p.ConfigurationTarget.Global),await t.secrets.store(Ee,i);let o=await p.window.withProgress({location:p.ProgressLocation.Notification,title:"Testing SAP connection..."},async()=>{let c=await O(t);return new X(c).testConnection()});St("Connect wizard",o),o.status==="ok"?(p.window.showInformationMessage(`Connected to SAP ${o.host} (client ${o.client}, ${o.description}).`),await Et(t,!1)):await p.window.showErrorMessage(`Connection ${o.status}: ${o.message||"unknown"}. Settings were saved.`,"Show diagnostics")==="Show diagnostics"&&V?.show(!0)}async function Et(t,e){let s=await z();if(!s.claudeCodeUser&&!s.claudeDesktop){e||p.window.showInformationMessage("MCP server is registered for VS Code (Copilot Chat / Cursor). Claude Code or Claude Desktop weren't detected on this machine.");return}let n=[];s.claudeCodeUser&&n.push({label:"Claude Code (~/.claude.json)",picked:!0,key:"claudeCodeUser"}),s.claudeDesktop&&n.push({label:"Claude Desktop (claude_desktop_config.json)",picked:!0,key:"claudeDesktop"});let r=await p.window.showQuickPick(n,{canPickMany:!0,title:"Register SAP ABAP MCP with detected Claude clients?",placeHolder:"Press Enter to apply, Esc to skip."});if(!r)return;let i={claudeCodeUser:!1,claudeDesktop:!1};for(let o of r)i[o.key]=!0;await bt(t,i)}async function bt(t,e){let s=await O(t);if(!s.host||!s.user||!s.password){p.window.showWarningMessage("SAP ABAP MCP is not configured yet. Run 'SAP ABAP: Connect to System' first.");return}let n=await se(s,e);Ct(n)}function Ct(t){for(let e of t.written)E(`sync: ${e}`);for(let e of t.skipped)E(`sync: skipped ${e}`);for(let e of t.errors)E(`sync error (${e.target}): ${e.message}`);t.errors.length>0?p.window.showWarningMessage(`Synced with errors: ${t.errors.map(e=>e.target).join(", ")}. See output for details.`):t.written.length>0&&p.window.showInformationMessage(`Registered SAP ABAP MCP in: ${t.written.map(e=>e.split(" ")[0]+" "+e.split(" ")[1]).join(", ")}. Restart the Claude client to pick it up.`)}function St(t,e){E(`--- ${t} result: ${e.status} ---`),e.message&&E(`message: ${e.message}`),e.diagnostic?.httpStatus!==void 0&&E(`http status: ${e.diagnostic.httpStatus}`),e.diagnostic?.rawXml&&(E("raw response (first 4000 chars):"),E(e.diagnostic.rawXml))}async function nn(t){let e=await O(t);if(!e.host||!e.user||!e.password){await p.window.showWarningMessage("SAP ABAP MCP is not configured yet.","Configure now")==="Configure now"&&await p.commands.executeCommand("sapAbapMcp.connect");return}let s=await p.window.withProgress({location:p.ProgressLocation.Notification,title:`Testing connection to ${e.host}...`},()=>new X(e).testConnection());St("Test connection command",s),s.status==="ok"?p.window.showInformationMessage(`OK \u2014 SAP ${s.host}, client ${s.client} (${s.description})`):await p.window.showErrorMessage(`${s.status}: ${s.message||"unknown error"}`,"Show diagnostics")==="Show diagnostics"&&V?.show(!0)}async function rn(t){let e=await O(t),s=!!e.password,n=["SAP ABAP MCP \u2014 current configuration","",`Host: ${e.host||"(not set)"}`,`Client: ${e.client}`,`User: ${e.user||"(not set)"}`,`Password: ${s?"stored in keychain":"(not set)"}`,`Language: ${e.lang}`,`Verify SSL: ${e.verifySsl}`,`Read-only: ${e.readonly}`,`Timeout: ${e.timeoutMs/1e3}s`],r=await p.workspace.openTextDocument({content:n.join(`
43
+ `),language:"plaintext"});await p.window.showTextDocument(r,{preview:!0})}async function J(t,e){let s=await O(t);if(!s.host||!s.user||!s.password)e.text="$(plug) SAP: not configured",e.tooltip="Click to configure SAP ABAP MCP";else{let n=s.readonly?" [RO]":"";e.text=`$(database) SAP: ${s.user}@${on(s.host)}${n}`,e.tooltip=`${s.host}
44
+ Client ${s.client}
45
+ User ${s.user}`+(s.readonly?`
46
+ Read-only mode`:"")}e.show()}function on(t){try{return new URL(t).hostname}catch{return t}}async function an(t){let e=await O(t);if(e.host&&e.user&&e.password||t.globalState.get("sapAbapMcp.welcomed",!1))return;await t.globalState.update("sapAbapMcp.welcomed",!0),await p.window.showInformationMessage("SAP ABAP MCP is installed. Configure your SAP system to enable the Copilot Chat tools.","Configure now","Later")==="Configure now"&&await p.commands.executeCommand("sapAbapMcp.connect")}0&&(module.exports={activate,deactivate});