sap-ai-dev-toolkit 0.7.0 → 0.7.2

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
@@ -813,7 +813,8 @@ NPM_PUBLISH_TOKEN=npm_...
813
813
 
814
814
  - `npm run publish:npm` publishes the version already set in `package.json`.
815
815
  - 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`.
816
- - Preview the package without publishing or changing its version with `npm run publish:npm -- --dry-run`.
816
+ - 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.
817
+ - Preview the package without publishing, changing its version, or building with `npm run publish:npm -- --dry-run`.
817
818
 
818
819
  The token is not printed or stored in the repository.
819
820
 
@@ -0,0 +1,5 @@
1
+ 8ab555658815db7de670b956dafe0f12d6a249e4f1e1cbbb058deb658a89a37d vsp-linux-x64
2
+ 7011b716e295ce2cecc40b9a56e57d9a1ec24c2b9d6aa25ab46e5cde0ec23998 vsp-linux-arm64
3
+ 5c240a6b53e15ebaae817612aed1c5b95624a99adfc38e6abb9afa377de30d1a vsp-darwin-x64
4
+ 28032c4d331253808ec9318e6db570420c6c9308935964de665e34374465d89f vsp-darwin-arm64
5
+ 5bb45857489bbe5d57587d9abda0b768d3a1b352d89a2a6bf13b23af8d2fd45e 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.7.0",
3
+ "version": "0.7.2",
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",
@@ -27,6 +27,7 @@
27
27
  "test:visibility": "node --test test/setup.test.mjs test/terminal-ui.test.mjs",
28
28
  "test:mutation": "node scripts/mutation-terminal-ui.mjs",
29
29
  "publish:npm": "node scripts/publish-npm.mjs",
30
+ "publish": "node scripts/build-vsp.mjs && node scripts/publish-npm.mjs",
30
31
  "ensure:go": "node scripts/ensure-go.mjs",
31
32
  "build:vsp": "node scripts/build-vsp.mjs"
32
33
  },
@@ -1,12 +1,14 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
3
- import { dirname, join } from 'node:path';
3
+ import { realpathSync } from 'node:fs';
4
+ import { dirname, join, resolve } from 'node:path';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { tmpdir } from 'node:os';
7
+ import { packagedBinaryAssets } from '../src/binary.mjs';
6
8
 
7
9
  const root = dirname(dirname(fileURLToPath(import.meta.url)));
8
10
  const args = new Set(process.argv.slice(2));
9
- const allowedArgs = new Set(['--patch', '--dry-run']);
11
+ const allowedArgs = new Set(['--patch', '--dry-run', '--skip-build', '--verify-only']);
10
12
 
11
13
  function parseToken(value) {
12
14
  const tokenValue = value.trim();
@@ -57,6 +59,23 @@ function runNpm(npmArgs, env) {
57
59
  });
58
60
  }
59
61
 
62
+ // dist/ is gitignored, so a publish from a clean checkout silently ships no
63
+ // VSP binaries and every `npm install` of it fails (the 0.7.0 incident):
64
+ // postinstall only downloads from a GitHub release as a fallback. The
65
+ // prepublishOnly hook in package.json builds the binaries and re-invokes this
66
+ // script with --verify-only, so an incomplete dist/ can never be published —
67
+ // through publish:npm or a plain `npm publish` alike.
68
+ export async function missingDistBinaries(directory = root) {
69
+ let text;
70
+ try {
71
+ text = await readFile(join(directory, 'dist', 'checksums.txt'), 'utf8');
72
+ } catch {
73
+ return packagedBinaryAssets();
74
+ }
75
+ const listed = new Set(text.split(/\r?\n/).map(line => line.trim().split(/\s+/)[1]).filter(Boolean));
76
+ return packagedBinaryAssets().filter(asset => !listed.has(asset));
77
+ }
78
+
60
79
  async function main() {
61
80
  for (const argument of args) {
62
81
  if (!allowedArgs.has(argument)) throw new Error(`Unknown option: ${argument}`);
@@ -65,6 +84,20 @@ async function main() {
65
84
  const patch = args.has('--patch');
66
85
  if (dryRun && patch) throw new Error('--dry-run cannot be combined with --patch; it never changes the package version');
67
86
 
87
+ // Second half of the prepublishOnly hook (after build-vsp.mjs ran): refuse
88
+ // to let an incomplete dist/ reach the registry.
89
+ if (args.has('--verify-only')) {
90
+ const missing = await missingDistBinaries();
91
+ if (missing.length > 0) throw new Error(`dist/checksums.txt is missing ${missing.join(', ')}; run npm run build:vsp first`);
92
+ console.error('dist/checksums.txt lists every pinned VSP binary.');
93
+ return;
94
+ }
95
+
96
+ if (dryRun) {
97
+ const missing = await missingDistBinaries();
98
+ if (missing.length > 0) console.error(`Dry-run note: dist/ is missing ${missing.join(', ')}; a real publish builds them via the prepublishOnly hook.`);
99
+ }
100
+
68
101
  let authDirectory;
69
102
  try {
70
103
  let env = { ...process.env };
@@ -83,7 +116,10 @@ async function main() {
83
116
 
84
117
  if (patch) await runNpm(['version', 'patch', '--no-git-tag-version'], env);
85
118
  const packageJson = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
86
- const publishArgs = ['publish', '--access', 'public', ...(dryRun ? ['--dry-run'] : [])];
119
+ // --dry-run and --skip-build bypass lifecycle scripts so neither waits
120
+ // through the prepublishOnly build; a real publish always runs it.
121
+ const bypassScripts = dryRun || args.has('--skip-build');
122
+ const publishArgs = ['publish', '--access', 'public', ...(bypassScripts ? ['--ignore-scripts'] : []), ...(dryRun ? ['--dry-run'] : [])];
87
123
  console.error(`${dryRun ? 'Dry-running' : 'Publishing'} ${packageJson.name}@${packageJson.version}${dryRun ? '' : ' to npm'}...`);
88
124
  await runNpm(publishArgs, env);
89
125
  } finally {
@@ -91,7 +127,9 @@ async function main() {
91
127
  }
92
128
  }
93
129
 
94
- main().catch(error => {
95
- console.error(`publish:npm: ${error.message}`);
96
- process.exitCode = 1;
97
- });
130
+ if (process.argv[1] && realpathSync(fileURLToPath(import.meta.url)) === realpathSync(resolve(process.argv[1]))) {
131
+ main().catch(error => {
132
+ console.error(`publish:npm: ${error.message}`);
133
+ process.exitCode = 1;
134
+ });
135
+ }
package/src/binary.mjs CHANGED
@@ -15,7 +15,7 @@ const platformMap = {
15
15
  'linux:arm64': ['linux', 'arm64', ''],
16
16
  'darwin:x64': ['darwin', 'x64', ''],
17
17
  'darwin:arm64': ['darwin', 'arm64', ''],
18
- 'win32:x64': ['windows', 'x64', '.exe']
18
+ 'win32:x64': ['win32', 'x64', '.exe']
19
19
  };
20
20
 
21
21
  export function binaryTarget(platform = process.platform, arch = process.arch) {
@@ -24,6 +24,12 @@ export function binaryTarget(platform = process.platform, arch = process.arch) {
24
24
  return { os: target[0], arch: target[1], extension: target[2], asset: `vsp-${target[0]}-${target[1]}${target[2]}` };
25
25
  }
26
26
 
27
+ // Every VSP asset the npm tarball must bundle; publish:npm refuses to ship a
28
+ // package whose dist/checksums.txt does not list all of them.
29
+ export function packagedBinaryAssets() {
30
+ return Object.keys(platformMap).map(key => binaryTarget(...key.split(':')).asset);
31
+ }
32
+
27
33
  export function bundledBinaryPath(platform = process.platform, arch = process.arch) {
28
34
  return join(packageRoot, 'dist', binaryTarget(platform, arch).asset);
29
35
  }