diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/build.js | 54 | ||||
| -rwxr-xr-x | scripts/build.sh | 30 | ||||
| -rw-r--r-- | scripts/build_package.js | 37 | ||||
| -rwxr-xr-x | scripts/build_package.sh | 33 | ||||
| -rw-r--r-- | scripts/build_sandbox.js | 125 | ||||
| -rwxr-xr-x | scripts/build_sandbox.sh | 102 | ||||
| -rw-r--r-- | scripts/clean.js | 32 | ||||
| -rwxr-xr-x | scripts/clean.sh | 21 | ||||
| -rw-r--r-- | scripts/copy_bundle_assets.js | 48 | ||||
| -rwxr-xr-x | scripts/copy_bundle_assets.sh | 13 | ||||
| -rw-r--r-- | scripts/generate-git-commit-info.js | 61 | ||||
| -rwxr-xr-x | scripts/generate-git-commit-info.sh | 44 | ||||
| -rw-r--r-- | scripts/publish-sandbox.js | 55 | ||||
| -rwxr-xr-x | scripts/publish-sandbox.sh | 41 | ||||
| -rw-r--r-- | scripts/sandbox.js | 123 | ||||
| -rwxr-xr-x | scripts/sandbox.sh | 103 | ||||
| -rw-r--r-- | scripts/sandbox_command.js | 126 | ||||
| -rwxr-xr-x | scripts/sandbox_command.sh | 122 | ||||
| -rw-r--r-- | scripts/setup-dev.js | 42 | ||||
| -rwxr-xr-x | scripts/setup-dev.sh | 34 | ||||
| -rw-r--r-- | scripts/start.js | 61 | ||||
| -rwxr-xr-x | scripts/start.sh | 37 |
22 files changed, 764 insertions, 580 deletions
diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 00000000..373e268e --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; +import { existsSync } from 'fs'; +import { join } from 'path'; + +const root = join(import.meta.dirname, '..'); + +// npm install if node_modules was removed (e.g. via npm run clean or scripts/clean.js) +if (!existsSync(join(root, 'node_modules'))) { + execSync('npm install', { stdio: 'inherit', cwd: root }); +} + +// build all workspaces/packages +execSync('npm run generate', { stdio: 'inherit', cwd: root }); +execSync('npm run build --workspaces', { stdio: 'inherit', cwd: root }); + +// also build container image if sandboxing is enabled +// skip (-s) npm install + build since we did that above +try { + execSync('node scripts/sandbox_command.js -q', { + stdio: 'inherit', + cwd: root, + }); + if ( + process.env.BUILD_SANDBOX === '1' || + process.env.BUILD_SANDBOX === 'true' + ) { + execSync('node scripts/build_sandbox.js -s', { + stdio: 'inherit', + cwd: root, + }); + } +} catch { + // ignore +} diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100755 index 0eba264f..00000000 --- a/scripts/build.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -# npm install if node_modules was removed (e.g. via npm run clean or scripts/clean.sh) -if [ ! -d "node_modules" ]; then - npm install -fi - -# build all workspaces/packages -npm run build --workspaces - -# also build container image if sandboxing is enabled -# skip (-s) npm install + build since we did that above -if scripts/sandbox_command.sh -q && [[ "${BUILD_SANDBOX:-}" =~ ^(1|true)$ ]]; then - scripts/build_sandbox.sh -s -fi diff --git a/scripts/build_package.js b/scripts/build_package.js new file mode 100644 index 00000000..9e1b05bf --- /dev/null +++ b/scripts/build_package.js @@ -0,0 +1,37 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; +import { writeFileSync } from 'fs'; +import { join } from 'path'; + +if (!process.cwd().includes('packages')) { + console.error('must be invoked from a package directory'); + process.exit(1); +} + +// build typescript files +execSync('tsc --build', { stdio: 'inherit' }); + +// copy .{md,json} files +execSync('node ../../scripts/copy_files.js', { stdio: 'inherit' }); + +// touch dist/.last_build +writeFileSync(join(process.cwd(), 'dist', '.last_build'), ''); +process.exit(0); diff --git a/scripts/build_package.sh b/scripts/build_package.sh deleted file mode 100755 index e64d98cc..00000000 --- a/scripts/build_package.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -if [[ $(pwd) != *"/packages/"* ]]; then - echo "must be invoked from a package directory" - exit 1 -fi - -# clean dist directory -# rm -rf dist/* - -# build typescript files -tsc --build - -# copy .{md,json} files -node ../../scripts/copy_files.js - -# touch dist/.last_build -touch dist/.last_build diff --git a/scripts/build_sandbox.js b/scripts/build_sandbox.js new file mode 100644 index 00000000..bfcf1bf9 --- /dev/null +++ b/scripts/build_sandbox.js @@ -0,0 +1,125 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; +import { chmodSync, readFileSync, rmSync } from 'fs'; +import { join } from 'path'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; + +const argv = yargs(hideBin(process.argv)) + .option('s', { + alias: 'skip-npm-install-build', + type: 'boolean', + default: false, + description: 'skip npm install + npm run build', + }) + .option('f', { + alias: 'dockerfile', + type: 'string', + description: 'use <dockerfile> for custom image', + }) + .option('i', { + alias: 'image', + type: 'string', + description: 'use <image> name for custom image', + }).argv; + +let sandboxCommand; +try { + sandboxCommand = execSync('node scripts/sandbox_command.js') + .toString() + .trim(); +} catch { + console.warn( + 'WARNING: container-based sandboxing is disabled (see README.md#sandboxing)', + ); + process.exit(0); +} + +if (sandboxCommand === 'sandbox-exec') { + console.warn( + 'WARNING: container-based sandboxing is disabled (see README.md#sandboxing)', + ); + process.exit(0); +} + +console.log(`using ${sandboxCommand} for sandboxing`); + +const baseImage = 'gemini-cli-sandbox'; +const customImage = argv.i; +const baseDockerfile = 'Dockerfile'; +const customDockerfile = argv.f; + +if (!argv.s) { + execSync('npm install', { stdio: 'inherit' }); + execSync('npm run build --workspaces', { stdio: 'inherit' }); +} + +console.log('packing @gemini-cli/cli ...'); +const cliPackageDir = join('packages', 'cli'); +rmSync(join(cliPackageDir, 'dist', 'gemini-cli-cli-*.tgz'), { force: true }); +execSync(`npm pack -w @gemini-cli/cli --pack-destination ./packages/cli/dist`, { + stdio: 'ignore', +}); + +console.log('packing @gemini-cli/core ...'); +const corePackageDir = join('packages', 'core'); +rmSync(join(corePackageDir, 'dist', 'gemini-cli-core-*.tgz'), { force: true }); +execSync( + `npm pack -w @gemini-cli/core --pack-destination ./packages/core/dist`, + { stdio: 'ignore' }, +); + +const packageVersion = JSON.parse( + readFileSync(join(process.cwd(), 'package.json'), 'utf-8'), +).version; + +chmodSync( + join(cliPackageDir, 'dist', `gemini-cli-cli-${packageVersion}.tgz`), + 0o755, +); +chmodSync( + join(corePackageDir, 'dist', `gemini-cli-core-${packageVersion}.tgz`), + 0o755, +); + +const buildStdout = process.env.VERBOSE ? 'inherit' : 'ignore'; + +function buildImage(imageName, dockerfile) { + console.log(`building ${imageName} ... (can be slow first time)`); + const buildCommand = + sandboxCommand === 'podman' + ? `${sandboxCommand} build --authfile=<(echo '{}')` + : `${sandboxCommand} --config=".docker" buildx build`; + + execSync( + `${buildCommand} ${process.env.BUILD_SANDBOX_FLAGS || ''} -f "${dockerfile}" -t "${imageName}" .`, + { stdio: buildStdout }, + ); + console.log(`built ${imageName}`); +} + +buildImage(baseImage, baseDockerfile); + +if (customDockerfile && customImage) { + buildImage(customImage, customDockerfile); +} + +execSync(`${sandboxCommand} image prune -f`, { stdio: 'ignore' }); diff --git a/scripts/build_sandbox.sh b/scripts/build_sandbox.sh deleted file mode 100755 index dabcffcf..00000000 --- a/scripts/build_sandbox.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -# exit with warning if container-based sandboxing is disabled -# note this includes the case where sandbox-exec (seatbelt) is used -# this happens most commonly when user runs `npm run build:all` without enabling sandboxing -if ! scripts/sandbox_command.sh -q || [ "$(scripts/sandbox_command.sh)" == "sandbox-exec" ]; then - echo "WARNING: container-based sandboxing is disabled (see CONTRIBUTING.md#enabling-sandboxing)" - exit 0 -fi - -CMD=$(scripts/sandbox_command.sh) -echo "using $CMD for sandboxing" - -BASE_IMAGE=gemini-cli-sandbox -CUSTOM_IMAGE='' -BASE_DOCKERFILE=Dockerfile -CUSTOM_DOCKERFILE='' - -SKIP_NPM_INSTALL_BUILD=false -while getopts "sf:i:" opt; do - case ${opt} in - s) SKIP_NPM_INSTALL_BUILD=true ;; - f) - CUSTOM_DOCKERFILE=$OPTARG - ;; - i) - CUSTOM_IMAGE=$OPTARG - ;; - \?) - echo "usage: $(basename "$0") [-s] [-f <dockerfile>]" - echo " -s: skip npm install + npm run build" - echo " -f <dockerfile>: use <dockerfile> for custom image" - echo " -i <image>: use <image> name for custom image" - exit 1 - ;; - esac -done -shift $((OPTIND - 1)) - -# npm install + npm run build unless skipping via -s option -if [ "$SKIP_NPM_INSTALL_BUILD" = false ]; then - npm install - npm run build --workspaces -fi - -# prepare global installation files for prod builds -# pack cli -echo "packing @gemini-cli/cli ..." -rm -f packages/cli/dist/gemini-cli-cli-*.tgz -npm pack -w @gemini-cli/cli --pack-destination ./packages/cli/dist &>/dev/null -# pack core -echo "packing @gemini-cli/core ..." -rm -f packages/core/dist/gemini-cli-core-*.tgz -npm pack -w @gemini-cli/core --pack-destination ./packages/core/dist &>/dev/null -# give node user (used during installation, see Dockerfile) access to these files -chmod 755 packages/*/dist/gemini-cli-*.tgz - -# redirect build output to /dev/null unless VERBOSE is set -BUILD_STDOUT="/dev/null" -if [ -n "${VERBOSE:-}" ]; then - BUILD_STDOUT="/dev/stdout" -fi - -build_image() { - if [[ "$CMD" == "podman" ]]; then - # use empty --authfile to skip unnecessary auth refresh overhead - $CMD build --authfile=<(echo '{}') "$@" >$BUILD_STDOUT - elif [[ "$CMD" == "docker" ]]; then - $CMD --config=".docker" buildx build "$@" >$BUILD_STDOUT - else - $CMD build "$@" >$BUILD_STDOUT - fi -} - -echo "building $BASE_IMAGE ... (can be slow first time)" -# shellcheck disable=SC2086 # allow globbing and word splitting for BUILD_SANDBOX_FLAGS -build_image ${BUILD_SANDBOX_FLAGS:-} -f "$BASE_DOCKERFILE" -t "$BASE_IMAGE" . -echo "built $BASE_IMAGE" - -if [[ -n "$CUSTOM_DOCKERFILE" && -n "$CUSTOM_IMAGE" ]]; then - echo "building $CUSTOM_IMAGE ... (can be slow first time)" - # shellcheck disable=SC2086 # allow globbing and word splitting for BUILD_SANDBOX_FLAGS - build_image ${BUILD_SANDBOX_FLAGS:-} -f "$CUSTOM_DOCKERFILE" -t "$CUSTOM_IMAGE" . - echo "built $CUSTOM_IMAGE" -fi - -$CMD image prune -f >/dev/null diff --git a/scripts/clean.js b/scripts/clean.js new file mode 100644 index 00000000..dd2911e9 --- /dev/null +++ b/scripts/clean.js @@ -0,0 +1,32 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; +import { rmSync } from 'fs'; +import { join } from 'path'; + +const root = join(import.meta.dirname, '..'); + +// remove npm install/build artifacts +rmSync(join(root, 'node_modules'), { recursive: true, force: true }); +rmSync(join(root, 'packages/cli/src/generated/'), { + recursive: true, + force: true, +}); +execSync('npm run clean --workspaces', { stdio: 'inherit', cwd: root }); diff --git a/scripts/clean.sh b/scripts/clean.sh deleted file mode 100755 index 2f6bc3c0..00000000 --- a/scripts/clean.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -# remove npm install/build artifacts -rm -rf node_modules -rm -rf packages/cli/src/generated/ -npm run clean --workspaces diff --git a/scripts/copy_bundle_assets.js b/scripts/copy_bundle_assets.js new file mode 100644 index 00000000..cb1ac197 --- /dev/null +++ b/scripts/copy_bundle_assets.js @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { copyFileSync, existsSync, mkdirSync } from 'fs'; +import { join, basename } from 'path'; +import { glob } from 'glob'; + +const root = join(import.meta.dirname, '..'); +const bundleDir = join(root, 'bundle'); + +// Create the bundle directory if it doesn't exist +if (!existsSync(bundleDir)) { + mkdirSync(bundleDir); +} + +// Copy specific shell files to the root of the bundle directory +copyFileSync( + join(root, 'packages/core/src/tools/shell.md'), + join(bundleDir, 'shell.md'), +); +copyFileSync( + join(root, 'packages/core/src/tools/shell.json'), + join(bundleDir, 'shell.json'), +); + +// Find and copy all .sb files from packages to the root of the bundle directory +const sbFiles = glob.sync('packages/**/*.sb', { cwd: root }); +for (const file of sbFiles) { + copyFileSync(join(root, file), join(bundleDir, basename(file))); +} + +console.log('Assets copied to bundle/'); diff --git a/scripts/copy_bundle_assets.sh b/scripts/copy_bundle_assets.sh deleted file mode 100755 index 93d46364..00000000 --- a/scripts/copy_bundle_assets.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Create the bundle directory if it doesn't exist -mkdir -p bundle - -# Copy specific shell files to the root of the bundle directory -cp "packages/core/src/tools/shell.md" "bundle/shell.md" -cp "packages/core/src/tools/shell.json" "bundle/shell.json" - -# Find and copy all .sb files from packages to the root of the bundle directory -find packages -name '*.sb' -exec cp -f {} bundle/ \; - -echo "Assets copied to bundle/"
\ No newline at end of file diff --git a/scripts/generate-git-commit-info.js b/scripts/generate-git-commit-info.js new file mode 100644 index 00000000..f046a7fb --- /dev/null +++ b/scripts/generate-git-commit-info.js @@ -0,0 +1,61 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; +import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import { join } from 'path'; + +const root = join(import.meta.dirname, '..'); +const generatedDir = join(root, 'packages/cli/src/generated'); +const gitCommitFile = join(generatedDir, 'git-commit.ts'); +let gitCommitInfo = 'N/A'; + +if (!existsSync(generatedDir)) { + mkdirSync(generatedDir, { recursive: true }); +} + +try { + const gitHash = execSync('git rev-parse --short HEAD', { + encoding: 'utf-8', + }).trim(); + if (gitHash) { + gitCommitInfo = gitHash; + const gitStatus = execSync('git status --porcelain', { + encoding: 'utf-8', + }).trim(); + if (gitStatus) { + gitCommitInfo = `${gitHash} (local modifications)`; + } + } +} catch { + // ignore +} + +const fileContent = `/** + * @license + * Copyright ${new Date().getFullYear()} Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// This file is auto-generated by the build script (scripts/build.js) +// Do not edit this file manually. +export const GIT_COMMIT_INFO = '${gitCommitInfo}'; +`; + +writeFileSync(gitCommitFile, fileContent); diff --git a/scripts/generate-git-commit-info.sh b/scripts/generate-git-commit-info.sh deleted file mode 100755 index 2a64830f..00000000 --- a/scripts/generate-git-commit-info.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -GENERATED_DIR="packages/cli/src/generated" -GIT_COMMIT_FILE="$GENERATED_DIR/git-commit.ts" -GIT_COMMIT_INFO="N/A" - -mkdir -p "$GENERATED_DIR" - -if command -v git &> /dev/null && git rev-parse --is-inside-work-tree &> /dev/null; then - GIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "") - if [ -n "$GIT_HASH" ]; then - GIT_COMMIT_INFO="$GIT_HASH" - if [ -n "$(git status --porcelain 2>/dev/null)" ]; then - GIT_COMMIT_INFO="$GIT_HASH (local modifications)" - fi - fi -fi - -cat <<EOL > "$GIT_COMMIT_FILE" -/** - * @license - * Copyright $(date +%Y) Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -// This file is auto-generated by the build script (scripts/build.sh) -// Do not edit this file manually. -export const GIT_COMMIT_INFO = '$GIT_COMMIT_INFO'; -EOL diff --git a/scripts/publish-sandbox.js b/scripts/publish-sandbox.js new file mode 100644 index 00000000..916089be --- /dev/null +++ b/scripts/publish-sandbox.js @@ -0,0 +1,55 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; + +const { + SANDBOX_IMAGE_REGISTRY, + SANDBOX_IMAGE_NAME, + npm_package_version, + DOCKER_DRY_RUN, +} = process.env; + +if (!SANDBOX_IMAGE_REGISTRY) { + console.error( + 'Error: SANDBOX_IMAGE_REGISTRY environment variable is not set.', + ); + process.exit(1); +} + +if (!SANDBOX_IMAGE_NAME) { + console.error('Error: SANDBOX_IMAGE_NAME environment variable is not set.'); + process.exit(1); +} + +if (!npm_package_version) { + console.error( + 'Error: npm_package_version environment variable is not set (should be run via npm).', + ); + process.exit(1); +} + +const imageUri = `${SANDBOX_IMAGE_REGISTRY}/${SANDBOX_IMAGE_NAME}:${npm_package_version}`; + +if (DOCKER_DRY_RUN) { + console.log(`DRY RUN: Would execute: docker push "${imageUri}"`); +} else { + console.log(`Executing: docker push "${imageUri}"`); + execSync(`docker push "${imageUri}"`, { stdio: 'inherit' }); +} diff --git a/scripts/publish-sandbox.sh b/scripts/publish-sandbox.sh deleted file mode 100755 index dfc16353..00000000 --- a/scripts/publish-sandbox.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -# Ensure required environment variables are set -if [ -z "${SANDBOX_IMAGE_REGISTRY}" ]; then - echo "Error: SANDBOX_IMAGE_REGISTRY environment variable is not set." >&2 - exit 1 -fi - -if [ -z "${SANDBOX_IMAGE_NAME}" ]; then - echo "Error: SANDBOX_IMAGE_NAME environment variable is not set." >&2 - exit 1 -fi - -if [ -z "${npm_package_version}" ]; then - echo "Error: npm_package_version environment variable is not set (should be run via npm)." >&2 - exit 1 -fi - -IMAGE_URI="${SANDBOX_IMAGE_REGISTRY}/${SANDBOX_IMAGE_NAME}:${npm_package_version}" - -if [ -n "${DOCKER_DRY_RUN:-}" ]; then - echo "DRY RUN: Would execute: docker push \"${IMAGE_URI}\"" -else - echo "Executing: docker push \"${IMAGE_URI}\"" - docker push "${IMAGE_URI}" -fi diff --git a/scripts/sandbox.js b/scripts/sandbox.js new file mode 100644 index 00000000..58223180 --- /dev/null +++ b/scripts/sandbox.js @@ -0,0 +1,123 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync, spawn } from 'child_process'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; + +try { + execSync('node scripts/sandbox_command.js -q'); +} catch { + console.error('ERROR: sandboxing disabled. See docs to enable sandboxing.'); + process.exit(1); +} + +const argv = yargs(hideBin(process.argv)).option('i', { + alias: 'interactive', + type: 'boolean', + default: false, +}).argv; + +if (argv.i && !process.stdin.isTTY) { + console.error( + 'ERROR: interactive mode (-i) requested without a terminal attached', + ); + process.exit(1); +} + +const image = 'gemini-cli-sandbox'; +const sandboxCommand = execSync('node scripts/sandbox_command.js') + .toString() + .trim(); + +const sandboxes = execSync( + `${sandboxCommand} ps --filter "ancestor=${image}" --format "{{.Names}}"`, +) + .toString() + .trim() + .split('\n') + .filter(Boolean); + +let sandboxName; +const firstArg = argv._[0]; + +if (firstArg) { + if (firstArg.startsWith(image) || /^\d+$/.test(firstArg)) { + sandboxName = firstArg.startsWith(image) + ? firstArg + : `${image}-${firstArg}`; + argv._.shift(); + } +} + +if (!sandboxName) { + if (sandboxes.length === 0) { + console.error( + 'No sandboxes found. Are you running gemini-cli with sandboxing enabled?', + ); + process.exit(1); + } + if (sandboxes.length > 1) { + console.error('Multiple sandboxes found:'); + sandboxes.forEach((s) => console.error(` ${s}`)); + console.error( + 'Sandbox name or index (0,1,...) must be specified as first argument', + ); + process.exit(1); + } + sandboxName = sandboxes[0]; +} + +if (!sandboxes.includes(sandboxName)) { + console.error(`unknown sandbox ${sandboxName}`); + console.error('known sandboxes:'); + sandboxes.forEach((s) => console.error(` ${s}`)); + process.exit(1); +} + +const execArgs = []; +let commandToRun = []; + +// Determine interactive flags. +// If a command is provided, only be interactive if -i is passed. +// If no command is provided, always be interactive. +if (argv._.length > 0) { + if (argv.i) { + execArgs.push('-it'); + } +} else { + execArgs.push('-it'); +} + +// Determine the command to run inside the container. +if (argv._.length > 0) { + // Join all positional arguments into a single command string. + const userCommand = argv._.join(' '); + // The container is Linux, so we use bash -l -c to execute the command string. + // This is cross-platform because it's what the container runs, not the host. + commandToRun = ['bash', '-l', '-c', userCommand]; +} else { + // No command provided, so we start an interactive bash login shell. + commandToRun = ['bash', '-l']; +} + +const spawnArgs = ['exec', ...execArgs, sandboxName, ...commandToRun]; + +// Use spawn to avoid shell injection issues and handle arguments correctly. +spawn(sandboxCommand, spawnArgs, { stdio: 'inherit' }); diff --git a/scripts/sandbox.sh b/scripts/sandbox.sh deleted file mode 100755 index b6a52c14..00000000 --- a/scripts/sandbox.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -if ! scripts/sandbox_command.sh -q; then - echo "ERROR: sandboxing disabled. See docs to enable sandboxing." - exit 1 -fi - -# parse flags -interactive=false -while getopts "i" opt; do - case "$opt" in - \?) - echo "usage: sandbox.sh [-i] [sandbox-name-or-index = AUTO] [command... = bash -l]" - echo " -i: enable interactive mode for custom command (enabled by default for login shell)" - echo " (WARNING: interactive mode causes stderr to be redirected to stdout)" - exit 1 - ;; - i) - interactive=true - if [ ! -t 0 ]; then - echo "ERROR: interactive mode (-i) requested without a terminal attached" - exit 1 - fi - ;; - esac -done -shift $((OPTIND - 1)) - -IMAGE=gemini-cli-sandbox -CMD=$(scripts/sandbox_command.sh) - -# list all containers running on sandbox image -sandboxes=() -while IFS= read -r line; do - sandboxes+=("$line") -done < <($CMD ps --filter "ancestor=$IMAGE" --format "{{.Names}}") - -# take first argument as sandbox name if it starts with image name or is an integer -# otherwise require a unique sandbox to be running and take its name -if [[ "${1:-}" =~ ^$IMAGE(-[0-9]+)?$ ]]; then - SANDBOX=$1 - shift -elif [[ "${1:-}" =~ ^[0-9]+$ ]]; then - SANDBOX=$IMAGE-$1 - shift -else - # exit if no sandbox is running - if [ ${#sandboxes[@]} -eq 0 ]; then - echo "No sandboxes found. Are you running gemini-cli with sandboxing enabled?" - exit 1 - fi - # exit if multiple sandboxes are running - if [ ${#sandboxes[@]} -gt 1 ]; then - echo "Multiple sandboxes found:" - for sandbox in "${sandboxes[@]}"; do - echo " $sandbox" - done - echo "Sandbox name or index (0,1,...) must be specified as first argument" - exit 1 - fi - SANDBOX=${sandboxes[0]} -fi - -# check that sandbox exists -if ! [[ " ${sandboxes[*]} " == *" $SANDBOX "* ]]; then - echo "unknown sandbox $SANDBOX" - echo "known sandboxes:" - for sandbox in "${sandboxes[@]}"; do - echo " $sandbox" - done - exit 1 -fi - -# determine command and args for exec -if [ $# -gt 0 ]; then - cmd=(bash -l -c "$(printf '%q ' "$@")") # fixes quoting, e.g. bash -c 'echo $SANDBOX' - exec_args=() - if [ "$interactive" = true ]; then - exec_args=(-it) - fi -else - cmd=(bash -l) - exec_args=(-it) -fi - -# run command in sandbox -exec_args+=("$SANDBOX" "${cmd[@]}") -$CMD exec "${exec_args[@]}" diff --git a/scripts/sandbox_command.js b/scripts/sandbox_command.js new file mode 100644 index 00000000..7f8e8381 --- /dev/null +++ b/scripts/sandbox_command.js @@ -0,0 +1,126 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; +import { existsSync, readFileSync } from 'fs'; +import { join, dirname } from 'path'; +import os from 'os'; +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import dotenv from 'dotenv'; + +const argv = yargs(hideBin(process.argv)).option('q', { + alias: 'quiet', + type: 'boolean', + default: false, +}).argv; + +let geminiSandbox = process.env.GEMINI_SANDBOX; + +if (!geminiSandbox) { + const userSettingsFile = join(os.homedir(), '.gemini', 'settings.json'); + if (existsSync(userSettingsFile)) { + const settings = JSON.parse(readFileSync(userSettingsFile, 'utf-8')); + if (settings.sandbox) { + geminiSandbox = settings.sandbox; + } + } +} + +if (!geminiSandbox) { + let currentDir = process.cwd(); + while (currentDir !== '/') { + const geminiEnv = join(currentDir, '.gemini', '.env'); + const regularEnv = join(currentDir, '.env'); + if (existsSync(geminiEnv)) { + dotenv.config({ path: geminiEnv }); + break; + } else if (existsSync(regularEnv)) { + dotenv.config({ path: regularEnv }); + break; + } + currentDir = dirname(currentDir); + } + geminiSandbox = process.env.GEMINI_SANDBOX; +} + +if (process.env.GEMINI_CODE_SANDBOX) { + console.warn( + 'WARNING: GEMINI_CODE_SANDBOX is deprecated. Use GEMINI_SANDBOX instead.', + ); + geminiSandbox = process.env.GEMINI_CODE_SANDBOX; +} + +geminiSandbox = (geminiSandbox || '').toLowerCase(); + +const commandExists = (cmd) => { + const checkCommand = os.platform() === 'win32' ? 'where' : 'command -v'; + try { + execSync(`${checkCommand} ${cmd}`, { stdio: 'ignore' }); + return true; + } catch { + if (os.platform() === 'win32') { + try { + execSync(`${checkCommand} ${cmd}.exe`, { stdio: 'ignore' }); + return true; + } catch { + return false; + } + } + return false; + } +}; + +let command = ''; +if (['1', 'true'].includes(geminiSandbox)) { + if (commandExists('docker')) { + command = 'docker'; + } else if (commandExists('podman')) { + command = 'podman'; + } else { + console.error( + 'ERROR: install docker or podman or specify command in GEMINI_SANDBOX', + ); + process.exit(1); + } +} else if (geminiSandbox && !['0', 'false'].includes(geminiSandbox)) { + if (commandExists(geminiSandbox)) { + command = geminiSandbox; + } else { + console.error( + `ERROR: missing sandbox command '${geminiSandbox}' (from GEMINI_SANDBOX)`, + ); + process.exit(1); + } +} else { + if (os.platform() === 'darwin' && process.env.SEATBELT_PROFILE !== 'none') { + if (commandExists('sandbox-exec')) { + command = 'sandbox-exec'; + } else { + process.exit(1); + } + } else { + process.exit(1); + } +} + +if (!argv.q) { + console.log(command); +} +process.exit(0); diff --git a/scripts/sandbox_command.sh b/scripts/sandbox_command.sh deleted file mode 100755 index 468a4834..00000000 --- a/scripts/sandbox_command.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# usage: scripts/sandbox_command.sh [-q] -# -q: quiet mode (do not print command, just exit w/ code 0 or 1) - -set -euo pipefail - -# parse flags -QUIET=false -while getopts ":q" opt; do - case ${opt} in - q) QUIET=true ;; - \?) - echo "Usage: $0 [-q]" - exit 1 - ;; - esac -done -shift $((OPTIND - 1)) - -# if GEMINI_SANDBOX is not set, see if it is set in user settings -# note it can be string or boolean, and if missing `npx json` will return empty string -USER_SETTINGS_FILE="$HOME/.gemini/settings.json" -if [ -z "${GEMINI_SANDBOX:-}" ] && [ -f "$USER_SETTINGS_FILE" ]; then - # Check if jq is available (more reliable than npx json) - if command -v jq &>/dev/null; then - USER_SANDBOX_SETTING=$(jq -r '.sandbox // empty' "$USER_SETTINGS_FILE" 2>/dev/null || echo "") - else - # Fallback to npx json with error handling - USER_SANDBOX_SETTING=$(sed -e 's/\/\/.*//' -e 's/\/\*.*\*\///g' -e '/^[[:space:]]*\/\//d' "$USER_SETTINGS_FILE" | npx json 'sandbox' 2>/dev/null || echo "") - fi - - # Avoid setting GEMINI_SANDBOX to complex objects - if [ -n "$USER_SANDBOX_SETTING" ] && [[ ! "$USER_SANDBOX_SETTING" =~ ^\{.*\}$ ]]; then - GEMINI_SANDBOX=$USER_SANDBOX_SETTING - fi -fi - -# if GEMINI_SANDBOX is not set, try to source .env in case set there -# allow .env to be in any ancestor directory (same as findEnvFile in config.ts) -# prefer gemini-specific .env under .gemini folder (also same as in findEnvFile) -if [ -z "${GEMINI_SANDBOX:-}" ]; then - current_dir=$(pwd) - dot_env_sourced=false - while [ "$current_dir" != "/" ]; do - if [ -f "$current_dir/.gemini/.env" ]; then - source "$current_dir/.gemini/.env" - dot_env_sourced=true - break - elif [ -f "$current_dir/.env" ]; then - source "$current_dir/.env" - dot_env_sourced=true - break - fi - current_dir=$(dirname "$current_dir") - done - # if .env is not found in any ancestor directory, try home as fallback - if [ "$dot_env_sourced" = false ]; then - if [ -f "$HOME/.gemini/.env" ]; then - source "$HOME/.gemini/.env" - dot_env_sourced=true - elif [ -f "$HOME/.env" ]; then - source "$HOME/.env" - dot_env_sourced=true - fi - fi -fi - -# copy and warn about deprecated GEMINI_CODE_SANDBOX -if [ -n "${GEMINI_CODE_SANDBOX:-}" ]; then - echo "WARNING: GEMINI_CODE_SANDBOX is deprecated. Use GEMINI_SANDBOX instead." >&2 - GEMINI_SANDBOX=$GEMINI_CODE_SANDBOX - export GEMINI_SANDBOX -fi - -# lowercase GEMINI_SANDBOX -GEMINI_SANDBOX=$(echo "${GEMINI_SANDBOX:-}" | tr '[:upper:]' '[:lower:]') - -# if GEMINI_SANDBOX is set to 1|true, then try to use docker or podman -# if non-empty and not 0|false, treat as custom command and check that it exists -# if empty or 0|false, then fail silently (after checking for possible fallbacks) -command="" -if [[ "${GEMINI_SANDBOX:-}" =~ ^(1|true)$ ]]; then - if command -v docker &>/dev/null; then - command="docker" - elif command -v podman &>/dev/null; then - command="podman" - else - echo "ERROR: install docker or podman or specify command in GEMINI_SANDBOX" >&2 - exit 1 - fi -elif [ -n "${GEMINI_SANDBOX:-}" ] && [[ ! "${GEMINI_SANDBOX:-}" =~ ^(0|false)$ ]]; then - if ! command -v "$GEMINI_SANDBOX" &>/dev/null; then - echo "ERROR: missing sandbox command '$GEMINI_SANDBOX' (from GEMINI_SANDBOX)" >&2 - exit 1 - fi - command="$GEMINI_SANDBOX" -else - # if we are on macOS and sandbox-exec is available, use that for minimal sandboxing - # unless SEATBELT_PROFILE is set to 'none', which we allow as an escape hatch - if [ "$(uname)" = "Darwin" ] && command -v sandbox-exec &>/dev/null && [ "${SEATBELT_PROFILE:-}" != "none" ]; then - command="sandbox-exec" - else # GEMINI_SANDBOX is empty or 0|false, so we fail w/o error msg - exit 1 - fi -fi - -if [ "$QUIET" = false ]; then echo "$command"; fi -exit 0 diff --git a/scripts/setup-dev.js b/scripts/setup-dev.js new file mode 100644 index 00000000..c4e2b22c --- /dev/null +++ b/scripts/setup-dev.js @@ -0,0 +1,42 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { execSync } from 'child_process'; + +try { + execSync('command -v npm', { stdio: 'ignore' }); +} catch { + console.log('npm not found. Installing npm via nvm...'); + try { + execSync( + 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash', + { stdio: 'inherit' }, + ); + const nvmsh = `\\. "$HOME/.nvm/nvm.sh"`; + execSync(`${nvmsh} && nvm install 22`, { stdio: 'inherit' }); + execSync(`${nvmsh} && node -v`, { stdio: 'inherit' }); + execSync(`${nvmsh} && nvm current`, { stdio: 'inherit' }); + execSync(`${nvmsh} && npm -v`, { stdio: 'inherit' }); + } catch { + console.error('Failed to install nvm or node.'); + process.exit(1); + } +} + +console.log('Development environment setup complete.'); diff --git a/scripts/setup-dev.sh b/scripts/setup-dev.sh deleted file mode 100755 index de2ae336..00000000 --- a/scripts/setup-dev.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -# Check if npm is installed -if ! command -v npm &>/dev/null; then - echo "npm not found. Installing npm via nvm..." - # Download and install nvm: - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash - # in lieu of restarting the shell - \. "$HOME/.nvm/nvm.sh" - # Download and install Node.js: - nvm install 22 - # Verify the Node.js version: - node -v # Should print "v22.15.0". - nvm current # Should print "v22.15.0". - # Verify npm version: - npm -v # Should print "10.9.2". -fi - -echo "Development environment setup complete." diff --git a/scripts/start.js b/scripts/start.js new file mode 100644 index 00000000..f9f85c8e --- /dev/null +++ b/scripts/start.js @@ -0,0 +1,61 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law_or_agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { spawn, execSync } from 'child_process'; +import { join } from 'path'; + +const root = join(import.meta.dirname, '..'); + +// check build status, write warnings to file for app to display if needed +execSync('node ./scripts/check-build-status.js', { + stdio: 'inherit', + cwd: root, +}); + +// if debugging is enabled and sandboxing is disabled, use --inspect-brk flag +// note with sandboxing this flag is passed to the binary inside the sandbox +// inside sandbox SANDBOX should be set and sandbox_command.js should fail +const nodeArgs = []; +try { + execSync('node scripts/sandbox_command.js -q', { + stdio: 'inherit', + cwd: root, + }); + if (process.env.DEBUG) { + if (process.env.SANDBOX) { + const port = process.env.DEBUG_PORT || '9229'; + nodeArgs.push(`--inspect-brk=0.0.0.0:${port}`); + } else { + nodeArgs.push('--inspect-brk'); + } + } +} catch { + // ignore +} + +nodeArgs.push('./packages/cli'); +nodeArgs.push(...process.argv.slice(2)); + +const env = { + ...process.env, + CLI_VERSION: 'development', + DEV: 'true', +}; + +spawn('node', nodeArgs, { stdio: 'inherit', env }); diff --git a/scripts/start.sh b/scripts/start.sh deleted file mode 100755 index 2caf540d..00000000 --- a/scripts/start.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# Copyright 2025 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -euo pipefail - -# check build status, write warnings to file for app to display if needed -node ./scripts/check-build-status.js - -# if debugging is enabled and sandboxing is disabled, use --inspect-brk flag -# note with sandboxing this flag is passed to the binary inside the sandbox -# inside sandbox SANDBOX should be set and sandbox_command.sh should fail -node_args=() -if [ -n "${DEBUG:-}" ] && ! scripts/sandbox_command.sh -q; then - if [ -n "${SANDBOX:-}" ]; then - port="${DEBUG_PORT:-9229}" - node_args=("--inspect-brk=0.0.0.0:$port") - else - node_args=(--inspect-brk) - fi -fi -node_args+=("./packages/cli" "$@") - -# DEV=true to enable React Dev Tools (https://github.com/vadimdemedes/ink?tab=readme-ov-file#using-react-devtools) -# CLI_VERSION to display in the app ui footer -CLI_VERSION='development' DEV=true node "${node_args[@]}" |
