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 +2 -2
- package/dist/checksums.txt +5 -5
- package/dist/vsp-darwin-arm64 +0 -0
- package/dist/vsp-darwin-x64 +0 -0
- package/dist/vsp-linux-arm64 +0 -0
- package/dist/vsp-linux-x64 +0 -0
- package/dist/vsp-win32-x64.exe +0 -0
- package/package.json +1 -1
- package/src/binary.mjs +12 -4
- package/src/launcher.mjs +21 -4
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`.
|
|
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.
|
package/dist/checksums.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
package/dist/vsp-darwin-arm64
CHANGED
|
Binary file
|
package/dist/vsp-darwin-x64
CHANGED
|
Binary file
|
package/dist/vsp-linux-arm64
CHANGED
|
Binary file
|
package/dist/vsp-linux-x64
CHANGED
|
Binary file
|
package/dist/vsp-win32-x64.exe
CHANGED
|
Binary file
|
package/package.json
CHANGED
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
|
|
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 ${
|
|
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
|
-
|
|
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
|
|
168
|
-
|
|
169
|
-
|
|
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() {
|