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/CHANGELOG.md +190 -0
- package/LICENSE +202 -0
- package/README.md +318 -0
- package/out/extension.js +46 -0
- package/out/mcp-server.js +117 -0
- package/package.json +153 -0
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.)
|
package/out/extension.js
ADDED
|
@@ -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 '
'");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:"&"},{regex:new RegExp(">","g"),val:">"},{regex:new RegExp("<","g"),val:"<"},{regex:new RegExp("'","g"),val:"'"},{regex:new RegExp('"',"g"),val:"""}],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("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}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});
|