sap-ai-dev-toolkit 0.5.5 โ 0.5.7
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/.github/agents/abap-developer.agent.md +8 -8
- package/.github/agents/abap-runtime-debugger.agent.md +6 -6
- package/.github/agents/hana-cloud-hdi-specialist.agent.md +1 -1
- package/.github/agents/rap-service-developer.agent.md +5 -5
- package/.github/agents/sap-solution-architect.agent.md +2 -2
- package/.github/skills/abap-debugging/SKILL.md +3 -3
- package/.github/skills/abap-development/SKILL.md +3 -3
- package/.github/skills/abap-runtime-analysis/SKILL.md +4 -4
- package/.github/skills/abap-testing-quality/SKILL.md +3 -3
- package/.github/skills/cds-development/SKILL.md +3 -3
- package/.github/skills/clean-core-extensibility/SKILL.md +1 -1
- package/.github/skills/hana-cloud-inspection/SKILL.md +2 -2
- package/.github/skills/hana-cloud-native-development/SKILL.md +2 -2
- package/.github/skills/hana-cloud-validation/SKILL.md +1 -1
- package/.github/skills/rap-development/SKILL.md +3 -3
- package/.github/skills/rap-service-delivery/SKILL.md +2 -2
- package/.github/skills/sap-sdlc-orchestration/SKILL.md +1 -1
- package/.github/skills/sap-standard-api-analysis/SKILL.md +1 -1
- package/.github/skills/sap-transport-release/SKILL.md +2 -2
- package/README.md +30 -23
- package/inventory.md +181 -0
- package/package.json +2 -2
- package/scripts/build-vsp.mjs +2 -1
- package/scripts/postinstall.mjs +14 -16
- package/src/bas-destination-relay.mjs +25 -3
- package/src/bas-discovery.mjs +9 -3
- package/src/binary.mjs +101 -17
- package/src/cf-destination.mjs +55 -1
- package/src/credentials-store.mjs +0 -10
- package/src/engineering-tools.mjs +32 -10
- package/src/hana-tools.mjs +9 -2
- package/src/launcher.mjs +14 -13
- package/src/mcp-config.mjs +19 -1
- package/src/mcp-proxy.mjs +284 -103
- package/src/redact.mjs +28 -0
- package/src/setup.mjs +30 -1
- package/tools.md +10 -2
- package/test/bas-destination-relay.test.mjs +0 -415
- package/test/cf-connectivity.test.mjs +0 -287
- package/test/cf-destination.test.mjs +0 -307
- package/test/cf-runtime.test.mjs +0 -527
- package/test/copilot-assets.test.mjs +0 -63
- package/test/copilot-content.test.mjs +0 -249
- package/test/credentials-store.test.mjs +0 -187
- package/test/discovery.test.mjs +0 -282
- package/test/fixtures/fake-vsp.mjs +0 -266
- package/test/hana-config.test.mjs +0 -168
- package/test/hana-inspector-stdio.test.mjs +0 -44
- package/test/hana-tools.test.mjs +0 -206
- package/test/launcher.test.mjs +0 -401
- package/test/live-s4h.test.mjs +0 -204
- package/test/mcp-config-cf.test.mjs +0 -475
- package/test/mcp-proxy.test.mjs +0 -604
- package/test/pty.mjs +0 -8
- package/test/setup-cf.test.mjs +0 -489
- package/test/setup.test.mjs +0 -417
- package/test/terminal-ui.test.mjs +0 -47
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ Then connect a destination in SAP Business Application Studio:
|
|
|
68
68
|
|
|
69
69
|
Use the attached destination-prefixed tools directly in chat. Do not launch `sap-ai-dev` or handcraft MCP JSON-RPC in a terminal to discover or call them.
|
|
70
70
|
|
|
71
|
-
**Prerequisite:** Node.js 20 or newer.
|
|
71
|
+
**Prerequisite:** Node.js 20 or newer. The pinned VSP runtime ships with the package; no Go toolchain is installed or required.
|
|
72
72
|
|
|
73
73
|
## ๐ค Available agents and skills
|
|
74
74
|
|
|
@@ -78,7 +78,7 @@ Use the attached destination-prefixed tools directly in chat. Do not launch `sap
|
|
|
78
78
|
| --- | --- | --- |
|
|
79
79
|
| ๐งญ | **SAP Solution Architect** | System investigation, SAP standard/API recommendations, Clean Core and side-by-side design, and SDLC orchestration through implementation handoffs and validation gates |
|
|
80
80
|
| ๐งโ๐ป | **ABAP Developer** | General ABAP, CDS, and RAP implementation, validation, and transport-preparation tasks |
|
|
81
|
-
| ๐ | **ABAP Runtime Debugger** | Runtime incidents,
|
|
81
|
+
| ๐ | **ABAP Runtime Debugger** | Runtime incidents, application logs, debugger sessions, and performance symptoms; call relationships are derived from source inspection |
|
|
82
82
|
| ๐ | **RAP Service Developer** | RAP business objects, behavior implementations, projections, service definitions, service bindings, and OData validation |
|
|
83
83
|
| ๐๏ธ | **HANA Cloud/HDI Specialist** | Read-only HANA Cloud container inspection, CAP/HDI artifact generation, local validation, and user-run deployment handoffs |
|
|
84
84
|
|
|
@@ -168,7 +168,7 @@ The package ships with five custom agents plus fourteen task-focused Copilot Age
|
|
|
168
168
|
| ๐งฑ | `clean-core-extensibility` | Clean Core, released extensibility, and side-by-side extension design with risk classification |
|
|
169
169
|
| ๐ | `sap-sdlc-orchestration` | Requirement-to-release lifecycle planning, delegated implementation, quality gates, validation, and handover |
|
|
170
170
|
| ๐ | `abap-debugging` | Dumps, logs, traces, and runtime failure diagnosis |
|
|
171
|
-
| ๐ฌ | `abap-runtime-analysis` | Incident triage,
|
|
171
|
+
| ๐ฌ | `abap-runtime-analysis` | Incident triage, debugger state, and performance analysis; call relationships come from source inspection |
|
|
172
172
|
| ๐ | `rap-service-delivery` | RAP service activation, publication, OData validation, and end-to-end runtime checks |
|
|
173
173
|
| ๐ | `sap-transport-release` | Dependency checks and transport preparation; release itself is intentionally unavailable here |
|
|
174
174
|
| ๐ | `hana-cloud-inspection` | Verify the selected HANA Cloud binding and inspect bounded HDI catalog/data results |
|
|
@@ -237,6 +237,7 @@ Once the destination server is enabled in Copilot Chat, ask for outcomes instead
|
|
|
237
237
|
| --- | --- |
|
|
238
238
|
| ๐ฏ **Explicit target** | SAP changes only proceed when the destination and required target details are known. |
|
|
239
239
|
| ๐ฆ **Explicit state change** | Activation, service publication, and transport creation happen only when requested and authorized. |
|
|
240
|
+
| ๐๏ธ **Optional read-only mode** | `SAP_AI_DEV_TOOLKIT_READ_ONLY=true` removes every write/activate/transport-create tool from the surface and starts VSP with `--transport-read-only`. Recommended for exploration destinations. |
|
|
240
241
|
| ๐งช **Verification first** | The agent uses available lint, syntax, unit-test, ATC, and diagnostics workflows and reports what actually ran. |
|
|
241
242
|
| ๐ **SAP authorization remains authoritative** | The add-on does not bypass backend SAP permissions. |
|
|
242
243
|
| ๐ **Curated VSP tool surface** | The proxy exposes a cherry-picked developer-lifecycle set from VSP plus local workflow tools, keeping one destination below 60 tools; SAP authorizations and VSP safety checks still apply. |
|
|
@@ -270,14 +271,14 @@ The guided setup can also offer companion MCP entries with `sap-ai-dev --setup -
|
|
|
270
271
|
| CAP tools | `@cap-js/mcp-server` | CAP CDS/service model inspection and CAP app development |
|
|
271
272
|
| Browser validation | `@playwright/mcp` | Fiori/UI smoke tests, screenshots, and browser runtime validation |
|
|
272
273
|
|
|
273
|
-
The installer handles
|
|
274
|
+
The installer handles VSP provisioning automatically:
|
|
274
275
|
|
|
275
|
-
-
|
|
276
|
-
-
|
|
276
|
+
- Uses the package's bundled patched VSP binary for the current platform, verified against the npm-published `dist/checksums.txt`. A checksum-anchored remote download is the fallback only when the package has no bundled asset.
|
|
277
|
+
- No Go toolchain is downloaded or required at install time; Go is only used by the repository's own `build:vsp` development script.
|
|
277
278
|
|
|
278
279
|
With `H2O_URL` set, an interactive install opens a checkbox picker with no destinations selected by default. Use **Space** to choose destinations and **Enter** to confirm. Press **a** to toggle all destinations (select all if any are unchecked; otherwise clear the selection). Confirming with none selected removes this add-on's managed MCP entries. When the `cf` CLI 8.18 or newer is authenticated to a targeted space, setup first offers an optional import from that space's Destination service; type **y** then **Enter** to include it, or press **Enter** to skip. Accepted CF and BAS destinations appear together in the picker. npm may run its install hook without an interactive terminal, even when the shell is interactive; in that case, selection is skipped without changing MCP config.
|
|
279
280
|
|
|
280
|
-
Some current npm versions also require install hooks to be approved. If npm reports that `sap-ai-dev-toolkit`'s `postinstall` was blocked, allow it during a fresh install with `npm install --global --allow-scripts=sap-ai-dev-toolkit sap-ai-dev-toolkit`, or run `sap-ai-dev
|
|
281
|
+
Some current npm versions also require install hooks to be approved. If npm reports that `sap-ai-dev-toolkit`'s `postinstall` was blocked, allow it during a fresh install with `npm install --global --allow-scripts=sap-ai-dev-toolkit sap-ai-dev-toolkit`, or run `sap-ai-dev --setup` from an interactive BAS terminal after installation.
|
|
281
282
|
|
|
282
283
|
The setup report uses icons and terminal colors; set `NO_COLOR=1` to disable ANSI colors. The table is a weather report, not a bouncer: green **PASS** means the ADT probe responded, red **FAIL** means it failed, and yellow **SKIPPED** means it was skipped. Probe failures do not block MCP registration or startup for destinations you select.
|
|
283
284
|
|
|
@@ -300,7 +301,7 @@ This lists discovered systems in the same checkbox picker, with nothing selected
|
|
|
300
301
|
For a non-interactive installation or a platform without a published VSP asset, provide a trusted binary override:
|
|
301
302
|
|
|
302
303
|
```sh
|
|
303
|
-
|
|
304
|
+
SAP_AI_DEV_TOOLKIT_BINARY=/path/to/vsp npm install --global sap-ai-dev-toolkit
|
|
304
305
|
```
|
|
305
306
|
|
|
306
307
|
At the end of a global install, the color-coded summary shows the MCP config path, each generated entry name, destination/client/authentication, launch command, and environment key names (not values). The installer does not open an editor automatically; in BAS/VS Code:
|
|
@@ -339,7 +340,7 @@ The package includes five user-invocable custom agents (**SAP Solution Architect
|
|
|
339
340
|
| ๐งฑ | `clean-core-extensibility` | Design Clean Core compliant in-app, developer, API/event, and side-by-side extension patterns. |
|
|
340
341
|
| ๐ | `sap-sdlc-orchestration` | Orchestrate discovery, design, implementation handoffs, quality gates, transport readiness, and handover. |
|
|
341
342
|
| ๐ | `abap-debugging` | Diagnose dumps, application logs, traces, and runtime failures. |
|
|
342
|
-
| ๐ฌ | `abap-runtime-analysis` | Analyze incidents,
|
|
343
|
+
| ๐ฌ | `abap-runtime-analysis` | Analyze incidents, debugger state, and performance symptoms; derive call relationships from source inspection. |
|
|
343
344
|
| ๐ | `rap-service-delivery` | Validate RAP service bindings, activation, publication, and end-to-end OData behavior. |
|
|
344
345
|
| ๐ | `sap-transport-release` | Check dependencies and prepare changes for transport; release is not available here. |
|
|
345
346
|
| ๐ | `hana-cloud-inspection` | Verify the attached HANA target and inspect bounded HDI metadata and rows. |
|
|
@@ -348,7 +349,7 @@ The package includes five user-invocable custom agents (**SAP Solution Architect
|
|
|
348
349
|
|
|
349
350
|
### ๐ฅ Install for your BAS user
|
|
350
351
|
|
|
351
|
-
After destination setup, the installer prints a ๐ค notice that it is waiting for confirmation, then offers to install all bundled agents and skills under `$HOME/.copilot`.
|
|
352
|
+
After destination setup, the installer prints a ๐ค notice that it is waiting for confirmation, then offers to install all bundled agents and skills under `$HOME/.copilot`. Type **y** then **Enter** to install; pressing **Enter** alone skips (the default). Declining leaves those files unchanged.
|
|
352
353
|
|
|
353
354
|
These user-level customizations are available across workspaces opened by the same BAS user in the same dev space. Copilot must be available in BAS and may need a window reload to discover new files. A non-interactive install skips the optional prompt; `npm install --ignore-scripts` skips the postinstall wizard entirely.
|
|
354
355
|
|
|
@@ -403,7 +404,7 @@ For on-premise systems, configure Cloud Connector access to the backend host and
|
|
|
403
404
|
|
|
404
405
|
Think of `H2O_URL` as BAS's front door: it must point to the endpoint serving `/api/listDestinations`, not to the SAP backend.
|
|
405
406
|
|
|
406
|
-
The `/api/listDestinations` response is a JSON array of destination records
|
|
407
|
+
The `/api/listDestinations` response is a JSON array of destination records. A representative record:
|
|
407
408
|
|
|
408
409
|
```json
|
|
409
410
|
{
|
|
@@ -447,7 +448,7 @@ One selected system, one isolated stdio MCP entry. Here's the shape:
|
|
|
447
448
|
}
|
|
448
449
|
```
|
|
449
450
|
|
|
450
|
-
The MCP protocol `serverInfo.name`
|
|
451
|
+
The MCP protocol `serverInfo.name` is the lowercased destination slug (from `SAP_AI_DEV_TOOLKIT_DESTINATION`, legacy `BAS_VSP_DESTINATION` accepted), so each wizard-generated destination has its own identity instead of the shared `sap-ai-dev-toolkit` name.
|
|
451
452
|
|
|
452
453
|
Credentials, cookies, SAP usernames, passwords, and raw BAS destination payloads are not written to the MCP configuration.
|
|
453
454
|
|
|
@@ -489,7 +490,7 @@ Without `H2O_URL`, the command passes arguments directly to the installed VSP bi
|
|
|
489
490
|
|
|
490
491
|
`sap-ai-dev` is an MCP stdio server and destination router, not a terminal command for individual SAP operations. No shell incantations needed: your MCP client discovers the tools, picks one for the chat request, and sends the call over stdio.
|
|
491
492
|
|
|
492
|
-
Each generated MCP server entry is named with the lowercased destination slug: `DEMO_ABAP` becomes `demo-abap`.
|
|
493
|
+
Each generated MCP server entry is named with the lowercased destination slug: `DEMO_ABAP` becomes `demo-abap`. Because every generated entry is scoped to exactly one destination, tool names carry no redundant prefix โ they are plain lowercase snake_case (`get_source`, `run_query`, `lint_abap`); the server name already states which SAP system it targets. Only when one server fronts several destinations (manual multi-destination startup) does each name gain its destination slug (`demo-abap_run_query`) to stay unambiguous. Lowercase names are deliberate: BAS and VS Code derive chat tool references from the server and tool names and only bind lowercase identifiers, so mixed-case names show up in the tools picker but never bind to the chat session. Use the exact names shown by your MCP client; punctuation can change during slugification.
|
|
493
494
|
|
|
494
495
|
Upgrading from an earlier release that wrote mixed-case entry names (for example `ActionS4D` or `cf:<guid>:<guid>:<name>`)? Re-run `sap-ai-dev --setup` to replace legacy entries โ this is the only migration path for Cloud Foundry entries โ or run `sap-ai-dev --doctor` to rename BAS entries in place. Then reload the BAS window and start a new chat; an existing chat keeps its stale tool binding. If setup reports that the lowercase name already exists and is not managed by this package, rename or remove that user-owned server entry first.
|
|
495
496
|
|
|
@@ -505,7 +506,7 @@ The menu includes the tools registered by the active VSP mode, the `GetApplicati
|
|
|
505
506
|
|
|
506
507
|
### ๐งน Lint submitted ABAP source locally
|
|
507
508
|
|
|
508
|
-
The
|
|
509
|
+
The tool is named `lint_abap` (the local workflow name `LintABAP` exposed in snake_case; on a multi-destination server it is `<destination-slug>_lint_abap`). It accepts caller-supplied abapGit-serialized source files; config is optional and, when present, is the full abaplint configuration rather than a merge with defaults.
|
|
509
510
|
|
|
510
511
|
```json
|
|
511
512
|
{
|
|
@@ -545,7 +546,7 @@ For an ABAP Cloud assessment, get object URIs from `SearchObject` and pass them
|
|
|
545
546
|
|
|
546
547
|
`tools/list` confirms what this MCP server exposes; it does not prove that VS Code attached the server to the active chat. Start the selected destination in **MCP: List Servers**, enable it in the Chat tools picker, and reload/reselect the agent if the host binding is stale. This add-on cannot inspect or repair another MCP server's registration or a host-wide tool budget.
|
|
547
548
|
|
|
548
|
-
`sap-ai-dev
|
|
549
|
+
`sap-ai-dev --demo` starts an isolated server with sample ABAP objects, test and ATC results, a sample transport, and synthetic OData metadata and rows. Source edits and transport creation stay in process memory and disappear on exit. The demo does not discover or contact BAS or SAP destinations.
|
|
549
550
|
|
|
550
551
|
### ๐ Find and understand ABAP objects
|
|
551
552
|
|
|
@@ -605,6 +606,7 @@ The write and activation tools change SAP state. Confirm the target, package, an
|
|
|
605
606
|
| `GetSystemInfo` | Read system ID, SAP release, kernel, and database details. |
|
|
606
607
|
| `GetInstalledComponents` | List installed software components and versions. |
|
|
607
608
|
| `GetFeatures` | Probe optional system capabilities, including abapGit, RAP/OData, AMDP debugging, UI5/BSP, and CTS transports. |
|
|
609
|
+
| `GetConnectionInfo` | Show the connected user, client, URL, mode, and feature-probe summary for the current destination session. |
|
|
608
610
|
| `PrettyPrint` | Format ABAP source text without saving it to SAP. |
|
|
609
611
|
|
|
610
612
|
### ๐ Inspect and create transports
|
|
@@ -642,7 +644,7 @@ The proxy intentionally does not expose the full child VSP process. Object delet
|
|
|
642
644
|
3. Ask for the operation in plain language. The MCP client sends `tools/call`; no need to type a tool such as `GetSource` into a terminal.
|
|
643
645
|
4. Check the response in chat. For source edits, ask for a syntax check and tests before activation when that matches your workflow.
|
|
644
646
|
|
|
645
|
-
For a quick table readโsay, company codes from `T001`โselect the destination's `RunQuery` tool (
|
|
647
|
+
For a quick table readโsay, company codes from `T001`โselect the destination's `RunQuery` tool (exposed as `run_query`; `demo-abap_run_query` only on a multi-destination server) and pass:
|
|
646
648
|
|
|
647
649
|
```json
|
|
648
650
|
{
|
|
@@ -659,7 +661,7 @@ The same request can be expressed to an MCP client as:
|
|
|
659
661
|
"id": 2,
|
|
660
662
|
"method": "tools/call",
|
|
661
663
|
"params": {
|
|
662
|
-
"name": "
|
|
664
|
+
"name": "run_query",
|
|
663
665
|
"arguments": {
|
|
664
666
|
"sql_query": "SELECT BUKRS, BUTXT, WAERS, LAND1 FROM T001",
|
|
665
667
|
"max_rows": 100
|
|
@@ -695,7 +697,7 @@ The MCP client discovers the schemas; callers do not need to memorize every argu
|
|
|
695
697
|
| Runtime and tool-call logs | Select the MCP server in the Output view. Startup, call lifecycle, and child stderr logs are written to stderr; child MCP log notifications are forwarded to the client. Tool arguments and result contents are not logged. |
|
|
696
698
|
| Installed package version | `npm list --global sap-ai-dev-toolkit` |
|
|
697
699
|
|
|
698
|
-
If the server is running but an agent reports that SAP tools are unavailable, verify that the same chat is in Agent mode, the generated server is enabled in that chat's tools picker, and concrete names such as `
|
|
700
|
+
If the server is running but an agent reports that SAP tools are unavailable, verify that the same chat is in Agent mode, the generated server is enabled in that chat's tools picker, and concrete names such as `s4h_get_system_info` are listed. All generated server and tool names are lowercase; a mixed-case entry such as `ActionS4D` is a pre-upgrade leftover that chat cannot bind โ rerun setup or `--doctor` as described above to migrate it. Reselect the agent or start a new chat if the tool binding is stale, then inspect the MCP server's Output log for startup or `tools/list` errors. Do not try to work around a missing chat binding by starting the server or handcrafting JSON-RPC from the terminal.
|
|
699
701
|
|
|
700
702
|
After MCP initialization, the host internally sends a request like this; agents should not reproduce it in the terminal:
|
|
701
703
|
|
|
@@ -707,7 +709,7 @@ The response contains a `tools` array. A `RunQuery` entry resembles this excerpt
|
|
|
707
709
|
|
|
708
710
|
```json
|
|
709
711
|
{
|
|
710
|
-
"name": "
|
|
712
|
+
"name": "run_query",
|
|
711
713
|
"description": "Execute an ABAP SQL query [destination: DEMO_ABAP]",
|
|
712
714
|
"inputSchema": {
|
|
713
715
|
"type": "object",
|
|
@@ -734,13 +736,18 @@ The response contains a `tools` array. A `RunQuery` entry resembles this excerpt
|
|
|
734
736
|
| `SAP_AI_DEV_TOOLKIT_DISABLE_BAS_RELAY=true` | Disable the built-in BAS destination relay. By default the add-on self-heals `.dest` destinations through a local relay that keeps all access destination-based while handling ADT CSRF fetch/retry behavior before VSP calls SAP. |
|
|
735
737
|
| `SAP_AI_DEV_TOOLKIT_HTTP_PROXY` | Egress proxy for relay and discovery traffic. Takes precedence over `HTTP_PROXY`/`http_proxy`; unset means the default BAS proxy for `.dest` hosts, empty means direct except for OnPremise credential overrides, which require a BAS proxy tunnel. |
|
|
736
738
|
| `SAP_AI_DEV_TOOLKIT_MAX_CSRF_RETRIES` | Bounded retries after explicit CSRF-session rejection per unsafe request (default 3, maximum 10). Invalid values use the default. |
|
|
739
|
+
| `SAP_AI_DEV_TOOLKIT_READ_ONLY=true` | Read-only mode: hides `WriteSource`, `EditSource`, `Activate`, `ActivateMultiple`, `CreateTransport`, `SetBreakpoint`, and the change-set workflow tools, and starts VSP with `--transport-read-only`. |
|
|
740
|
+
| `SAP_AI_DEV_TOOLKIT_REQUEST_TIMEOUT_MS` | Per-request timeout for calls forwarded to a VSP child (default 600000 = 10 minutes; `0` disables). A stalled request fails with a timeout error; the child is left running. |
|
|
737
741
|
| `SAP_AI_DEV_MCP_CONFIG` | Explicit MCP configuration path; highest precedence. |
|
|
738
742
|
| `SAP_AI_DEV_TOOLKIT_MCP_CONFIG` | Branded compatibility alias for the MCP configuration path. |
|
|
739
743
|
| `BAS_VSP_MCP_CONFIG` | Backward-compatible alias for the MCP configuration path. |
|
|
740
|
-
| `
|
|
741
|
-
| `
|
|
742
|
-
| `
|
|
743
|
-
| `
|
|
744
|
+
| `SAP_AI_DEV_TOOLKIT_CREDENTIALS_FILE` | Explicit path for the optional SAP backend credential-override file (default: beside `mcp.json`). |
|
|
745
|
+
| `SAP_AI_DEV_TOOLKIT_BINARY` | Trusted prebuilt VSP executable; skips binary provisioning. Legacy `BAS_VSP_BINARY` still works. |
|
|
746
|
+
| `SAP_AI_DEV_TOOLKIT_BINARY_URL` | Alternate VSP binary download URL (checksum-verified). Legacy `BAS_VSP_BINARY_URL` still works. |
|
|
747
|
+
| `SAP_AI_DEV_TOOLKIT_RELEASE_BASE_URL` | Override the base URL that VSP release binaries are downloaded from. |
|
|
748
|
+
| `SAP_AI_DEV_TOOLKIT_CACHE_DIR` | Binary cache directory. Legacy `BAS_VSP_CACHE_DIR` still works. |
|
|
749
|
+
| `BAS_CF_SPACE_GUID`, `BAS_CF_DESTINATION_INSTANCE_GUID`, `BAS_CF_DESTINATION_INSTANCE`, `BAS_CF_DESTINATION_KEY`, `BAS_CF_DESTINATION_NAME`, `BAS_CF_CONNECTIVITY_INSTANCE_GUID`, `BAS_CF_CONNECTIVITY_INSTANCE`, `BAS_CF_CONNECTIVITY_KEY` | Written into generated Cloud Foundry destination entries; they reference service instances and key **names** (never credentials). |
|
|
750
|
+
| `GO_BINARY` | Explicit Go executable for the repository-only `build:vsp` script; not used during installation. |
|
|
744
751
|
| `SAP_AI_DEV_TOOLKIT_SKIP_PROBE=true` | Skip destination probes; useful for controlled diagnostics or fixtures. |
|
|
745
752
|
| `HTTP_PROXY` / `HTTPS_PROXY` | BAS proxy settings used for destination-list requests, destination probing, and child processes. |
|
|
746
753
|
| `NO_PROXY` | Proxy bypass list for BAS destination-list requests; `.dest` hosts remain routed through the BAS proxy. |
|
package/inventory.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# SAP AI Dev Toolkit Tool Inventory
|
|
2
|
+
|
|
3
|
+
This inventory reflects the current SAP AI Dev Toolkit proxy behavior in `src/mcp-proxy.mjs`. The proxy exposes a curated VSP allowlist plus destination-scoped local workflows; it does not expose every tool registered by VSP. The live MCP `tools/list` response remains authoritative because capabilities vary by VSP mode and SAP system.
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
| Status | Count | Notes |
|
|
8
|
+
| --- | ---: | --- |
|
|
9
|
+
| VSP tools | Up to 51 | Curated from the child VSP tool list and exposed in lowercase snake_case, unprefixed (`get_source`) on single-destination servers; a destination slug prefix (`demo-abap_get_source`) appears only when one server fronts multiple destinations. |
|
|
10
|
+
| Local lint tool | 1 per destination | `LintABAP` analyzes caller-supplied ABAP source in memory; it is exposed publicly as `lint_abap`. |
|
|
11
|
+
| Workflow tools | Up to 6 per destination | Review/apply change sets, transport evidence, Clean Core release assessment, and read-only RAP regression suites. Some are exposed only when their upstream VSP tools are registered. |
|
|
12
|
+
| Convenience mapping | Dynamic | `GetApplicationLog` maps to VSP `SAP(action="analyze", type="application_log")` when the SAP router is registered. |
|
|
13
|
+
| Intentionally filtered VSP tools | Dynamic | Destructive, broad-router, trace, and unsupported VSP operations are hidden from direct calls. |
|
|
14
|
+
| Mode-dependent | Dynamic | Focused/expert mode and backend capabilities determine what VSP registers. |
|
|
15
|
+
|
|
16
|
+
The maximum fixture surface is 59 tools per destination when expert-mode capabilities and all local workflows are available. Multiple selected destinations create separate MCP servers; this add-on cannot inspect VS Code's aggregate tool budget or per-chat tool binding.
|
|
17
|
+
|
|
18
|
+
## Known upstream VSP tools
|
|
19
|
+
|
|
20
|
+
These names are known from fixtures, README, and historical upstream VSP inventories. They are not a statement that the proxy exposes them; only the curated list in [tools.md](tools.md) is public through the proxy. Names absent from that allowlist are filtered even when VSP registers them.
|
|
21
|
+
|
|
22
|
+
### Baseline/source inspection
|
|
23
|
+
|
|
24
|
+
- `GetSource`
|
|
25
|
+
- `SearchObject`
|
|
26
|
+
- `GrepObjects`
|
|
27
|
+
- `GrepPackages`
|
|
28
|
+
- `FindDefinition`
|
|
29
|
+
- `FindReferences`
|
|
30
|
+
- `GetContext`
|
|
31
|
+
- `CompareSource`
|
|
32
|
+
- `GetClassInfo`
|
|
33
|
+
- `GetPackage`
|
|
34
|
+
- `GetFunctionGroup`
|
|
35
|
+
- `GetMessages`
|
|
36
|
+
- `GetInactiveObjects`
|
|
37
|
+
- `GetAPIReleaseState`
|
|
38
|
+
|
|
39
|
+
### Data, CDS, and metadata
|
|
40
|
+
|
|
41
|
+
- `GetTable`
|
|
42
|
+
- `GetTableContents`
|
|
43
|
+
- `RunQuery`
|
|
44
|
+
- `GetCDSDependencies`
|
|
45
|
+
- `GetCDSImpactAnalysis`
|
|
46
|
+
- `GetCDSElementInfo`
|
|
47
|
+
- `GetFeatures`
|
|
48
|
+
- `GetSystemInfo`
|
|
49
|
+
- `GetInstalledComponents`
|
|
50
|
+
|
|
51
|
+
### Create, update, activate, and quality
|
|
52
|
+
|
|
53
|
+
- `WriteSource`
|
|
54
|
+
- `EditSource`
|
|
55
|
+
- `CreatePackage`
|
|
56
|
+
- `CreateTable`
|
|
57
|
+
- `SyntaxCheck`
|
|
58
|
+
- `Activate`
|
|
59
|
+
- `ActivateMultiple`
|
|
60
|
+
- `ActivatePackage`
|
|
61
|
+
- `PrettyPrint`
|
|
62
|
+
- `RunUnitTests`
|
|
63
|
+
- `RunATCCheck`
|
|
64
|
+
|
|
65
|
+
### Transport tools
|
|
66
|
+
|
|
67
|
+
- `GetTransport`
|
|
68
|
+
- `GetTransportInfo`
|
|
69
|
+
- `GetUserTransports`
|
|
70
|
+
- `ListTransports`
|
|
71
|
+
- `CreateTransport`
|
|
72
|
+
- `ReleaseTransport`
|
|
73
|
+
- `DeleteTransport`
|
|
74
|
+
|
|
75
|
+
### Additional analysis, help, and call graph tools
|
|
76
|
+
|
|
77
|
+
- `AnalyzeABAPCode`
|
|
78
|
+
- `AnalyzeCallGraph`
|
|
79
|
+
- `CodeCompletion`
|
|
80
|
+
- `GetAbapHelp`
|
|
81
|
+
- `GetCallGraph`
|
|
82
|
+
- `GetCalleesOf`
|
|
83
|
+
- `GetCallersOf`
|
|
84
|
+
- `GetCodeCoverage`
|
|
85
|
+
- `GetConnectionInfo`
|
|
86
|
+
- `GetObjectStructure`
|
|
87
|
+
- `GetTypeHierarchy`
|
|
88
|
+
- `GetTypeInfo`
|
|
89
|
+
- `GrepObject`
|
|
90
|
+
- `GrepPackage`
|
|
91
|
+
- `CallRFC`
|
|
92
|
+
|
|
93
|
+
### Debugging, dumps, breakpoints, and trace
|
|
94
|
+
|
|
95
|
+
- `DebuggerAttach`
|
|
96
|
+
- `DebuggerDetach`
|
|
97
|
+
- `DebuggerGetStack`
|
|
98
|
+
- `DebuggerGetVariables`
|
|
99
|
+
- `DebuggerListen`
|
|
100
|
+
- `DebuggerStep`
|
|
101
|
+
- `DeleteBreakpoint`
|
|
102
|
+
- `GetBreakpoints`
|
|
103
|
+
- `GetDump`
|
|
104
|
+
- `GetSQLTraceState`
|
|
105
|
+
- `GetTrace`
|
|
106
|
+
- `ListDumps`
|
|
107
|
+
- `SetBreakpoint`
|
|
108
|
+
- `ListSQLTraces`
|
|
109
|
+
|
|
110
|
+
### Object, source, dependency, and service operations
|
|
111
|
+
|
|
112
|
+
- `CloneObject`
|
|
113
|
+
- `CreateAndActivateProgram`
|
|
114
|
+
- `CreateClassWithTests`
|
|
115
|
+
- `CreateObject`
|
|
116
|
+
- `CreateTestInclude`
|
|
117
|
+
- `DeleteObject`
|
|
118
|
+
- `ExecuteABAP`
|
|
119
|
+
- `GetClass`
|
|
120
|
+
- `GetClassComponents`
|
|
121
|
+
- `GetClassInclude`
|
|
122
|
+
- `GetFunction`
|
|
123
|
+
- `GetInclude`
|
|
124
|
+
- `GetInterface`
|
|
125
|
+
- `GetProgram`
|
|
126
|
+
- `GetStructure`
|
|
127
|
+
- `GetTransaction`
|
|
128
|
+
- `LockObject`
|
|
129
|
+
- `MoveObject`
|
|
130
|
+
- `RecoverFailedCreate`
|
|
131
|
+
- `RenameObject`
|
|
132
|
+
- `SaveToFile`
|
|
133
|
+
- `UnlockObject`
|
|
134
|
+
- `UpdateClassInclude`
|
|
135
|
+
- `UpdateSource`
|
|
136
|
+
- `WriteClass`
|
|
137
|
+
- `WriteProgram`
|
|
138
|
+
- `ListDependencies`
|
|
139
|
+
- `PublishServiceBinding`
|
|
140
|
+
- `UnpublishServiceBinding`
|
|
141
|
+
|
|
142
|
+
### General VSP router
|
|
143
|
+
|
|
144
|
+
- `SAP`
|
|
145
|
+
|
|
146
|
+
## Enabled add-on/local tools
|
|
147
|
+
|
|
148
|
+
- `LintABAP` โ local add-on tool; lints caller-supplied ABAP source without contacting SAP.
|
|
149
|
+
- `GetApplicationLog` โ add-on convenience tool mapped to VSP `SAP` with `action="analyze"` and `type="application_log"`.
|
|
150
|
+
|
|
151
|
+
These logical names are exposed through MCP in lowercase snake_case (`lint_abap`, `get_application_log`) because BAS/VS Code chat tool references bind only lowercase identifiers.
|
|
152
|
+
|
|
153
|
+
## Destination workflow tools
|
|
154
|
+
|
|
155
|
+
- `PrepareABAPChangeSet` โ stage full-source `WriteSource` changes and return review diffs and source fingerprints.
|
|
156
|
+
- `ApplyABAPChangeSet` โ re-read staged objects before writing and report conflicts or partial application.
|
|
157
|
+
- `CheckTransportReadiness` โ collect selected transport, dependency, inactive-object, ABAP Unit, and ATC evidence.
|
|
158
|
+
- `PlanABAPCloudMigration` โ batch-check API release state for supplied ADT object URIs and prioritize recognized unreleased APIs.
|
|
159
|
+
- `GenerateRAPRegressionSuite` โ read service metadata and emit reusable GET-only smoke cases for entity sets.
|
|
160
|
+
- `RunRAPRegressionSuite` โ execute saved cases with status, content-type, and JSON-path assertions over the connected destination.
|
|
161
|
+
|
|
162
|
+
## Notes
|
|
163
|
+
|
|
164
|
+
- Runtime tool names are unprefixed lowercase snake_case (`run_query`) on the normal single-destination server; a `<destination-slug>_` prefix appears only on multi-destination servers. `tools/call` accepts the exact name returned by `tools/list`.
|
|
165
|
+
- The proxy starts VSP with `--enable-transports`; generated MCP entries set `SAP_ALLOW_TRANSPORTABLE_EDITS=true`.
|
|
166
|
+
- `SAP_AI_DEV_TOOLKIT_READ_ONLY=true` switches a server to read-only: the write/activate/transport-create/breakpoint tools above are removed from the surface, change-set workflows are not registered, and VSP starts with `--transport-read-only` instead.
|
|
167
|
+
- `SAP_AI_DEV_TOOLKIT_REQUEST_TIMEOUT_MS` (default 600000) bounds each forwarded call; stalled requests fail without killing the child.
|
|
168
|
+
- Transport release/deletion and the general-purpose `SAP` router are intentionally hidden from direct proxy calls. `GetApplicationLog` is the bounded convenience mapping for the SAP application-log route.
|
|
169
|
+
|
|
170
|
+
## Separate optional HANA Cloud inspector
|
|
171
|
+
|
|
172
|
+
The HANA inspector is a standalone companion MCP process launched as `sap-ai-hana`; it is not a VSP child and is not destination-prefixed. It uses a read-only identity selected from `HANA_RO_*` variables or one unambiguous `VCAP_SERVICES` binding. Its host/schema target is fixed by process configuration; tool arguments cannot change it.
|
|
173
|
+
|
|
174
|
+
| Tool | Behavior |
|
|
175
|
+
| --- | --- |
|
|
176
|
+
| `hana_connection_info` | Report selected endpoint, service/binding name, configured and current schema, database user, and TLS validation state. Does not return credentials. |
|
|
177
|
+
| `hana_list_objects` | List tables and/or views in the configured schema, capped at 200 objects. |
|
|
178
|
+
| `hana_describe_object` | Return columns for a table or view verified in the configured schema. |
|
|
179
|
+
| `hana_read_rows` | Read selected catalog-verified columns with bound filter values and a hard 200-row maximum; credential-like columns are blocked. No free-form SQL. |
|
|
180
|
+
|
|
181
|
+
The process exposes no DDL, DML, arbitrary SQL, procedure-call, deployment, undeploy, grant, or service-key management tools. The separate HANA identity should also be granted only the reads required for the intended HDI container.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sap-ai-dev-toolkit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"description": "SAP AI development toolkit for BAS, ABAP, RAP, CAP, HANA Cloud, Fiori, UI5, and MCP",
|
|
5
5
|
"author": "Gurkan Yilmaz",
|
|
6
6
|
"type": "module",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"scripts/",
|
|
46
46
|
"patches/",
|
|
47
47
|
"dist/",
|
|
48
|
-
"test/",
|
|
49
48
|
"LICENSE",
|
|
50
49
|
"NOTICE",
|
|
51
50
|
"LICENSE-APACHE-2.0.txt",
|
|
52
51
|
"tools.md",
|
|
52
|
+
"inventory.md",
|
|
53
53
|
".github/agents/",
|
|
54
54
|
".github/skills/"
|
|
55
55
|
],
|
package/scripts/build-vsp.mjs
CHANGED
|
@@ -5,12 +5,13 @@ import { dirname, join } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
7
7
|
import { ensureGo } from './ensure-go.mjs';
|
|
8
|
+
import { UPSTREAM_COMMIT } from '../src/binary.mjs';
|
|
8
9
|
|
|
9
10
|
const exec = promisify(execFile);
|
|
10
11
|
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
11
12
|
const source = join(root, '.build', 'vibing-steampunk');
|
|
12
13
|
const dist = join(root, 'dist');
|
|
13
|
-
const commit =
|
|
14
|
+
const commit = UPSTREAM_COMMIT;
|
|
14
15
|
const upstream = 'https://github.com/oisee/vibing-steampunk.git';
|
|
15
16
|
const targets = [
|
|
16
17
|
['linux', 'amd64', 'linux', 'x64', ''],
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -2,7 +2,6 @@ import { open, readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { closeSync, openSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { dirname, join, resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { ensureGo } from './ensure-go.mjs';
|
|
6
5
|
import { installBinary } from '../src/binary.mjs';
|
|
7
6
|
import { runSetup } from '../src/setup.mjs';
|
|
8
7
|
import { installUserCopilotAssets } from './install-user-copilot-assets.mjs';
|
|
@@ -12,6 +11,7 @@ import { homedir } from 'node:os';
|
|
|
12
11
|
import { colorText, formatStatus } from '../src/terminal-ui.mjs';
|
|
13
12
|
import { brandedEnvValue, withBrandedEnvironment } from '../src/branding.mjs';
|
|
14
13
|
import { generatedServerName } from '../src/mcp-config.mjs';
|
|
14
|
+
import { redactText } from '../src/redact.mjs';
|
|
15
15
|
|
|
16
16
|
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
17
17
|
const pkg = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
|
|
@@ -77,10 +77,10 @@ async function runCopilotAssetInstall() {
|
|
|
77
77
|
await announce([
|
|
78
78
|
'Optional Copilot setup is waiting for your choice.',
|
|
79
79
|
'',
|
|
80
|
-
'
|
|
80
|
+
'Type y then press Enter to install the bundled agents and all skills in the path shown below; press Enter alone to skip.',
|
|
81
81
|
'',
|
|
82
|
-
`${colorText('โ
|
|
83
|
-
`${colorText('โญ๏ธ
|
|
82
|
+
`${colorText('โ
Type y then Enter', 'green', true)} to install the bundled agents and all skills.`,
|
|
83
|
+
`${colorText('โญ๏ธ Press Enter', 'yellow', true)} to skip this optional step (default).`,
|
|
84
84
|
'',
|
|
85
85
|
`${colorText('๐ Target folder:', 'cyan', true)}`,
|
|
86
86
|
` ${copilotRoot}`,
|
|
@@ -89,11 +89,13 @@ async function runCopilotAssetInstall() {
|
|
|
89
89
|
const prompt = createInterface({ input: terminal.input, output: terminal.output });
|
|
90
90
|
let answer;
|
|
91
91
|
try {
|
|
92
|
-
answer = await prompt.question(`${colorText('๐ค Install the bundled agents and all skills?', 'magenta', terminal.output)} ${colorText('[
|
|
92
|
+
answer = await prompt.question(`${colorText('๐ค Install the bundled agents and all skills?', 'magenta', terminal.output)} ${colorText('[y/N]', 'yellow', terminal.output)} `);
|
|
93
93
|
} finally {
|
|
94
94
|
prompt.close();
|
|
95
95
|
}
|
|
96
|
-
|
|
96
|
+
// Default is skip: writing instruction files into ~/.copilot affects
|
|
97
|
+
// every Copilot session on the machine, so it needs an explicit yes.
|
|
98
|
+
if (!/^y(?:es)?$/i.test(answer.trim())) {
|
|
97
99
|
await announce('Copilot agent and skills were skipped. Your files were not changed.', 'info');
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
@@ -111,8 +113,7 @@ async function runCopilotAssetInstall() {
|
|
|
111
113
|
function probeCell(destination) {
|
|
112
114
|
const probe = destination.probe || {};
|
|
113
115
|
if (probe.status === 'skipped') return { text: 'SKIPPED (probe disabled)', color: 'yellow' };
|
|
114
|
-
const error = destination.source === 'cloud-foundry' ? '' :
|
|
115
|
-
.replace(/(authorization|cookie|password|secret|token)\s*[:=]\s*[^\s,;]+/gi, '$1=[redacted]')
|
|
116
|
+
const error = destination.source === 'cloud-foundry' ? '' : redactText(probe.error || '')
|
|
116
117
|
.replace(/[\u0000-\u001f\u007f]/g, ' ')
|
|
117
118
|
.replace(/\s+/g, ' ')
|
|
118
119
|
.slice(0, 100);
|
|
@@ -219,17 +220,14 @@ async function announceSetup(result) {
|
|
|
219
220
|
async function main() {
|
|
220
221
|
if (process.env.npm_config_ignore_scripts === 'true') return;
|
|
221
222
|
|
|
223
|
+
// Go is intentionally NOT provisioned here: the installed package never
|
|
224
|
+
// runs `go` (only the repository-only build:vsp script does), so a toolchain
|
|
225
|
+
// download at install time was pure cost. The pinned, checksum-verified VSP
|
|
226
|
+
// binary ships with the package; the download below is the fallback.
|
|
222
227
|
try {
|
|
223
228
|
if (brandedEnvValue(runtimeEnv, 'BINARY')) {
|
|
224
229
|
await announce('Using the SAP_AI_DEV_TOOLKIT_BINARY override.', 'info');
|
|
225
230
|
} else {
|
|
226
|
-
await announce('Checking for Go. The supported version installs automatically if needed; this may take a few minutes.', 'progress');
|
|
227
|
-
try {
|
|
228
|
-
await ensureGo();
|
|
229
|
-
await announce('Go is ready.', 'success');
|
|
230
|
-
} catch (error) {
|
|
231
|
-
throw new Error(`Go provisioning failed: ${error.message}`);
|
|
232
|
-
}
|
|
233
231
|
await announce('Preparing the pinned VSP runtime for this platform.', 'progress');
|
|
234
232
|
try {
|
|
235
233
|
await installBinary(pkg, { env: runtimeEnv });
|
|
@@ -240,7 +238,7 @@ async function main() {
|
|
|
240
238
|
}
|
|
241
239
|
} catch (error) {
|
|
242
240
|
await announce(error.message, 'error');
|
|
243
|
-
await announce('
|
|
241
|
+
await announce('Set SAP_AI_DEV_TOOLKIT_BINARY only when supplying a trusted prebuilt VSP executable.', 'info');
|
|
244
242
|
process.exitCode = 1;
|
|
245
243
|
return;
|
|
246
244
|
}
|
|
@@ -2,6 +2,7 @@ import http from 'node:http';
|
|
|
2
2
|
import { fetch as undiciFetch, ProxyAgent } from 'undici';
|
|
3
3
|
import { CookieJar } from 'tough-cookie';
|
|
4
4
|
import { brandedEnvValue } from './branding.mjs';
|
|
5
|
+
import { redactText } from './redact.mjs';
|
|
5
6
|
|
|
6
7
|
const DEFAULT_PROXY = 'http://127.0.0.1:8887';
|
|
7
8
|
const MAX_BODY_BYTES = 64 * 1024 * 1024;
|
|
@@ -274,7 +275,14 @@ export function createBasDestinationRelay(destination, { env = process.env, fetc
|
|
|
274
275
|
function authHeaders(extra = {}) {
|
|
275
276
|
if (!credentials?.user || !credentials?.password) return extra;
|
|
276
277
|
const basic = Buffer.from(`${credentials.user}:${credentials.password}`).toString('base64');
|
|
277
|
-
|
|
278
|
+
// The stored credential override wins over any inbound authorization
|
|
279
|
+
// header: the override exists precisely to pair Basic auth with the
|
|
280
|
+
// relay's CSRF session, and silently forwarding a caller-supplied header
|
|
281
|
+
// would disable that pairing without any diagnostic.
|
|
282
|
+
const headers = { ...extra };
|
|
283
|
+
delete headers.authorization;
|
|
284
|
+
delete headers.Authorization;
|
|
285
|
+
return { ...headers, authorization: `Basic ${basic}` };
|
|
278
286
|
}
|
|
279
287
|
|
|
280
288
|
async function forward(method, requestUrl, requestHeaders, body, session) {
|
|
@@ -339,11 +347,17 @@ export function createBasDestinationRelay(destination, { env = process.env, fetc
|
|
|
339
347
|
const body = UNSAFE.has(method) ? await readRequestBody(req) : Buffer.alloc(0);
|
|
340
348
|
const { response, body: responseBody } = await forwardWithRetry(method, requestUrl, req.headers, body);
|
|
341
349
|
const responseHeaders = {};
|
|
350
|
+
// SAP sessions commonly set several cookies at once; a plain object
|
|
351
|
+
// assignment would collapse them to the last value. undici exposes the
|
|
352
|
+
// full list via getSetCookie, and Node's http server serializes an
|
|
353
|
+
// array as repeated headers.
|
|
354
|
+
const setCookies = response.headers.getSetCookie?.() || [];
|
|
355
|
+
if (setCookies.length) responseHeaders['set-cookie'] = setCookies;
|
|
342
356
|
for (const [name, value] of response.headers) {
|
|
343
357
|
const lower = name.toLowerCase();
|
|
344
358
|
// undici decompresses response bodies; the stale content-encoding and
|
|
345
359
|
// content-length would misdescribe the plain bytes handed to VSP.
|
|
346
|
-
if (HOP_BY_HOP.has(lower) || lower === 'content-encoding' || lower === 'content-length') continue;
|
|
360
|
+
if (lower === 'set-cookie' || HOP_BY_HOP.has(lower) || lower === 'content-encoding' || lower === 'content-length') continue;
|
|
347
361
|
responseHeaders[name] = value;
|
|
348
362
|
}
|
|
349
363
|
responseHeaders['x-sap-ai-dev-toolkit-relay'] = 'bas-destination';
|
|
@@ -351,10 +365,18 @@ export function createBasDestinationRelay(destination, { env = process.env, fetc
|
|
|
351
365
|
res.end(responseBody);
|
|
352
366
|
})().catch(error => {
|
|
353
367
|
if (!res.headersSent) res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8', 'connection': 'close' });
|
|
354
|
-
|
|
368
|
+
// Proxy and transport errors can embed the full proxy URL including
|
|
369
|
+
// userinfo; redact before the body reaches the child (and the tool result).
|
|
370
|
+
res.end(`BAS destination relay failed: ${redactText(error.message)}\n`);
|
|
355
371
|
});
|
|
356
372
|
});
|
|
357
373
|
|
|
374
|
+
// Keep an error listener for the server's whole lifetime: after listen()
|
|
375
|
+
// succeeds, a later 'error' event (port collision cleanup, socket reset)
|
|
376
|
+
// with no listener would be an uncaught exception that kills the process.
|
|
377
|
+
server.on('error', error => {
|
|
378
|
+
log(`[${destination.name}] BAS relay server error: ${redactText(error.message)}`);
|
|
379
|
+
});
|
|
358
380
|
// Bind eagerly and report the real port through `ready`. Callers must
|
|
359
381
|
// await `ready` before handing the URL to a VSP child; binding failures
|
|
360
382
|
// surface as a rejected promise instead of a silently wrong guessed port.
|
package/src/bas-discovery.mjs
CHANGED
|
@@ -92,9 +92,15 @@ export function sanitizeChildEnv(input = process.env) {
|
|
|
92
92
|
if (!SECRET_KEY.test(key)) env[key] = value;
|
|
93
93
|
}
|
|
94
94
|
env.SAP_PROXY_CONTEXTID_GUARD = 'true';
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
// The BAS dev-space proxy (127.0.0.1:8887) is only implied inside BAS
|
|
96
|
+
// (H2O_URL present). Outside a dev space the default would route every
|
|
97
|
+
// child request โ including SAP Basic credentials โ to whatever local
|
|
98
|
+
// process happens to own that port, so it is not applied there.
|
|
99
|
+
const proxy = env.HTTP_PROXY || env.http_proxy || (env.H2O_URL ? DEFAULT_PROXY : undefined);
|
|
100
|
+
if (proxy) {
|
|
101
|
+
if (!env.HTTP_PROXY && !env.http_proxy) env.HTTP_PROXY = proxy;
|
|
102
|
+
if (!env.HTTPS_PROXY && !env.https_proxy) env.HTTPS_PROXY = proxy;
|
|
103
|
+
}
|
|
98
104
|
const noProxyKey = env.NO_PROXY != null ? 'NO_PROXY' : (env.no_proxy != null ? 'no_proxy' : 'NO_PROXY');
|
|
99
105
|
const entries = String(env[noProxyKey] || '').split(',').map(value => value.trim()).filter(Boolean).filter(value => !value.toLowerCase().includes('.dest'));
|
|
100
106
|
env[noProxyKey] = entries.join(',');
|