Dashboard › cli › Session 0nMvfr5aBdC4
0nMvfr5aBdC45KeEdREAD-ONLY correctness merge-gate review getsentry/cli PR #1569 exact base ec83887a16f780f32fba4b7d710bad262dba3a22 head 4a1d5bad105c006193c68459175f5eb3c7f78e08 worktree /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade. Verify clean immutable state; inspect all changed files/tests. Entire bridge: pinned bypasses latest; channel selectors latest; 404-only fallback; source affinity; canonical paginated highest SemVer; strict/exact nightly annotations; raw HTTP and raw/normalized prefetched changelog filtering; GHCR AbortError/token/redirect; delta/full/cache/offline/API compatibility. Last commit only updates stale exact-tag test fixture and request count. Intentional nightly repo probe/source-neutral verified cache. Return NON-EMPTY findings-first PASS/CONCERN/MUST-FIX/BLOCKED report with exact current file:line, deterministic regressions, residual gaps. Final line exactly MERGE or DO-NOT-MERGE. Never modify. Empty forbidden.
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/AGENTS.md</path> <type>file</type> <content> 1: # Jared (Outpost agent) 2: 3: Autonomous GitHub coding agent. Work in `/workspace/repo`. 4: 5: ## Model tiers 6: 7: The primary model is chosen per event (see `src/agents/models.ts`): heavy for 8: code-producing situations, cheaper for lightweight ones. 9: 10: | Role | Subagent | Model | 11: | --- | --- | --- | 12: | Triage / plan / review (heavy) | (primary Jared) | Claude Opus 4.8 | 13: | Triage / plan / review (light) | (primary Jared) | xAI Grok 4.3 | 14: | Explore | `explore` | OpenAI gpt-5-mini | 15: | Implement | `implement` | Moonshot kimi-k2.7-code | 16: | Ship (commit/push/PR) | `ship` | xAI Grok (`grok-build-0.1`) | 17: 18: Pipeline: triage → explore → plan → implement → review → ship. 19: (`worker` is a deprecated alias of `implement`.) 20: 21: Operators also talk to Jared directly from the Outpost dashboard. ...
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/.lore.md /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/package.json /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/package.json /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/codemods/sentry-v3-to-v4/package.json /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/apps/local/package.json /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/apps/cli-docs/package.json /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/init-eval/templates/sveltekit-app/package.json /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb...
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/.lore.md</path>
<type>file</type>
<content>
1: <!-- Managed by lore (https://github.com/BYK/loreai) — manual edits are imported on next session. -->
2:
3: ## Long-term Knowledge
4:
5: ### Architecture
6:
7: <!-- lore:01a02357-f0a8-7fdb-9e9d-b0710cfe65c9 -->
8: * **API output binary and HTTP contracts**: Always preserve strict output-mode and binary-safety contracts. `sentry api` must preserve `rawApiRequest()` status text; empty textual non-2xx bodies must produce an HTTP status/request fallback, and JSON mode must expose `{status, statusText, body}` so empty success and error responses are distinguishable. Binary `Uint8Array` successes bypass formatters and remain raw; binary errors emit only status/content-type/byte-count summaries, never bytes or JSON coercion. Prompts must never block scripted runs or interleave with stdout JSON.
9:
10: <!-- ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/CONTRIBUTING.md</path> <type>file</type> <content> 1: # Contributing to Sentry CLI 2: 3: This guide documents the patterns and conventions used in this CLI for consistency. 4: 5: ## Command Patterns 6: 7: We follow [gh CLI](https://cli.github.com/) conventions for best-in-class developer experience. 8: 9: ### List Commands 10: 11: List commands use **optional positional arguments** for context with smart auto-detection. 12: 13: ```bash 14: sentry org list [--limit N] [--json] 15: sentry project list [org] [--limit N] [--json] 16: sentry issue list [<org>/<project>] [--json] 17: ``` 18: 19: **Target syntax**: 20: - `<org>/<project>` - Explicit organization and project (e.g., `my-org/frontend`) 21: - `<org>/` - All projects in the specified organization 22: - `<project>` - Search for project by name across all accessible organizations 23: - *(omit)* - ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "toolkit-cli-workspace",
3: "version": "0.0.0",
4: "private": true,
5: "type": "module",
6: "packageManager": "pnpm@10.11.0",
7: "engines": {
8: "node": ">=20.0"
9: },
10: "scripts": {
11: "tsx": "pnpm --filter sentry run tsx",
12: "cli": "pnpm --filter sentry run cli",
13: "dev": "pnpm --filter sentry run dev",
14: "build": "pnpm --filter sentry run build",
15: "build:all": "pnpm --filter sentry run build:all",
16: "bundle": "pnpm --filter sentry run bundle",
17: "typecheck": "pnpm --filter sentry run typecheck",
18: "lint": "pnpm --filter sentry run lint",
19: "lint:fix": "pnpm --filter sentry run lint:fix",
20: "test": "pnpm --filter sentry run test",
21: "test:unit": "pnpm --filter sentry run test:unit",
22: "test:changed": "pnpm --filter ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/package.json</path>
<type>file</type>
<content>
1: {
2: "name": "sentry",
3: "version": "0.45.0-dev.0",
4: "description": "Sentry CLI - A command-line interface for using Sentry built by robots and humans for robots and humans",
5: "repository": {
6: "type": "git",
7: "url": "git+https://github.com/getsentry/cli.git"
8: },
9: "main": "./dist/index.cjs",
10: "type": "module",
11: "types": "./dist/index.d.cts",
12: "exports": {
13: ".": {
14: "import": {
15: "types": "./dist/index.d.mts",
16: "default": "./dist/index.mjs"
17: },
18: "require": {
19: "types": "./dist/index.d.cts",
20: "default": "./dist/index.cjs"
21: }
22: }
23: },
24: "bin": {
25: "sentry": "./dist/bin.cjs"
26: },
27: "files": [
28: "dist/bin.cjs",
29: "dist/index.cjs",
30: ...
4a1d5bad105c006193c68459175f5eb3c7f78e08 ec83887a16f780f32fba4b7d710bad262dba3a22 M packages/cli/src/commands/cli/upgrade.ts M packages/cli/src/lib/binary.ts M packages/cli/src/lib/delta-upgrade.ts M packages/cli/src/lib/ghcr.ts M packages/cli/src/lib/release-notes.ts M packages/cli/src/lib/upgrade.ts M packages/cli/src/lib/version-check.ts M packages/cli/test/commands/cli.test.ts M packages/cli/test/commands/cli/upgrade.test.ts M packages/cli/test/lib/binary.test.ts M packages/cli/test/lib/delta-upgrade.mocked.test.ts M packages/cli/test/lib/delta-upgrade.test.ts M packages/cli/test/lib/ghcr.test.ts M packages/cli/test/lib/release-notes.test.ts M packages/cli/test/lib/upgrade.test.ts M packages/cli/test/lib/version-check.test.ts bd98f2d9f7e5ce09a4d1271fb230d763348e59068ac12de292898fb8697b7fc5 - 4a1d5bad1 (HEAD -> feat/toolkit-bridge-upgrade, origin/feat/toolkit-bridge-upgrade) test(cli): update pinned version fixture packages/cli/test/commands/cli.test.ts | 10 +--------- 1 file ...
packages/cli/src/commands/cli/upgrade.ts | 149 ++++-- packages/cli/src/lib/binary.ts | 154 +++++- packages/cli/src/lib/delta-upgrade.ts | 139 ++++-- packages/cli/src/lib/ghcr.ts | 91 +++- packages/cli/src/lib/release-notes.ts | 140 ++++-- packages/cli/src/lib/upgrade.ts | 414 ++++++++++++++--- packages/cli/src/lib/version-check.ts | 21 +- packages/cli/test/commands/cli.test.ts | 29 +- packages/cli/test/commands/cli/upgrade.test.ts | 134 +++++- packages/cli/test/lib/binary.test.ts | 130 +++++- packages/cli/test/lib/delta-upgrade.mocked.test.ts | 14 +- packages/cli/test/lib/delta-upgrade.test.ts | 201 +++++++- packages/cli/test/lib/ghcr.test.ts | 107 ++++- packages/cli/test/lib/release-notes.test.ts | 185 +++++++- packages/cli/test/lib/upgrade.test.ts | 517 +++++++++++++++++++-- ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path> <type>file</type> <content> 1: /** 2: * sentry cli upgrade 3: * 4: * Self-update the Sentry CLI to the latest or a specific version. 5: * After upgrading, spawns the NEW binary with `cli setup` to update 6: * completions, agent skills, and record installation metadata. 7: * 8: * Supports two release channels: 9: * - stable (default): tracks the latest GitHub release 10: * - nightly: tracks the rolling nightly prerelease built from main 11: * 12: * The channel can be set via --channel or by passing "nightly"/"stable" 13: * as the version argument. The choice is persisted in the local database 14: * so that subsequent bare `sentry cli upgrade` calls use the same channel. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
1: /**
2: * Binary Management
3: *
4: * Shared utilities for installing, replacing, and managing the CLI binary.
5: * Used by both `setup --install` (fresh installs) and `upgrade` (self-updates).
6: */
7:
8: import { spawnSync } from "node:child_process";
9: import {
10: existsSync,
11: mkdirSync,
12: readFileSync,
13: renameSync,
14: unlinkSync,
15: writeFileSync,
16: } from "node:fs";
17: import { chmod, copyFile, mkdir, realpath, unlink } from "node:fs/promises";
18: import { delimiter, dirname, isAbsolute, join, resolve, sep } from "node:path";
19: import { compare as semverCompare } from "semver";
20: import { getUserAgent } from "./constants.js";
21: import {
22: buildTlsErrorDetail,
23: customFetch,
24: isTlsCertError,
25: } from "./custom-ca.js";
26: import { stringifyUnknown, ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts</path>
<type>file</type>
<content>
1: /** Delta upgrade discovery and application backed by binpatch. */
2:
3: import { join } from "node:path";
4: // biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
5: import * as Sentry from "@sentry/node-core/light";
6: import {
7: applyPatchChainInMemory,
8: extractStableChain as binpatchExtractStableChain,
9: filterAndSortChainTags as binpatchFilterAndSortChainTags,
10: validateChainStep as binpatchValidateChainStep,
11: type DeltaTelemetry,
12: type DeltaUnavailableReason,
13: type ExtractStableChainOpts,
14: type GitHubRelease,
15: getPatchFromVersion,
16: getPatchTargetSha256,
17: ghcrSource,
18: githubReleaseSource,
19: type InstrumentHook,
20: MAX_NIGHTLY_CHAIN_DEPTH,
21: makeCache,
22: OciClient,
23: type OciManifest,
24: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/ghcr.ts</path> <type>file</type> <content> 1: /** 2: * GHCR (GitHub Container Registry) Client 3: * 4: * Encapsulates the OCI download protocol for fetching nightly CLI binaries 5: * from ghcr.io/getsentry/cli. Nightly builds are pushed as OCI artifacts 6: * via ORAS with the version baked into the manifest annotation. 7: * 8: * Key design decisions: 9: * - Anonymous access: nightly package is public; no token needed beyond the 10: * standard ghcr.io anonymous token exchange. 11: * - Version discovery from manifest annotation: `annotations.version` in the 12: * OCI manifest holds the nightly version. Checking the latest version only 13: * requires a token exchange + manifest fetch (2 HTTP requests total). 14: * - Redirect quirk: ghcr.io blob downloads return 307 to Azure Blob Storage. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts</path> <type>file</type> <content> 1: /** 2: * Release Notes Parser & Aggregation 3: * 4: * Extracts user-facing changelog entries from GitHub Release bodies (stable) 5: * or conventional commit messages (nightly). Uses `marked.lexer()` for 6: * AST-based section extraction and produces structured data that can be 7: * re-serialized as filtered markdown for rendering via `renderMarkdown()`. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
1: /**
2: * Upgrade Module
3: *
4: * Detects how the CLI was installed and provides self-upgrade functionality.
5: * Binary management helpers (download URLs, locking, replacement) live in
6: * binary.ts and are shared with the setup --install flow.
7: */
8:
9: import { spawn } from "node:child_process";
10: import {
11: chmodSync,
12: closeSync,
13: existsSync,
14: openSync,
15: realpathSync,
16: statSync,
17: unlinkSync,
18: writeSync,
19: } from "node:fs";
20: import { writeFile } from "node:fs/promises";
21: import { homedir } from "node:os";
22: import { dirname, isAbsolute, join, sep } from "node:path";
23: import { setTimeout } from "node:timers/promises";
24: import { valid as semverValid } from "semver";
25: import {
26: acquireLock,
27: cleanupOldBinary,
28: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts</path>
<type>file</type>
<content>
1: /**
2: * Background version check for "new version available" notifications.
3: *
4: * For nightly builds (CLI_VERSION contains "-dev.<timestamp>"), checks GHCR for the
5: * latest nightly version via the OCI manifest annotation. For stable builds,
6: * checks GitHub Releases. Results are cached in the database and shown on
7: * subsequent runs.
8: */
9:
10: // biome-ignore lint/performance/noNamespaceImport: Sentry SDK recommends namespace import
11: import * as Sentry from "@sentry/node-core/light";
12: import { compare as semverCompare } from "semver";
13: import type { UpgradeSource } from "./binary.js";
14: import { CLI_VERSION } from "./constants.js";
15: import { getReleaseChannel } from "./db/release-channel.js";
16: import {
17: getVersionCheckInfo,
18: markUpdateNotified,
19: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
984: async *func(this: SentryContext, flags: UpgradeFlags, version?: string) {
985: const { channel, versionArg, channelChanged, method } =
986: await resolveContext(version, flags);
987:
988: log.debug(`Installation method: ${method}`);
989: log.debug(`Current version: ${CLI_VERSION}`);
990:
991: const resolved = await withProgress(
992: { message: "Checking for updates...", json: flags.json },
993: async () =>
994: resolveTargetWithFallback({
995: resolveOpts: { method, channel, versionArg, channelChanged, flags },
996: versionArg,
997: offline: flags.offline,
998: method,
999: persistChannelFn: () =>
1000: persistChannel(channel, channelChanged, version),
1001: })
1002: );
1003: ...
...output truncated...
Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_08947196f001rzlMEWlhKE7avN
// separator (e.g. `/custom/bin//`) that would break the startsWith checks.
paths.push(join(xdgBinHome, ".") + sep);
}
return paths;
}
/**
* Memoized known curl paths. Computed lazily (not at module load) to avoid TDZ
* issues from circular imports — `KNOWN_CURL_DIRS` must be fully initialized
* before access.
*/
let _knownCurlPaths: string[] | undefined;
function getKnownCurlPaths(): string[] {
_knownCurlPaths ??= buildKnownCurlPaths(homedir(), process.env);
return _knownCurlPaths;
}
/**
* Get file paths for curl-installed binary.
*
* Priority for determining install path:
* 1. Stored install path from DB (if method is curl AND its directory still
* exists — a stale path whose directory was purged is skipped)
* 2. process.execPath if it's in a known curl install location
* 3. ...
231 packages/cli/test/commands/cli.test.ts 1296 packages/cli/test/commands/cli/upgrade.test.ts 916 packages/cli/test/lib/binary.test.ts 500 packages/cli/test/lib/delta-upgrade.mocked.test.ts 2015 packages/cli/test/lib/delta-upgrade.test.ts 655 packages/cli/test/lib/ghcr.test.ts 476 packages/cli/test/lib/release-notes.test.ts 2613 packages/cli/test/lib/upgrade.test.ts 670 packages/cli/test/lib/version-check.test.ts 9372 total
diff --git a/packages/cli/test/commands/cli.test.ts b/packages/cli/test/commands/cli.test.ts
index cd1514eb0..124e91b8f 100644
--- a/packages/cli/test/commands/cli.test.ts
+++ b/packages/cli/test/commands/cli.test.ts
@@ -97,140 +97,135 @@ describe("feedbackCommand.func", () => {
// Sentry is disabled in test environment (no DSN)
await expect(
func.call(mockContext, {}, "test", "feedback")
).rejects.toThrow("Feedback not sent: telemetry is disabled.");
});
});
// Test the upgrade command func
describe("upgradeCommand.func", () => {
let originalFetch: typeof globalThis.fetch;
let restoreStderr: (() => void) | undefined;
beforeEach(() => {
originalFetch = globalThis.fetch;
});
afterEach(() => {
restoreStderr?.();
restoreStderr = undefined;
globalThis.fetch = originalFetch;
});
// Note: We skip testing "unknown installation method" case because
// detectInstallationMethod() runs actual shell commands (npm ...
diff --git a/packages/cli/test/lib/delta-upgrade.mocked.test.ts b/packages/cli/test/lib/delta-upgrade.mocked.test.ts
index cd0a2fddc..f6186ab59 100644
--- a/packages/cli/test/lib/delta-upgrade.mocked.test.ts
+++ b/packages/cli/test/lib/delta-upgrade.mocked.test.ts
@@ -77,75 +77,75 @@ function versionHex(version: string): string {
.map((c) => c.charCodeAt(0).toString(16).padStart(2, "0"))
.join("");
}
function tempFile(name: string): string {
return join(
tmpdir(),
`delta-iso-${Date.now()}-${Math.random().toString(36).slice(2)}-${name}`
);
}
// ============================================================================
// resolveStableDelta
// ============================================================================
describe("resolveStableDelta", () => {
test("resolves and applies a stable delta patch", async () => {
// Create a "current binary" to patch from
const oldBinaryPath = tempFile("old-binary.bin");
const destPath = ...
...output truncated...
Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_089484e18001ZCSLR22n9WagCa
+ originalFetch = globalThis.fetch;
+ });
+
+ afterEach(() => {
+ globalThis.fetch = originalFetch;
+ });
+
+ test("fetches stable releases only from the explicitly selected Toolkit source", async () => {
+ const requestedUrls: string[] = [];
+ globalThis.fetch = mockFetch(async (input) => {
+ requestedUrls.push(String(input));
+ return new Response(
+ JSON.stringify([
+ makeRelease(
+ "mcp@99.0.0",
+ "### New Features ✨\n\n- Unrelated Toolkit package release"
+ ),
+ makeRelease(
+ "0.21.0",
+ "### Bug Fixes 🐛\n\n- Unprefixed Toolkit release"
+ ),
+ makeRelease(
+ "cli@0.21.0",
+ "### Bug Fixes 🐛\n\n- Keep release stages source-affine"
+ ),
+ ]),
+ { status: 200 }
+ );
+ });
+
+ const ...
<path>/home/byk/.local/share/opencode/tool-output/tool_089484e18001ZCSLR22n9WagCa</path>
<type>file</type>
<content>
1: diff --git a/packages/cli/test/lib/release-notes.test.ts b/packages/cli/test/lib/release-notes.test.ts
2: index 78963b471..e0a2e04bd 100644
3: --- a/packages/cli/test/lib/release-notes.test.ts
4: +++ b/packages/cli/test/lib/release-notes.test.ts
5: @@ -1,41 +1,47 @@
6: /**
7: * Unit Tests for Release Notes Parser & Aggregation
8: *
9: * Tests core invariants (section extraction, version filtering, truncation)
10: * that are hard to express as property-based tests due to format specifics.
11: *
12: * Core random-input invariants (category validity, filtering, commit parsing)
13: * are tested via property-based tests in release-notes.property.test.ts.
14: */
15:
16: import { marked } from "marked";
17: -import { describe, expect, test } from "vitest";
18: -import type { GitHubRelease } from "../../src/lib/delta-upgrade.js";
19: +import { afterEach, ...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 209: await expect(fetchLatestFromGitHub()).resolves.toBe("1.3.0");
Line 239: await expect(fetchLatestFromGitHub()).resolves.toBe("1.2.3");
Line 262: await expect(fetchLatestFromGitHub()).resolves.toBe("1.3.0");
Line 278: await expect(fetchLatestFromGitHub()).rejects.toThrow(
Line 295: await expect(fetchLatestFromGitHub()).rejects.toMatchObject({
Line 313: await expect(fetchLatestFromGitHub()).rejects.toThrow(
Line 331: await expect(fetchLatestFromGitHub()).resolves.toBe("1.2.3");
Line 347: await expect(fetchLatestFromGitHub()).rejects.toThrow(
Line 364: const version = await fetchLatestFromGitHub();
Line 377: const version = await fetchLatestFromGitHub();
Line 390: const version = await fetchLatestFromGitHub();
Line ...
Found 43 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts: Line 538: export async function fetchLatestFromGitHub( Line 623: const token = await getAnonymousToken(source, signal); Line 624: const manifest = await fetchManifest(token, tag, signal, source); Line 637: export async function fetchLatestNightlyVersion( Line 666: return fetchLatestNightlyVersion(); Line 669: ? ...
No files found
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/node_modules</path> <type>directory</type> <entries> .modules.yaml .pnpm-workspace-state.json .pnpm/ (3 entries) </entries>
No files found
No files found
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/node_modules/binpatch</path> <type>directory</type> <entries> dist/ LICENSE package.json README.md (4 entries) </entries>
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/node_modules/binpatch/dist</path> <type>directory</type> <entries> index.d.ts index.js index.js.map (3 entries) </entries>
Found 3 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/node_modules/binpatch/dist/index.js:
Line 654: async function resolveAndApply(opts) {
Line 1038: function ghcrSource(config) {
Line 1225: function githubReleaseSource(config) {
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/node_modules/binpatch/dist/index.js</path>
<type>file</type>
<content>
600: files = await readdir(cacheDir);
601: } catch (err) {
602: if (isNotFound(err)) return;
603: throw err;
604: }
605: await Promise.all(
606: files.map((file) => unlink(join(cacheDir, file)).catch(() => {
607: }))
608: );
609: }
610: function makeCache(cacheDir) {
611: return {
612: save: (chain, steps) => savePatchesToCache(cacheDir, chain, steps),
613: load: (currentVersion, targetVersion) => loadCachedChain(cacheDir, currentVersion, targetVersion),
614: cleanup: () => cleanupPatchCache(cacheDir),
615: clear: () => clearPatchCache(cacheDir)
616: };
617: }
618:
619: // src/contract.ts
620: var MAX_STABLE_CHAIN_DEPTH = 10;
621: var MAX_NIGHTLY_CHAIN_DEPTH = 30;
622: var SIZE_THRESHOLD_RATIO = 0.6;
623: var PATCH_TAG_PREFIX = "patch-";
624: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/node_modules/binpatch/dist/index.js</path>
<type>file</type>
<content>
767: var OciClient = class {
768: registry;
769: repo;
770: userAgent;
771: fetch;
772: constructor(config) {
773: this.registry = config.registry;
774: this.repo = config.repo;
775: this.userAgent = config.userAgent;
776: this.fetch = config.fetch ?? fetch;
777: }
778: async fetchWithRetry(url, init, context, options) {
779: const timeout = options?.timeout ?? REQUEST_TIMEOUT;
780: const externalSignal = options?.signal;
781: let lastError;
782: for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
783: try {
784: return await this.fetch(url, {
785: ...init,
786: signal: buildSignal(timeout, externalSignal)
787: });
788: } catch (error) {
789: lastError = error instanceof Error ? ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/node_modules/binpatch/dist/index.js</path>
<type>file</type>
<content>
1130: };
1131: }
1132: return {
1133: async resolveChain(currentVersion, targetVersion, signal, report) {
1134: try {
1135: const token = await i("ghcr-token", () => client.getAnonymousToken(signal));
1136: const [targetManifest, patchTags] = await Promise.all([
1137: i(
1138: "fetch-target-manifest",
1139: () => client.fetchManifest(token, targetTag(targetVersion), signal)
1140: ),
1141: i(
1142: "list-patch-tags",
1143: () => client.listTags(token, PATCH_TAG_PREFIX, signal)
1144: )
1145: ]);
1146: const gzLayer = targetManifest.layers.find(
1147: (l) => l.annotations?.["org.opencontainers.image.title"] === `${binaryName}.gz`
1148: ...
c6030fbf4 fix(cli): bind nightly manifests to versions
packages/cli/src/lib/upgrade.ts | 17 ++++++++
packages/cli/test/lib/upgrade.test.ts | 80 ++++++++++++++++++++++++++++++++++-
2 files changed, 95 insertions(+), 2 deletions(-)
commit c6030fbf4d0c190f037c86d832edb6680d3e54ab
Author: Burak Yigit Kaya <byk@sentry.io>
Date: Thu Sep 10 02:34:15 2026 +0000
fix(cli): bind nightly manifests to versions
diff --git a/packages/cli/src/lib/upgrade.ts b/packages/cli/src/lib/upgrade.ts
index b669cd87b..663adf772 100644
--- a/packages/cli/src/lib/upgrade.ts
+++ b/packages/cli/src/lib/upgrade.ts
@@ -641,91 +641,105 @@ export async function fetchLatestNightlyVersion(
signal,
source ? [source] : UPGRADE_SOURCES
)
).version;
}
/**
* Fetch the latest available version based on installation method and channel. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts</path>
<type>file</type>
<content>
170: test("parses valid methods", () => {
171: expect(parseInstallationMethod("curl")).toBe("curl");
172: expect(parseInstallationMethod("brew")).toBe("brew");
173: expect(parseInstallationMethod("npm")).toBe("npm");
174: expect(parseInstallationMethod("pnpm")).toBe("pnpm");
175: expect(parseInstallationMethod("bun")).toBe("bun");
176: expect(parseInstallationMethod("yarn")).toBe("yarn");
177: });
178:
179: test("parses case-insensitively", () => {
180: expect(parseInstallationMethod("NPM")).toBe("npm");
181: expect(parseInstallationMethod("Curl")).toBe("curl");
182: expect(parseInstallationMethod("YARN")).toBe("yarn");
183: });
184:
185: test("throws on invalid method", () => {
186: expect(() => parseInstallationMethod("pip")).toThrow("Invalid method: ...
function extractReleaseVersions(
data:
| { tag_name?: string; draft?: boolean; prerelease?: boolean }
| Array<{ tag_name?: string; draft?: boolean; prerelease?: boolean }>,
source: UpgradeSource
): string[] {
const releases = Array.isArray(data) ? data : [data];
return releases
.filter((release) => !(release.draft || release.prerelease))
.map((release) => release.tag_name)
.filter(
(tag): tag is string =>
typeof tag === "string" && tag.startsWith(source.tagPrefix)
)
.map((tag) => tag.slice(source.tagPrefix.length))
.map((tag) => tag.replace(VERSION_PREFIX_REGEX, ""))
.filter((tag) => semverValid(tag) !== null)
.sort((a, b) => compareVersions(b, a));
}
describe("fetchLatestFromGitHub", () => {
test("selects the latest CLI-prefixed Toolkit release", async () => {
const requests: string[] = [];
mockFetch(async (url) => {
requests.push(String(url));
return new Response(
JSON.stringify([
{ ...
M packages/cli/src/commands/cli/upgrade.ts
M packages/cli/src/lib/upgrade.ts
M packages/cli/test/commands/cli/upgrade.test.ts
M packages/cli/test/lib/upgrade.test.ts
diff --git a/packages/cli/test/lib/upgrade.test.ts b/packages/cli/test/lib/upgrade.test.ts
index cb3daa43c..efa454a7e 100644
--- a/packages/cli/test/lib/upgrade.test.ts
+++ b/packages/cli/test/lib/upgrade.test.ts
@@ -198,6 +198,7 @@ describe("fetchLatestFromGitHub", () => {
JSON.stringify([
{ tag_name: "mcp@9.0.0" },
{ tag_name: "cli@not-a-version" },
+ { tag_name: "cli@99.0.0-dev.1", prerelease: false },
{ tag_name: "cli@1.2.3" },
{ tag_name: "cli@1.3.0" },
]),
@@ -742,6 +743,26 @@ describe("versionExists", () => {
);
});
+ test.each([
+ ["empty body", ""],
+ ["invalid JSON", "{"],
+ ["missing tag", JSON.stringify({})],
+ ["mismatched tag", JSON.stringify({ tag_name: "mcp@1.0.0" })],
+ ])("rejects pinned Toolkit %s without ...
diff --git a/packages/cli/src/commands/cli/upgrade.ts b/packages/cli/src/commands/cli/upgrade.ts
index 2d4f927d2..8c03fa3f4 100644
--- a/packages/cli/src/commands/cli/upgrade.ts
+++ b/packages/cli/src/commands/cli/upgrade.ts
@@ -24,0 +25 @@ import {
+ isNightlyVersion,
@@ -1066 +1067 @@ export const upgradeCommand = buildCommand({
- if (channel === "nightly" && method !== "curl") {
+ if (isNightlyVersion(target) && method !== "curl") {
diff --git a/packages/cli/src/lib/upgrade.ts b/packages/cli/src/lib/upgrade.ts
index 663adf772..4a23b4b25 100644
--- a/packages/cli/src/lib/upgrade.ts
+++ b/packages/cli/src/lib/upgrade.ts
@@ -24 +24 @@ import { setTimeout } from "node:timers/promises";
-import { valid as semverValid } from "semver";
+import { prerelease as semverPrerelease, valid as semverValid } from "semver";
@@ -134 +134,3 @@ function extractReleaseVersions(
- .filter((tag) => semverValid(tag) !== null)
+ .filter(
+ (tag) => semverValid(tag) !== null && ...
The worktree changed during this read-only review, so it is no longer an immutable checkout of head 4a1d5bad105c006193c68459175f5eb3c7f78e08.
Initial verification passed:
ec83887a16f780f32fba4b7d710bad262dba3a22.bd98f2d9f7e5ce09a4d1271fb230d763348e59068ac12de292898fb8697b7fc5.During inspection, these files became modified:
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts:25,1067/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:24,134-136,713-733,761-767/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/commands/cli/upgrade.test.ts:1124-1186/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:201,746-765,978-1001These uncommitted changes alter stable prerelease filtering, exact-tag response validation, nightly annotation validation, and migration behavior—the core review scope. Any verdict would mix the requested head with a different patch.
No files or repository state were modified by this review. Tests were not run after drift. Restore a clean exact-head worktree and restart the full review.
DO-NOT-MERGE
* 🔴 (03:09) Commit `c6030fbf4d0c190f037c86d832edb6680d3e54ab` (`fix(cli): bind nightly manifests to versions`) by Burak Yigit Kaya `<byk@sentry.io>` changed `packages/cli/src/lib/upgrade.ts` and `packages/cli/test/lib/upgrade.test.ts`, with 95 insertions and 2 deletions. * 🔴 (03:09) Commit `c6030fbf4d0c190f037c86d832edb6680d3e54ab` changed `downloadNightlyToPath()` in `packages/cli/src/lib/upgr…
Date: Sep 10, 2026 * 🔴 (03:07) Source search located upgrade-related functions in `packages/cli/src/lib/upgrade.ts`: `fetchLatestFromGitHub()` at line 538, `fetchLatestNightlyVersion()` at line 637, `resolveLatestUpgradeVersion()` at line 674, `resolveExistingUpgradeVersion()` at line 697, `versionExists()` at line 811, `downloadBinaryToTemp()` at line 1164, and `executeUpgrade()` at line 1402. …
Date: Sep 10, 2026 * 🔴 (03:07) Test coverage includes the exact case `"checks for update when never checked before"` and invokes the background update-check path when no prior check exists. * 🔴 (03:07) Release-fetch tests expect the Toolkit GitHub API URL `https://api.github.com/repos/getsentry/toolkit/releases?per_page=30`. * 🔴 (03:07) Added invalid GitHub release-pagination handling with the…
* 🔴 (03:06) Added test `"fetches stable releases only from the explicitly selected Toolkit source"`, recording requested URLs and validating that stable-release fetching uses the explicitly selected Toolkit source. * 🔴 (03:06) Added coverage ensuring nightly transport error text is not misclassified as a not-found response; the operation must reject with `UpgradeError`. * 🔴 (03:06) The update-…
* 🔴 (03:06) In `packages/cli/test/lib/delta-upgrade.mocked.test.ts`, stable delta-upgrade release fixtures were migrated from legacy unprefixed tags such as `0.14.0` and `0.13.0` to Toolkit product-prefixed tags `cli@0.14.0` and `cli@0.13.0`. * 🔴 (03:06) Stable delta patch URLs in `packages/cli/test/lib/delta-upgrade.mocked.test.ts` now target `https://github.com/getsentry/toolkit/releases/down…
Date: September 10, 2026 * 🔴 (03:06) In `packages/cli/test/commands/cli.test.ts`, upgrade-command GitHub mocks were updated from the legacy `releases/latest` response `{ tag_name: "v0.0.0-dev" }` to the Toolkit releases-list endpoint matching `getsentry/toolkit/releases?per_page=100`, returning `[{ tag_name: "cli@0.0.0-dev" }]`. * 🔴 (03:06) Version mocks in `packages/cli/test/commands/cli.test.…
Date: September 10, 2026 * 🔴 (03:06) User stated installation detection must always check Homebrew first because stored install information may be stale—for example, a user may switch from a recorded curl installation to Homebrew; the cheap realpath check is authoritative. * 🔴 (03:06) User-provided `detectInstallationMethod()` priority is: 1. Homebrew via cheap realpath check, overriding stale …
Date: September 10, 2026 * 🔴 (03:05) User-provided background version-check implementation is non-throwing: errors are caught and reported to Sentry; expected abort errors caused by process exit are not reported. * 🔴 (03:05) User-provided update-notification design coordinates the human-only update banner with another notification path using once-per-process state so the two never double-emit. …
* 🔴 (03:05) User-provided upgrade logic always checks for Homebrew first because stored install information may be stale. * 🔴 (03:05) User-provided upgrade source includes legacy detection for existing installations without stored install information and auto-saves the detected installation method on a best-effort basis for future runs. * 🔴 (03:05) User-provided package-manager detection defau…
Date: Sep 10, 2026 * 🔴 (03:05) User-provided GHCR source imports `getUserAgent` from `./constants.js` and supports the standard `ghcr.io` anonymous token exchange. * 🔴 (03:05) User-provided GHCR source notes that `AbortSignal.timeout()` throws a `TimeoutError` `DOMException` and checks the error by name. * 🔴 (03:05) User-provided GHCR request logic uses `options?.timeout ?? GHCR_REQUEST_TIMEOU…
Date: Sep 10, 2026 * 🔴 (03:04) User-provided upgrade source states path normalization strips a trailing path separator but never strips it from a bare root such as `/`. * 🔴 (03:04) User-provided upgrade source passes the successful source-probe response to the caller so the caller never repeats the successful probe request. * 🔴 (03:04) User-provided upgrade source defines legacy installation s…
Date: Sep 10, 2026 * 🔴 (03:03) User-provided `packages/cli/CONTRIBUTING.md` states Sentry CLI follows `gh` CLI conventions: list commands use optional positional context with smart auto-detection; view commands use optional positional primary identifiers where possible; `issue view` requires an issue ID and `event view` requires an event ID. * 🔴 (03:03) User-provided target syntax is: `<org>/<p…
Date: Sep 10, 2026 * 🔴 [enforced-workflow] (03:03) User-provided `AGENTS.md` mandates loading `repo-setup` before situation skills. Skills live under `.agents/skills/`, are generated from canonical `skills/` by `scripts/sync-skills.mjs`. * 🔴 (03:03) User-provided `AGENTS.md` defines the agent pipeline as triage → explore → plan → implement → review → ship; `worker` is a deprecated alias of `imp…
Date: Sep 10, 2026 * 🔴 [requested-review] (03:02) User requested a READ-ONLY correctness merge-gate review of getsentry/cli PR #1569 at exact base ec83887a16f780f32fba4b7d710bad262dba3a22 and head 4a1d5bad105c006193c68459175f5eb3c7f78e08 in worktree /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade; instructed never to modify files. * 🟡 (03…