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.
Files changed (57) hide show
  1. package/.github/agents/abap-developer.agent.md +8 -8
  2. package/.github/agents/abap-runtime-debugger.agent.md +6 -6
  3. package/.github/agents/hana-cloud-hdi-specialist.agent.md +1 -1
  4. package/.github/agents/rap-service-developer.agent.md +5 -5
  5. package/.github/agents/sap-solution-architect.agent.md +2 -2
  6. package/.github/skills/abap-debugging/SKILL.md +3 -3
  7. package/.github/skills/abap-development/SKILL.md +3 -3
  8. package/.github/skills/abap-runtime-analysis/SKILL.md +4 -4
  9. package/.github/skills/abap-testing-quality/SKILL.md +3 -3
  10. package/.github/skills/cds-development/SKILL.md +3 -3
  11. package/.github/skills/clean-core-extensibility/SKILL.md +1 -1
  12. package/.github/skills/hana-cloud-inspection/SKILL.md +2 -2
  13. package/.github/skills/hana-cloud-native-development/SKILL.md +2 -2
  14. package/.github/skills/hana-cloud-validation/SKILL.md +1 -1
  15. package/.github/skills/rap-development/SKILL.md +3 -3
  16. package/.github/skills/rap-service-delivery/SKILL.md +2 -2
  17. package/.github/skills/sap-sdlc-orchestration/SKILL.md +1 -1
  18. package/.github/skills/sap-standard-api-analysis/SKILL.md +1 -1
  19. package/.github/skills/sap-transport-release/SKILL.md +2 -2
  20. package/README.md +30 -23
  21. package/inventory.md +181 -0
  22. package/package.json +2 -2
  23. package/scripts/build-vsp.mjs +2 -1
  24. package/scripts/postinstall.mjs +14 -16
  25. package/src/bas-destination-relay.mjs +25 -3
  26. package/src/bas-discovery.mjs +9 -3
  27. package/src/binary.mjs +101 -17
  28. package/src/cf-destination.mjs +55 -1
  29. package/src/credentials-store.mjs +0 -10
  30. package/src/engineering-tools.mjs +32 -10
  31. package/src/hana-tools.mjs +9 -2
  32. package/src/launcher.mjs +14 -13
  33. package/src/mcp-config.mjs +19 -1
  34. package/src/mcp-proxy.mjs +284 -103
  35. package/src/redact.mjs +28 -0
  36. package/src/setup.mjs +30 -1
  37. package/tools.md +10 -2
  38. package/test/bas-destination-relay.test.mjs +0 -415
  39. package/test/cf-connectivity.test.mjs +0 -287
  40. package/test/cf-destination.test.mjs +0 -307
  41. package/test/cf-runtime.test.mjs +0 -527
  42. package/test/copilot-assets.test.mjs +0 -63
  43. package/test/copilot-content.test.mjs +0 -249
  44. package/test/credentials-store.test.mjs +0 -187
  45. package/test/discovery.test.mjs +0 -282
  46. package/test/fixtures/fake-vsp.mjs +0 -266
  47. package/test/hana-config.test.mjs +0 -168
  48. package/test/hana-inspector-stdio.test.mjs +0 -44
  49. package/test/hana-tools.test.mjs +0 -206
  50. package/test/launcher.test.mjs +0 -401
  51. package/test/live-s4h.test.mjs +0 -204
  52. package/test/mcp-config-cf.test.mjs +0 -475
  53. package/test/mcp-proxy.test.mjs +0 -604
  54. package/test/pty.mjs +0 -8
  55. package/test/setup-cf.test.mjs +0 -489
  56. package/test/setup.test.mjs +0 -417
  57. 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. If Go is not already available, the installer can provision the pinned supported Go release automatically.
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, dumps, logs, traces, debugger sessions, call graphs, and performance symptoms |
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, traces, debugger state, call graphs, and performance analysis |
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 two setup tasks automatically:
274
+ The installer handles VSP provisioning automatically:
274
275
 
275
- - Looks for Go in `GO_BINARY`, `PATH`, or the package-local Go installation. If none is available, it downloads and installs the pinned supported Go release without prompting.
276
- - Uses the package's checksum-verified patched VSP binary for the current platform. A remote download is the fallback only when the package has no bundled asset.
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-toolkit --setup` from an interactive BAS terminal after installation.
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
- BAS_VSP_BINARY=/path/to/vsp npm install --global sap-ai-dev-toolkit
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, traces, debugger state, call graphs, and performance symptoms. |
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`. Press **Enter** to install; type **n** then **Enter** to skip. Declining leaves those files unchanged.
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, like the provided `dests.sample.json`. A representative record:
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` matches `BAS_VSP_DESTINATION`, so each wizard-generated destination has its own identity instead of the shared `sap-ai-dev-toolkit` 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`. Tool names carry a `sap_system_<destination-slug>_<tool>` prefix with a lowercase snake_case tool segment (`sap_system_demo-abap_get_source`, `sap_system_demo-abap_run_query`, `sap_system_demo-abap_lint_abap`), so every tool states which SAP system it targets. 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
+ 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 per-destination tool name is `sap_system_<destination-slug>_lint_abap`, for example `sap_system_demo-abap_lint_abap` (the local workflow name `LintABAP` is exposed in snake_case). 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
+ 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-toolkit --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
+ `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 (for `DEMO_ABAP`, `sap_system_demo-abap_run_query`) and pass:
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": "sap_system_demo-abap_run_query",
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 `sap_system_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.
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": "sap_system_demo-abap_run_query",
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
- | `BAS_VSP_BINARY` | Trusted prebuilt VSP executable; skips Go and binary provisioning. |
741
- | `BAS_VSP_BINARY_URL` | Alternate VSP binary download URL. |
742
- | `BAS_VSP_CACHE_DIR` | Binary cache directory. |
743
- | `GO_BINARY` | Explicit Go executable used for provisioning when automatic Go installation is unavailable. |
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.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
  ],
@@ -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 = '9886d2727f47506368b0a3c2f1c1766f1200f747';
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', ''],
@@ -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
- 'Press Enter to install the bundled agents and all skills in the path shown below; type n then press Enter to skip.',
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('โœ… Press Enter', 'green', true)} to install the bundled agents and all skills.`,
83
- `${colorText('โญ๏ธ Type n then Enter', 'yellow', true)} to skip this optional step.`,
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('[Y/n]', 'yellow', terminal.output)} `);
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
- if (/^n(?:o)?$/i.test(answer.trim())) {
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' ? '' : String(probe.error || '')
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('Go is provisioned automatically. Set SAP_AI_DEV_TOOLKIT_BINARY only when supplying a trusted prebuilt VSP executable.', 'info');
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
- return { authorization: `Basic ${basic}`, ...extra };
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
- res.end(`BAS destination relay failed: ${error.message}\n`);
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.
@@ -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
- const proxy = env.HTTP_PROXY || env.http_proxy || DEFAULT_PROXY;
96
- if (!env.HTTP_PROXY && !env.http_proxy) env.HTTP_PROXY = proxy;
97
- if (!env.HTTPS_PROXY && !env.https_proxy) env.HTTPS_PROXY = proxy;
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(',');