mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-22 10:14:22 +01:00
chore: generate sdk into packages/sdk
This commit is contained in:
18
packages/sdk/scripts/bootstrap
Executable file
18
packages/sdk/scripts/bootstrap
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then
|
||||
brew bundle check >/dev/null 2>&1 || {
|
||||
echo "==> Installing Homebrew dependencies…"
|
||||
brew bundle
|
||||
}
|
||||
fi
|
||||
|
||||
echo "==> Installing Node dependencies…"
|
||||
|
||||
PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm")
|
||||
|
||||
$PACKAGE_MANAGER install
|
||||
51
packages/sdk/scripts/build
Executable file
51
packages/sdk/scripts/build
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -exuo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
node scripts/utils/check-version.cjs
|
||||
|
||||
# Build into dist and will publish the package from there,
|
||||
# so that src/resources/foo.ts becomes <package root>/resources/foo.js
|
||||
# This way importing from `"@opencode-ai/sdk/resources/foo"` works
|
||||
# even with `"moduleResolution": "node"`
|
||||
|
||||
rm -rf dist; mkdir dist
|
||||
# Copy src to dist/src and build from dist/src into dist, so that
|
||||
# the source map for index.js.map will refer to ./src/index.ts etc
|
||||
cp -rp src README.md dist
|
||||
for file in LICENSE CHANGELOG.md; do
|
||||
if [ -e "${file}" ]; then cp "${file}" dist; fi
|
||||
done
|
||||
if [ -e "bin/cli" ]; then
|
||||
mkdir -p dist/bin
|
||||
cp -p "bin/cli" dist/bin/;
|
||||
fi
|
||||
if [ -e "bin/migration-config.json" ]; then
|
||||
mkdir -p dist/bin
|
||||
cp -p "bin/migration-config.json" dist/bin/;
|
||||
fi
|
||||
# this converts the export map paths for the dist directory
|
||||
# and does a few other minor things
|
||||
node scripts/utils/make-dist-package-json.cjs > dist/package.json
|
||||
|
||||
# build to .js/.mjs/.d.ts files
|
||||
./node_modules/.bin/tsc-multi
|
||||
# we need to patch index.js so that `new module.exports()` works for cjs backwards
|
||||
# compat. No way to get that from index.ts because it would cause compile errors
|
||||
# when building .mjs
|
||||
node scripts/utils/fix-index-exports.cjs
|
||||
cp tsconfig.dist-src.json dist/src/tsconfig.json
|
||||
|
||||
node scripts/utils/postprocess-files.cjs
|
||||
|
||||
# make sure that nothing crashes when we require the output CJS or
|
||||
# import the output ESM
|
||||
(cd dist && node -e 'require("@opencode-ai/sdk")')
|
||||
(cd dist && node -e 'import("@opencode-ai/sdk")' --input-type=module)
|
||||
|
||||
if [ -e ./scripts/build-deno ]
|
||||
then
|
||||
./scripts/build-deno
|
||||
fi
|
||||
12
packages/sdk/scripts/format
Executable file
12
packages/sdk/scripts/format
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
echo "==> Running eslint --fix"
|
||||
./node_modules/.bin/eslint --fix .
|
||||
|
||||
echo "==> Running prettier --write"
|
||||
# format things eslint didn't
|
||||
./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs'
|
||||
21
packages/sdk/scripts/lint
Executable file
21
packages/sdk/scripts/lint
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
echo "==> Running eslint"
|
||||
./node_modules/.bin/eslint .
|
||||
|
||||
echo "==> Building"
|
||||
./scripts/build
|
||||
|
||||
echo "==> Checking types"
|
||||
./node_modules/typescript/bin/tsc
|
||||
|
||||
echo "==> Running Are The Types Wrong?"
|
||||
./node_modules/.bin/attw --pack dist -f json >.attw.json || true
|
||||
node scripts/utils/attw-report.cjs
|
||||
|
||||
echo "==> Running publint"
|
||||
./node_modules/.bin/publint dist
|
||||
41
packages/sdk/scripts/mock
Executable file
41
packages/sdk/scripts/mock
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if [[ -n "$1" && "$1" != '--'* ]]; then
|
||||
URL="$1"
|
||||
shift
|
||||
else
|
||||
URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)"
|
||||
fi
|
||||
|
||||
# Check if the URL is empty
|
||||
if [ -z "$URL" ]; then
|
||||
echo "Error: No OpenAPI spec path/url provided or found in .stats.yml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Starting mock server with URL ${URL}"
|
||||
|
||||
# Run prism mock on the given spec
|
||||
if [ "$1" == "--daemon" ]; then
|
||||
npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log &
|
||||
|
||||
# Wait for server to come online
|
||||
echo -n "Waiting for server"
|
||||
while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do
|
||||
echo -n "."
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if grep -q "✖ fatal" ".prism.log"; then
|
||||
cat .prism.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
else
|
||||
npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL"
|
||||
fi
|
||||
56
packages/sdk/scripts/test
Executable file
56
packages/sdk/scripts/test
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
function prism_is_running() {
|
||||
curl --silent "http://localhost:4010" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
kill_server_on_port() {
|
||||
pids=$(lsof -t -i tcp:"$1" || echo "")
|
||||
if [ "$pids" != "" ]; then
|
||||
kill "$pids"
|
||||
echo "Stopped $pids."
|
||||
fi
|
||||
}
|
||||
|
||||
function is_overriding_api_base_url() {
|
||||
[ -n "$TEST_API_BASE_URL" ]
|
||||
}
|
||||
|
||||
if ! is_overriding_api_base_url && ! prism_is_running ; then
|
||||
# When we exit this script, make sure to kill the background mock server process
|
||||
trap 'kill_server_on_port 4010' EXIT
|
||||
|
||||
# Start the dev server
|
||||
./scripts/mock --daemon
|
||||
fi
|
||||
|
||||
if is_overriding_api_base_url ; then
|
||||
echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}"
|
||||
echo
|
||||
elif ! prism_is_running ; then
|
||||
echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server"
|
||||
echo -e "running against your OpenAPI spec."
|
||||
echo
|
||||
echo -e "To run the server, pass in the path or url of your OpenAPI"
|
||||
echo -e "spec to the prism command:"
|
||||
echo
|
||||
echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}"
|
||||
echo
|
||||
|
||||
exit 1
|
||||
else
|
||||
echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}"
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "==> Running tests"
|
||||
./node_modules/.bin/jest "$@"
|
||||
24
packages/sdk/scripts/utils/attw-report.cjs
Normal file
24
packages/sdk/scripts/utils/attw-report.cjs
Normal file
@@ -0,0 +1,24 @@
|
||||
const fs = require('fs');
|
||||
const problems = Object.values(JSON.parse(fs.readFileSync('.attw.json', 'utf-8')).problems)
|
||||
.flat()
|
||||
.filter(
|
||||
(problem) =>
|
||||
!(
|
||||
// This is intentional, if the user specifies .mjs they get ESM.
|
||||
(
|
||||
(problem.kind === 'CJSResolvesToESM' && problem.entrypoint.endsWith('.mjs')) ||
|
||||
// This is intentional for backwards compat reasons.
|
||||
(problem.kind === 'MissingExportEquals' && problem.implementationFileName.endsWith('/index.js')) ||
|
||||
// this is intentional, we deliberately attempt to import types that may not exist from parent node_modules
|
||||
// folders to better support various runtimes without triggering automatic type acquisition.
|
||||
(problem.kind === 'InternalResolutionError' && problem.moduleSpecifier.includes('node_modules'))
|
||||
)
|
||||
),
|
||||
);
|
||||
fs.unlinkSync('.attw.json');
|
||||
if (problems.length) {
|
||||
process.stdout.write('The types are wrong!\n' + JSON.stringify(problems, null, 2) + '\n');
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
process.stdout.write('Types ok!\n');
|
||||
}
|
||||
9
packages/sdk/scripts/utils/check-is-in-git-install.sh
Executable file
9
packages/sdk/scripts/utils/check-is-in-git-install.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Check if you happen to call prepare for a repository that's already in node_modules.
|
||||
[ "$(basename "$(dirname "$PWD")")" = 'node_modules' ] ||
|
||||
# The name of the containing directory that 'npm` uses, which looks like
|
||||
# $HOME/.npm/_cacache/git-cloneXXXXXX
|
||||
[ "$(basename "$(dirname "$PWD")")" = 'tmp' ] ||
|
||||
# The name of the containing directory that 'yarn` uses, which looks like
|
||||
# $(yarn cache dir)/.tmp/XXXXX
|
||||
[ "$(basename "$(dirname "$PWD")")" = '.tmp' ]
|
||||
20
packages/sdk/scripts/utils/check-version.cjs
Normal file
20
packages/sdk/scripts/utils/check-version.cjs
Normal file
@@ -0,0 +1,20 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const main = () => {
|
||||
const pkg = require('../../package.json');
|
||||
const version = pkg['version'];
|
||||
if (!version) throw 'The version property is not set in the package.json file';
|
||||
if (typeof version !== 'string') {
|
||||
throw `Unexpected type for the package.json version field; got ${typeof version}, expected string`;
|
||||
}
|
||||
|
||||
const versionFile = path.resolve(__dirname, '..', '..', 'src', 'version.ts');
|
||||
const contents = fs.readFileSync(versionFile, 'utf8');
|
||||
const output = contents.replace(/(export const VERSION = ')(.*)(')/g, `$1${version}$3`);
|
||||
fs.writeFileSync(versionFile, output);
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
17
packages/sdk/scripts/utils/fix-index-exports.cjs
Normal file
17
packages/sdk/scripts/utils/fix-index-exports.cjs
Normal file
@@ -0,0 +1,17 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const indexJs =
|
||||
process.env['DIST_PATH'] ?
|
||||
path.resolve(process.env['DIST_PATH'], 'index.js')
|
||||
: path.resolve(__dirname, '..', '..', 'dist', 'index.js');
|
||||
|
||||
let before = fs.readFileSync(indexJs, 'utf8');
|
||||
let after = before.replace(
|
||||
/^(\s*Object\.defineProperty\s*\(exports,\s*["']__esModule["'].+)$/m,
|
||||
`exports = module.exports = function (...args) {
|
||||
return new exports.default(...args)
|
||||
}
|
||||
$1`.replace(/^ /gm, ''),
|
||||
);
|
||||
fs.writeFileSync(indexJs, after, 'utf8');
|
||||
13
packages/sdk/scripts/utils/git-swap.sh
Executable file
13
packages/sdk/scripts/utils/git-swap.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -exuo pipefail
|
||||
# the package is published to NPM from ./dist
|
||||
# we want the final file structure for git installs to match the npm installs, so we
|
||||
|
||||
# delete everything except ./dist and ./node_modules
|
||||
find . -maxdepth 1 -mindepth 1 ! -name 'dist' ! -name 'node_modules' -exec rm -rf '{}' +
|
||||
|
||||
# move everything from ./dist to .
|
||||
mv dist/* .
|
||||
|
||||
# delete the now-empty ./dist
|
||||
rmdir dist
|
||||
21
packages/sdk/scripts/utils/make-dist-package-json.cjs
Normal file
21
packages/sdk/scripts/utils/make-dist-package-json.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
const pkgJson = require(process.env['PKG_JSON_PATH'] || '../../package.json');
|
||||
|
||||
function processExportMap(m) {
|
||||
for (const key in m) {
|
||||
const value = m[key];
|
||||
if (typeof value === 'string') m[key] = value.replace(/^\.\/dist\//, './');
|
||||
else processExportMap(value);
|
||||
}
|
||||
}
|
||||
processExportMap(pkgJson.exports);
|
||||
|
||||
for (const key of ['types', 'main', 'module']) {
|
||||
if (typeof pkgJson[key] === 'string') pkgJson[key] = pkgJson[key].replace(/^(\.\/)?dist\//, './');
|
||||
}
|
||||
|
||||
delete pkgJson.devDependencies;
|
||||
delete pkgJson.scripts.prepack;
|
||||
delete pkgJson.scripts.prepublishOnly;
|
||||
delete pkgJson.scripts.prepare;
|
||||
|
||||
console.log(JSON.stringify(pkgJson, null, 2));
|
||||
94
packages/sdk/scripts/utils/postprocess-files.cjs
Normal file
94
packages/sdk/scripts/utils/postprocess-files.cjs
Normal file
@@ -0,0 +1,94 @@
|
||||
// @ts-check
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const distDir =
|
||||
process.env['DIST_PATH'] ?
|
||||
path.resolve(process.env['DIST_PATH'])
|
||||
: path.resolve(__dirname, '..', '..', 'dist');
|
||||
|
||||
async function* walk(dir) {
|
||||
for await (const d of await fs.promises.opendir(dir)) {
|
||||
const entry = path.join(dir, d.name);
|
||||
if (d.isDirectory()) yield* walk(entry);
|
||||
else if (d.isFile()) yield entry;
|
||||
}
|
||||
}
|
||||
|
||||
async function postprocess() {
|
||||
for await (const file of walk(distDir)) {
|
||||
if (!/(\.d)?[cm]?ts$/.test(file)) continue;
|
||||
|
||||
const code = await fs.promises.readFile(file, 'utf8');
|
||||
|
||||
// strip out lib="dom", types="node", and types="react" references; these
|
||||
// are needed at build time, but would pollute the user's TS environment
|
||||
const transformed = code.replace(
|
||||
/^ *\/\/\/ *<reference +(lib="dom"|types="(node|react)").*?\n/gm,
|
||||
// replace with same number of characters to avoid breaking source maps
|
||||
(match) => ' '.repeat(match.length - 1) + '\n',
|
||||
);
|
||||
|
||||
if (transformed !== code) {
|
||||
console.error(`wrote ${path.relative(process.cwd(), file)}`);
|
||||
await fs.promises.writeFile(file, transformed, 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
const newExports = {
|
||||
'.': {
|
||||
require: {
|
||||
types: './index.d.ts',
|
||||
default: './index.js',
|
||||
},
|
||||
types: './index.d.mts',
|
||||
default: './index.mjs',
|
||||
},
|
||||
};
|
||||
|
||||
for (const entry of await fs.promises.readdir(distDir, { withFileTypes: true })) {
|
||||
if (entry.isDirectory() && entry.name !== 'src' && entry.name !== 'internal' && entry.name !== 'bin') {
|
||||
const subpath = './' + entry.name;
|
||||
newExports[subpath + '/*.mjs'] = {
|
||||
default: subpath + '/*.mjs',
|
||||
};
|
||||
newExports[subpath + '/*.js'] = {
|
||||
default: subpath + '/*.js',
|
||||
};
|
||||
newExports[subpath + '/*'] = {
|
||||
import: subpath + '/*.mjs',
|
||||
require: subpath + '/*.js',
|
||||
};
|
||||
} else if (entry.isFile() && /\.[cm]?js$/.test(entry.name)) {
|
||||
const { name, ext } = path.parse(entry.name);
|
||||
const subpathWithoutExt = './' + name;
|
||||
const subpath = './' + entry.name;
|
||||
newExports[subpathWithoutExt] ||= { import: undefined, require: undefined };
|
||||
const isModule = ext[1] === 'm';
|
||||
if (isModule) {
|
||||
newExports[subpathWithoutExt].import = subpath;
|
||||
} else {
|
||||
newExports[subpathWithoutExt].require = subpath;
|
||||
}
|
||||
newExports[subpath] = {
|
||||
default: subpath,
|
||||
};
|
||||
}
|
||||
}
|
||||
await fs.promises.writeFile(
|
||||
'dist/package.json',
|
||||
JSON.stringify(
|
||||
Object.assign(
|
||||
/** @type {Record<String, unknown>} */ (
|
||||
JSON.parse(await fs.promises.readFile('dist/package.json', 'utf-8'))
|
||||
),
|
||||
{
|
||||
exports: newExports,
|
||||
},
|
||||
),
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
}
|
||||
postprocess();
|
||||
25
packages/sdk/scripts/utils/upload-artifact.sh
Executable file
25
packages/sdk/scripts/utils/upload-artifact.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -exuo pipefail
|
||||
|
||||
RESPONSE=$(curl -X POST "$URL" \
|
||||
-H "Authorization: Bearer $AUTH" \
|
||||
-H "Content-Type: application/json")
|
||||
|
||||
SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url')
|
||||
|
||||
if [[ "$SIGNED_URL" == "null" ]]; then
|
||||
echo -e "\033[31mFailed to get signed URL.\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \
|
||||
-H "Content-Type: application/gzip" \
|
||||
--data-binary @- "$SIGNED_URL" 2>&1)
|
||||
|
||||
if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then
|
||||
echo -e "\033[32mUploaded build to Stainless storage.\033[0m"
|
||||
echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/opencode-typescript/$SHA'\033[0m"
|
||||
else
|
||||
echo -e "\033[31mFailed to upload artifact.\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user