sap-ai-dev-toolkit 0.9.5 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -297,7 +297,7 @@ The guided setup can also offer companion MCP entries with `sap-ai-dev --setup -
297
297
 
298
298
  The installer handles VSP provisioning automatically:
299
299
 
300
- - 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.
300
+ - Uses the package's bundled patched VSP binary for the current platform, verified against the npm-published `dist/checksums.txt`. When the bundled asset is missing (an interrupted install, an antivirus quarantine, or a git checkout without `dist/`), a checksum-anchored download from the matching GitHub release is the fallback; MCP server startup runs it too, because npx entries skip install scripts.
301
301
  - No Go toolchain is downloaded or required at install time; Go is only used by the repository's own `build:vsp` development script.
302
302
 
303
303
  Setup detects where it is running. With `H2O_URL` set, it treats the environment as SAP Business Application Studio and opens a checkbox picker for BAS destinations, 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.
@@ -880,7 +880,7 @@ NPM_PUBLISH_TOKEN=npm_...
880
880
  - To publish a patch bump, run `npm run publish:npm -- --patch`; it updates `package.json` and `package-lock.json` before publishing. If publishing fails after the bump, retry without `--patch`.
881
881
  - npm's `prepublishOnly` hook builds the pinned VSP binaries for all platforms (including the Go toolchain if missing) and refuses to ship a tarball whose `dist/checksums.txt` does not list all five assets; it guards `npm run publish:npm` and a plain `npm publish` alike. Pass `--skip-build` to republish an already-built `dist/` without rebuilding.
882
882
  - Preview the package without publishing, changing its version, or building with `npm run publish:npm -- --dry-run`.
883
- - GitHub Actions runs the test suite on pushes to `main` and pull requests. A push to `main` that changes the `package.json` version runs the same checks, builds the VSP binaries, publishes that version to npm, and creates a `v<version>` GitHub release with generated notes.
883
+ - GitHub Actions runs the test suite on pushes to `main` and pull requests. A push to `main` that changes the `package.json` version runs the same checks, builds the VSP binaries, publishes that version to npm, and creates a `v<version>` GitHub release with generated notes and the VSP binaries plus `checksums.txt` attached for the download fallback.
884
884
  - The publish workflow uses the `NPM_PUBLISH_TOKEN` GitHub repository secret. Verify it with `gh secret list`; the token value is never stored in the repository.
885
885
 
886
886
  The token is not printed or stored in the repository.
@@ -1,5 +1,5 @@
1
- 85333f1ac7cbc25bc10a938cea5712b43d1c7b241911f19c6794f897dbcb589c vsp-linux-x64
2
- 68cd2b79e7cda145135f9f516b6ba76f33839bc9226bbf58ea015ff2442b4b2d vsp-linux-arm64
3
- 62fd8cd8eba8d61e36813c098938a2479af68047fd2fa1c85782edb4d4b5261b vsp-darwin-x64
4
- 71eb9e64e292e3ac83a2ab6a630367cfb0d79fe465d62ad1cfb05ef8c6c2b6e7 vsp-darwin-arm64
5
- 952a6d5a90265fb6a6b3494d01a5d143fd7c471f7ce560bed200c399522b180f vsp-win32-x64.exe
1
+ a5b602573f54ce3d03d161aaaeb78559fd73bd51f2ae9a3b7549cee1ddc3fbf6 vsp-linux-x64
2
+ 2e336e2999c3654e5eb1e3a8bb42616eb5d5e422ab7ae74ffbff4634be45189d vsp-linux-arm64
3
+ afc7fd0f2e40ae5ebfcd3ddb8ac3cb7e7501b2b66d76ac96e3b6054b09366bb5 vsp-darwin-x64
4
+ 2d28a870c4a006900eec245384b4bbc2e84651e0ba911cca6107c132ace73575 vsp-darwin-arm64
5
+ 7d0189aa7ff936a145b0e3f15bffce8de5aebc252465a720edc3a9b122bd2a28 vsp-win32-x64.exe
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sap-ai-dev-toolkit",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
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",
package/src/binary.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { chmod, mkdir, readFile, rename, stat, writeFile } from 'node:fs/promises';
3
- import { homedir, tmpdir } from 'node:os';
3
+ import { homedir } from 'node:os';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { brandedEnvValue } from './branding.mjs';
@@ -114,12 +114,14 @@ export async function findBinary(pkg, options = {}) {
114
114
  await stat(bundled);
115
115
  const verified = await verifyAgainstPackagedChecksums(bundled, target);
116
116
  if (verified === false) {
117
- log(`bundled VSP binary ${target.asset} failed checksum verification; ignoring it`);
117
+ log(`bundled VSP binary ${bundled} failed checksum verification; ignoring it`);
118
118
  } else {
119
119
  if (verified === null) log(`bundled VSP binary ${target.asset} has no packaged checksum entry; using it unverified`);
120
120
  return bundled;
121
121
  }
122
- } catch {}
122
+ } catch (error) {
123
+ log(`bundled VSP binary not found at ${bundled} (${error.code || error.message})`);
124
+ }
123
125
  }
124
126
  const path = cachedBinaryPath(pkg, options.platform, options.arch, env);
125
127
  try {
@@ -158,6 +160,11 @@ export async function installBinary(pkg, options = {}) {
158
160
  if (String(error?.message || '').includes('checksum verification')) throw error;
159
161
  }
160
162
  }
163
+ return downloadBinary(pkg, options);
164
+ }
165
+
166
+ export async function downloadBinary(pkg, options = {}) {
167
+ const env = options.env || process.env;
161
168
  const target = binaryTarget(options.platform, options.arch);
162
169
  const base = releaseBaseUrl(pkg, pkg.version);
163
170
  const assetUrl = brandedEnvValue(env, 'BINARY_URL') || `${base}/${target.asset}`;
@@ -184,7 +191,8 @@ export async function installBinary(pkg, options = {}) {
184
191
  await mkdir(dir, { recursive: true, mode: 0o700 });
185
192
  await chmod(dir, 0o700);
186
193
  const destination = cachedBinaryPath(pkg, options.platform, options.arch, env);
187
- const temporary = join(tmpdir(), `sap-ai-dev-toolkit-vsp-${process.pid}-${Date.now()}`);
194
+ // Same directory as the destination: rename fails with EXDEV across filesystems (tmpfs /tmp).
195
+ const temporary = `${destination}.${process.pid}-${Date.now()}.tmp`;
188
196
  await writeFile(temporary, bytes, { mode: 0o700 });
189
197
  await chmod(temporary, 0o700);
190
198
  await rename(temporary, destination);
package/src/launcher.mjs CHANGED
@@ -5,7 +5,7 @@ import { dirname, join } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { discoverDestinations, remediation, slugifyDestination, statusRows } from './bas-discovery.mjs';
7
7
  import { discoverSapGuiSystems } from './local-sap-gui.mjs';
8
- import { findBinary } from './binary.mjs';
8
+ import { binaryTarget, downloadBinary, findBinary } from './binary.mjs';
9
9
  import { MCPProxy } from './mcp-proxy.mjs';
10
10
  import { installMcpConfig, npxMcpLauncher, repairManagedMcpConfig } from './mcp-config.mjs';
11
11
  import { runSetup } from './setup.mjs';
@@ -163,10 +163,27 @@ function probeDiagnostic(destination) {
163
163
  return `[sap-ai-dev] ${destination.name}: probe=${probe.status || 'unknown'}${details.length ? ` (${details.join('; ')})` : ''}`;
164
164
  }
165
165
 
166
+ // npx MCP entries run with --ignore-scripts, so postinstall's verified
167
+ // download fallback never ran; a missing or corrupt bundled binary heals here.
166
168
  async function binaryOrError() {
167
- const path = await findBinary(pkg, { env: runtimeEnv });
168
- if (path) return path;
169
- throw new Error('VSP binary is not installed. Reinstall with scripts enabled, set SAP_AI_DEV_TOOLKIT_BINARY to a trusted patched binary, or run npm run build:vsp.');
169
+ const notes = [];
170
+ const found = await findBinary(pkg, { env: runtimeEnv, log: note => notes.push(note) });
171
+ if (found) return found;
172
+ logLine(`[sap-ai-dev] ${notes.join('; ') || 'no VSP binary found'}; downloading a checksum-verified copy`);
173
+ try {
174
+ const downloaded = await downloadBinary(pkg, { env: runtimeEnv });
175
+ logLine(`[sap-ai-dev] VSP binary installed at ${downloaded}`);
176
+ return downloaded;
177
+ } catch (error) {
178
+ notes.push(`download fallback failed: ${error.message}${error.cause?.code ? ` (${error.cause.code})` : ''}`);
179
+ }
180
+ const npxDirectory = root.match(/^(.*[\\/]_npx[\\/][^\\/]+)[\\/]node_modules[\\/]/)?.[1];
181
+ throw new Error([
182
+ `VSP binary ${binaryTarget().asset} is unavailable for ${pkg.name}@${pkg.version}: ${notes.join('; ')}.`,
183
+ npxDirectory
184
+ ? `The npm package ships this binary, so an interrupted install or an antivirus quarantine usually removed it: delete ${npxDirectory} and restart the MCP server so npx reinstalls the package, or set SAP_AI_DEV_TOOLKIT_BINARY to a trusted patched VSP binary.`
185
+ : `Reinstall ${pkg.name} (a git checkout needs npm run build:vsp), check whether antivirus quarantined the binary, or set SAP_AI_DEV_TOOLKIT_BINARY to a trusted patched VSP binary.`
186
+ ].join(' '));
170
187
  }
171
188
 
172
189
  async function discoverForCommand() {