diff --git a/.craft.yml b/.craft.yml new file mode 100644 index 00000000..281f422b --- /dev/null +++ b/.craft.yml @@ -0,0 +1,15 @@ +minVersion: '2.14.0' +changelog: + policy: auto +preReleaseCommand: npm --no-git-tag-version version ${CRAFT_NEW_VERSION} +postReleaseCommand: >- + npm --no-git-tag-version version preminor --preid=dev && + git diff --quiet || (git commit -anm "meta: Bump new development version + + #skip-changelog" && git pull --rebase && git push) +requireNames: + - /^sentry-.+$/ + - /^sentry-.*\.tgz$/ +targets: + - name: npm + - name: github diff --git a/.github/workflows/changelog-preview.yml b/.github/workflows/changelog-preview.yml new file mode 100644 index 00000000..75d37a28 --- /dev/null +++ b/.github/workflows/changelog-preview.yml @@ -0,0 +1,13 @@ +name: Changelog Preview +on: + pull_request_target: + types: [opened, synchronize, reopened, edited, labeled, unlabeled] + +permissions: + contents: read + pull-requests: write + +jobs: + changelog-preview: + uses: getsentry/craft/.github/workflows/changelog-preview.yml@v2 + secrets: inherit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd1c2951..1a756226 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,40 +1,168 @@ name: CI on: + push: + branches: [main, release/**] + paths: + - 'src/**' + - 'test/**' + - 'script/**' + - 'package.json' + - 'bun.lock' + - '.github/workflows/ci.yml' pull_request: paths: - - 'packages/cli/**' + - 'src/**' + - 'test/**' + - 'script/**' + - 'package.json' + - 'bun.lock' - '.github/workflows/ci.yml' + workflow_call: concurrency: group: ci-${{ github.ref }} cancel-in-progress: true -defaults: - run: - working-directory: packages/cli - jobs: - build: - name: Build + lint: + name: Lint & Typecheck runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - name: Setup Bun - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@v2 + - uses: actions/cache@v4 + id: cache with: - bun-version: latest + path: node_modules + key: node-modules-${{ hashFiles('bun.lock') }} + - if: steps.cache.outputs.cache-hit != 'true' + run: bun install --frozen-lockfile + - run: bun run lint + - run: bun run typecheck - - name: Install dependencies - run: bun install - - - name: Build (current platform only) + test: + name: Test + runs-on: ubuntu-latest + permissions: + contents: read + actions: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + - uses: actions/cache@v4 + id: cache + with: + path: node_modules + key: node-modules-${{ hashFiles('bun.lock') }} + - if: steps.cache.outputs.cache-hit != 'true' + run: bun install --frozen-lockfile + - name: Test env: - SENTRY_CLIENT_ID: ${{ secrets.SENTRY_CLIENT_ID }} - run: bun run build + SENTRY_TEST_AUTH_TOKEN: ${{ secrets.SENTRY_TEST_AUTH_TOKEN }} + SENTRY_TEST_ORG: ${{ secrets.SENTRY_TEST_ORG }} + SENTRY_TEST_PROJECT: ${{ secrets.SENTRY_TEST_PROJECT }} + run: bun test --coverage --coverage-reporter=lcov + - name: Upload Coverage + uses: getsentry/codecov-action@main + with: + token: ${{ secrets.GITHUB_TOKEN }} + post-pr-comment: true + build-binary: + name: Build Binary (${{ matrix.target }}) + needs: [lint, test] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + # Native builds (can run smoke test) + - target: darwin-arm64 + os: macos-latest + can-test: true + - target: linux-x64 + os: ubuntu-latest + can-test: true + - target: windows-x64 + os: windows-latest + can-test: true + # Cross-compiled builds (cannot run smoke test) + - target: darwin-x64 + os: macos-latest + can-test: false + - target: linux-arm64 + os: ubuntu-latest + can-test: false + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + - uses: actions/cache@v4 + id: cache + with: + path: node_modules + key: node-modules-${{ matrix.os }}-${{ hashFiles('bun.lock') }} + - if: steps.cache.outputs.cache-hit != 'true' + run: bun install --frozen-lockfile + - name: Build + env: + SENTRY_CLIENT_ID: ${{ vars.SENTRY_CLIENT_ID }} + run: bun run build --target ${{ matrix.target }} - name: Smoke test + if: matrix.can-test + shell: bash run: | - ./dist/sentry-linux-x64/bin/sentry --help - echo "Build successful!" + if [[ "${{ matrix.target }}" == "windows-x64" ]]; then + ./dist/sentry-windows-x64/bin/sentry.exe --help + else + ./dist/sentry-${{ matrix.target }}/bin/sentry --help + fi + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: sentry-${{ matrix.target }} + path: dist/sentry-*/bin/sentry* + + build-npm: + name: Build npm Package + needs: [lint, test] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + - uses: actions/setup-node@v4 + with: + node-version: '22' + - uses: actions/cache@v4 + id: cache + with: + path: node_modules + key: node-modules-${{ hashFiles('bun.lock') }} + - if: steps.cache.outputs.cache-hit != 'true' + run: bun install --frozen-lockfile + - name: Bundle + env: + SENTRY_CLIENT_ID: ${{ vars.SENTRY_CLIENT_ID }} + run: bun run bundle + - name: Smoke test (Node.js) + run: node dist/bin.mjs --help + - run: npm pack + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: npm-package + path: '*.tgz' + + merge-artifacts: + name: Merge Artifacts + needs: [build-binary, build-npm] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + - uses: actions/upload-artifact@v4 + with: + name: ${{ github.sha }} + path: | + sentry-*/ + npm-package/*.tgz diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 9ceaff0f..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: Publish to npm - -on: - push: - branches: [main] - paths: - - 'packages/cli/**' - - '.github/workflows/publish.yml' - workflow_dispatch: - -concurrency: - group: publish-${{ github.ref }} - cancel-in-progress: false - -defaults: - run: - working-directory: packages/cli - -jobs: - publish: - name: Build and Publish - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - - - name: Install dependencies - run: bun install - - - name: Bump version - id: version - run: | - # Read current version - CURRENT_VERSION=$(jq -r '.version' package.json) - echo "Current version: $CURRENT_VERSION" - - # Parse major.minor.patch - MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) - MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) - PATCH=$(echo $CURRENT_VERSION | cut -d. -f3) - - # Increment minor version (0.X.Y -> 0.X+1.0) - NEW_MINOR=$((MINOR + 1)) - NEW_VERSION="${MAJOR}.${NEW_MINOR}.0" - echo "New version: $NEW_VERSION" - - # Update package.json - jq --arg v "$NEW_VERSION" '.version = $v' package.json > package.json.tmp - mv package.json.tmp package.json - - echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT - - - name: Build all platforms - env: - SENTRY_CLIENT_ID: ${{ secrets.SENTRY_CLIENT_ID }} - run: bun run build:all - - - name: Package main CLI - run: bun run package - - - name: Setup npm - run: | - echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc - - - name: Publish platform packages - run: | - for pkg in sentry-darwin-arm64 sentry-darwin-x64 sentry-linux-arm64 sentry-linux-x64 sentry-windows-x64; do - echo "Publishing $pkg..." - cd dist/$pkg && npm publish --access public && cd ../.. - done - - - name: Publish main package - run: | - cd dist/@betegon-sentry && npm publish --access public - - - name: Commit version bump - run: | - cd ../.. - git config --local user.email "github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git add packages/cli/package.json - git commit -m "chore: bump CLI version to ${{ steps.version.outputs.version }}" - git push diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3c772e80 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: Release +on: + workflow_dispatch: + inputs: + version: + description: Version to release (semver, bump type, or "auto") + required: true + default: 'auto' + force: + description: Force release even with blockers + required: false + +jobs: + ci: + uses: ./.github/workflows/ci.yml + permissions: + contents: read + secrets: inherit + + release: + needs: [ci] + uses: getsentry/craft/.github/workflows/release.yml@v2 + with: + version: ${{ inputs.version }} + force: ${{ inputs.force }} + publish_repo: getsentry/publish + secrets: inherit + permissions: + contents: write diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 84c8fb0b..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Test - -on: - push: - branches: [main] - paths: - - 'packages/cli/**' - - '.github/workflows/test.yml' - pull_request: - branches: [main] - paths: - - 'packages/cli/**' - - '.github/workflows/test.yml' - workflow_dispatch: # Manual trigger - -permissions: - contents: read - actions: read - pull-requests: write - -jobs: - test: - name: Run Tests - runs-on: ubuntu-latest - defaults: - run: - working-directory: packages/cli - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - - - name: Install dependencies - run: bun install - - - name: Test - env: - SENTRY_TEST_AUTH_TOKEN: ${{ secrets.SENTRY_TEST_AUTH_TOKEN }} - SENTRY_TEST_ORG: ${{ secrets.SENTRY_TEST_ORG }} - SENTRY_TEST_PROJECT: ${{ secrets.SENTRY_TEST_PROJECT }} - run: bun test --reporter=junit --reporter-outfile=./report.junit.xml --coverage --coverage-reporter=lcov - - - name: Upload Coverage - uses: getsentry/codecov-action@main - with: - token: ${{ secrets.GITHUB_TOKEN }} - post-pr-comment: true - diff --git a/.gitignore b/.gitignore index 6d1fc723..8ed1cd20 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json .eslintcache .cache *.tsbuildinfo +.turbo # IntelliJ based IDEs .idea diff --git a/AGENTS.md b/AGENTS.md index b27fdc33..ec73573f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,25 +11,23 @@ Before working on this codebase, read the Cursor rules: ## Quick Reference: Commands -> **Note**: Always check `package.json` and `packages/cli/package.json` for the latest scripts. +> **Note**: Always check `package.json` for the latest scripts. ```bash # Development bun install # Install dependencies -bun run dev # Run CLI in dev mode (from packages/cli) -bun run --env-file=../../.env.local src/bin.ts # Dev with env vars +bun run dev # Run CLI in dev mode +bun run --env-file=.env.local src/bin.ts # Dev with env vars # Build bun run build # Build for current platform bun run build:all # Build for all platforms -turbo build # Build all packages # Type Checking -turbo typecheck # Check all packages -bun run typecheck # Check single package (from packages/cli) +bun run typecheck # Check types # Linting & Formatting -bun run lint # Check for issues (via turbo) +bun run lint # Check for issues bun run lint:fix # Auto-fix issues (run before committing) # Testing @@ -70,20 +68,18 @@ mkdirSync(dir, { recursive: true, mode: 0o700 }); ## Architecture ``` -stellar-orchid/ -├── packages/ -│ └── cli/ # Main CLI package -│ ├── src/ -│ │ ├── bin.ts # Entry point -│ │ ├── app.ts # Stricli application setup -│ │ ├── context.ts # Dependency injection context -│ │ ├── commands/ # CLI commands (auth/, issue/, org/, project/) -│ │ ├── lib/ # Shared utilities (api-client, config, oauth) -│ │ └── types/ # TypeScript types and Zod schemas -│ └── script/ # Build scripts -├── .cursor/rules/ # Cursor AI rules (read these!) -├── biome.jsonc # Linting config (extends ultracite) -└── turbo.json # Turborepo config +sentry-cli/ +├── src/ +│ ├── bin.ts # Entry point +│ ├── app.ts # Stricli application setup +│ ├── context.ts # Dependency injection context +│ ├── commands/ # CLI commands (auth/, issue/, org/, project/) +│ ├── lib/ # Shared utilities (api-client, config, oauth) +│ └── types/ # TypeScript types and Zod schemas +├── test/ # Test files (mirrors src/ structure) +├── script/ # Build scripts +├── .cursor/rules/ # Cursor AI rules (read these!) +└── biome.jsonc # Linting config (extends ultracite) ``` ## Key Patterns @@ -232,7 +228,7 @@ Minimal comments, maximum clarity. Comments explain **intent and reasoning**, no ## Testing (bun:test) -**Test files go in `packages/cli/test/`**, not alongside source files. +**Test files go in `test/`**, not alongside source files. - Name test files: `*.test.ts` - Mirror source structure: `test/lib/config.test.ts` tests `src/lib/config.ts` - E2E tests go in `test/e2e/` @@ -256,9 +252,9 @@ mock.module("./some-module", () => ({ | What | Where | |------|-------| -| Add new command | `packages/cli/src/commands//` | -| Add API types | `packages/cli/src/types/sentry.ts` | -| Add config types | `packages/cli/src/types/config.ts` | -| Add utility | `packages/cli/src/lib/` | -| Build scripts | `packages/cli/script/` | -| Add tests | `packages/cli/test/` (mirror `src/` structure) | +| Add new command | `src/commands//` | +| Add API types | `src/types/sentry.ts` | +| Add config types | `src/types/config.ts` | +| Add utility | `src/lib/` | +| Build scripts | `script/` | +| Add tests | `test/` (mirror `src/` structure) | diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..fccde639 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + + diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d029729a..cf532e2f 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -5,14 +5,6 @@ - [Bun](https://bun.sh/) installed - A Sentry OAuth application (create one at https://sentry.io/settings/account/api/applications/) -## Project Structure - -``` -sentry-cli-next/ -└── packages/ - └── cli/ # The Sentry CLI -``` - ## Setup 1. Install dependencies: @@ -34,8 +26,7 @@ Get the client ID from your Sentry OAuth application settings. ## Running Locally ```bash -cd packages/cli -bun run --env-file=../../.env.local src/bin.ts auth login +bun run --env-file=.env.local src/bin.ts auth login ``` ## Testing the Device Flow @@ -43,8 +34,7 @@ bun run --env-file=../../.env.local src/bin.ts auth login 1. Run the CLI login command: ```bash -cd packages/cli -bun run --env-file=../../.env.local src/bin.ts auth login +bun run --env-file=.env.local src/bin.ts auth login ``` 2. You'll see output like: @@ -85,7 +75,6 @@ When creating your Sentry OAuth application: ## Building ```bash -cd packages/cli bun run build ``` diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..6e9bafc7 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,105 @@ +# Functional Source License, Version 1.1, Apache 2.0 Future License + +## Abbreviation + +FSL-1.1-Apache-2.0 + +## Notice + +Copyright 2025 Functional Software, Inc. dba Sentry + +## Terms and Conditions + +### Licensor ("We") + +The party offering the Software under these Terms and Conditions. + +### The Software + +The "Software" is each version of the software that we make available under +these Terms and Conditions, as indicated by our inclusion of these Terms and +Conditions with the Software. + +### License Grant + +Subject to your compliance with this License Grant and the Patents, +Redistribution and Trademark clauses below, we hereby grant you the right to +use, copy, modify, create derivative works, publicly perform, publicly display +and redistribute the Software for any Permitted Purpose identified below. + +### Permitted Purpose + +A Permitted Purpose is any purpose other than a Competing Use. A Competing Use +means making the Software available to others in a commercial product or +service that: + +1. substitutes for the Software; + +2. substitutes for any other product or service we offer using the Software + that exists as of the date we make the Software available; or + +3. offers the same or substantially similar functionality as the Software. + +Permitted Purposes specifically include using the Software: + +1. for your internal use and access; + +2. for non-commercial education; + +3. for non-commercial research; and + +4. in connection with professional services that you provide to a licensee + using the Software in accordance with these Terms and Conditions. + +### Patents + +To the extent your use for a Permitted Purpose would necessarily infringe our +patents, the license grant above includes a license under our patents. If you +make a claim against any party that the Software infringes or contributes to +the infringement of any patent, then your patent license to the Software ends +immediately. + +### Redistribution + +The Terms and Conditions apply to all copies, modifications and derivatives of +the Software. + +If you redistribute any copies, modifications or derivatives of the Software, +you must include a copy of or a link to these Terms and Conditions and not +remove any copyright notices provided in or with the Software. + +### Disclaimer + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT. + +IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE +SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, +EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE. + +### Trademarks + +Except for displaying the License Details and identifying us as the origin of +the Software, you have no right under these Terms and Conditions to use our +trademarks, trade names, service marks or product names. + +## Grant of Future License + +We hereby irrevocably grant you an additional license to use the Software under +the Apache License, Version 2.0 that is effective on the second anniversary of +the date we make the Software available. On or after that date, you may use the +Software under the Apache License, Version 2.0, in which case the following +will apply: + +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. diff --git a/README.md b/README.md index 49daca64..25eab987 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# sentry-cli-next +# sentry A gh-like CLI for Sentry. @@ -63,9 +63,8 @@ sentry api /organizations/ --include # Show headers ```bash bun install -cd packages/cli -bun run --env-file=../../.env.local src/bin.ts --help # Run CLI in dev mode -bun run build # Build binary +bun run --env-file=.env.local src/bin.ts --help # Run CLI in dev mode +bun run build # Build binary ``` See [DEVELOPMENT.md](DEVELOPMENT.md) for detailed development instructions. diff --git a/biome.jsonc b/biome.jsonc index a36fa09f..d498314e 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -3,5 +3,25 @@ "extends": ["ultracite/core"], "javascript": { "globals": ["Bun"] - } + }, + "overrides": [ + { + "includes": ["test/**/*.ts"], + "linter": { + "rules": { + "performance": { + "useTopLevelRegex": "off", + "noDelete": "off" + }, + "style": { + "useBlockStatements": "off", + "noNonNullAssertion": "off" + }, + "suspicious": { + "useAwait": "off" + } + } + } + } + ] } diff --git a/bun.lock b/bun.lock index 6fcdffe3..c861bd74 100644 --- a/bun.lock +++ b/bun.lock @@ -3,60 +3,26 @@ "configVersion": 1, "workspaces": { "": { - "name": "sry", + "name": "sentry", "devDependencies": { "@biomejs/biome": "2.3.8", - "turbo": "^2.3.3", - "typescript": "^5", - "ultracite": "6.3.10", - }, - }, - "packages/cli": { - "name": "@betegon/sentry", - "version": "0.16.0", - "bin": { - "sentry": "./bin/sentry", - }, - "dependencies": { - "@ast-grep/napi": "^0.31.0", "@stricli/auto-complete": "^1.2.4", "@stricli/core": "^1.2.4", - "chalk": "^5.6.2", - "ky": "^1.14.2", - "qrcode-terminal": "^0.12.0", - "zod": "^3.24.0", - }, - "devDependencies": { "@types/bun": "latest", "@types/node": "^20", "@types/qrcode-terminal": "^0.12.2", + "chalk": "^5.6.2", + "esbuild": "^0.25.0", + "ky": "^1.14.2", + "qrcode-terminal": "^0.12.0", + "tinyglobby": "^0.2.15", "typescript": "^5", + "ultracite": "6.3.10", + "zod": "^3.24.0", }, }, }, "packages": { - "@ast-grep/napi": ["@ast-grep/napi@0.31.1", "", { "optionalDependencies": { "@ast-grep/napi-darwin-arm64": "0.31.1", "@ast-grep/napi-darwin-x64": "0.31.1", "@ast-grep/napi-linux-arm64-gnu": "0.31.1", "@ast-grep/napi-linux-arm64-musl": "0.31.1", "@ast-grep/napi-linux-x64-gnu": "0.31.1", "@ast-grep/napi-linux-x64-musl": "0.31.1", "@ast-grep/napi-win32-arm64-msvc": "0.31.1", "@ast-grep/napi-win32-ia32-msvc": "0.31.1", "@ast-grep/napi-win32-x64-msvc": "0.31.1" } }, "sha512-XOFCIeCYdXeRhp1OesRtes/sjPlTSe9Q7tKLLztM8sbDVYgla8k1eCTU3ia7xYIwdK3pjwc39akb8Z7qlOpzHg=="], - - "@ast-grep/napi-darwin-arm64": ["@ast-grep/napi-darwin-arm64@0.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-i2GOKyowGyGWwnwBmzZj8MFACTh5QzWrYTV7Si7V+4JjYLlrm94A/KgxBWX16mwXQr1qxziS6GjlQDqRSBxCtw=="], - - "@ast-grep/napi-darwin-x64": ["@ast-grep/napi-darwin-x64@0.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-oUyxBoWT6o1hsJ1H0id9PkK2jgwDS1RSziZ+ORJxlV+VuvXbqPC2yrrqjWK60yBSK49GPNQjuQueGC3Js9Zqhg=="], - - "@ast-grep/napi-linux-arm64-gnu": ["@ast-grep/napi-linux-arm64-gnu@0.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-UVGjseE/RLW2Qx21t8TSGArFgmud2YPqdpgneLuRiW4unM9FIM1PKyxnm9AKzkQbJJzpG7CSWBnMbVkmvWMB/A=="], - - "@ast-grep/napi-linux-arm64-musl": ["@ast-grep/napi-linux-arm64-musl@0.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-K6LBPjbd1ugHYG4EPaepYgfg7M2UOpTC1fFGkViLuONDfpiH5A/i0HAkcDBkEbfzcOGv2WU7aqnHJ2rqKDLodg=="], - - "@ast-grep/napi-linux-x64-gnu": ["@ast-grep/napi-linux-x64-gnu@0.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-VeJ5XVFyETypqIxTcB0JaMt+dadOHzXnrU5qSrbUsrnhtIUoleazvxHEzaoXQ0wglCVgl0odLAwgcwkHRxJ/Pg=="], - - "@ast-grep/napi-linux-x64-musl": ["@ast-grep/napi-linux-x64-musl@0.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-6pGQDPiaMqSHXCahVoJCpThc8TEk7HaJBP/n+xay/OTwqrqe54nS6baRnEm9k5q9vh4V2ceaOVf3754tkg8TSg=="], - - "@ast-grep/napi-win32-arm64-msvc": ["@ast-grep/napi-win32-arm64-msvc@0.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-JVIFHBDPoxVjG5c/XauJywypn1wkv0I+WqiwIzlMTNpqmEoJEnJGIom3gJZGqgrFmPpc6/PiATTw6DEjGJs4QA=="], - - "@ast-grep/napi-win32-ia32-msvc": ["@ast-grep/napi-win32-ia32-msvc@0.31.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-PTyEPvJgNuvzj0kWyR9/0+AAL13LftvGijp5sZ0lgXIpig8MfF3czIU62Nf6AMpABhsu0h+u4KmD4DaMxdw0EA=="], - - "@ast-grep/napi-win32-x64-msvc": ["@ast-grep/napi-win32-x64-msvc@0.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-tEgj2Fp2Pi5qXXDLR3AWkZwQTj8yeSN3I7Pvw2DOfINu9imE2EY+Aq5kOhfvduGWVPmP8az68xUFC4b29+yrUw=="], - - "@betegon/sentry": ["@betegon/sentry@workspace:packages/cli"], - "@biomejs/biome": ["@biomejs/biome@2.3.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.8", "@biomejs/cli-darwin-x64": "2.3.8", "@biomejs/cli-linux-arm64": "2.3.8", "@biomejs/cli-linux-arm64-musl": "2.3.8", "@biomejs/cli-linux-x64": "2.3.8", "@biomejs/cli-linux-x64-musl": "2.3.8", "@biomejs/cli-win32-arm64": "2.3.8", "@biomejs/cli-win32-x64": "2.3.8" }, "bin": { "biome": "bin/biome" } }, "sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA=="], "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww=="], @@ -79,19 +45,71 @@ "@clack/prompts": ["@clack/prompts@0.11.0", "", { "dependencies": { "@clack/core": "0.5.0", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], - "@stricli/auto-complete": ["@stricli/auto-complete@1.2.4", "", { "dependencies": { "@stricli/core": "^1.2.4" }, "bin": { "auto-complete": "dist/bin/cli.js" } }, "sha512-MxGgeBbFyH+YtzhIjJeOr68NSx0r8mn4+hWRGgWn31YTG9u0Oa2y9oGHPY+PHeoTfvS7vhgllFvOrHcTVpwTrA=="], + "@stricli/auto-complete": ["@stricli/auto-complete@1.2.5", "", { "dependencies": { "@stricli/core": "^1.2.5" }, "bin": { "auto-complete": "dist/bin/cli.js" } }, "sha512-C6G88Hh4lUWBwiqsxbcA4I1ricSQwiLaOziTWW3NmBoX7WGTW7i7RvyooXMpZk1YMLf2olv5Odxmg127ik1DKQ=="], - "@stricli/core": ["@stricli/core@1.2.4", "", {}, "sha512-ujvJDQpC2FINWvlTjkFz+Qzw/vsB8p/LyZEW18idisqIyjXR6yb+sF3WTUPksl+5ZON5r4fHQnCqQWnJxeqSzg=="], + "@stricli/core": ["@stricli/core@1.2.5", "", {}, "sha512-+afyztQW7fwWkqmU2WQZbdc3LjnZThWYdtE0l+hykZ1Rvy7YGxZSvsVCS/wZ/2BNv117pQ9TU1GZZRIcPnB4tw=="], - "@trpc/server": ["@trpc/server@11.7.2", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-AgB26PXY69sckherIhCacKLY49rxE2XP5h38vr/KMZTbLCL1p8IuIoKPjALTcugC2kbyQ7Lbqo2JDVfRSmPmfQ=="], + "@trpc/server": ["@trpc/server@11.8.1", "", { "peerDependencies": { "typescript": ">=5.7.2" } }, "sha512-P4rzZRpEL7zDFgjxK65IdyH0e41FMFfTkQkuq0BA5tKcr7E6v9/v38DEklCpoDN6sPiB1Sigy/PUEzHENhswDA=="], "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], - "@types/node": ["@types/node@20.19.26", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg=="], + "@types/node": ["@types/node@20.19.30", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g=="], "@types/qrcode-terminal": ["@types/qrcode-terminal@0.12.2", "", {}, "sha512-v+RcIEJ+Uhd6ygSQ0u5YYY7ZM+la7GgPbs0V/7l/kFs2uO4S8BcIUEMoP7za4DNIqNnUD5npf0A/7kBhrCKG5Q=="], @@ -99,17 +117,15 @@ "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="], "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], - "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], - - "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], - "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], - "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], @@ -123,7 +139,7 @@ "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], - "nypm": ["nypm@0.6.2", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="], + "nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="], "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], @@ -131,7 +147,7 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "qrcode-terminal": ["qrcode-terminal@0.12.0", "", { "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="], @@ -139,21 +155,9 @@ "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], - "trpc-cli": ["trpc-cli@0.12.1", "", { "dependencies": { "commander": "^14.0.0" }, "peerDependencies": { "@orpc/server": "^1.0.0", "@trpc/server": "^10.45.2 || ^11.0.1", "@valibot/to-json-schema": "^1.1.0", "effect": "^3.14.2 || ^4.0.0", "valibot": "^1.1.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@orpc/server", "@trpc/server", "@valibot/to-json-schema", "effect", "valibot", "zod"], "bin": { "trpc-cli": "dist/bin.js" } }, "sha512-/D/mIQf3tUrS7ZKJZ1gmSPJn2psAABJfkC5Eevm55SZ4s6KwANOUNlwhAGXN9HT4VSJVfoF2jettevE9vHPQlg=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - "turbo": ["turbo@2.6.3", "", { "optionalDependencies": { "turbo-darwin-64": "2.6.3", "turbo-darwin-arm64": "2.6.3", "turbo-linux-64": "2.6.3", "turbo-linux-arm64": "2.6.3", "turbo-windows-64": "2.6.3", "turbo-windows-arm64": "2.6.3" }, "bin": { "turbo": "bin/turbo" } }, "sha512-bf6YKUv11l5Xfcmg76PyWoy/e2vbkkxFNBGJSnfdSXQC33ZiUfutYh6IXidc5MhsnrFkWfdNNLyaRk+kHMLlwA=="], - - "turbo-darwin-64": ["turbo-darwin-64@2.6.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-BlJJDc1CQ7SK5Y5qnl7AzpkvKSnpkfPmnA+HeU/sgny3oHZckPV2776ebO2M33CYDSor7+8HQwaodY++IINhYg=="], - - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.6.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MwVt7rBKiOK7zdYerenfCRTypefw4kZCue35IJga9CH1+S50+KTiCkT6LBqo0hHeoH2iKuI0ldTF2a0aB72z3w=="], - - "turbo-linux-64": ["turbo-linux-64@2.6.3", "", { "os": "linux", "cpu": "x64" }, "sha512-cqpcw+dXxbnPtNnzeeSyWprjmuFVpHJqKcs7Jym5oXlu/ZcovEASUIUZVN3OGEM6Y/OTyyw0z09tOHNt5yBAVg=="], - - "turbo-linux-arm64": ["turbo-linux-arm64@2.6.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-MterpZQmjXyr4uM7zOgFSFL3oRdNKeflY7nsjxJb2TklsYqiu3Z9pQ4zRVFFH8n0mLGna7MbQMZuKoWqqHb45w=="], - - "turbo-windows-64": ["turbo-windows-64@2.6.3", "", { "os": "win32", "cpu": "x64" }, "sha512-biDU70v9dLwnBdLf+daoDlNJVvqOOP8YEjqNipBHzgclbQlXbsi6Gqqelp5er81Qo3BiRgmTNx79oaZQTPb07Q=="], - - "turbo-windows-arm64": ["turbo-windows-arm64@2.6.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-dDHVKpSeukah3VsI/xMEKeTnV9V9cjlpFSUs4bmsUiLu3Yv2ENlgVEZv65wxbeE0bh0jjpmElDT+P1KaCxArQQ=="], + "trpc-cli": ["trpc-cli@0.12.2", "", { "dependencies": { "commander": "^14.0.0" }, "peerDependencies": { "@orpc/server": "^1.0.0", "@trpc/server": "^10.45.2 || ^11.0.1", "@valibot/to-json-schema": "^1.1.0", "effect": "^3.14.2 || ^4.0.0", "valibot": "^1.1.0", "zod": "^3.24.0 || ^4.0.0" }, "optionalPeers": ["@orpc/server", "@trpc/server", "@valibot/to-json-schema", "effect", "valibot", "zod"], "bin": { "trpc-cli": "dist/bin.js" } }, "sha512-kGNCiyOimGlfcZFImbWzFF2Nn3TMnenwUdyuckiN5SEaceJbIac7+Iau3WsVHjQpoNgugFruZMDOKf8GNQNtJw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], @@ -163,10 +167,6 @@ "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "bun-types/@types/node": ["@types/node@25.0.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-rl78HwuZlaDIUSeUKkmogkhebA+8K1Hy7tddZuJ3D0xV8pZSfsYGTsliGUol1JPzu9EKnTxPC4L1fiWouStRew=="], - - "ultracite/zod": ["zod@4.1.13", "", {}, "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig=="], - - "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "ultracite/zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], } } diff --git a/packages/cli/bunfig.toml b/bunfig.toml similarity index 100% rename from packages/cli/bunfig.toml rename to bunfig.toml diff --git a/package.json b/package.json index 80c3f551..d73c3708 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,48 @@ { - "name": "sentry-cli-next", - "version": "0.1.0", - "private": true, - "packageManager": "bun@1.3.3", - "description": "A gh-like CLI for Sentry", - "workspaces": [ - "packages/*" + "name": "sentry", + "version": "0.2.0", + "description": "Sentry CLI - A command-line interface for using Sentry built by robots and humans for robots and humans", + "type": "module", + "bin": { + "sentry": "./dist/bin.mjs" + }, + "files": [ + "dist/bin.mjs" ], "scripts": { - "dev": "turbo dev", - "build": "turbo build", - "lint": "turbo lint", - "lint:fix": "turbo lint:fix", - "typecheck": "turbo typecheck" + "dev": "bun run src/bin.ts", + "build": "bun run script/build.ts --single", + "build:all": "bun run script/build.ts", + "bundle": "bun run script/bundle.ts", + "typecheck": "tsc --noEmit", + "lint": "bunx ultracite check", + "lint:fix": "bunx ultracite fix", + "test": "bun test", + "test:e2e": "bun test test/e2e" }, "devDependencies": { "@biomejs/biome": "2.3.8", - "turbo": "^2.3.3", + "@stricli/auto-complete": "^1.2.4", + "@stricli/core": "^1.2.4", + "@types/bun": "latest", + "@types/node": "^20", + "@types/qrcode-terminal": "^0.12.2", + "chalk": "^5.6.2", + "esbuild": "^0.25.0", + "ky": "^1.14.2", + "qrcode-terminal": "^0.12.0", + "tinyglobby": "^0.2.15", "typescript": "^5", - "ultracite": "6.3.10" - } + "ultracite": "6.3.10", + "zod": "^3.24.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/getsentry/cli.git" + }, + "license": "FSL-1.1-Apache-2.0", + "engines": { + "node": ">=22" + }, + "packageManager": "bun@1.3.3" } diff --git a/packages/cli/bin/sentry b/packages/cli/bin/sentry deleted file mode 100755 index 36366ee5..00000000 --- a/packages/cli/bin/sentry +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env node - -const childProcess = require("child_process") -const fs = require("fs") -const path = require("path") -const os = require("os") - -function run(target) { - const result = childProcess.spawnSync(target, process.argv.slice(2), { - stdio: "inherit", - }) - if (result.error) { - console.error(result.error.message) - process.exit(1) - } - const code = typeof result.status === "number" ? result.status : 0 - process.exit(code) -} - -const platformMap = { - darwin: "darwin", - linux: "linux", - win32: "windows", -} - -const archMap = { - x64: "x64", - arm64: "arm64", -} - -let platform = platformMap[os.platform()] -if (!platform) { - console.error(`Unsupported platform: ${os.platform()}`) - process.exit(1) -} - -let arch = archMap[os.arch()] -if (!arch) { - console.error(`Unsupported architecture: ${os.arch()}`) - process.exit(1) -} - -const packageName = `sentry-${platform}-${arch}` -const binaryName = platform === "windows" ? "sentry.exe" : "sentry" - -function findBinary(startDir) { - let current = startDir - for (;;) { - const modules = path.join(current, "node_modules") - if (fs.existsSync(modules)) { - const candidate = path.join(modules, packageName, "bin", binaryName) - if (fs.existsSync(candidate)) { - return candidate - } - } - const parent = path.dirname(current) - if (parent === current) { - return null - } - current = parent - } -} - -const scriptDir = path.dirname(fs.realpathSync(__filename)) -const resolved = findBinary(scriptDir) - -if (!resolved) { - console.error( - `Could not find the sentry binary for your platform.\n` + - `Expected package: ${packageName}\n` + - `You can try manually installing it: npm install ${packageName}` - ) - process.exit(1) -} - -run(resolved) diff --git a/packages/cli/package.json b/packages/cli/package.json deleted file mode 100644 index 3dc790c0..00000000 --- a/packages/cli/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@betegon/sentry", - "version": "0.19.0", - "description": "A gh-like CLI for Sentry", - "type": "module", - "bin": { - "sentry": "./bin/sentry" - }, - "scripts": { - "dev": "bun run src/bin.ts", - "build": "bun run script/build.ts --single", - "build:all": "bun run script/build.ts", - "package": "bun run script/package.ts", - "prepublish": "bun run script/build.ts && bun run script/package.ts", - "typecheck": "tsc --noEmit", - "lint": "bunx ultracite check", - "lint:fix": "bunx ultracite fix", - "test": "bun test", - "test:e2e": "bun test test/e2e" - }, - "devDependencies": { - "@types/bun": "latest", - "@types/node": "^20", - "@types/qrcode-terminal": "^0.12.2", - "typescript": "^5" - }, - "dependencies": { - "@ast-grep/napi": "^0.31.0", - "@stricli/auto-complete": "^1.2.4", - "@stricli/core": "^1.2.4", - "chalk": "^5.6.2", - "ky": "^1.14.2", - "qrcode-terminal": "^0.12.0", - "zod": "^3.24.0" - } -} diff --git a/packages/cli/script/package.ts b/packages/cli/script/package.ts deleted file mode 100644 index 78517a3e..00000000 --- a/packages/cli/script/package.ts +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env bun -/** - * Package script for Sentry CLI - * - * Creates the main @betegon/sentry package with: - * - bin/sentry launcher script (Node.js) - * - package.json with optionalDependencies on platform packages - * - * Run this after build.ts to prepare all packages for publishing. - * - * Usage: - * bun run script/package.ts - * - * Output: - * dist/@betegon/sentry/ - * bin/sentry - * package.json - */ - -import { $ } from "bun"; -import path from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const cliDir = path.resolve(__dirname, ".."); - -process.chdir(cliDir); - -// Import binaries from build (assumes build.ts was run) -import pkg from "../package.json"; - -const VERSION = pkg.version; -const MAIN_PACKAGE_NAME = "@betegon/sentry"; - -// Platform packages that should exist in dist/ -const PLATFORM_PACKAGES = [ - "sentry-darwin-arm64", - "sentry-darwin-x64", - "sentry-linux-arm64", - "sentry-linux-x64", - "sentry-windows-x64", -]; - -async function packageMain(): Promise { - console.log(`\nPackaging ${MAIN_PACKAGE_NAME} v${VERSION}`); - console.log("=".repeat(40)); - - // Verify platform packages exist - console.log("\nVerifying platform packages..."); - const binaries: Record = {}; - - for (const name of PLATFORM_PACKAGES) { - const pkgPath = `dist/${name}/package.json`; - const exists = await Bun.file(pkgPath).exists(); - if (exists) { - binaries[name] = VERSION; - console.log(` Found ${name}`); - } else { - console.warn(` Warning: ${name} not found - run build.ts first`); - } - } - - if (Object.keys(binaries).length === 0) { - console.error("\nNo platform packages found. Run build.ts first:"); - console.error(" bun run script/build.ts"); - process.exit(1); - } - - // Create main package directory - const mainPkgDir = `dist/${MAIN_PACKAGE_NAME.replace("/", "-")}`; - await $`mkdir -p ${mainPkgDir}/bin`; - - // Copy launcher script - console.log("\nCopying launcher script..."); - await $`cp bin/sentry ${mainPkgDir}/bin/sentry`; - await $`chmod +x ${mainPkgDir}/bin/sentry`; - console.log(` -> ${mainPkgDir}/bin/sentry`); - - // Create package.json for main package - console.log("\nCreating package.json..."); - const mainPkg = { - name: MAIN_PACKAGE_NAME, - version: VERSION, - description: "A gh-like CLI for Sentry", - bin: { - sentry: "./bin/sentry", - }, - optionalDependencies: binaries, - repository: { - type: "git", - url: "https://github.com/betegon/sentry-cli-next", - }, - license: "MIT", - engines: { - node: ">=18", - }, - }; - - await Bun.file(`${mainPkgDir}/package.json`).write( - JSON.stringify(mainPkg, null, 2) - ); - console.log(` -> ${mainPkgDir}/package.json`); - - // Summary - console.log(`\n${"=".repeat(40)}`); - console.log("Packaging complete!"); - console.log("\nPackages ready for publishing:"); - console.log(` Main: ${mainPkgDir}/`); - for (const name of Object.keys(binaries)) { - console.log(` Platform: dist/${name}/`); - } - - console.log("\nTo publish manually:"); - console.log(" # First, publish platform packages:"); - for (const name of Object.keys(binaries)) { - console.log(` cd dist/${name} && npm publish --access public && cd ../..`); - } - console.log("\n # Then, publish main package:"); - console.log(` cd ${mainPkgDir} && npm publish --access public`); -} - -await packageMain(); diff --git a/packages/cli/script/build.ts b/script/build.ts similarity index 63% rename from packages/cli/script/build.ts rename to script/build.ts index e63ca29d..2a430afc 100644 --- a/packages/cli/script/build.ts +++ b/script/build.ts @@ -3,20 +3,19 @@ * Build script for Sentry CLI * * Creates standalone executables for multiple platforms using Bun.build(). - * Each platform gets its own npm package structure in dist/. + * Binaries are uploaded to GitHub Releases. * * Usage: - * bun run script/build.ts # Build for all platforms - * bun run script/build.ts --single # Build for current platform only + * bun run script/build.ts # Build for all platforms + * bun run script/build.ts --single # Build for current platform only + * bun run script/build.ts --target darwin-x64 # Build for specific target (cross-compile) * * Output structure: * dist/ * sentry-darwin-arm64/ * bin/sentry - * package.json * sentry-darwin-x64/ * bin/sentry - * package.json * ... */ @@ -25,14 +24,10 @@ import pkg from "../package.json"; const VERSION = pkg.version; -/** - * Build-time constants injected into the binary - */ +/** Build-time constants injected into the binary */ const SENTRY_CLIENT_ID = process.env.SENTRY_CLIENT_ID ?? ""; -/** - * Build targets configuration - */ +/** Build targets configuration */ type BuildTarget = { os: "darwin" | "linux" | "win32"; arch: "arm64" | "x64"; @@ -46,24 +41,18 @@ const ALL_TARGETS: BuildTarget[] = [ { os: "win32", arch: "x64" }, ]; -/** - * Get package name for a target (uses "windows" instead of "win32" for npm) - */ +/** Get package name for a target (uses "windows" instead of "win32") */ function getPackageName(target: BuildTarget): string { const platformName = target.os === "win32" ? "windows" : target.os; return `sentry-${platformName}-${target.arch}`; } -/** - * Get Bun compile target string - */ +/** Get Bun compile target string */ function getBunTarget(target: BuildTarget): string { return `bun-${target.os}-${target.arch}`; } -/** - * Build for a single target - */ +/** Build for a single target */ async function buildTarget(target: BuildTarget): Promise { const packageName = getPackageName(target); const binaryName = target.os === "win32" ? "sentry.exe" : "sentry"; @@ -100,47 +89,58 @@ async function buildTarget(target: BuildTarget): Promise { return false; } - // Create package.json for this platform package - // Note: os field uses "win32" for Windows (npm's convention) - await Bun.file(`dist/${packageName}/package.json`).write( - JSON.stringify( - { - name: packageName, - version: VERSION, - os: [target.os], - cpu: [target.arch], - description: "Platform-specific binary for @betegon/sentry CLI", - }, - null, - 2 - ) - ); - console.log(` -> ${outfile}`); return true; } -/** - * Main build function - */ -async function build(): Promise> { +/** Parse target string (e.g., "darwin-x64" or "linux-arm64") into BuildTarget */ +function parseTarget(targetStr: string): BuildTarget | null { + // Handle "windows" alias for "win32" + const normalized = targetStr.replace("windows-", "win32-"); + const [os, arch] = normalized.split("-") as [ + BuildTarget["os"], + BuildTarget["arch"], + ]; + + const target = ALL_TARGETS.find((t) => t.os === os && t.arch === arch); + return target ?? null; +} + +/** Main build function */ +async function build(): Promise { const args = process.argv.slice(2); const singleBuild = args.includes("--single"); + const targetIndex = args.indexOf("--target"); + const targetArg = targetIndex !== -1 ? args[targetIndex + 1] : null; console.log(`\nSentry CLI Build v${VERSION}`); console.log("=".repeat(40)); if (!SENTRY_CLIENT_ID) { - console.warn( - "\nWarning: SENTRY_CLIENT_ID not set. OAuth will not work in the built binary." + console.error( + "\nError: SENTRY_CLIENT_ID environment variable is required." ); - console.warn(" Set it via: SENTRY_CLIENT_ID=xxx bun run build\n"); + console.error(" The CLI requires OAuth to function."); + console.error(" Set it via: SENTRY_CLIENT_ID=xxx bun run build\n"); + process.exit(1); } // Determine targets let targets: BuildTarget[]; - if (singleBuild) { + if (targetArg) { + // Explicit target specified (for cross-compilation) + const target = parseTarget(targetArg); + if (!target) { + console.error(`Invalid target: ${targetArg}`); + console.error( + `Valid targets: ${ALL_TARGETS.map((t) => `${t.os === "win32" ? "windows" : t.os}-${t.arch}`).join(", ")}` + ); + process.exit(1); + } + targets = [target]; + console.log(`\nBuilding for target: ${getPackageName(target)}`); + } else if (singleBuild) { const currentTarget = ALL_TARGETS.find( (t) => t.os === process.platform && t.arch === process.arch ); @@ -165,7 +165,6 @@ async function build(): Promise> { console.log(""); // Build all targets - const binaries: Record = {}; let successCount = 0; let failCount = 0; @@ -173,7 +172,6 @@ async function build(): Promise> { const success = await buildTarget(target); if (success) { successCount += 1; - binaries[getPackageName(target)] = VERSION; } else { failCount += 1; } @@ -186,10 +184,6 @@ async function build(): Promise> { if (failCount > 0) { process.exit(1); } - - return binaries; } -// Run build and export binaries for use by package.ts -const binaries = await build(); -export { binaries, VERSION }; +await build(); diff --git a/script/bundle.ts b/script/bundle.ts new file mode 100644 index 00000000..329efe5b --- /dev/null +++ b/script/bundle.ts @@ -0,0 +1,55 @@ +#!/usr/bin/env bun +/** + * Bundle script for npm package + * + * Creates a single-file Node.js bundle using esbuild. + * Injects Bun polyfills for Node.js compatibility. + * + * Usage: + * bun run script/bundle.ts + * + * Output: + * dist/bin.mjs - Minified, single-file bundle for npm + */ +import { build } from "esbuild"; +import pkg from "../package.json"; + +const VERSION = pkg.version; +const SENTRY_CLIENT_ID = process.env.SENTRY_CLIENT_ID ?? ""; + +console.log(`\nBundling sentry v${VERSION} for npm`); +console.log("=".repeat(40)); + +if (!SENTRY_CLIENT_ID) { + console.error("\nError: SENTRY_CLIENT_ID environment variable is required."); + console.error(" The CLI requires OAuth to function."); + console.error(" Set it via: SENTRY_CLIENT_ID=xxx bun run bundle\n"); + process.exit(1); +} + +const result = await build({ + entryPoints: ["./src/bin.ts"], + bundle: true, + minify: true, + platform: "node", + target: "node22", + format: "esm", + outfile: "./dist/bin.mjs", + inject: ["./script/node-polyfills.ts"], + define: { + SENTRY_CLI_VERSION: JSON.stringify(VERSION), + SENTRY_CLIENT_ID_BUILD: JSON.stringify(SENTRY_CLIENT_ID), + }, + // Only externalize Node.js built-ins - bundle all npm packages + external: ["node:*"], + metafile: true, +}); + +// Calculate bundle size +const outputs = Object.values(result.metafile?.outputs || {}); +const bundleSize = outputs.reduce((sum, out) => sum + out.bytes, 0); +const bundleSizeKB = (bundleSize / 1024).toFixed(1); + +console.log(`\n -> dist/bin.mjs (${bundleSizeKB} KB)`); +console.log(`\n${"=".repeat(40)}`); +console.log("Bundle complete!"); diff --git a/script/node-polyfills.ts b/script/node-polyfills.ts new file mode 100644 index 00000000..b014f8dc --- /dev/null +++ b/script/node-polyfills.ts @@ -0,0 +1,99 @@ +/** + * Node.js polyfills for Bun APIs + * + * Injected at esbuild bundle time to provide Node.js-compatible + * implementations of Bun globals. This allows the same source code + * to run on both Bun (native) and Node.js (polyfilled). + */ +import { execSync, spawn as nodeSpawn } from "node:child_process"; +import { access, readFile, writeFile } from "node:fs/promises"; + +import { glob } from "tinyglobby"; + +declare global { + var Bun: typeof BunPolyfill; +} + +const BunPolyfill = { + file(path: string) { + return { + async exists(): Promise { + try { + await access(path); + return true; + } catch { + return false; + } + }, + text(): Promise { + return readFile(path, "utf-8"); + }, + async json(): Promise { + const text = await readFile(path, "utf-8"); + return JSON.parse(text); + }, + }; + }, + + async write(path: string, content: string): Promise { + await writeFile(path, content, "utf-8"); + }, + + which(command: string): string | null { + try { + const isWindows = process.platform === "win32"; + const cmd = isWindows ? `where ${command}` : `which ${command}`; + return ( + execSync(cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }) + .trim() + .split("\n")[0] || null + ); + } catch { + return null; + } + }, + + spawn( + cmd: string[], + opts?: { stdout?: "pipe" | "ignore"; stderr?: "pipe" | "ignore" } + ) { + const [command, ...args] = cmd; + // Map Bun's stdout/stderr options to Node's stdio array format + // Currently only supports "ignore" - "pipe" would require returning streams + const stdio: ("pipe" | "ignore")[] = [ + "ignore", // stdin + opts?.stdout ?? "ignore", + opts?.stderr ?? "ignore", + ]; + const proc = nodeSpawn(command, args, { + detached: true, + stdio, + }); + return { + unref() { + proc.unref(); + }, + }; + }, + + sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + }, + + Glob: class BunGlobPolyfill { + private pattern: string; + constructor(pattern: string) { + this.pattern = pattern; + } + async *scan(opts?: { cwd?: string }): AsyncIterable { + const results = await glob(this.pattern, { + cwd: opts?.cwd || process.cwd(), + }); + for (const result of results) { + yield result; + } + } + }, +}; + +globalThis.Bun = BunPolyfill as typeof Bun; diff --git a/packages/cli/src/app.ts b/src/app.ts similarity index 86% rename from packages/cli/src/app.ts rename to src/app.ts index 0cf4fc28..4b76e72b 100644 --- a/packages/cli/src/app.ts +++ b/src/app.ts @@ -24,9 +24,12 @@ const routes = buildRouteMap({ }, }); +declare const SENTRY_CLI_VERSION: string; + export const app = buildApplication(routes, { name: "sentry", versionInfo: { - currentVersion: "0.1.0", + currentVersion: + typeof SENTRY_CLI_VERSION !== "undefined" ? SENTRY_CLI_VERSION : "0.0.0", }, }); diff --git a/packages/cli/src/bin.ts b/src/bin.ts similarity index 95% rename from packages/cli/src/bin.ts rename to src/bin.ts index 0995a3ba..21eaa1f2 100755 --- a/packages/cli/src/bin.ts +++ b/src/bin.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env bun +#!/usr/bin/env node import { run } from "@stricli/core"; import { app } from "./app.js"; import { buildContext } from "./context.js"; diff --git a/packages/cli/src/commands/api.ts b/src/commands/api.ts similarity index 100% rename from packages/cli/src/commands/api.ts rename to src/commands/api.ts diff --git a/packages/cli/src/commands/auth/index.ts b/src/commands/auth/index.ts similarity index 100% rename from packages/cli/src/commands/auth/index.ts rename to src/commands/auth/index.ts diff --git a/packages/cli/src/commands/auth/login.ts b/src/commands/auth/login.ts similarity index 100% rename from packages/cli/src/commands/auth/login.ts rename to src/commands/auth/login.ts diff --git a/packages/cli/src/commands/auth/logout.ts b/src/commands/auth/logout.ts similarity index 100% rename from packages/cli/src/commands/auth/logout.ts rename to src/commands/auth/logout.ts diff --git a/packages/cli/src/commands/auth/status.ts b/src/commands/auth/status.ts similarity index 100% rename from packages/cli/src/commands/auth/status.ts rename to src/commands/auth/status.ts diff --git a/packages/cli/src/commands/event/get.ts b/src/commands/event/get.ts similarity index 100% rename from packages/cli/src/commands/event/get.ts rename to src/commands/event/get.ts diff --git a/packages/cli/src/commands/event/index.ts b/src/commands/event/index.ts similarity index 100% rename from packages/cli/src/commands/event/index.ts rename to src/commands/event/index.ts diff --git a/packages/cli/src/commands/issue/get.ts b/src/commands/issue/get.ts similarity index 100% rename from packages/cli/src/commands/issue/get.ts rename to src/commands/issue/get.ts diff --git a/packages/cli/src/commands/issue/index.ts b/src/commands/issue/index.ts similarity index 100% rename from packages/cli/src/commands/issue/index.ts rename to src/commands/issue/index.ts diff --git a/packages/cli/src/commands/issue/list.ts b/src/commands/issue/list.ts similarity index 100% rename from packages/cli/src/commands/issue/list.ts rename to src/commands/issue/list.ts diff --git a/packages/cli/src/commands/org/get.ts b/src/commands/org/get.ts similarity index 100% rename from packages/cli/src/commands/org/get.ts rename to src/commands/org/get.ts diff --git a/packages/cli/src/commands/org/index.ts b/src/commands/org/index.ts similarity index 100% rename from packages/cli/src/commands/org/index.ts rename to src/commands/org/index.ts diff --git a/packages/cli/src/commands/org/list.ts b/src/commands/org/list.ts similarity index 100% rename from packages/cli/src/commands/org/list.ts rename to src/commands/org/list.ts diff --git a/packages/cli/src/commands/project/get.ts b/src/commands/project/get.ts similarity index 100% rename from packages/cli/src/commands/project/get.ts rename to src/commands/project/get.ts diff --git a/packages/cli/src/commands/project/index.ts b/src/commands/project/index.ts similarity index 100% rename from packages/cli/src/commands/project/index.ts rename to src/commands/project/index.ts diff --git a/packages/cli/src/commands/project/list.ts b/src/commands/project/list.ts similarity index 100% rename from packages/cli/src/commands/project/list.ts rename to src/commands/project/list.ts diff --git a/packages/cli/src/context.ts b/src/context.ts similarity index 100% rename from packages/cli/src/context.ts rename to src/context.ts diff --git a/packages/cli/src/lib/api-client.ts b/src/lib/api-client.ts similarity index 100% rename from packages/cli/src/lib/api-client.ts rename to src/lib/api-client.ts diff --git a/packages/cli/src/lib/browser.ts b/src/lib/browser.ts similarity index 100% rename from packages/cli/src/lib/browser.ts rename to src/lib/browser.ts diff --git a/packages/cli/src/lib/config.ts b/src/lib/config.ts similarity index 100% rename from packages/cli/src/lib/config.ts rename to src/lib/config.ts diff --git a/packages/cli/src/lib/dsn/cache.ts b/src/lib/dsn/cache.ts similarity index 100% rename from packages/cli/src/lib/dsn/cache.ts rename to src/lib/dsn/cache.ts diff --git a/packages/cli/src/lib/dsn/detector.ts b/src/lib/dsn/detector.ts similarity index 100% rename from packages/cli/src/lib/dsn/detector.ts rename to src/lib/dsn/detector.ts diff --git a/packages/cli/src/lib/dsn/env-file.ts b/src/lib/dsn/env-file.ts similarity index 100% rename from packages/cli/src/lib/dsn/env-file.ts rename to src/lib/dsn/env-file.ts diff --git a/packages/cli/src/lib/dsn/env.ts b/src/lib/dsn/env.ts similarity index 100% rename from packages/cli/src/lib/dsn/env.ts rename to src/lib/dsn/env.ts diff --git a/packages/cli/src/lib/dsn/errors.ts b/src/lib/dsn/errors.ts similarity index 100% rename from packages/cli/src/lib/dsn/errors.ts rename to src/lib/dsn/errors.ts diff --git a/packages/cli/src/lib/dsn/index.ts b/src/lib/dsn/index.ts similarity index 98% rename from packages/cli/src/lib/dsn/index.ts rename to src/lib/dsn/index.ts index ed716b16..af2541e5 100644 --- a/packages/cli/src/lib/dsn/index.ts +++ b/src/lib/dsn/index.ts @@ -1,3 +1,4 @@ +// biome-ignore-all lint/performance/noBarrelFile: intentional public API /** * DSN Detection Module * diff --git a/packages/cli/src/lib/dsn/languages/go.ts b/src/lib/dsn/languages/go.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/go.ts rename to src/lib/dsn/languages/go.ts diff --git a/packages/cli/src/lib/dsn/languages/index.ts b/src/lib/dsn/languages/index.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/index.ts rename to src/lib/dsn/languages/index.ts diff --git a/packages/cli/src/lib/dsn/languages/java.ts b/src/lib/dsn/languages/java.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/java.ts rename to src/lib/dsn/languages/java.ts diff --git a/packages/cli/src/lib/dsn/languages/javascript.ts b/src/lib/dsn/languages/javascript.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/javascript.ts rename to src/lib/dsn/languages/javascript.ts diff --git a/packages/cli/src/lib/dsn/languages/php.ts b/src/lib/dsn/languages/php.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/php.ts rename to src/lib/dsn/languages/php.ts diff --git a/packages/cli/src/lib/dsn/languages/python.ts b/src/lib/dsn/languages/python.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/python.ts rename to src/lib/dsn/languages/python.ts diff --git a/packages/cli/src/lib/dsn/languages/ruby.ts b/src/lib/dsn/languages/ruby.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/ruby.ts rename to src/lib/dsn/languages/ruby.ts diff --git a/packages/cli/src/lib/dsn/languages/types.ts b/src/lib/dsn/languages/types.ts similarity index 100% rename from packages/cli/src/lib/dsn/languages/types.ts rename to src/lib/dsn/languages/types.ts diff --git a/packages/cli/src/lib/dsn/parser.ts b/src/lib/dsn/parser.ts similarity index 100% rename from packages/cli/src/lib/dsn/parser.ts rename to src/lib/dsn/parser.ts diff --git a/packages/cli/src/lib/dsn/resolver.ts b/src/lib/dsn/resolver.ts similarity index 100% rename from packages/cli/src/lib/dsn/resolver.ts rename to src/lib/dsn/resolver.ts diff --git a/packages/cli/src/lib/dsn/types.ts b/src/lib/dsn/types.ts similarity index 100% rename from packages/cli/src/lib/dsn/types.ts rename to src/lib/dsn/types.ts diff --git a/packages/cli/src/lib/errors.ts b/src/lib/errors.ts similarity index 100% rename from packages/cli/src/lib/errors.ts rename to src/lib/errors.ts diff --git a/packages/cli/src/lib/formatters/colors.ts b/src/lib/formatters/colors.ts similarity index 100% rename from packages/cli/src/lib/formatters/colors.ts rename to src/lib/formatters/colors.ts diff --git a/packages/cli/src/lib/formatters/human.ts b/src/lib/formatters/human.ts similarity index 99% rename from packages/cli/src/lib/formatters/human.ts rename to src/lib/formatters/human.ts index a944744d..49bcbdd5 100644 --- a/packages/cli/src/lib/formatters/human.ts +++ b/src/lib/formatters/human.ts @@ -368,6 +368,7 @@ export function formatIssueDetails(issue: SentryIssue): string[] { * @param header - Optional header text (defaults to "Latest Event") * @returns Array of formatted lines */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: formatting logic export function formatEventDetails( event: SentryEvent, header = "Latest Event" diff --git a/packages/cli/src/lib/formatters/index.ts b/src/lib/formatters/index.ts similarity index 72% rename from packages/cli/src/lib/formatters/index.ts rename to src/lib/formatters/index.ts index 7fa2aa73..18b088a9 100644 --- a/packages/cli/src/lib/formatters/index.ts +++ b/src/lib/formatters/index.ts @@ -1,3 +1,4 @@ +// biome-ignore-all lint/performance/noBarrelFile: intentional public API /** * Formatters * diff --git a/packages/cli/src/lib/formatters/json.ts b/src/lib/formatters/json.ts similarity index 100% rename from packages/cli/src/lib/formatters/json.ts rename to src/lib/formatters/json.ts diff --git a/packages/cli/src/lib/formatters/output.ts b/src/lib/formatters/output.ts similarity index 100% rename from packages/cli/src/lib/formatters/output.ts rename to src/lib/formatters/output.ts diff --git a/packages/cli/src/lib/oauth.ts b/src/lib/oauth.ts similarity index 99% rename from packages/cli/src/lib/oauth.ts rename to src/lib/oauth.ts index 9645cc6f..d969b5b1 100644 --- a/packages/cli/src/lib/oauth.ts +++ b/src/lib/oauth.ts @@ -27,7 +27,7 @@ const SENTRY_URL = process.env.SENTRY_URL ?? "https://sentry.io"; * Build-time: Injected via Bun.build({ define: { SENTRY_CLIENT_ID: "..." } }) * Runtime: Can be overridden via SENTRY_CLIENT_ID env var (for self-hosted) * - * @see packages/cli/script/build.ts + * @see script/build.ts */ declare const SENTRY_CLIENT_ID_BUILD: string | undefined; const SENTRY_CLIENT_ID = diff --git a/packages/cli/src/lib/qrcode.ts b/src/lib/qrcode.ts similarity index 100% rename from packages/cli/src/lib/qrcode.ts rename to src/lib/qrcode.ts diff --git a/packages/cli/src/lib/resolve-target.ts b/src/lib/resolve-target.ts similarity index 100% rename from packages/cli/src/lib/resolve-target.ts rename to src/lib/resolve-target.ts diff --git a/packages/cli/src/types/config.ts b/src/types/config.ts similarity index 100% rename from packages/cli/src/types/config.ts rename to src/types/config.ts diff --git a/packages/cli/src/types/index.ts b/src/types/index.ts similarity index 93% rename from packages/cli/src/types/index.ts rename to src/types/index.ts index cc01d24b..d172efc1 100644 --- a/packages/cli/src/types/index.ts +++ b/src/types/index.ts @@ -1,3 +1,4 @@ +// biome-ignore-all lint/performance/noBarrelFile: intentional public API /** * Type definitions for the Sentry CLI * diff --git a/packages/cli/src/types/oauth.ts b/src/types/oauth.ts similarity index 100% rename from packages/cli/src/types/oauth.ts rename to src/types/oauth.ts diff --git a/packages/cli/src/types/sentry.ts b/src/types/sentry.ts similarity index 100% rename from packages/cli/src/types/sentry.ts rename to src/types/sentry.ts diff --git a/packages/cli/test/commands/api.test.ts b/test/commands/api.test.ts similarity index 98% rename from packages/cli/test/commands/api.test.ts rename to test/commands/api.test.ts index 143d5581..bfed9232 100644 --- a/packages/cli/test/commands/api.test.ts +++ b/test/commands/api.test.ts @@ -1,3 +1,4 @@ +// biome-ignore-all lint/performance/useTopLevelRegex: regex in test assertions is fine /** * API Command Unit Tests * diff --git a/packages/cli/test/e2e/api.test.ts b/test/e2e/api.test.ts similarity index 100% rename from packages/cli/test/e2e/api.test.ts rename to test/e2e/api.test.ts diff --git a/packages/cli/test/e2e/auth.test.ts b/test/e2e/auth.test.ts similarity index 100% rename from packages/cli/test/e2e/auth.test.ts rename to test/e2e/auth.test.ts diff --git a/packages/cli/test/e2e/event.test.ts b/test/e2e/event.test.ts similarity index 100% rename from packages/cli/test/e2e/event.test.ts rename to test/e2e/event.test.ts diff --git a/packages/cli/test/e2e/issue.test.ts b/test/e2e/issue.test.ts similarity index 100% rename from packages/cli/test/e2e/issue.test.ts rename to test/e2e/issue.test.ts diff --git a/packages/cli/test/e2e/project.test.ts b/test/e2e/project.test.ts similarity index 52% rename from packages/cli/test/e2e/project.test.ts rename to test/e2e/project.test.ts index bdbafb29..9133ff62 100644 --- a/packages/cli/test/e2e/project.test.ts +++ b/test/e2e/project.test.ts @@ -56,30 +56,38 @@ describe("sentry org list", () => { expect(result.stderr + result.stdout).toMatch(/not authenticated|login/i); }); - test("lists organizations with valid auth", async () => { - await setAuthToken(TEST_TOKEN); + test( + "lists organizations with valid auth", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli(["org", "list"], { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - }); + const result = await runCli(["org", "list"], { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + }); - expect(result.exitCode).toBe(0); - // Should contain header and at least one org - expect(result.stdout).toContain("SLUG"); - }); + expect(result.exitCode).toBe(0); + // Should contain header and at least one org + expect(result.stdout).toContain("SLUG"); + }, + { timeout: 15_000 } + ); - test("supports --json output", async () => { - await setAuthToken(TEST_TOKEN); + test( + "supports --json output", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli(["org", "list", "--json"], { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - }); + const result = await runCli(["org", "list", "--json"], { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + }); - expect(result.exitCode).toBe(0); - const data = JSON.parse(result.stdout); - expect(Array.isArray(data)).toBe(true); - expect(data.length).toBeGreaterThan(0); - }); + expect(result.exitCode).toBe(0); + const data = JSON.parse(result.stdout); + expect(Array.isArray(data)).toBe(true); + expect(data.length).toBeGreaterThan(0); + }, + { timeout: 15_000 } + ); }); describe("sentry project list", () => { @@ -92,35 +100,43 @@ describe("sentry project list", () => { expect(result.stderr + result.stdout).toMatch(/not authenticated|login/i); }); - test("lists projects with valid auth and org filter", async () => { - await setAuthToken(TEST_TOKEN); + test( + "lists projects with valid auth and org filter", + async () => { + await setAuthToken(TEST_TOKEN); - // Use --org flag to filter by organization - const result = await runCli( - ["project", "list", "--org", TEST_ORG, "--limit", "5"], - { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - } - ); + // Use --org flag to filter by organization + const result = await runCli( + ["project", "list", "--org", TEST_ORG, "--limit", "5"], + { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + } + ); - expect(result.exitCode).toBe(0); - }); + expect(result.exitCode).toBe(0); + }, + { timeout: 15_000 } + ); - test("supports --json output", async () => { - await setAuthToken(TEST_TOKEN); + test( + "supports --json output", + async () => { + await setAuthToken(TEST_TOKEN); - // Use --org flag to filter by organization - const result = await runCli( - ["project", "list", "--org", TEST_ORG, "--json", "--limit", "5"], - { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - } - ); + // Use --org flag to filter by organization + const result = await runCli( + ["project", "list", "--org", TEST_ORG, "--json", "--limit", "5"], + { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + } + ); - expect(result.exitCode).toBe(0); - const data = JSON.parse(result.stdout); - expect(Array.isArray(data)).toBe(true); - }); + expect(result.exitCode).toBe(0); + const data = JSON.parse(result.stdout); + expect(Array.isArray(data)).toBe(true); + }, + { timeout: 15_000 } + ); }); describe("sentry org get", () => { @@ -133,40 +149,52 @@ describe("sentry org get", () => { expect(result.stderr + result.stdout).toMatch(/not authenticated|login/i); }); - test("gets organization details", async () => { - await setAuthToken(TEST_TOKEN); + test( + "gets organization details", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli(["org", "get", TEST_ORG], { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - }); + const result = await runCli(["org", "get", TEST_ORG], { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + }); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(TEST_ORG); - expect(result.stdout).toContain("Slug:"); - }); + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain(TEST_ORG); + expect(result.stdout).toContain("Slug:"); + }, + { timeout: 15_000 } + ); - test("supports --json output", async () => { - await setAuthToken(TEST_TOKEN); + test( + "supports --json output", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli(["org", "get", TEST_ORG, "--json"], { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - }); + const result = await runCli(["org", "get", TEST_ORG, "--json"], { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + }); - expect(result.exitCode).toBe(0); - const data = JSON.parse(result.stdout); - expect(data.slug).toBe(TEST_ORG); - }); + expect(result.exitCode).toBe(0); + const data = JSON.parse(result.stdout); + expect(data.slug).toBe(TEST_ORG); + }, + { timeout: 15_000 } + ); - test("handles non-existent org", async () => { - await setAuthToken(TEST_TOKEN); + test( + "handles non-existent org", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli(["org", "get", "nonexistent-org-12345"], { - env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, - }); + const result = await runCli(["org", "get", "nonexistent-org-12345"], { + env: { SENTRY_CLI_CONFIG_DIR: testConfigDir }, + }); - expect(result.exitCode).toBe(1); - expect(result.stderr + result.stdout).toMatch(/not found|error|404/i); - }); + expect(result.exitCode).toBe(1); + expect(result.stderr + result.stdout).toMatch(/not found|error|404/i); + }, + { timeout: 15_000 } + ); }); describe("sentry project get", () => { @@ -204,31 +232,39 @@ describe("sentry project get", () => { ); }); - test("gets project details", async () => { - await setAuthToken(TEST_TOKEN); + test( + "gets project details", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli( - ["project", "get", TEST_PROJECT, "--org", TEST_ORG], - { env: { SENTRY_CLI_CONFIG_DIR: testConfigDir } } - ); + const result = await runCli( + ["project", "get", TEST_PROJECT, "--org", TEST_ORG], + { env: { SENTRY_CLI_CONFIG_DIR: testConfigDir } } + ); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(TEST_PROJECT); - expect(result.stdout).toContain("Slug:"); - }); + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain(TEST_PROJECT); + expect(result.stdout).toContain("Slug:"); + }, + { timeout: 15_000 } + ); - test("supports --json output", async () => { - await setAuthToken(TEST_TOKEN); + test( + "supports --json output", + async () => { + await setAuthToken(TEST_TOKEN); - const result = await runCli( - ["project", "get", TEST_PROJECT, "--org", TEST_ORG, "--json"], - { env: { SENTRY_CLI_CONFIG_DIR: testConfigDir } } - ); + const result = await runCli( + ["project", "get", TEST_PROJECT, "--org", TEST_ORG, "--json"], + { env: { SENTRY_CLI_CONFIG_DIR: testConfigDir } } + ); - expect(result.exitCode).toBe(0); - const data = JSON.parse(result.stdout); - expect(data.slug).toBe(TEST_PROJECT); - }); + expect(result.exitCode).toBe(0); + const data = JSON.parse(result.stdout); + expect(data.slug).toBe(TEST_PROJECT); + }, + { timeout: 15_000 } + ); test( "handles non-existent project", @@ -243,6 +279,6 @@ describe("sentry project get", () => { expect(result.exitCode).toBe(1); expect(result.stderr + result.stdout).toMatch(/not found|error|404/i); }, - { timeout: 15000 } + { timeout: 15_000 } ); }); diff --git a/packages/cli/test/fixture.ts b/test/fixture.ts similarity index 99% rename from packages/cli/test/fixture.ts rename to test/fixture.ts index 8a9b7783..849c226b 100644 --- a/packages/cli/test/fixture.ts +++ b/test/fixture.ts @@ -89,11 +89,11 @@ export function mockProcess() { // CLI Runner // ───────────────────────────────────────────────────────────────────────────── -export interface CliResult { +export type CliResult = { stdout: string; stderr: string; exitCode: number; -} +}; /** * Run CLI command and capture output diff --git a/packages/cli/test/lib/config.test.ts b/test/lib/config.test.ts similarity index 100% rename from packages/cli/test/lib/config.test.ts rename to test/lib/config.test.ts diff --git a/packages/cli/test/lib/dsn.test.ts b/test/lib/dsn.test.ts similarity index 100% rename from packages/cli/test/lib/dsn.test.ts rename to test/lib/dsn.test.ts diff --git a/packages/cli/test/lib/dsn/cache.test.ts b/test/lib/dsn/cache.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/cache.test.ts rename to test/lib/dsn/cache.test.ts diff --git a/packages/cli/test/lib/dsn/detector.test.ts b/test/lib/dsn/detector.test.ts similarity index 98% rename from packages/cli/test/lib/dsn/detector.test.ts rename to test/lib/dsn/detector.test.ts index b55d606c..ed8809ea 100644 --- a/packages/cli/test/lib/dsn/detector.test.ts +++ b/test/lib/dsn/detector.test.ts @@ -46,11 +46,11 @@ describe("DSN Detector (New Module)", () => { // Clear any cached DSN for the test directory await clearDsnCache(testDir); // Clear SENTRY_DSN env var - process.env.SENTRY_DSN = undefined; + delete process.env.SENTRY_DSN; }); afterEach(() => { - process.env.SENTRY_DSN = undefined; + delete process.env.SENTRY_DSN; cleanupDir(testDir); cleanupDir(TEST_CONFIG_DIR); }); @@ -169,7 +169,9 @@ describe("DSN Detector (New Module)", () => { const distDsn = "https://dist@o222.ingest.sentry.io/222"; // Put DSNs in directories that should be skipped - mkdirSync(join(testDir, "node_modules/some-package"), { recursive: true }); + mkdirSync(join(testDir, "node_modules/some-package"), { + recursive: true, + }); writeFileSync( join(testDir, "node_modules/some-package/index.js"), `Sentry.init({ dsn: "${nodeModulesDsn}" })` diff --git a/packages/cli/test/lib/dsn/languages/go.test.ts b/test/lib/dsn/languages/go.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/languages/go.test.ts rename to test/lib/dsn/languages/go.test.ts diff --git a/packages/cli/test/lib/dsn/languages/java.test.ts b/test/lib/dsn/languages/java.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/languages/java.test.ts rename to test/lib/dsn/languages/java.test.ts diff --git a/packages/cli/test/lib/dsn/languages/javascript.test.ts b/test/lib/dsn/languages/javascript.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/languages/javascript.test.ts rename to test/lib/dsn/languages/javascript.test.ts diff --git a/packages/cli/test/lib/dsn/languages/php.test.ts b/test/lib/dsn/languages/php.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/languages/php.test.ts rename to test/lib/dsn/languages/php.test.ts diff --git a/packages/cli/test/lib/dsn/languages/python.test.ts b/test/lib/dsn/languages/python.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/languages/python.test.ts rename to test/lib/dsn/languages/python.test.ts diff --git a/packages/cli/test/lib/dsn/languages/ruby.test.ts b/test/lib/dsn/languages/ruby.test.ts similarity index 100% rename from packages/cli/test/lib/dsn/languages/ruby.test.ts rename to test/lib/dsn/languages/ruby.test.ts diff --git a/packages/cli/test/preload.ts b/test/preload.ts similarity index 91% rename from packages/cli/test/preload.ts rename to test/preload.ts index b2653075..b820cb70 100644 --- a/packages/cli/test/preload.ts +++ b/test/preload.ts @@ -11,15 +11,19 @@ import { join, resolve } from "node:path"; // Load .env.local for test credentials (SENTRY_TEST_*) // This mimics what would happen in CI where secrets are injected as env vars -const envLocalPath = resolve(import.meta.dir, "../../../.env.local"); +const envLocalPath = resolve(import.meta.dir, "../.env.local"); if (existsSync(envLocalPath)) { const content = readFileSync(envLocalPath, "utf-8"); for (const line of content.split("\n")) { const trimmed = line.trim(); - if (!trimmed || trimmed.startsWith("#")) continue; + if (!trimmed || trimmed.startsWith("#")) { + continue; + } const eqIndex = trimmed.indexOf("="); - if (eqIndex === -1) continue; + if (eqIndex === -1) { + continue; + } const key = trimmed.slice(0, eqIndex).trim(); let value = trimmed.slice(eqIndex + 1).trim(); diff --git a/packages/cli/tsconfig.json b/tsconfig.json similarity index 100% rename from packages/cli/tsconfig.json rename to tsconfig.json diff --git a/turbo.json b/turbo.json deleted file mode 100644 index 40d21258..00000000 --- a/turbo.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://turbo.build/schema.json", - "tasks": { - "build": { - "dependsOn": ["^build"], - "outputs": ["dist/**", "dist-bin/**"] - }, - "dev": { - "cache": false, - "persistent": true - }, - "lint": { - "dependsOn": ["^lint"] - }, - "lint:fix": { - "cache": false - }, - "typecheck": { - "dependsOn": ["^typecheck"] - } - } -}