mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
fix(install): build gsd-sdk from in-repo sdk/ source, not stale npm package
PR #2386 v1 installed the published @gsd-build/sdk from npm, which ships an older version that lacks query handlers needed by current workflows. Every GSD release would drift further from what the installer put on PATH. This commit rewires installSdkIfNeeded() to build from the in-repo sdk/ source tree instead: 1. cd sdk && npm install (build-time deps incl. tsc) 2. npm run build (tsc → sdk/dist/) 3. npm install -g . (global install; gsd-sdk on PATH) Each step is a hard gate — failures warn loudly and point users at the manual equivalent command. No more silent drift between installed SDK and the rest of the GSD system. Root package.json `files` now ships sdk/src, sdk/prompts, sdk/package.json, sdk/package-lock.json, and sdk/tsconfig.json so npm-registry installs also carry the source tree needed to build gsd-sdk locally. Also fixes a blocking tsc error in sdk/src/event-stream.ts:313 — the cast to `Array<{ type: string; [key: string]: unknown }>` needed a double-cast via `unknown` because BetaContentBlock's variants don't carry an index signature. Runtime-neutral type-widening; sdk vitest suite unchanged (1256 passing; the lone failure is a pre-existing integration test that requires external API access). Updates the #1657/#2385 regression test to assert the new build-from-source path (path.resolve(__dirname, '..', 'sdk') + `npm run build` + `npm install -g .`) plus a new assertion that root package.json files array ships sdk source. Refs #2385 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6634,8 +6634,13 @@ function promptLocation(runtimes) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure `@gsd-build/sdk` (the `gsd-sdk` binary) is installed globally so
|
||||
* workflow commands that shell out to `gsd-sdk query …` succeed.
|
||||
* Build `@gsd-build/sdk` from the in-repo `sdk/` source tree and install the
|
||||
* resulting `gsd-sdk` binary globally so workflow commands that shell out to
|
||||
* `gsd-sdk query …` succeed.
|
||||
*
|
||||
* We build from source rather than `npm install -g @gsd-build/sdk` because the
|
||||
* npm-published package lags the source tree and shipping a stale SDK breaks
|
||||
* every /gsd-* command that depends on newer query handlers.
|
||||
*
|
||||
* Skip if --no-sdk. Skip if already on PATH (unless --sdk was explicit).
|
||||
* Failures are warnings, not fatal.
|
||||
@@ -6647,6 +6652,8 @@ function installSdkIfNeeded() {
|
||||
}
|
||||
|
||||
const { spawnSync } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
if (!hasSdk) {
|
||||
const probe = spawnSync(process.platform === 'win32' ? 'where' : 'which', ['gsd-sdk'], { stdio: 'ignore' });
|
||||
@@ -6656,19 +6663,48 @@ function installSdkIfNeeded() {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n ${cyan}Installing GSD SDK (@gsd-build/sdk)…${reset}`);
|
||||
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const result = spawnSync(npmCmd, ['install', '-g', '@gsd-build/sdk'], { stdio: 'inherit' });
|
||||
// Locate the in-repo sdk/ directory relative to this installer file.
|
||||
// For global npm installs this resolves inside the published package dir;
|
||||
// for git-based installs (npx github:..., local clone) it resolves to the
|
||||
// repo's sdk/ tree. Both contain the source tree because root package.json
|
||||
// includes "sdk" in its `files` array.
|
||||
const sdkDir = path.resolve(__dirname, '..', 'sdk');
|
||||
const sdkPackageJson = path.join(sdkDir, 'package.json');
|
||||
|
||||
const warnManual = (reason) => {
|
||||
console.warn(` ${yellow}⚠${reset} ${reason}`);
|
||||
console.warn(` Run manually: ${cyan}npm install -g @gsd-build/sdk${reset}`);
|
||||
console.warn(` Build manually from the repo sdk/ directory:`);
|
||||
console.warn(` ${cyan}cd ${sdkDir} && npm install && npm run build && npm install -g .${reset}`);
|
||||
console.warn(` Then restart your shell so the updated PATH is picked up.`);
|
||||
console.warn(` Without it, /gsd-* commands will fail with "command not found: gsd-sdk".`);
|
||||
};
|
||||
|
||||
if (result.status !== 0) {
|
||||
warnManual('Failed to install @gsd-build/sdk automatically.');
|
||||
if (!fs.existsSync(sdkPackageJson)) {
|
||||
warnManual(`SDK source tree not found at ${sdkDir}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\n ${cyan}Building GSD SDK from source (${sdkDir})…${reset}`);
|
||||
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
|
||||
// 1. Install sdk build-time dependencies (tsc, etc.)
|
||||
const installResult = spawnSync(npmCmd, ['install'], { cwd: sdkDir, stdio: 'inherit' });
|
||||
if (installResult.status !== 0) {
|
||||
warnManual('Failed to `npm install` in sdk/.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Compile TypeScript → sdk/dist/
|
||||
const buildResult = spawnSync(npmCmd, ['run', 'build'], { cwd: sdkDir, stdio: 'inherit' });
|
||||
if (buildResult.status !== 0) {
|
||||
warnManual('Failed to `npm run build` in sdk/.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Install the built package globally so `gsd-sdk` lands on PATH.
|
||||
const globalResult = spawnSync(npmCmd, ['install', '-g', '.'], { cwd: sdkDir, stdio: 'inherit' });
|
||||
if (globalResult.status !== 0) {
|
||||
warnManual('Failed to `npm install -g .` from sdk/.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6679,9 +6715,9 @@ function installSdkIfNeeded() {
|
||||
const resolverCmd = process.platform === 'win32' ? 'where' : 'which';
|
||||
const verify = spawnSync(resolverCmd, ['gsd-sdk'], { encoding: 'utf-8' });
|
||||
if (verify.status === 0 && verify.stdout && verify.stdout.trim()) {
|
||||
console.log(` ${green}✓${reset} Installed @gsd-build/sdk (gsd-sdk resolved at ${verify.stdout.trim().split('\n')[0]})`);
|
||||
console.log(` ${green}✓${reset} Built and installed GSD SDK from source (gsd-sdk resolved at ${verify.stdout.trim().split('\n')[0]})`);
|
||||
} else {
|
||||
warnManual('Installed @gsd-build/sdk but gsd-sdk is not on PATH — npm global bin may not be in your PATH.');
|
||||
warnManual('Built and installed GSD SDK from source but gsd-sdk is not on PATH — npm global bin may not be in your PATH.');
|
||||
if (verify.stderr) console.warn(` resolver stderr: ${verify.stderr.trim()}`);
|
||||
}
|
||||
}
|
||||
@@ -6701,9 +6737,12 @@ function installAllRuntimes(runtimes, isGlobal, isInteractive) {
|
||||
const primaryStatuslineResult = results.find(r => statuslineRuntimes.includes(r.runtime));
|
||||
|
||||
const finalize = (shouldInstallStatusline) => {
|
||||
// Install @gsd-build/sdk so `gsd-sdk` lands on PATH.
|
||||
// Every /gsd-* command shells out to `gsd-sdk query …`; without this,
|
||||
// commands fail with "command not found: gsd-sdk".
|
||||
// Build @gsd-build/sdk from the in-repo sdk/ source and install it globally
|
||||
// so `gsd-sdk` lands on PATH. Every /gsd-* command shells out to
|
||||
// `gsd-sdk query …`; without this, commands fail with "command not found:
|
||||
// gsd-sdk". The npm-published @gsd-build/sdk is kept intentionally frozen
|
||||
// at an older version; we always build from source so users get the SDK
|
||||
// that matches the installed GSD version.
|
||||
// Runs by default; skip with --no-sdk. Idempotent when already present.
|
||||
installSdkIfNeeded();
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@
|
||||
"get-shit-done",
|
||||
"agents",
|
||||
"hooks",
|
||||
"scripts"
|
||||
"scripts",
|
||||
"sdk/src",
|
||||
"sdk/prompts",
|
||||
"sdk/package.json",
|
||||
"sdk/package-lock.json",
|
||||
"sdk/tsconfig.json"
|
||||
],
|
||||
"keywords": [
|
||||
"claude",
|
||||
|
||||
1
sdk/package-lock.json
generated
1
sdk/package-lock.json
generated
@@ -7,6 +7,7 @@
|
||||
"": {
|
||||
"name": "@gsd-build/sdk",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.2.84",
|
||||
"ws": "^8.20.0"
|
||||
|
||||
@@ -309,8 +309,10 @@ export class GSDEventStream extends EventEmitter {
|
||||
): GSDEvent | null {
|
||||
const events: GSDEvent[] = [];
|
||||
|
||||
// Extract text blocks — content blocks are a discriminated union with a 'type' field
|
||||
const content = msg.message.content as Array<{ type: string; [key: string]: unknown }>;
|
||||
// Extract text blocks — content blocks are a discriminated union with a 'type' field.
|
||||
// Double-cast via unknown because BetaContentBlock's internal variants don't
|
||||
// carry an index signature, so TS rejects the direct cast without a widening step.
|
||||
const content = msg.message.content as unknown as Array<{ type: string; [key: string]: unknown }>;
|
||||
|
||||
const textBlocks = content.filter(
|
||||
(b): b is { type: 'text'; text: string } => b.type === 'text',
|
||||
|
||||
@@ -80,11 +80,35 @@ describe('#1657 / #2385: SDK install must be wired into installer source', () =>
|
||||
);
|
||||
});
|
||||
|
||||
test('install.js installs @gsd-build/sdk by default (#2385)', () => {
|
||||
test('install.js builds gsd-sdk from in-repo sdk/ source (#2385)', () => {
|
||||
src = src || fs.readFileSync(INSTALL_SRC, 'utf-8');
|
||||
// The installer must locate the in-repo sdk/ directory, run the build,
|
||||
// and install it globally. We intentionally do NOT install
|
||||
// @gsd-build/sdk from npm because that published version lags the source
|
||||
// tree and shipping it breaks query handlers added since the last
|
||||
// publish.
|
||||
assert.ok(
|
||||
src.includes('@gsd-build/sdk'),
|
||||
'installer must reference @gsd-build/sdk so gsd-sdk lands on PATH'
|
||||
src.includes("path.resolve(__dirname, '..', 'sdk')") ||
|
||||
src.includes('path.resolve(__dirname, "..", "sdk")'),
|
||||
'installer must locate the in-repo sdk/ directory'
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("'npm install -g .'") ||
|
||||
src.includes("['install', '-g', '.']"),
|
||||
'installer must run `npm install -g .` from sdk/ to install the built package globally'
|
||||
);
|
||||
assert.ok(
|
||||
src.includes("['run', 'build']"),
|
||||
'installer must compile TypeScript via `npm run build` before installing globally'
|
||||
);
|
||||
});
|
||||
|
||||
test('package.json ships sdk source in published tarball (#2385)', () => {
|
||||
const rootPkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
||||
const files = rootPkg.files || [];
|
||||
assert.ok(
|
||||
files.some((f) => f === 'sdk' || f.startsWith('sdk/')),
|
||||
'root package.json `files` must include sdk source so npm-registry installs can build gsd-sdk from source'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user