Dashboard › cli › Session 1W0vc18fUQ99
1W0vc18fUQ99w7CwTRead-only analysis in /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade. Analyze packages/cli/src/lib/delta-upgrade.ts, relevant tests, and binpatch 0.4.2 public source/API (use GitHub/raw source, never node_modules). Determine the smallest exact changes needed to pass an explicit UpgradeSource through stable/nightly delta resolution and prefetch, including support for Toolkit tags cli@<version> and preserving legacy unprefixed tags. Identify whether binpatch githubReleaseSource supports tag prefixes; if not, propose a minimal adapter that does not mix repositories. Identify exact tests to add/update. Do not edit files or run broad tests. Return file/symbol-level recommendations and risks.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade</path> <type>directory</type> <entries> .craft.yml .git .github/ .gitignore .lore.md .nojekyll .npmrc AGENTS.md apps/ CHANGELOG.md codemods/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md (18 entries) </entries>
<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/packages/cli/AGENTS.md /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/AGENTS.md
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md 2: 3: Guidelines for AI agents working in this codebase. 4: 5: ## Project Overview 6: 7: **Sentry CLI** is a command-line interface for [Sentry](https://sentry.io), built with Node.js, [pnpm](https://pnpm.io), and [Stricli](https://bloomberg.github.io/stricli/). It lives in `packages/cli` of a pnpm workspace; the docs site lives in `apps/cli-docs`. ...
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/e2e/delta-upgrade.test.ts
Found 94 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/package.json:
Line 111: "binpatch": "^0.4.2",
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/e2e/delta-upgrade.test.ts:
Line 18: import { applyPatch, applyPatchChainInMemory } from "binpatch";
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/commands/init.test.ts:
Line 22: import * as prefetchNs from "../../src/lib/init/org-prefetch.js";
Line 23: import { resetPrefetch } from "../../src/lib/init/org-prefetch.js";
Line 85: warmSpy = vi.spyOn(prefetchNs, "warmOrgDetection").mockImplementation(
Line 581: test("warms prefetch when org is not explicit", async () => {
Line 588: test("skips prefetch when org is explicit", async () => {
Line 594: test("skips prefetch ...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/types/feedback.ts:
Line 120: source: optional(
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/types/dashboard.ts:
Line 1053: source: string(),
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts:
Line 136: const sources: { path: string; source: CaSource; label: string }[] = [
Line 137: { path: storedPath, source: "default", label: "stored default" },
Line 140: source: "env",
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/telemetry.ts:
Line 115: source: string;
Line 132: return { enabled: false, source: `env:${TELEMETRY_ENV_VAR}` };
Line ...
No files found
No files found
<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/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, ...
Found 41 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts:
Line 237: await prefetchNightlyPatches(latestVersion, signal);
Line 239: await prefetchStablePatches(latestVersion, signal);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 991: return await attemptDeltaUpgrade(
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts:
Line 270: export function resolveStableChain(
Line 278: export async function resolveNightlyChain(opts: {
Line 487: export function resolveStableDelta(
Line 505: export function resolveNightlyDelta(
Line 523: export function attemptDeltaUpgrade(
Line 615: export function prefetchNightlyPatches(
Line 622: export function ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
850: */
851: async function waitForBinaryVisible(path: string): Promise<number> {
852: for (let attempt = 1; attempt <= VERIFY_MAX_ATTEMPTS; attempt++) {
853: const size = probeBinaryFile(path);
854: if (size !== null) {
855: if (attempt > 1) {
856: log.debug(`Binary became visible after ${attempt} attempts`);
857: }
858: return size;
859: }
860: if (attempt === VERIFY_MAX_ATTEMPTS) {
861: break;
862: }
863: const delay = VERIFY_BASE_DELAY_MS * 2 ** (attempt - 1);
864: log.debug(
865: `Downloaded binary not yet visible at ${path}, retrying in ${delay}ms (attempt ${attempt}/${VERIFY_MAX_ATTEMPTS})`
866: );
867: await setTimeout(delay);
868: }
869: throw new UpgradeError(
870: "execution_failed",
871: `Downloaded binary is ...
Found 9 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 579: /** Result from downloadBinaryToTemp — includes both the binary path and lock path */
Line 728: async function downloadNightlyToPath(
Line 761: async function downloadStableToPath(
Line 881: * from GHCR using the OCI blob download protocol via {@link downloadNightlyToPath}.
Line 884: * {@link downloadStableToPath}.
Line 902: export async function downloadBinaryToTemp(
Line 1014: await downloadNightlyToPath(destPath, version, setMessage);
Line 1016: await downloadStableToPath(downloadTag ?? version, destPath, setMessage);
Line 1131: return downloadBinaryToTemp(version, downloadTag, offline, setMessage);
Found 16 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 975: const url = getBinaryDownloadUrl("1.0.0");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/binary.test.ts:
Line 34: resolveUpgradeSource,
Line 43: const url = getBinaryDownloadUrl("1.0.0");
Line 57: const url = getBinaryDownloadUrl("2.0.0");
Line 83: describe("resolveUpgradeSource", () => {
Line 87: const resolved = await resolveUpgradeSource(async (url) => {
Line 106: const resolved = await resolveUpgradeSource(async (url) => {
Line 129: resolveUpgradeSource(async (url) => {
Line 145: resolveUpgradeSource(async (url) => {
Line 160: resolveUpgradeSource(async (url) => ...
## feat/toolkit-bridge-upgrade...origin/main [behind 2]
M packages/cli/src/lib/binary.ts
M packages/cli/test/lib/binary.test.ts
M packages/cli/test/lib/ghcr.test.ts
M packages/cli/test/lib/install-script.test.ts
packages/cli/src/lib/binary.ts | 88 +++++++++++++++++++--
packages/cli/test/lib/binary.test.ts | 109 +++++++++++++++++++++++++++
packages/cli/test/lib/ghcr.test.ts | 30 ++++++++
packages/cli/test/lib/install-script.test.ts | 10 +++
4 files changed, 232 insertions(+), 5 deletions(-)
diff --git a/packages/cli/src/lib/binary.ts b/packages/cli/src/lib/binary.ts
index 75582612a..a50bc0949 100644
--- a/packages/cli/src/lib/binary.ts
+++ b/packages/cli/src/lib/binary.ts
@@ -102,6 +102,33 @@ export type InstallationMethod =
| "yarn"
| "unknown";
+/** A repository pair that hosts CLI stable releases and nightly OCI images. */
+export type UpgradeSource = {
+ /** GitHub `owner/repository` containing CLI release assets. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Unit Tests for Delta Upgrade Module
3: *
4: * Tests the exported pure-computation functions that drive chain resolution
5: * for both stable (GitHub Releases) and nightly (GHCR) channels, plus
6: * async orchestration functions tested via fetch mocking.
7: */
8:
9: import { createHash } from "node:crypto";
10: import { existsSync, unlinkSync } from "node:fs";
11: import { access, readFile } from "node:fs/promises";
12: import { tmpdir } from "node:os";
13: import { join } from "node:path";
14: import { afterEach, beforeEach, describe, expect, test } from "vitest";
15: import { getPlatformBinaryName } from "../../src/lib/binary.js";
16: import {
17: applyPatchChain,
18: attemptDeltaUpgrade,
19: canAttemptDelta,
20: downloadStablePatch,
21: type ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
850:
851: const result = await fetchRecentReleases();
852: expect(result).toEqual([]);
853: });
854: });
855:
856: // downloadStablePatch
857:
858: describe("downloadStablePatch", () => {
859: test("returns Uint8Array on success", async () => {
860: const patchData = new Uint8Array([1, 2, 3, 4, 5]);
861:
862: mockFetch(async (url) => {
863: expect(String(url)).toBe("https://example.com/patch.bin");
864: return new Response(patchData.buffer as ArrayBuffer, {
865: status: 200,
866: });
867: });
868:
869: const result = await downloadStablePatch("https://example.com/patch.bin");
870: expect(result).not.toBeNull();
871: expect(result).toEqual(patchData);
872: });
873:
874: test("returns null on HTTP 404", async () => {
875: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1550: const patchData = await readFile(join(fixturesDir, "small.trdiff10"));
1551:
1552: const chain: PatchChain = {
1553: patches: [
1554: {
1555: data: new Uint8Array(patchData),
1556: size: patchData.byteLength,
1557: },
1558: {
1559: data: new Uint8Array(patchData),
1560: size: patchData.byteLength,
1561: },
1562: ],
1563: totalSize: patchData.byteLength * 2,
1564: expectedSha256: "anything",
1565: };
1566:
1567: try {
1568: await applyPatchChain(chain, oldPath, destPath).catch(() => {
1569: // Expected — second patch applied to mismatched bytes fails verification
1570: });
1571:
1572: // The in-memory chain never creates scratch files on disk. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
700: tags,
701: "0.0.0-dev.101",
702: "0.0.0-dev.102"
703: );
704: expect(result).toEqual(["patch-0.0.0-dev.102"]);
705: });
706: });
707:
708: // validateChainStep
709:
710: describe("validateChainStep", () => {
711: const PATCH_LAYER_NAME = `${getPlatformBinaryName()}.patch`;
712:
713: function makeLayer(
714: title: string,
715: size: number
716: ): OciManifest["layers"][number] {
717: return {
718: digest: `sha256:${title.replace(/\W/g, "")}`,
719: mediaType: "application/octet-stream",
720: size,
721: annotations: { "org.opencontainers.image.title": title },
722: };
723: }
724:
725: test("returns version-mismatch when from-version differs", () => {
726: const manifest = makePatchManifest("0.1.0", {}, [
727: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts</path> <type>file</type> <content> 1: /** 2: * Integration tests for delta upgrade orchestration with a non-dev CLI_VERSION. 3: * 4: * These tests use `vi.mock()` to override `CLI_VERSION` from constants.js 5: * so that `canAttemptDelta()` passes its dev-build guard (the real `CLI_VERSION` 6: * is "0.0.0-dev" in test mode, which short-circuits the orchestrator). 7: * 8: * Kept as a sibling file to `delta-upgrade.test.ts` because its 9: * `vi.mock()` would invert the assumptions of the dev-mode null-return 10: * tests in that file. Under `bun test --isolate` each file gets a fresh 11: * module graph, so the mocks here don't leak. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/e2e/delta-upgrade.test.ts</path> <type>file</type> <content> 1: /** 2: * E2E Test: Delta Upgrade via Binary Patching 3: * 4: * Downloads two consecutive stable release binaries from GitHub, 5: * generates a TRDIFF10 patch using zig-bsdiff, and verifies that 6: * our `applyPatch()` produces byte-identical output. 7: * 8: * Requires: zig-bsdiff binary available at /tmp/bsdiff (or via ZIG_BSDIFF_PATH env). 9: * Skipped in CI unless ZIG_BSDIFF_PATH is set. ...
StatusCode: non 2xx status code (401 GET https://api.github.com/search/code?q=%22githubReleaseSource%22+%22binpatch%22)
{"bugs":{"url":"https://github.com/BYK/binpatch/issues"},"dist":{"shasum":"48c635e950ded2c620fc932fe1a44e2fdad2d68d","tarball":"https://registry.npmjs.org/binpatch/-/binpatch-0.4.2.tgz","fileCount":6,"integrity":"sha512-aShVdFVzDrqVRlyhDQabzKV6b9suWegARr0IPTer58eNQoo1KqpuCr+VtbwwuirmfXqmWuuxsoZlXJN1tTZBcw==","signatures":[{"sig":"MEUCIQD7P6no2s3UpvTTLw+cyPpgh91Zocgt00IrBp0xnZSKpgIgBKh83uJhzQSZzVKLcSOC5ub2vuveBDMYMq9NQ0yU5S8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/binpatch@0.4.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":206575},"main":"./dist/index.js","name":"binpatch","type":"module","_from":"file:/tmp/craft-cY6qx5/binpatch-0.4.2.tgz","types":"./dist/index.d.ts","author":{"name":"BYK"},"engines":{"node":">=22.15.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"license":"MIT","scripts":{"test":"vitest ...
StatusCode: non 2xx status code (404 GET https://api.github.com/repos/BYK/binpatch/git/trees/v0.4.2?recursive=1)
[
{
"name": "0.4.2",
"zipball_url": "https://api.github.com/repos/BYK/binpatch/zipball/refs/tags/0.4.2",
"tarball_url": "https://api.github.com/repos/BYK/binpatch/tarball/refs/tags/0.4.2",
"commit": {
"sha": "9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"url": "https://api.github.com/repos/BYK/binpatch/commits/9ba6bbb8227fcbd2521852d2311c82afac5e9573"
},
"node_id": "REF_kwDOThqhQK9yZWZzL3RhZ3MvMC40LjI"
},
{
"name": "0.4.1",
"zipball_url": "https://api.github.com/repos/BYK/binpatch/zipball/refs/tags/0.4.1",
"tarball_url": "https://api.github.com/repos/BYK/binpatch/tarball/refs/tags/0.4.1",
"commit": {
"sha": "d0593cdd89eb720edddf9644e0753613e4a8e622",
"url": "https://api.github.com/repos/BYK/binpatch/commits/d0593cdd89eb720edddf9644e0753613e4a8e622"
},
"node_id": "REF_kwDOThqhQK9yZWZzL3RhZ3MvMC40LjE"
},
{
"name": "0.4.0",
"zipball_url": ...
{
"sha": "9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"url": "https://api.github.com/repos/BYK/binpatch/git/trees/9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"tree": [
{
"path": ".craft.yml",
"mode": "100644",
"type": "blob",
"sha": "36f34fdd754de842419fe5a5cb2844a8c98f80df",
"size": 1143,
"url": "https://api.github.com/repos/BYK/binpatch/git/blobs/36f34fdd754de842419fe5a5cb2844a8c98f80df"
},
{
"path": ".github",
"mode": "040000",
"type": "tree",
"sha": "dc6a71d7d4d393c0e072cb45ac745fc2a61f60ef",
"url": "https://api.github.com/repos/BYK/binpatch/git/trees/dc6a71d7d4d393c0e072cb45ac745fc2a61f60ef"
},
{
"path": ".github/workflows",
"mode": "040000",
"type": "tree",
"sha": "da820a4798f068f6531c69b3544f97601baa4cfa",
"url": "https://api.github.com/repos/BYK/binpatch/git/trees/da820a4798f068f6531c69b3544f97601baa4cfa"
},
{
"path": ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
/**
* GHCR / OCI patch source (the "nightly" channel).
*
* Resolves a patch chain from OCI patch-manifest tags. Patches are published
* under `<patchTagPrefix><version>` tags whose manifests carry:
* - annotation `from-version=<prev>` — the chain back-pointer
* - annotation `sha256-<binaryName>=<hex>` — the target's uncompressed SHA-256
* - a patch layer whose title is `<binaryName>.patch`
*
* The target binary's gzipped size (for the ratio gate) is read from the
* target's own image manifest (its `<binaryName>.gz` layer). All product
* specifics — registry, repo, user-agent, binary name, the version→target-tag
* scheme, and version comparison — are injected. Generalized from Lore's
* nightly-channel resolver.
*/
import {
type InstrumentHook,
MAX_NIGHTLY_CHAIN_DEPTH,
PATCH_TAG_PREFIX,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy, UnavailableReporter } from "../discover";
import { BinpatchError } ...
/**
* Chain discovery + resolve-and-apply orchestration.
*
* A {@link SourceStrategy} knows how to resolve a {@link PatchChain} from some
* backing store (an OCI registry, GitHub Release assets, ...). This module ties
* a strategy together with the offline cache, the apply core, integrity
* verification, and progress events — with every product-specific concern
* (version, telemetry, logging, cache location) injected.
*/
import { applyPatchChainInMemory, parsePatchHeader } from "./bspatch";
import type { PatchCache } from "./patch-cache";
import type { DeltaResult, PatchChain } from "./contract";
import { type ProgressHandler, safeProgress } from "./events";
/**
* A source of patch chains. Given the current and target versions, resolve the
* ordered chain of patches (oldest hop first) plus the expected final SHA-256,
* or `null` when no usable chain exists (caller falls back to a full download). ...
/**
* binpatch — reusable binary delta-update engine.
*
* Two things, joined by one wire contract (see README):
* - **apply core** — parse + apply a TRDIFF10/bsdiff patch chain to a binary.
* - **discovery** — resolve a patch chain from a pluggable `SourceStrategy`
* (OCI/GHCR tags or GitHub Release assets), then apply + verify it.
*
* Pure Node (`node:*` builtins only), zero product coupling — the consumer
* injects the cache directory, the download source, version comparison,
* progress handling, and telemetry.
*/
export {
addDiffChunk,
applyPatch,
applyPatchChainInMemory,
applyPatchToMemory,
MAX_OUTPUT_SIZE,
offtin,
parsePatchHeader,
type PatchHeader,
} from "./bspatch";
export {
type ChainMeta,
chainFileName,
makeCache,
type PatchCache,
patchFileName,
type PatchStepMeta,
} from "./patch-cache";
// Wire-contract constants + shared chain types. ...
<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 { CLI_VERSION } from "./constants.js";
14: import { getReleaseChannel } from "./db/release-channel.js";
15: import {
16: getVersionCheckInfo,
17: markUpdateNotified,
18: setVersionCheckInfo,
19: } from ...
Found 5 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 399: export async function fetchLatestFromGitHub(
Line 433: export async function fetchLatestFromNpm(): Promise<string> {
Line 467: export async function fetchLatestNightlyVersion(
Line 503: return fetchLatestNightlyVersion();
Line 506: ? fetchLatestFromGitHub()
<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 {
25: acquireLock,
26: cleanupOldBinary,
27: determineInstallDir,
28: fetchWithUpgradeError,
29: ...
Found 3 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/pnpm-lock.yaml:
Line 136: binpatch:
Line 2169: binpatch@0.4.2:
Line 6698: binpatch@0.4.2: {}
Found 13 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts: Line 286: ? await fetchLatestNightlyVersion(signal) Line 287: : await fetchLatestFromGitHub(signal); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts: Line 399: export async function fetchLatestFromGitHub( Line 467: export async function fetchLatestNightlyVersion( Line 498: export function fetchLatestVersion( Line 503: return fetchLatestNightlyVersion(); Line 506: ? fetchLatestFromGitHub() Line 551: export async function versionExists( Line 902: export async function downloadBinaryToTemp( Line 1131: return downloadBinaryToTemp(version, downloadTag, offline, ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
250: // Offline mode is only supported for curl-installed binaries — package
251: // managers always need network to fetch and install packages.
252: if (offline && method !== "curl") {
253: throw new UpgradeError(
254: "unsupported_operation",
255: "Offline upgrade is only supported for curl-installed binaries."
256: );
257: }
258: }
259:
260: type ResolveTargetOptions = {
261: method: InstallationMethod;
262: channel: ReleaseChannel;
263: versionArg: string | undefined;
264: channelChanged: boolean;
265: flags: UpgradeFlags;
266: };
267:
268: /**
269: * Result of resolving the target version. ...
Found 3 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts:
Line 463: // CLI-1D3). `downloadBinaryToTemp`'s visibility-race retry loop
Line 642: executeUpgrade(method, target, downloadTag, offline, setMessage)
Line 727: executeUpgrade("curl", target, downloadTag, undefined, setMessage)
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
560: }
561:
562: function resolveUpdatedCliPath(
563: execPath: string,
564: entryPath: string | undefined,
565: pathEnv: string | undefined
566: ): string {
567: return whichSync("sentry", { PATH: pathEnv }) ?? entryPath ?? execPath;
568: }
569:
570: /**
571: * Decide which directory a curl upgrade should install into.
572: *
573: * Normally the binary stays where it currently lives — pinning the install
574: * dir keeps an in-place update from relocating a binary that is already on
575: * the user's `PATH` (upgrade runs setup with `--no-modify-path`, so it can't
576: * add a new directory to `PATH`).
577: *
578: * The one exception is a legacy `~/.sentry/bin` install: those should move to
579: * the XDG-aligned location so users actually migrate off `~/.sentry`. ...
/** * Patch Cache * * File-based cache for delta upgrade patches. Patches are downloaded * during background version checks so that an upgrade can apply them * offline without any network calls. * * Cache layout, under the caller-provided cache directory: * - <fromVersion>-<toVersion>.patch — raw binary patch data * - chain-<fromVersion>-<toVersion>.json — chain metadata * * Uses file-based storage to avoid bloating a DB with 50-80KB binary * blobs. Channel-agnostic — the same version-based naming works for * both nightly (GHCR) and stable (GitHub Releases) channels. * * The cache directory is injected by the consumer via `makeCache(cacheDir)` * so this module carries no product-specific coupling (no config-dir * lookup, no env vars). Adapted from Sentry CLI's patch-cache.ts. ...
Found 1 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/version-check.test.ts:
Line 474: expect(infoBefore.latestVersion).toBe("1.0.0");
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/version-check.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Version Check Logic Tests
3: */
4:
5: import { setTimeout as sleep } from "node:timers/promises";
6: import { afterEach, beforeEach, describe, expect, test } from "vitest";
7: import { setReleaseChannel } from "../../src/lib/db/release-channel.js";
8: import {
9: getVersionCheckInfo,
10: setVersionCheckInfo,
11: } from "../../src/lib/db/version-check.js";
12: import {
13: ApiError,
14: ContextError,
15: ValidationError,
16: } from "../../src/lib/errors.js";
17: import {
18: abortPendingVersionCheck,
19: getErrorUpdateNotification,
20: getUpdateNotification,
21: maybeCheckForUpdateInBackground,
22: resetUpdateNotificationState,
23: shouldSuppressNotification,
24: } from "../../src/lib/version-check.js";
25: import { mockFetch, useTestConfigDir } from ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/binary.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Binary Management Tests
3: *
4: * Tests for shared binary helpers: install directory selection, paths,
5: * download URLs, locking, and binary installation.
6: */
7:
8: import {
9: chmodSync,
10: mkdirSync,
11: readFileSync,
12: realpathSync,
13: rmSync,
14: symlinkSync,
15: writeFileSync,
16: } from "node:fs";
17: import { access, readFile, writeFile } from "node:fs/promises";
18: import { join, sep } from "node:path";
19: import { afterEach, beforeEach, describe, expect, test } from "vitest";
20: import {
21: acquireLock,
22: compareVersions,
23: determineInstallDir,
24: fetchWithUpgradeError,
25: getBinaryDownloadUrl,
26: getBinaryFilename,
27: getBinaryPaths,
28: getGitHubReleaseByTagUrl,
29: getLegacyInstallDirs,
30: getPlatformBinaryName,
31: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
220: os = "linux";
221: }
222: const arch = process.arch === "arm64" ? "arm64" : "x64";
223: const libcSuffix = isMusl() ? "-musl" : "";
224: const suffix = process.platform === "win32" ? ".exe" : "";
225: return `sentry-${os}-${arch}${libcSuffix}${suffix}`;
226: }
227:
228: /**
229: * Build the download URL for a platform-specific binary from GitHub releases.
230: *
231: * @param version - Version to download (without 'v' prefix)
232: * @returns Download URL for the binary
233: */
234: export function getBinaryDownloadUrl(
235: version: string,
236: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
237: ): string {
238: const tag = `${source.tagPrefix}${version}`;
239: return `https://github.com/${source.githubRepo}/releases/download/${tag}/${getPlatformBinaryName()}`;
240: }
241: ...
/**
* Wire-contract constants and shared types.
*
* These values are part of the binpatch wire contract — the generator (the
* publishing side) and this library MUST agree on them. See the package README
* for the full contract spec.
*/
/** Maximum stable patches to chain before falling back to a full download. */
export const MAX_STABLE_CHAIN_DEPTH = 10;
/** Maximum nightly patches to chain before falling back to a full download. */
export const MAX_NIGHTLY_CHAIN_DEPTH = 30;
/**
* Maximum ratio of total patch-chain size to the full (gzipped) download size.
* Above this, a full download is cheaper — abandon the chain.
*/
export const SIZE_THRESHOLD_RATIO = 0.6;
/** GHCR tag prefix under which per-version patch manifests are published. */
export const PATCH_TAG_PREFIX = "patch-";
/** A single link in a patch chain: the raw patch bytes and their size. */
export type PatchLink = {
data: Uint8Array;
size: number;
};
/** One from->to hop, used for cache keying. ...
diff --git a/packages/cli/src/lib/binary.ts b/packages/cli/src/lib/binary.ts
index 75582612a..bebf1da0c 100644
--- a/packages/cli/src/lib/binary.ts
+++ b/packages/cli/src/lib/binary.ts
@@ -102,6 +102,33 @@ export type InstallationMethod =
| "yarn"
| "unknown";
+/** A repository pair that hosts CLI stable releases and nightly OCI images. */
+export type UpgradeSource = {
+ /** GitHub `owner/repository` containing CLI release assets. */
+ readonly githubRepo: string;
+ /** GHCR `owner/package` containing CLI nightly images and delta patches. */
+ readonly ghcrRepo: string;
+ /** Prefix attached to CLI release tags in this repository. */
+ readonly tagPrefix: string;
+};
+
+/** Ordered CLI release sources. The resolver falls through only on HTTP 404. ...
{
"url": "https://api.github.com/repos/getsentry/cli/issues/1244",
"repository_url": "https://api.github.com/repos/getsentry/cli",
"labels_url": "https://api.github.com/repos/getsentry/cli/issues/1244/labels{/name}",
"comments_url": "https://api.github.com/repos/getsentry/cli/issues/1244/comments",
"events_url": "https://api.github.com/repos/getsentry/cli/issues/1244/events",
"html_url": "https://github.com/getsentry/cli/issues/1244",
"id": 4890976993,
"node_id": "I_kwDOQm6jAs8AAAABI4Zi4Q",
"number": 1244,
"title": "toolkit merge: bridge CLI release + dual-source upgrade compatibility",
"user": {
"login": "BYK",
"id": 126780,
"node_id": "MDQ6VXNlcjEyNjc4MA==",
"avatar_url": "https://avatars.githubusercontent.com/u/126780?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/BYK",
"html_url": "https://github.com/BYK",
"followers_url": "https://api.github.com/users/BYK/followers",
"following_url": ...
[
{
"url": "https://api.github.com/repos/getsentry/cli/issues/comments/4978828102",
"html_url": "https://github.com/getsentry/cli/issues/1244#issuecomment-4978828102",
"issue_url": "https://api.github.com/repos/getsentry/cli/issues/1244",
"id": 4978828102,
"node_id": "IC_kwDOQm6jAs8AAAABKMLjRg",
"user": {
"login": "BYK",
"id": 126780,
"node_id": "MDQ6VXNlcjEyNjc4MA==",
"avatar_url": "https://avatars.githubusercontent.com/u/126780?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/BYK",
"html_url": "https://github.com/BYK",
"followers_url": "https://api.github.com/users/BYK/followers",
"following_url": "https://api.github.com/users/BYK/following{/other_user}",
"gists_url": "https://api.github.com/users/BYK/gists{/gist_id}",
"starred_url": "https://api.github.com/users/BYK/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/BYK/subscriptions",
...
import { afterEach, describe, expect, it, vi } from "vitest";
import {
type InstrumentHook,
extractSha256,
extractStableChain,
filterAndSortChainTags,
getPatchFromVersion,
getPatchTargetSha256,
ghcrSource,
type GitHubRelease,
githubReleaseSource,
getStableTargetSha256,
OciClient,
type OciManifest,
validateChainStep,
} from "../src";
// Build a JSON Response for mocked fetch calls.
function json(body: unknown): Response {
return new Response(JSON.stringify(body), {
status: 200,
headers: { "content-type": "application/json" },
});
}
// A semver-ish comparator matching the gateway's compareVersions contract
// (returns -1 | 0 | 1) for the nightly tag-ordering tests.
function cmp(a: string, b: string): -1 | 0 | 1 {
const pa = a.split(".").map(Number);
const pb = b.split(".").map(Number);
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
const x = pa[i] ?? 0;
const y = pb[i] ?? ...
Found 27 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/ghcr.ts:
Line 25: type UpgradeSource,
Line 197: sourceOrSignal: UpgradeSource | AbortSignal = PRIMARY_UPGRADE_SOURCE,
Line 242: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 280: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 350: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 446: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 491: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 534: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 106: export type UpgradeSource = {
Line 116: export const UPGRADE_SOURCES: readonly UpgradeSource[] = [
Line 130: export const PRIMARY_UPGRADE_SOURCE = UPGRADE_SOURCES[0];
Line 236: source: ...
<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. ...
diff --git a/packages/cli/src/lib/ghcr.ts b/packages/cli/src/lib/ghcr.ts
index 43d6deb7e..f648ab78a 100644
--- a/packages/cli/src/lib/ghcr.ts
+++ b/packages/cli/src/lib/ghcr.ts
@@ -20,6 +20,10 @@
import { getUserAgent } from "./constants.js";
import { customFetch } from "./custom-ca.js";
import { UpgradeError } from "./errors.js";
+import {
+ PRIMARY_UPGRADE_SOURCE,
+ type UpgradeSource,
+} from "./binary.js";
/** Default timeout for GHCR HTTP requests (10 seconds) */
const GHCR_REQUEST_TIMEOUT = 10_000;
@@ -130,8 +134,8 @@ async function fetchWithRetry(
);
}
-/** GHCR repository for CLI distribution */
-export const GHCR_REPO = "getsentry/cli";
+/** Default GHCR repository for CLI distribution. */
+export const GHCR_REPO = PRIMARY_UPGRADE_SOURCE.ghcrRepo;
/** OCI tag for nightly builds */
export const GHCR_TAG = "nightly";
@@ -189,13 +193,20 @@ export type OciManifest = {
* @returns Bearer token string
* @throws {UpgradeError} On network failure or malformed ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
700:
701: /**
702: * Build the gzip filename for the current platform binary.
703: *
704: * Nightly builds are stored in GHCR as `sentry-<os>-<arch>.gz` (or
705: * `sentry-windows-x64.exe.gz` on Windows). This filename is the
706: * `org.opencontainers.image.title` annotation on the matching OCI layer.
707: *
708: * @returns Filename of the gzip-compressed binary for this platform
709: */
710: function getNightlyGzFilename(): string {
711: return `${getPlatformBinaryName()}.gz`;
712: }
713:
714: /**
715: * Download a nightly binary from GHCR and decompress it to `destPath`.
716: *
717: * Fetches an anonymous token, retrieves the OCI manifest, finds the layer
718: * matching this platform's `.gz` filename, then downloads and decompresses
719: * the blob in-stream. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
890: *
891: * If the child resolves to the same install path, it takes over the lock via
892: * process.ppid recognition in acquireLock — the parent's subsequent release
893: * is then a harmless no-op.
894: *
895: * @param version - Target version to download (used for display and comparison)
896: * @param downloadTag - Git tag to use in the download URL. Defaults to `version`.
897: * Pass `NIGHTLY_TAG` ("nightly") when installing from the rolling nightly release
898: * so the URL points to the prerelease assets regardless of the version string.
899: * @returns The downloaded binary path and lock path to release
900: * @throws {UpgradeError} When download fails
901: */
902: export async function downloadBinaryToTemp(
903: version: string,
904: downloadTag?: string,
905: offline?: ...
Found 7 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts:
Line 1814: const result = await attemptDeltaUpgrade(
Line 1834: await prefetchNightlyPatches("0.14.0-dev.123");
Line 1844: await prefetchStablePatches("0.14.0");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts:
Line 318: const result = await attemptDeltaUpgrade(
Line 335: const result = await attemptDeltaUpgrade(
Line 406: const result = await attemptDeltaUpgrade(
Line 481: const result = await attemptDeltaUpgrade(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts</path> <type>file</type> <content> 1: /** 2: * Integration tests for delta upgrade orchestration with a non-dev CLI_VERSION. 3: * 4: * These tests use `vi.mock()` to override `CLI_VERSION` from constants.js 5: * so that `canAttemptDelta()` passes its dev-build guard (the real `CLI_VERSION` 6: * is "0.0.0-dev" in test mode, which short-circuits the orchestrator). 7: * 8: * Kept as a sibling file to `delta-upgrade.test.ts` because its 9: * `vi.mock()` would invert the assumptions of the dev-mode null-return 10: * tests in that file. Under `bun test --isolate` each file gets a fresh 11: * module graph, so the mocks here don't leak. ...
Found 35 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts:
Line 18: githubReleaseSource,
Line 85: load(currentVersion, targetVersion) {
Line 86: const key = patchCacheKey(currentVersion, targetVersion);
Line 89: const result = await base.load(currentVersion, targetVersion);
Line 123: return githubReleaseSource({
Line 124: releasesUrl: GITHUB_RELEASES_URL,
Line 145: export function canAttemptDelta(targetVersion: string): boolean {
Line 149: if (isNightlyVersion(CLI_VERSION) !== isNightlyVersion(targetVersion)) {
Line 152: return !isDowngrade(CLI_VERSION, targetVersion);
Line 207: targetVersion: string
Line 212: targetVersion,
Line 272: targetVersion: string,
Line 275: return stableSource().resolveChain(currentVersion, targetVersion, signal);
Line 281: targetVersion: string;
Line 298: ...
StatusCode: non 2xx status code (404 GET https://api.github.com/repos/BYK/binpatch/git/ref/tags/v0.4.2)
[
{
"name": "0.4.2",
"zipball_url": "https://api.github.com/repos/BYK/binpatch/zipball/refs/tags/0.4.2",
"tarball_url": "https://api.github.com/repos/BYK/binpatch/tarball/refs/tags/0.4.2",
"commit": {
"sha": "9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"url": "https://api.github.com/repos/BYK/binpatch/commits/9ba6bbb8227fcbd2521852d2311c82afac5e9573"
},
"node_id": "REF_kwDOThqhQK9yZWZzL3RhZ3MvMC40LjI"
},
{
"name": "0.4.1",
"zipball_url": "https://api.github.com/repos/BYK/binpatch/zipball/refs/tags/0.4.1",
"tarball_url": "https://api.github.com/repos/BYK/binpatch/tarball/refs/tags/0.4.1",
"commit": {
"sha": "d0593cdd89eb720edddf9644e0753613e4a8e622",
"url": "https://api.github.com/repos/BYK/binpatch/commits/d0593cdd89eb720edddf9644e0753613e4a8e622"
},
"node_id": "REF_kwDOThqhQK9yZWZzL3RhZ3MvMC40LjE"
},
{
"name": "0.4.0",
"zipball_url": ...
{
"name": "binpatch",
"version": "0.4.2",
"type": "module",
"license": "MIT",
"description": "Reusable binary delta-update engine: apply TRDIFF10/bsdiff+zstd patch chains to a binary and discover chains from a pluggable source (OCI/GHCR or GitHub Releases). Pure Node, zero product coupling.",
"author": "BYK",
"homepage": "https://github.com/BYK/binpatch#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/BYK/binpatch.git"
},
"bugs": {
"url": "https://github.com/BYK/binpatch/issues"
},
"keywords": [
"bsdiff",
"bspatch",
"trdiff10",
"zstd",
"binary",
"delta",
"patch",
"update",
"self-update",
"oci",
"ghcr"
],
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist/",
"README.md",
"LICENSE"
],
"sideEffects": false,
"engines": {
"node": ...
# binpatch [](https://www.npmjs.com/package/binpatch) [](https://github.com/BYK/binpatch/actions) [](LICENSE) Reusable binary delta-update engine. Apply a **TRDIFF10 / bsdiff+zstd** patch chain to a binary, discover chains from a pluggable source (OCI/GHCR tags or GitHub Release assets), and generate + publish patches via a composite GitHub Action. Pure Node, zero product coupling — works for Electron apps, CLIs, agents, and any single-file binary artifact. ```sh npm install binpatch ``` **Docs:** https://binpatch.p.byk.im/ · **Source:** https://github.com/BYK/binpatch ## Why Every time your binary updates itself, your users pull the **entire file again** — even when the new release changed a few hundred kilobytes of a 100 MB Electron app, a 50 MB CLI, or a 200 MB game ...
<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: ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md 2: 3: Guidelines for AI agents working in this codebase. 4: 5: ## Project Overview 6: 7: **Sentry CLI** is a command-line interface for [Sentry](https://sentry.io), built with Node.js, [pnpm](https://pnpm.io), and [Stricli](https://bloomberg.github.io/stricli/). It lives in `packages/cli` of a pnpm workspace; the docs site lives in `apps/cli-docs`. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Unit Tests for Delta Upgrade Module
3: *
4: * Tests the exported pure-computation functions that drive chain resolution
5: * for both stable (GitHub Releases) and nightly (GHCR) channels, plus
6: * async orchestration functions tested via fetch mocking.
7: */
8:
9: import { createHash } from "node:crypto";
10: import { existsSync, unlinkSync } from "node:fs";
11: import { access, readFile } from "node:fs/promises";
12: import { tmpdir } from "node:os";
13: import { join } from "node:path";
14: import { afterEach, beforeEach, describe, expect, test } from "vitest";
15: import { getPlatformBinaryName } from "../../src/lib/binary.js";
16: import {
17: applyPatchChain,
18: attemptDeltaUpgrade,
19: canAttemptDelta,
20: downloadStablePatch,
21: type ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1050: const chain = await resolveStableChain("0.13.0", "0.14.0");
1051: expect(chain).toBeNull();
1052: });
1053:
1054: test("returns null when chain depth exceeds stable limit", async () => {
1055: const binaryName = getPlatformBinaryName();
1056: // 15 releases = 14 hops, exceeds MAX_STABLE_CHAIN_DEPTH (10)
1057: const versions = Array.from({ length: 15 }, (_, i) => `0.${i + 1}.0`);
1058: versions.reverse(); // newest first
1059: const releases = versions.map((v) =>
1060: makeRelease(v, [
1061: makeAsset({ name: binaryName, digest: `sha256:${versionHex(v)}` }),
1062: makeAsset({
1063: name: `${binaryName}.patch`,
1064: size: 100,
1065: browser_download_url: `https://example.com/${v}.patch`,
1066: ...
Found 17 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts:
Line 140: * @throws {UpgradeError} When no cached version is available
Line 150: "No cached version available. Run any command to trigger a background version check, then retry."
Line 181: // Channel switching with --offline is not supported: the cached version
Line 186: "Cannot switch channels in offline mode — the cached version belongs to the current channel. " +
Line 190: // Read the cached version BEFORE persisting the channel — setReleaseChannel
Line 194: log.info(`Offline mode: using cached target ${target}`);
Line 202: const resolved = await resolveTargetVersion(resolveOpts);
Line 219: log.warn("Network unavailable, falling back to cached upgrade target");
Line 220: log.info(`Using cached target: ${target}`);
Line 221: return { kind: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
110: * @returns `{ channel, versionArg }` where versionArg is undefined when the
111: * positional was a channel name (so we resolve to latest) or was omitted.
112: */
113: function resolveChannelAndVersion(positional: string | undefined): {
114: channel: ReleaseChannel;
115: versionArg: string | undefined;
116: } {
117: // "nightly" and "stable" as positional args select the channel rather than
118: // installing a specific version. Match case-insensitively for convenience.
119: const lower = positional?.toLowerCase();
120: if (lower === "nightly" || lower === "stable") {
121: return {
122: channel: lower,
123: versionArg: undefined,
124: };
125: }
126:
127: return {
128: channel: getReleaseChannel(),
129: versionArg: positional,
130: };
131: }
132: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
270: *
271: * - `target`: the version string to upgrade/downgrade to (proceed with upgrade)
272: * - `UpgradeResult`: structured result when no upgrade should proceed
273: * (check-only mode, or already up to date)
274: */
275: type ResolveResult =
276: | { kind: "target"; target: string }
277: | { kind: "done"; result: UpgradeResult };
278:
279: /**
280: * Resolve the target version and handle check-only mode.
281: *
282: * @returns A `ResolveResult` indicating whether to proceed with the upgrade
283: * or return a completed result immediately. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
80: /**
81: * Absolute legacy install directories for the given home. See
82: * {@link LEGACY_INSTALL_SUBDIRS} for why this is scoped to pre-XDG locations.
83: */
84: export function getLegacyInstallDirs(homeDir: string): string[] {
85: return LEGACY_INSTALL_SUBDIRS.map((dir) => join(homeDir, dir));
86: }
87:
88: /**
89: * How the CLI was installed. Determines the upgrade strategy.
90: *
91: * Defined here (alongside other installation constants like
92: * {@link KNOWN_CURL_DIRS}) so that both `upgrade.ts` and
93: * `db/install-info.ts` can import it without creating a circular
94: * dependency. ...
Found 10 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 498: export function fetchLatestVersion(
Line 551: export async function versionExists(
Line 579: /** Result from downloadBinaryToTemp — includes both the binary path and lock path */
Line 902: export async function downloadBinaryToTemp(
Line 1030: function executeUpgradeHomebrew(): Promise<void> {
Line 1065: function executeUpgradePackageManager(
Line 1122: export async function executeUpgrade(
Line 1131: return downloadBinaryToTemp(version, downloadTag, offline, setMessage);
Line 1133: await executeUpgradeHomebrew();
Line 1139: await executeUpgradePackageManager(method, version);
<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 {
25: acquireLock,
26: cleanupOldBinary,
27: determineInstallDir,
28: fetchWithUpgradeError,
29: ...
/**
* Chain discovery + resolve-and-apply orchestration.
*
* A {@link SourceStrategy} knows how to resolve a {@link PatchChain} from some
* backing store (an OCI registry, GitHub Release assets, ...). This module ties
* a strategy together with the offline cache, the apply core, integrity
* verification, and progress events — with every product-specific concern
* (version, telemetry, logging, cache location) injected.
*/
import { applyPatchChainInMemory, parsePatchHeader } from "./bspatch";
import type { PatchCache } from "./patch-cache";
import type { DeltaResult, PatchChain } from "./contract";
import { type ProgressHandler, safeProgress } from "./events";
/**
* A source of patch chains. Given the current and target versions, resolve the
* ordered chain of patches (oldest hop first) plus the expected final SHA-256,
* or `null` when no usable chain exists (caller falls back to a full download). ...
Found 45 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/binary.test.ts:
Line 35: resolveUpgradeSource,
Line 38: UPGRADE_SOURCES,
Line 67: describe("UPGRADE_SOURCES", () => {
Line 69: expect(UPGRADE_SOURCES).toEqual([
Line 84: describe("resolveUpgradeSource", () => {
Line 88: const resolved = await resolveUpgradeSource({
Line 99: source: UPGRADE_SOURCES[0],
Line 110: const resolved = await resolveUpgradeSource({
Line 123: expect(resolved.source).toBe(UPGRADE_SOURCES[1]);
Line 136: resolveUpgradeSource({
Line 155: resolveUpgradeSource({
Line 173: resolveUpgradeSource({
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 106: export type UpgradeSource = {
Line 116: export const UPGRADE_SOURCES: readonly UpgradeSource[] = [
...
/**
* binpatch — reusable binary delta-update engine.
*
* Two things, joined by one wire contract (see README):
* - **apply core** — parse + apply a TRDIFF10/bsdiff patch chain to a binary.
* - **discovery** — resolve a patch chain from a pluggable `SourceStrategy`
* (OCI/GHCR tags or GitHub Release assets), then apply + verify it.
*
* Pure Node (`node:*` builtins only), zero product coupling — the consumer
* injects the cache directory, the download source, version comparison,
* progress handling, and telemetry.
*/
export {
addDiffChunk,
applyPatch,
applyPatchChainInMemory,
applyPatchToMemory,
MAX_OUTPUT_SIZE,
offtin,
parsePatchHeader,
type PatchHeader,
} from "./bspatch";
export {
type ChainMeta,
chainFileName,
makeCache,
type PatchCache,
patchFileName,
type PatchStepMeta,
} from "./patch-cache";
// Wire-contract constants + shared chain types. ...
No files found
M packages/cli/src/lib/binary.ts M packages/cli/src/lib/ghcr.ts M packages/cli/test/lib/binary.test.ts M packages/cli/test/lib/ghcr.test.ts M packages/cli/test/lib/install-script.test.ts packages/cli/src/lib/binary.ts | 139 +++++++++++++++++++++++++-- packages/cli/src/lib/ghcr.ts | 52 ++++++---- packages/cli/test/lib/binary.test.ts | 129 ++++++++++++++++++++++++- packages/cli/test/lib/ghcr.test.ts | 30 ++++++ packages/cli/test/lib/install-script.test.ts | 10 ++ 5 files changed, 335 insertions(+), 25 deletions(-) diff --git a/packages/cli/src/lib/binary.ts b/packages/cli/src/lib/binary.ts index 75582612a..bebf1da0c 100644 --- a/packages/cli/src/lib/binary.ts +++ b/packages/cli/src/lib/binary.ts @@ -102,6 +102,33 @@ export type InstallationMethod = | "yarn" | "unknown"; +/** A repository pair that hosts CLI stable releases and nightly OCI images. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts</path>
<type>file</type>
<content>
180: // At 0% of interval: ~0% chance
181: // At 100% of interval: ~63% chance (1 - 1/e)
182: // At 200% of interval: ~86% chance
183: const probability = 1 - Math.exp(-elapsed / effectiveInterval);
184:
185: return Math.random() < probability;
186: }
187:
188: /**
189: * Check if update notifications should be suppressed for these args.
190: */
191: export function shouldSuppressNotification(args: string[]): boolean {
192: if (args.some((arg) => SUPPRESSED_ARGS.has(arg))) {
193: return true;
194: }
195: // Suppress for "cli <subcommand>" management commands (setup, fix). ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts</path>
<type>file</type>
<content>
270: pendingAbortController = new AbortController();
271: const { signal } = pendingAbortController;
272:
273: const channel = getReleaseChannel();
274:
275: Sentry.startSpanManual(
276: {
277: name: "version-check",
278: op: "version.check",
279: forceTransaction: true,
280: },
281: async (span) => {
282: try {
283: // Use GHCR for nightly channel; GitHub Releases for stable.
284: const latestVersion =
285: channel === "nightly"
286: ? ...
Found 10 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 137: fetchLatestFromGitHub,
Line 190: describe("fetchLatestFromGitHub", () => {
Line 205: const version = await fetchLatestFromGitHub();
Line 223: const version = await fetchLatestFromGitHub();
Line 241: const version = await fetchLatestFromGitHub();
Line 253: await expect(fetchLatestFromGitHub()).rejects.toThrow(UpgradeError);
Line 254: await expect(fetchLatestFromGitHub()).rejects.toThrow(
Line 264: await expect(fetchLatestFromGitHub()).rejects.toThrow(UpgradeError);
Line 265: await expect(fetchLatestFromGitHub()).rejects.toThrow(
Line 279: await expect(fetchLatestFromGitHub()).rejects.toThrow(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts</path>
<type>file</type>
<content>
100: }) as (cmd: string, args: string[], opts: object) => FakeProc,
101: },
102: }));
103: // Initialize with the real default now that fakeProcess is defined
104: spawnImpl.fn = () => fakeProcess(0);
105:
106: vi.mock("node:child_process", async (importOriginal) => {
107: const orig = await importOriginal<typeof import("node:child_process")>();
108: return {
109: ...orig,
110: spawn: (cmd: string, args: string[], opts: object) =>
111: spawnImpl.fn(cmd, args, opts),
112: };
113: });
114:
115: // Dynamic imports: must run AFTER vi.mock() so upgrade.ts picks up the
116: // mocked spawn.
117: import { isEnoentSpawnError } from "../../src/commands/cli/upgrade.js";
118: import {
119: acquireLock,
120: getBinaryDownloadUrl,
121: isNightlyVersion,
122: releaseLock,
123: } ...
Found 3 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts: Line 287: : await fetchLatestFromGitHub(signal); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts: Line 399: export async function fetchLatestFromGitHub( Line 506: ? fetchLatestFromGitHub()
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/binary.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Binary Management Tests
3: *
4: * Tests for shared binary helpers: install directory selection, paths,
5: * download URLs, locking, and binary installation.
6: */
7:
8: import {
9: chmodSync,
10: mkdirSync,
11: readFileSync,
12: realpathSync,
13: rmSync,
14: symlinkSync,
15: writeFileSync,
16: } from "node:fs";
17: import { access, readFile, writeFile } from "node:fs/promises";
18: import { join, sep } from "node:path";
19: import { afterEach, beforeEach, describe, expect, test } from "vitest";
20: import {
21: acquireLock,
22: compareVersions,
23: determineInstallDir,
24: fetchWithUpgradeError,
25: getBinaryDownloadUrl,
26: getBinaryFilename,
27: getBinaryPaths,
28: getGitHubReleaseByTagUrl,
29: getLegacyInstallDirs,
30: getPlatformBinaryName,
31: ...
Found 46 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 640: if (u.includes("/manifests/nightly-")) {
Line 656: if (u.includes("/manifests/nightly-")) {
Line 673: if (u.includes("/manifests/nightly-")) {
Line 1589: const nightlyBinDir = join(TEST_TMP_DIR, "upgrade-nightly-test");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/patch-cache.test.ts:
Line 337: const chain = makeChain([patchData], "nightly-sha");
Line 347: expect(result?.expectedSha256).toBe("nightly-sha");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/ghcr.test.ts:
Line 541: return ...
/**
* GHCR / OCI patch source (the "nightly" channel).
*
* Resolves a patch chain from OCI patch-manifest tags. Patches are published
* under `<patchTagPrefix><version>` tags whose manifests carry:
* - annotation `from-version=<prev>` — the chain back-pointer
* - annotation `sha256-<binaryName>=<hex>` — the target's uncompressed SHA-256
* - a patch layer whose title is `<binaryName>.patch`
*
* The target binary's gzipped size (for the ratio gate) is read from the
* target's own image manifest (its `<binaryName>.gz` layer). All product
* specifics — registry, repo, user-agent, binary name, the version→target-tag
* scheme, and version comparison — are injected. Generalized from Lore's
* nightly-channel resolver.
*/
import {
type InstrumentHook,
MAX_NIGHTLY_CHAIN_DEPTH,
PATCH_TAG_PREFIX,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy, UnavailableReporter } from "../discover";
import { BinpatchError } ...
No files found
StatusCode: non 2xx status code (404 GET https://raw.githubusercontent.com/BYK/binpatch/v0.4.2/src/sources/github-release.ts)
<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: ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/ghcr.ts</path>
<type>file</type>
<content>
120: // Propagate external abort immediately — don't retry caller cancellation
121: if (isExternalAbort(lastError, externalSignal)) {
122: break;
123: }
124: // Only retry on timeout or network errors — not HTTP errors
125: if (attempt >= GHCR_MAX_RETRIES || !isRetryableError(lastError)) {
126: break;
127: }
128: }
129: }
130:
131: throw new UpgradeError(
132: "network_error",
133: `${context}: ${lastError?.message ?? "unknown error"}`
134: );
135: }
136:
137: /** Default GHCR repository for CLI distribution. */
138: export const GHCR_REPO = PRIMARY_UPGRADE_SOURCE.ghcrRepo;
139:
140: /** OCI tag for nightly builds */
141: export const GHCR_TAG = "nightly";
142:
143: /** Base URL for GHCR registry API */
144: const GHCR_REGISTRY = ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
690: }
691:
692: if (writeError) {
693: throw writeError;
694: }
695:
696: if (streamError !== undefined) {
697: throw streamError;
698: }
699: }
700:
701: /**
702: * Build the gzip filename for the current platform binary.
703: *
704: * Nightly builds are stored in GHCR as `sentry-<os>-<arch>.gz` (or
705: * `sentry-windows-x64.exe.gz` on Windows). This filename is the
706: * `org.opencontainers.image.title` annotation on the matching OCI layer.
707: *
708: * @returns Filename of the gzip-compressed binary for this platform
709: */
710: function getNightlyGzFilename(): string {
711: return `${getPlatformBinaryName()}.gz`;
712: }
713:
714: /**
715: * Download a nightly binary from GHCR and decompress it to `destPath`. ...
[
{
"name": "0.4.2",
"zipball_url": "https://api.github.com/repos/BYK/binpatch/zipball/refs/tags/0.4.2",
"tarball_url": "https://api.github.com/repos/BYK/binpatch/tarball/refs/tags/0.4.2",
"commit": {
"sha": "9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"url": "https://api.github.com/repos/BYK/binpatch/commits/9ba6bbb8227fcbd2521852d2311c82afac5e9573"
},
"node_id": "REF_kwDOThqhQK9yZWZzL3RhZ3MvMC40LjI"
},
{
"name": "0.4.1",
"zipball_url": "https://api.github.com/repos/BYK/binpatch/zipball/refs/tags/0.4.1",
"tarball_url": "https://api.github.com/repos/BYK/binpatch/tarball/refs/tags/0.4.1",
"commit": {
"sha": "d0593cdd89eb720edddf9644e0753613e4a8e622",
"url": "https://api.github.com/repos/BYK/binpatch/commits/d0593cdd89eb720edddf9644e0753613e4a8e622"
},
"node_id": "REF_kwDOThqhQK9yZWZzL3RhZ3MvMC40LjE"
},
{
"name": "0.4.0",
"zipball_url": ...
Found 84 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts:
Line 18: attemptDeltaUpgrade,
Line 24: fetchRecentReleases,
Line 32: prefetchNightlyPatches,
Line 33: prefetchStablePatches,
Line 34: resolveNightlyChain,
Line 35: resolveNightlyDelta,
Line 36: resolveStableChain,
Line 37: resolveStableDelta,
Line 817: // fetchRecentReleases
Line 819: describe("fetchRecentReleases", () => {
Line 834: const result = await fetchRecentReleases();
Line 842: const result = await fetchRecentReleases();
Line 851: const result = await fetchRecentReleases();
Line 891: // resolveStableChain (async orchestrator)
Line 893: describe("resolveStableChain", () => {
Line 947: const chain = await resolveStableChain("0.13.0", "0.14.0");
Line 1000: const chain = await resolveStableChain("0.13.0", "0.15.0");
Line 1018: ...
{
"url": "https://api.github.com/repos/getsentry/cli/issues/1244",
"repository_url": "https://api.github.com/repos/getsentry/cli",
"labels_url": "https://api.github.com/repos/getsentry/cli/issues/1244/labels{/name}",
"comments_url": "https://api.github.com/repos/getsentry/cli/issues/1244/comments",
"events_url": "https://api.github.com/repos/getsentry/cli/issues/1244/events",
"html_url": "https://github.com/getsentry/cli/issues/1244",
"id": 4890976993,
"node_id": "I_kwDOQm6jAs8AAAABI4Zi4Q",
"number": 1244,
"title": "toolkit merge: bridge CLI release + dual-source upgrade compatibility",
"user": {
"login": "BYK",
"id": 126780,
"node_id": "MDQ6VXNlcjEyNjc4MA==",
"avatar_url": "https://avatars.githubusercontent.com/u/126780?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/BYK",
"html_url": "https://github.com/BYK",
"followers_url": "https://api.github.com/users/BYK/followers",
"following_url": ...
[
{
"url": "https://api.github.com/repos/getsentry/cli/issues/comments/4978828102",
"html_url": "https://github.com/getsentry/cli/issues/1244#issuecomment-4978828102",
"issue_url": "https://api.github.com/repos/getsentry/cli/issues/1244",
"id": 4978828102,
"node_id": "IC_kwDOQm6jAs8AAAABKMLjRg",
"user": {
"login": "BYK",
"id": 126780,
"node_id": "MDQ6VXNlcjEyNjc4MA==",
"avatar_url": "https://avatars.githubusercontent.com/u/126780?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/BYK",
"html_url": "https://github.com/BYK",
"followers_url": "https://api.github.com/users/BYK/followers",
"following_url": "https://api.github.com/users/BYK/following{/other_user}",
"gists_url": "https://api.github.com/users/BYK/gists{/gist_id}",
"starred_url": "https://api.github.com/users/BYK/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/BYK/subscriptions",
...
diff --git a/packages/cli/src/lib/ghcr.ts b/packages/cli/src/lib/ghcr.ts
index 43d6deb7e..f648ab78a 100644
--- a/packages/cli/src/lib/ghcr.ts
+++ b/packages/cli/src/lib/ghcr.ts
@@ -20,6 +20,10 @@
import { getUserAgent } from "./constants.js";
import { customFetch } from "./custom-ca.js";
import { UpgradeError } from "./errors.js";
+import {
+ PRIMARY_UPGRADE_SOURCE,
+ type UpgradeSource,
+} from "./binary.js";
/** Default timeout for GHCR HTTP requests (10 seconds) */
const GHCR_REQUEST_TIMEOUT = 10_000;
@@ -130,8 +134,8 @@ async function fetchWithRetry(
);
}
-/** GHCR repository for CLI distribution */
-export const GHCR_REPO = "getsentry/cli";
+/** Default GHCR repository for CLI distribution. */
+export const GHCR_REPO = PRIMARY_UPGRADE_SOURCE.ghcrRepo;
/** OCI tag for nightly builds */
export const GHCR_TAG = "nightly";
@@ -189,13 +193,20 @@ export type OciManifest = {
* @returns Bearer token string
* @throws {UpgradeError} On network failure or malformed ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
88: /**
89: * How the CLI was installed. Determines the upgrade strategy.
90: *
91: * Defined here (alongside other installation constants like
92: * {@link KNOWN_CURL_DIRS}) so that both `upgrade.ts` and
93: * `db/install-info.ts` can import it without creating a circular
94: * dependency.
95: */
96: export type InstallationMethod =
97: | "curl"
98: | "brew"
99: | "npm"
100: | "pnpm"
101: | "bun"
102: | "yarn"
103: | "unknown";
104:
105: /** A repository pair that hosts CLI stable releases and nightly OCI images. */
106: export type UpgradeSource = {
107: /** GitHub `owner/repository` containing CLI release assets. */
108: readonly githubRepo: string;
109: /** GHCR `owner/package` containing CLI nightly images and delta patches. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts</path>
<type>file</type>
<content>
180: // At 0% of interval: ~0% chance
181: // At 100% of interval: ~63% chance (1 - 1/e)
182: // At 200% of interval: ~86% chance
183: const probability = 1 - Math.exp(-elapsed / effectiveInterval);
184:
185: return Math.random() < probability;
186: }
187:
188: /**
189: * Check if update notifications should be suppressed for these args.
190: */
191: export function shouldSuppressNotification(args: string[]): boolean {
192: if (args.some((arg) => SUPPRESSED_ARGS.has(arg))) {
193: return true;
194: }
195: // Suppress for "cli <subcommand>" management commands (setup, fix). ...
Found 28 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 106: export type UpgradeSource = {
Line 112: readonly tagPrefix: string;
Line 116: export const UPGRADE_SOURCES: readonly UpgradeSource[] = [
Line 120: tagPrefix: "cli@",
Line 125: tagPrefix: "",
Line 236: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 238: const tag = `${source.tagPrefix}${version}`;
Line 244: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 252: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 254: const tag = `${source.tagPrefix}${version}`;
Line 260: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 262: return source.tagPrefix
Line 269: source: UpgradeSource = PRIMARY_UPGRADE_SOURCE
Line 278: export type ResolvedUpgradeSource = {
Line 280: readonly source: UpgradeSource;
Line 286: export type ResolveUpgradeSourceOptions ...
No files found
Found 8 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 766: const url = getBinaryDownloadUrl(version);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 116: export const UPGRADE_SOURCES: readonly UpgradeSource[] = [
Line 130: export const PRIMARY_UPGRADE_SOURCE = UPGRADE_SOURCES[0];
Line 234: export function getBinaryDownloadUrl(
Line 250: export function getGitHubReleaseByTagUrl(
Line 259: export function getGitHubLatestReleaseUrl(
Line 268: export function getGitHubRepositoryUrl(
Line 306: for (const source of UPGRADE_SOURCES) {
Found 17 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/binary.test.ts:
Line 28: getGitHubReleaseByTagUrl,
Line 35: resolveUpgradeSource,
Line 84: describe("resolveUpgradeSource", () => {
Line 88: const resolved = await resolveUpgradeSource({
Line 89: getProbeUrl: (source) => getGitHubReleaseByTagUrl("0.45.0", source),
Line 110: const resolved = await resolveUpgradeSource({
Line 111: getProbeUrl: (source) => getGitHubReleaseByTagUrl("0.45.0", source),
Line 136: resolveUpgradeSource({
Line 137: getProbeUrl: (source) => getGitHubReleaseByTagUrl("0.45.0", source),
Line 155: resolveUpgradeSource({
Line 156: getProbeUrl: (source) => getGitHubReleaseByTagUrl("0.45.0", source),
Line 173: resolveUpgradeSource({
Line 174: getProbeUrl: (source) => getGitHubReleaseByTagUrl("0.45.0", ...
/**
* binpatch — reusable binary delta-update engine.
*
* Two things, joined by one wire contract (see README):
* - **apply core** — parse + apply a TRDIFF10/bsdiff patch chain to a binary.
* - **discovery** — resolve a patch chain from a pluggable `SourceStrategy`
* (OCI/GHCR tags or GitHub Release assets), then apply + verify it.
*
* Pure Node (`node:*` builtins only), zero product coupling — the consumer
* injects the cache directory, the download source, version comparison,
* progress handling, and telemetry.
*/
export {
addDiffChunk,
applyPatch,
applyPatchChainInMemory,
applyPatchToMemory,
MAX_OUTPUT_SIZE,
offtin,
parsePatchHeader,
type PatchHeader,
} from "./bspatch";
export {
type ChainMeta,
chainFileName,
makeCache,
type PatchCache,
patchFileName,
type PatchStepMeta,
} from "./patch-cache";
// Wire-contract constants + shared chain types. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade</path> <type>directory</type> <entries> .craft.yml .git .github/ .gitignore .lore.md .nojekyll .npmrc AGENTS.md apps/ CHANGELOG.md codemods/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md (18 entries) </entries>
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md 2: 3: Guidelines for AI agents working in this codebase. 4: 5: ## Project Overview 6: 7: **Sentry CLI** is a command-line interface for [Sentry](https://sentry.io), built with Node.js, [pnpm](https://pnpm.io), and [Stricli](https://bloomberg.github.io/stricli/). It lives in `packages/cli` of a pnpm workspace; the docs site lives in `apps/cli-docs`. ...
I’m tracing the selected-source path into the delta entry points and checking the exact 0.4.2 public contracts before I give file- and symbol-level recommendations. I’ll keep this read-only and won’t run broad tests.
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts:
Line 14: import { getReleaseChannel } from "./db/release-channel.js";
Line 16: getVersionCheckInfo,
Line 18: setVersionCheckInfo,
Line 167: const { lastChecked } = getVersionCheckInfo();
Line 216: export function abortPendingVersionCheck(): void {
Line 228: channel: "stable" | "nightly",
Line 229: latestVersion: string,
Line 232: if (semverCompare(latestVersion, CLI_VERSION) !== 1) {
Line 236: if (channel === "nightly") {
Line 237: await prefetchNightlyPatches(latestVersion, signal);
Line 239: await prefetchStablePatches(latestVersion, signal);
Line 259: function checkForUpdateInBackgroundImpl(): void {
Line 273: const channel = getReleaseChannel();
Line 283: // Use GHCR for nightly channel; GitHub Releases for stable. ...
<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 {
25: acquireLock,
26: cleanupOldBinary,
27: determineInstallDir,
28: fetchWithUpgradeError,
29: ...
M packages/cli/src/lib/binary.ts M packages/cli/src/lib/ghcr.ts M packages/cli/test/lib/binary.test.ts M packages/cli/test/lib/ghcr.test.ts M packages/cli/test/lib/install-script.test.ts packages/cli/src/lib/binary.ts | 139 +++++++++++++++++++++++++-- packages/cli/src/lib/ghcr.ts | 52 ++++++---- packages/cli/test/lib/binary.test.ts | 129 ++++++++++++++++++++++++- packages/cli/test/lib/ghcr.test.ts | 30 ++++++ packages/cli/test/lib/install-script.test.ts | 10 ++ 5 files changed, 335 insertions(+), 25 deletions(-)
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Unit Tests for Delta Upgrade Module
3: *
4: * Tests the exported pure-computation functions that drive chain resolution
5: * for both stable (GitHub Releases) and nightly (GHCR) channels, plus
6: * async orchestration functions tested via fetch mocking.
7: */
8:
9: import { createHash } from "node:crypto";
10: import { existsSync, unlinkSync } from "node:fs";
11: import { access, readFile } from "node:fs/promises";
12: import { tmpdir } from "node:os";
13: import { join } from "node:path";
14: import { afterEach, beforeEach, describe, expect, test } from "vitest";
15: import { getPlatformBinaryName } from "../../src/lib/binary.js";
16: import {
17: applyPatchChain,
18: attemptDeltaUpgrade,
19: canAttemptDelta,
20: downloadStablePatch,
21: type ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts</path> <type>file</type> <content> 1: /** 2: * Integration tests for delta upgrade orchestration with a non-dev CLI_VERSION. 3: * 4: * These tests use `vi.mock()` to override `CLI_VERSION` from constants.js 5: * so that `canAttemptDelta()` passes its dev-build guard (the real `CLI_VERSION` 6: * is "0.0.0-dev" in test mode, which short-circuits the orchestrator). 7: * 8: * Kept as a sibling file to `delta-upgrade.test.ts` because its 9: * `vi.mock()` would invert the assumptions of the dev-mode null-return 10: * tests in that file. Under `bun test --isolate` each file gets a fresh 11: * module graph, so the mocks here don't leak. ...
/**
* Chain discovery + resolve-and-apply orchestration.
*
* A {@link SourceStrategy} knows how to resolve a {@link PatchChain} from some
* backing store (an OCI registry, GitHub Release assets, ...). This module ties
* a strategy together with the offline cache, the apply core, integrity
* verification, and progress events — with every product-specific concern
* (version, telemetry, logging, cache location) injected.
*/
import { applyPatchChainInMemory, parsePatchHeader } from "./bspatch";
import type { PatchCache } from "./patch-cache";
import type { DeltaResult, PatchChain } from "./contract";
import { type ProgressHandler, safeProgress } from "./events";
/**
* A source of patch chains. Given the current and target versions, resolve the
* ordered chain of patches (oldest hop first) plus the expected final SHA-256,
* or `null` when no usable chain exists (caller falls back to a full download). ...
Found 35 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/pnpm-lock.yaml:
Line 867: '@hono/mcp@0.2.5':
Line 1548: '@sentry/cli@2.58.6':
Line 4207: trpc-cli@0.12.4:
Line 5355: '@hono/mcp@0.2.5(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(hono-rate-limiter@0.4.2(hono@4.12.34))(hono@4.12.34)(zod@4.4.3)':
Line 6000: '@sentry/cli@2.58.6':
Line 9255: trpc-cli@0.12.4(@trpc/server@11.18.0(typescript@5.9.3))(valibot@1.4.2(typescript@5.9.3))(zod@4.4.3):
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/apps/cli-docs/src/fragments/commands/issue.md:
Line 220: sentry issue resolve CLI-G5 --in @commit:getsentry/cli@abc123def
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/binary.test.ts:
Line 46: expect(url).toContain("/cli@1.0.0/");
Line 73: ...
<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/delta-upgrade.ts</path>
<type>file</type>
<content>
220: currentVersion,
221: targetVersion,
222: compareVersions
223: );
224: }
225:
226: type ChainStepResult =
227: | { ok: true; digest: string; size: number }
228: | {
229: ok: false;
230: failure:
231: | {
232: reason: "version-mismatch";
233: expected: string;
234: actual: string | null;
235: }
236: | { reason: "missing-layer"; layerName: string }
237: | { reason: "size-exceeded"; layerSize: number; budget: number };
238: };
239:
240: export function validateChainStep(
241: manifest: OciManifest,
242: opts: { expectedFrom: string; patchLayerName: string; sizeLimit: number }
243: ): ChainStepResult {
244: const fromVersion = getPatchFromVersion(manifest);
245: if (fromVersion !== ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/install-script.test.ts:
Line 20: import { UPGRADE_SOURCES } from "../../src/lib/binary.js";
Line 83: https://api.github.com/repos/getsentry/toolkit/releases\\?per_page=100)
Line 88: *) body='[{"tag_name":"mcp@9.0.0"},{"tag_name":"cli@0.51.0-dev.1","prerelease":true},{"tag_name":"cli@0.50.0"}]' ;;
Line 91: https://api.github.com/repos/getsentry/cli/releases/latest)
Line 94: https://api.github.com/repos/getsentry/toolkit/releases/tags/cli%40*)
Line 99: *) body='{"tag_name":"cli@0.31.0"}' ;;
Line 102: https://api.github.com/repos/getsentry/cli/releases/tags/*)
Line 105: https://api.github.com/repos/getsentry/toolkit)
Line 109: body='{"full_name":"getsentry/toolkit"}'
Line 112: https://api.github.com/repos/getsentry/cli)
Line 113: ...
...output truncated...
Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_0863ef578001C7hRc8627Nyeti
isDowngrade,
isNightlyVersion,
+ PRIMARY_UPGRADE_SOURCE,
+ type UpgradeSource,
} from "./binary.js";
import { CLI_VERSION } from "./constants.js";
import { customFetch } from "./custom-ca.js";
import { getConfigDir } from "./db/index.js";
import { formatBytes } from "./formatters/numbers.js";
-import { GHCR_REPO } from "./ghcr.js";
import { logger } from "./logger.js";
import { makeByteProgress, type SetMessage } from "./progress.js";
import { withTracing, withTracingSpan } from "./telemetry.js";
@@ -68,11 +69,15 @@ export type DeltaResult = {
chainLength: number;
};
-// GHCR publishes nightlies to ghcr.io/getsentry/cli (see src/lib/ghcr.ts
-// GHCR_REPO). Importing as a named import keeps a single source of truth and
-// avoids the silent 404 introduced when this was a string literal.
const log = logger.withTag("delta-upgrade");
+function ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
274: /** GitHub API base URL for the primary release source. */
275: export const GITHUB_RELEASES_URL = getGitHubReleasesUrl();
276:
277: /** Result of selecting one source for an upgrade operation. */
278: export type ResolvedUpgradeSource = {
279: /** The selected release source. */
280: readonly source: UpgradeSource;
281: /** The successful response from the source probe. */
282: readonly response: Response;
283: };
284:
285: /** Configuration for selecting the first available upgrade source. */
286: export type ResolveUpgradeSourceOptions = {
287: /** Build the source-specific URL whose response proves source availability. */
288: readonly getProbeUrl: (source: UpgradeSource) => string;
289: /** Fetch implementation used for the probe. Defaults to the CLI CA-aware fetch. ...
Found 79 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 263: ? `${getGitHubReleasesUrl(source)}?per_page=100`
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/api/traces.ts:
Line 31: API_MAX_PER_PAGE,
Line 445: * When `limit` exceeds {@link API_MAX_PER_PAGE}, transparently fetches multiple
Line 582: * When `limit` exceeds {@link API_MAX_PER_PAGE}, transparently fetches multiple
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/api/repositories.ts:
Line 14: API_MAX_PER_PAGE,
Line 94: perPage: API_MAX_PER_PAGE,
Line 96: MAX_PAGINATION_PAGES * ...
Found 35 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts:
Line 58: resolveExistingUpgradeVersion,
Line 59: resolveLatestUpgradeVersion,
Line 182: source?: UpgradeSource;
Line 218: source: resolved.source,
Line 289: | { kind: "target"; target: string; source?: UpgradeSource }
Line 290: | { kind: "done"; result: UpgradeResult; source?: UpgradeSource };
Line 305: const resolved = await resolveExistingUpgradeVersion(target);
Line 309: return resolved.source;
Line 325: ? await resolveLatestUpgradeVersion(channel)
Line 331: let source = latestResolution?.source;
Line 343: source: latestResolution?.source,
Line 367: source = (await resolvePinnedVersion(lookupMethod, target)) ?? source;
Line 370: return { kind: "target", target, source };
Line 656: source?: UpgradeSource;
Line 669: source,
Line ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
36: } from "../../lib/db/release-channel.js";
37: import { getVersionCheckInfo } from "../../lib/db/version-check.js";
38: import { UpgradeError } from "../../lib/errors.js";
39: import { formatUpgradeResult } from "../../lib/formatters/human.js";
40: import { formatBytes } from "../../lib/formatters/numbers.js";
41: import { CommandOutput } from "../../lib/formatters/output.js";
42: import { logger } from "../../lib/logger.js";
43: import { withProgress } from "../../lib/polling.js";
44: import {
45: type ChangelogSummary,
46: fetchChangelog,
47: } from "../../lib/release-notes.js";
48: import { isInPath } from "../../lib/shell.js";
49: import {
50: detectInstallationMethod,
51: executeUpgrade,
52: fetchLatestVersion,
53: getCurlInstallPaths,
54: type InstallationMethod,
55: ...
import { afterEach, describe, expect, it, vi } from "vitest";
import {
type InstrumentHook,
extractSha256,
extractStableChain,
filterAndSortChainTags,
getPatchFromVersion,
getPatchTargetSha256,
ghcrSource,
type GitHubRelease,
githubReleaseSource,
getStableTargetSha256,
OciClient,
type OciManifest,
validateChainStep,
} from "../src";
// Build a JSON Response for mocked fetch calls.
function json(body: unknown): Response {
return new Response(JSON.stringify(body), {
status: 200,
headers: { "content-type": "application/json" },
});
}
// A semver-ish comparator matching the gateway's compareVersions contract
// (returns -1 | 0 | 1) for the nightly tag-ordering tests.
function cmp(a: string, b: string): -1 | 0 | 1 {
const pa = a.split(".").map(Number);
const pb = b.split(".").map(Number);
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
const x = pa[i] ?? 0;
const y = pb[i] ?? ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
/**
* GHCR / OCI patch source (the "nightly" channel).
*
* Resolves a patch chain from OCI patch-manifest tags. Patches are published
* under `<patchTagPrefix><version>` tags whose manifests carry:
* - annotation `from-version=<prev>` — the chain back-pointer
* - annotation `sha256-<binaryName>=<hex>` — the target's uncompressed SHA-256
* - a patch layer whose title is `<binaryName>.patch`
*
* The target binary's gzipped size (for the ratio gate) is read from the
* target's own image manifest (its `<binaryName>.gz` layer). All product
* specifics — registry, repo, user-agent, binary name, the version→target-tag
* scheme, and version comparison — are injected. Generalized from Lore's
* nightly-channel resolver.
*/
import {
type InstrumentHook,
MAX_NIGHTLY_CHAIN_DEPTH,
PATCH_TAG_PREFIX,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy, UnavailableReporter } from "../discover";
import { BinpatchError } ...
/**
* OCI (GHCR-style) anonymous-pull client.
*
* Encapsulates the OCI download protocol for fetching binaries and patch
* artifacts from a container registry (ghcr.io by default). Anonymous,
* read-only: performs the standard token exchange, fetches manifests, lists
* tags, and downloads blobs.
*
* Registry / repository / user-agent are all injected — no product coupling.
* Generalized from Lore's `ghcr.ts`.
*
* Redirect quirk: ghcr.io blob downloads return a 307 to Azure Blob Storage.
* Following the redirect automatically would forward the Authorization header
* to Azure (→ 404), so redirects are followed manually WITHOUT the auth header.
*/
import { BinpatchError } from "../errors";
/** Default timeout for registry metadata requests (10s). */
const REQUEST_TIMEOUT = 10_000;
/** Retry attempts for transient failures. */
const MAX_RETRIES = 1;
/** Timeout for (larger) blob downloads (30s). */
const BLOB_TIMEOUT = 30_000;
/** Page size for tag-listing pagination. ...
<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/test/lib/delta-upgrade.mocked.test.ts</path> <type>file</type> <content> 1: /** 2: * Integration tests for delta upgrade orchestration with a non-dev CLI_VERSION. 3: * 4: * These tests use `vi.mock()` to override `CLI_VERSION` from constants.js 5: * so that `canAttemptDelta()` passes its dev-build guard (the real `CLI_VERSION` 6: * is "0.0.0-dev" in test mode, which short-circuits the orchestrator). 7: * 8: * Kept as a sibling file to `delta-upgrade.test.ts` because its 9: * `vi.mock()` would invert the assumptions of the dev-mode null-return 10: * tests in that file. Under `bun test --isolate` each file gets a fresh 11: * module graph, so the mocks here don't leak. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
90: *
91: * Defined here (alongside other installation constants like
92: * {@link KNOWN_CURL_DIRS}) so that both `upgrade.ts` and
93: * `db/install-info.ts` can import it without creating a circular
94: * dependency.
95: */
96: export type InstallationMethod =
97: | "curl"
98: | "brew"
99: | "npm"
100: | "pnpm"
101: | "bun"
102: | "yarn"
103: | "unknown";
104:
105: /** A repository pair that hosts CLI stable releases and nightly OCI images. */
106: export type UpgradeSource = {
107: /** GitHub `owner/repository` containing CLI release assets. */
108: readonly githubRepo: string;
109: /** GHCR `owner/package` containing CLI nightly images and delta patches. */
110: readonly ghcrRepo: string;
111: /** Prefix attached to CLI release tags in this repository. ...
Found 100 matches (more matches available)
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/close-dispatcher.test.ts:
Line 2: import { closeGlobalDispatcher } from "../../src/lib/close-dispatcher.js";
Line 4: const GLOBAL_DISPATCHER = Symbol.for("undici.globalDispatcher.1");
Line 16: describe("closeGlobalDispatcher", () => {
Line 17: test("destroys the global dispatcher when one is registered", async () => {
Line 26: await closeGlobalDispatcher();
Line 31: test("resolves without throwing when no dispatcher is registered", async () => {
Line 34: await expect(closeGlobalDispatcher()).resolves.toBeUndefined();
Line 37: test("resolves when the dispatcher has no destroy method", async () => {
Line 40: await expect(closeGlobalDispatcher()).resolves.toBeUndefined();
Line 48: await ...
Found 7 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 1853: describe("downloadBinaryToTemp offline errors", () => {
Line 1887: await downloadBinaryToTemp("0.26.1", undefined, "explicit");
Line 1901: await downloadBinaryToTemp("0.26.1", undefined, "network-fallback");
Line 1918: describe("downloadBinaryToTemp verifies download integrity (CLI-1D3)", () => {
Line 1967: await downloadBinaryToTemp("0.26.1");
Line 1988: await expect(downloadBinaryToTemp("0.26.1")).rejects.toThrow(UpgradeError);
Line 2041: const result = await downloadBinaryToTemp("0.26.1");
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts</path>
<type>file</type>
<content>
1820: JSON.stringify({
1821: schemaVersion: 2,
1822: layers: [
1823: {
1824: digest: "sha256:blobdigest",
1825: mediaType: "application/octet-stream",
1826: size: gzipped.byteLength,
1827: annotations: { "org.opencontainers.image.title": title },
1828: },
1829: ],
1830: annotations: { version: "0.0.0-dev.1740000000" },
1831: }),
1832: { status: 200 }
1833: );
1834: }
1835: if (urlStr.includes("/blobs/")) {
1836: // Return gzipped blob directly (no redirect needed for test)
1837: return new Response(gzipped, { status: 200 });
1838: }
1839: return new Response("Not Found", { status: 404 ...
Found 3 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts: Line 28: type UpgradeSource, Line 29: } from "../../lib/binary.js"; Line 62: } from "../../lib/upgrade.js";
<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. ...
No files found
Found 47 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts:
Line 242: await prefetchNightlyPatches(latestVersion, signal, source);
Line 244: await prefetchStablePatches(latestVersion, signal, source);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 1149: return await attemptDeltaUpgrade(
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts:
Line 279: export function resolveStableChain(
Line 292: export async function resolveNightlyChain(opts: {
Line 503: export function resolveStableDelta(
Line 522: export function resolveNightlyDelta(
Line 541: export function attemptDeltaUpgrade(
Line 634: export function prefetchNightlyPatches(
Line 642: export function ...
Found 12 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts:
Line 46: const LEGACY_UPGRADE_SOURCE = UPGRADE_SOURCES[1];
Line 47: if (!LEGACY_UPGRADE_SOURCE) {
Line 855: await fetchRecentReleases(undefined, LEGACY_UPGRADE_SOURCE);
Line 988: resolveStableChain("0.13.0", "0.14.0", undefined, LEGACY_UPGRADE_SOURCE)
Line 1236: source: LEGACY_UPGRADE_SOURCE,
Line 1922: describe("selected source affinity", () => {
Line 1941: LEGACY_UPGRADE_SOURCE
Line 1966: LEGACY_UPGRADE_SOURCE
Line 1975: test("prefetchStablePatches keeps requests on the legacy source", async () => {
Line 1986: LEGACY_UPGRADE_SOURCE
Line 1994: test("prefetchNightlyPatches keeps requests on the legacy source", async () => {
Line 2006: LEGACY_UPGRADE_SOURCE
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/version-check.test.ts</path>
<type>file</type>
<content>
400: });
401:
402: describe("abortPendingVersionCheck", () => {
403: test("does not throw when no pending check", () => {
404: // Should be safe to call even when nothing is pending
405: expect(() => abortPendingVersionCheck()).not.toThrow();
406: });
407:
408: test("does not throw when called multiple times", () => {
409: // Should be safe to call multiple times
410: expect(() => {
411: abortPendingVersionCheck();
412: abortPendingVersionCheck();
413: abortPendingVersionCheck();
414: }).not.toThrow();
415: });
416: });
417:
418: describe("maybeCheckForUpdateInBackground", () => {
419: useTestConfigDir("test-version-bg-");
420: let savedNoUpdateCheck: string | undefined;
421: let originalFetch: typeof globalThis.fetch;
422:
423: ...
<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: ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
I’m tracing the remaining source-affinity path and the Toolkit tag mismatch before returning the read-only implementation report.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts</path>
<type>file</type>
<content>
210: return true;
211: }
212: }
213: return false;
214: }
215:
216: /**
217: * Abort any pending version check to allow process exit.
218: * Call this when main CLI work is complete.
219: */
220: export function abortPendingVersionCheck(): void {
221: pendingAbortController?.abort();
222: pendingAbortController = null;
223: }
224:
225: /**
226: * Pre-fetch delta patches for a newly discovered version.
227: *
228: * Best-effort: errors are silently caught so the version check still succeeds.
229: * After pre-fetching, opportunistically cleans up stale cached patches. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
380: *
381: * Priority:
382: * 1. Homebrew — cheap realpath check, overrides stale stored info
383: * 2. Stored install info in DB (fast path)
384: * 3. Legacy detection: curl paths → subprocess calls → node_modules path
385: * 4. Auto-save detected method for future runs
386: *
387: * @returns Detected installation method, or "unknown" if unable to determine
388: */
389: export async function detectInstallationMethod(): Promise<InstallationMethod> {
390: // Always check for Homebrew first — the stored install info may be stale
391: // (e.g. user previously had a curl install recorded, then switched to
392: // Homebrew). The realpath check is cheap and authoritative. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
580:
581: /**
582: * Fetch the latest available version based on installation method and channel.
583: *
584: * - nightly channel: fetches version from GHCR manifest annotation
585: * - curl/brew on stable: checks GitHub /releases/latest
586: * - package managers on stable: checks npm registry
587: *
588: * @param method - How the CLI was installed
589: * @param channel - Release channel ("stable" or "nightly"), defaults to "stable"
590: * @returns Latest version string (without 'v' prefix)
591: * @throws {UpgradeError} When version fetch fails
592: */
593: export function fetchLatestVersion(
594: method: InstallationMethod,
595: channel: ReleaseChannel = "stable"
596: ): Promise<string> {
597: if (channel === "nightly") {
598: return fetchLatestNightlyVersion();
599: }
600: return ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
1010: const delay = VERIFY_BASE_DELAY_MS * 2 ** (attempt - 1);
1011: log.debug(
1012: `Downloaded binary not yet visible at ${path}, retrying in ${delay}ms (attempt ${attempt}/${VERIFY_MAX_ATTEMPTS})`
1013: );
1014: await setTimeout(delay);
1015: }
1016: throw new UpgradeError(
1017: "execution_failed",
1018: `Downloaded binary is missing or empty at ${path}. ` +
1019: "This is usually transient — rerun `sentry cli upgrade` to retry."
1020: );
1021: }
1022:
1023: /**
1024: * Download the new binary to a temporary path and return its location.
1025: * Used by the upgrade command to download before spawning setup --install. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
1245: shell: process.platform === "win32",
1246: });
1247:
1248: proc.on("close", (code) => {
1249: if (code === 0) {
1250: resolve();
1251: } else {
1252: reject(
1253: new UpgradeError(
1254: "execution_failed",
1255: `${pm} install failed with exit code ${code}`
1256: )
1257: );
1258: }
1259: });
1260:
1261: proc.on("error", (err) => {
1262: reject(
1263: new UpgradeError("execution_failed", `${pm} failed: ${err.message}`)
1264: );
1265: });
1266: });
1267: }
1268:
1269: /**
1270: * Execute the upgrade using the appropriate method. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
250: offline: boolean
251: ): void {
252: if (method === "unknown") {
253: throw new UpgradeError("unknown_method");
254: }
255: // Homebrew manages versioning through the formula — pinning a specific
256: // stable version is not supported via this command.
257: if (method === "brew" && versionArg && channel === "stable") {
258: throw new UpgradeError(
259: "unsupported_operation",
260: "Homebrew does not support installing a specific version. Run 'brew upgrade getsentry/tools/sentry' to upgrade to the latest formula version."
261: );
262: }
263: // Offline mode is only supported for curl-installed binaries — package
264: // managers always need network to fetch and install packages.
265: if (offline && method !== "curl") {
266: throw new ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
340: return {
341: kind: "done",
342: result: buildCheckResult({ target, versionArg, method, channel, flags }),
343: source: latestResolution?.source,
344: };
345: }
346:
347: // Skip if already on target — unless forced or switching channels
348: if (CLI_VERSION === target && !flags.force && !channelChanged) {
349: return {
350: kind: "done",
351: result: {
352: action: "up-to-date",
353: currentVersion: CLI_VERSION,
354: targetVersion: target,
355: channel,
356: method,
357: forced: false,
358: },
359: };
360: }
361:
362: // Validate that a specific pinned version actually exists. ...
Found 9 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts:
Line 218: source: resolved.source,
Line 309: return resolved.source;
Line 645: async function executeStandardUpgrade(opts: {
Line 680: executeUpgrade(method, target, downloadTag, offline, setMessage, source)
Line 748: async function migrateToStandaloneForNightly(opts: {
Line 766: executeUpgrade("curl", target, downloadTag, undefined, setMessage, source)
Line 1005: source: resolved.source,
Line 1058: warnings = await migrateToStandaloneForNightly({
Line 1067: await executeStandardUpgrade({
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
180: target: string;
181: offline: OfflineMode;
182: source?: UpgradeSource;
183: }
184: | { kind: "done"; result: UpgradeResult }
185: > {
186: const { resolveOpts, versionArg, offline, method, persistChannelFn } = opts;
187:
188: if (offline) {
189: // Channel switching with --offline is not supported: the cached version
190: // belongs to the old channel and would install the wrong binary type.
191: if (resolveOpts.channelChanged && !versionArg) {
192: throw new UpgradeError(
193: "unsupported_operation",
194: "Cannot switch channels in offline mode — the cached version belongs to the current channel. " +
195: "Run 'sentry cli upgrade' with network access to switch channels."
196: );
197: }
198: // Read the ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
630: const { SENTRY_INSTALL_DIR: _pinned, ...envWithoutPin } = process.env;
631: const xdgInstallDir = determineInstallDir(homedir(), envWithoutPin);
632: if (
633: !samePath(xdgInstallDir, legacyBinDir) &&
634: isInPath(xdgInstallDir, pathEnv)
635: ) {
636: return xdgInstallDir;
637: }
638: return currentInstallDir;
639: }
640:
641: /**
642: * Execute the standard upgrade path: download via curl or package manager,
643: * then run setup on the new binary.
644: */
645: async function executeStandardUpgrade(opts: {
646: method: InstallationMethod;
647: channel: ReleaseChannel;
648: versionArg: string | undefined;
649: target: string;
650: execPath: string;
651: entryPath?: string;
652: pathEnv?: string;
653: offline?: OfflineMode;
654: json?: boolean;
655: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
960: kind: "boolean",
961: brief: "Skip agent skill installation for AI coding assistants",
962: default: false,
963: },
964: method: {
965: kind: "parsed",
966: parse: parseInstallationMethod,
967: brief: "Installation method to use (curl, brew, npm, pnpm, bun, yarn)",
968: optional: true,
969: placeholder: "method",
970: },
971: },
972: },
973: async *func(this: SentryContext, flags: UpgradeFlags, version?: string) {
974: const { channel, versionArg, channelChanged, method } =
975: await resolveContext(version, flags);
976:
977: log.debug(`Installation method: ${method}`);
978: log.debug(`Current version: ${CLI_VERSION}`);
979:
980: const resolved = await withProgress(
981: { ...
M .github/workflows/ci.yml M packages/cli/install M packages/cli/package.json 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/upgrade.test.ts M packages/cli/test/lib/binary.test.ts M packages/cli/test/lib/delta-upgrade.test.ts M packages/cli/test/lib/ghcr.test.ts M packages/cli/test/lib/install-script.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 .github/workflows/ci.yml | 1 + packages/cli/install | 192 +++++++++++--- packages/cli/package.json | 3 +- packages/cli/src/commands/cli/upgrade.ts | 114 ++++++--- packages/cli/src/lib/binary.ts ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
800: });
801: });
802: });
803:
804: // ===================================================================
805: // Async functions (fetch-mocked)
806: // ===================================================================
807:
808: /** Helper to mock globalThis.fetch */
809: function mockFetch(
810: fn: (url: string | URL | Request, init?: RequestInit) => Promise<Response>
811: ): void {
812: globalThis.fetch = fn as typeof globalThis.fetch;
813: }
814:
815: /** Store original fetch for restoration */
816: let originalFetch: typeof globalThis.fetch;
817:
818: beforeEach(() => {
819: originalFetch = globalThis.fetch;
820: });
821:
822: afterEach(() => {
823: globalThis.fetch = originalFetch;
824: });
825:
826: // fetchRecentReleases
827:
828: describe("fetchRecentReleases", () ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1900: throw new Error("fetch should not be called");
1901: });
1902:
1903: await prefetchStablePatches("0.14.0");
1904: });
1905: });
1906:
1907: async function importDeltaUpgradeWithVersion(version: string) {
1908: vi.resetModules();
1909: vi.doMock("../../src/lib/constants.js", async (importOriginal) => {
1910: const actual =
1911: await importOriginal<typeof import("../../src/lib/constants.js")>();
1912: return { ...actual, CLI_VERSION: version };
1913: });
1914: return import("../../src/lib/delta-upgrade.js");
1915: }
1916:
1917: function restoreDeltaUpgradeModule(): void {
1918: vi.doUnmock("../../src/lib/constants.js");
1919: vi.resetModules();
1920: }
1921:
1922: describe("selected source affinity", () => {
1923: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts</path> <type>file</type> <content> 1: /** 2: * Integration tests for delta upgrade orchestration with a non-dev CLI_VERSION. 3: * 4: * These tests use `vi.mock()` to override `CLI_VERSION` from constants.js 5: * so that `canAttemptDelta()` passes its dev-build guard (the real `CLI_VERSION` 6: * is "0.0.0-dev" in test mode, which short-circuits the orchestrator). 7: * 8: * Kept as a sibling file to `delta-upgrade.test.ts` because its 9: * `vi.mock()` would invert the assumptions of the dev-mode null-return 10: * tests in that file. Under `bun test --isolate` each file gets a fresh 11: * module graph, so the mocks here don't leak. ...
Found 47 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts:
Line 970: const chain = await resolveStableChain("0.13.0", "0.14.0");
Line 988: resolveStableChain("0.13.0", "0.14.0", undefined, LEGACY_UPGRADE_SOURCE)
Line 1039: const chain = await resolveStableChain("0.13.0", "0.15.0");
Line 1057: const chain = await resolveStableChain("0.12.0", "0.14.0");
Line 1064: const chain = await resolveStableChain("0.12.0", "0.13.0");
Line 1089: const chain = await resolveStableChain("0.13.0", "0.14.0");
Line 1112: const chain = await resolveStableChain("0.1.0", "0.15.0");
Line 1208: const chain = await resolveNightlyChain({
Line 1231: resolveNightlyChain({
Line 1246: const chain = await resolveNightlyChain({
Line 1265: const chain = await resolveNightlyChain({
Line 1320: const chain = await ...
import { afterEach, describe, expect, it, vi } from "vitest";
import {
type InstrumentHook,
extractSha256,
extractStableChain,
filterAndSortChainTags,
getPatchFromVersion,
getPatchTargetSha256,
ghcrSource,
type GitHubRelease,
githubReleaseSource,
getStableTargetSha256,
OciClient,
type OciManifest,
validateChainStep,
} from "../src";
// Build a JSON Response for mocked fetch calls.
function json(body: unknown): Response {
return new Response(JSON.stringify(body), {
status: 200,
headers: { "content-type": "application/json" },
});
}
// A semver-ish comparator matching the gateway's compareVersions contract
// (returns -1 | 0 | 1) for the nightly tag-ordering tests.
function cmp(a: string, b: string): -1 | 0 | 1 {
const pa = a.split(".").map(Number);
const pb = b.split(".").map(Number);
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
const x = pa[i] ?? 0;
const y = pb[i] ?? ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/patch-cache.ts</path>
<type>file</type>
<content>
1: import { join } from "node:path";
2: import { makeCache, type PatchCache, type PatchChain } from "binpatch";
3: import { getConfigDir } from "./db/index.js";
4:
5: export type { ChainMeta, PatchStepMeta } from "binpatch";
6: // biome-ignore lint/performance/noBarrelFile: preserve the existing cache API
7: export { chainFileName, patchFileName } from "binpatch";
8:
9: function cache(): PatchCache {
10: return makeCache(join(getConfigDir(), "patch-cache"));
11: }
12:
13: export function savePatchesToCache(
14: chain: Pick<PatchChain, "patches" | "expectedSha256">,
15: steps: { fromVersion: string; toVersion: string }[]
16: ): Promise<void> {
17: return cache().save(chain, steps);
18: }
19:
20: export async function loadCachedChain(
21: currentVersion: string,
22: targetVersion: string
23: ...
/**
* Chain discovery + resolve-and-apply orchestration.
*
* A {@link SourceStrategy} knows how to resolve a {@link PatchChain} from some
* backing store (an OCI registry, GitHub Release assets, ...). This module ties
* a strategy together with the offline cache, the apply core, integrity
* verification, and progress events — with every product-specific concern
* (version, telemetry, logging, cache location) injected.
*/
import { applyPatchChainInMemory, parsePatchHeader } from "./bspatch";
import type { PatchCache } from "./patch-cache";
import type { DeltaResult, PatchChain } from "./contract";
import { type ProgressHandler, safeProgress } from "./events";
/**
* A source of patch chains. Given the current and target versions, resolve the
* ordered chain of patches (oldest hop first) plus the expected final SHA-256,
* or `null` when no usable chain exists (caller falls back to a full download). ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
80: /**
81: * Absolute legacy install directories for the given home. See
82: * {@link LEGACY_INSTALL_SUBDIRS} for why this is scoped to pre-XDG locations.
83: */
84: export function getLegacyInstallDirs(homeDir: string): string[] {
85: return LEGACY_INSTALL_SUBDIRS.map((dir) => join(homeDir, dir));
86: }
87:
88: /**
89: * How the CLI was installed. Determines the upgrade strategy.
90: *
91: * Defined here (alongside other installation constants like
92: * {@link KNOWN_CURL_DIRS}) so that both `upgrade.ts` and
93: * `db/install-info.ts` can import it without creating a circular
94: * dependency. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
390: // Always check for Homebrew first — the stored install info may be stale
391: // (e.g. user previously had a curl install recorded, then switched to
392: // Homebrew). The realpath check is cheap and authoritative.
393: if (isHomebrewInstall()) {
394: return "brew";
395: }
396:
397: // Check stored info (fast path for non-Homebrew installs)
398: const stored = getInstallInfo();
399: if (stored?.method) {
400: return stored.method;
401: }
402:
403: // Legacy detection for existing installs (pre-setup command)
404: const legacyMethod = await detectLegacyInstallationMethod();
405:
406: // Auto-save detected method for future runs (best-effort —
407: // a read-only or broken DB shouldn't block detection)
408: if (legacyMethod !== "unknown") {
409: try {
410: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
615: /** Resolve and validate a pinned standalone version against ordered sources. */
616: export async function resolveExistingUpgradeVersion(
617: version: string
618: ): Promise<ResolvedUpgradeVersion | null> {
619: try {
620: if (isNightlyVersion(version)) {
621: const resolved = await resolveNightlyManifest(
622: `nightly-${version}`,
623: undefined,
624: UPGRADE_SOURCES
625: );
626: return { version, source: resolved.source };
627: }
628: const selected = await resolveUpgradeSource({
629: getProbeUrl: (source) => getGitHubReleaseByTagUrl(version, source),
630: });
631: return { version, source: selected.source };
632: } catch (error) {
633: if (isUpgradeSourceNotFound(error)) {
634: return null;
635: }
636: throw ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
1010: const delay = VERIFY_BASE_DELAY_MS * 2 ** (attempt - 1);
1011: log.debug(
1012: `Downloaded binary not yet visible at ${path}, retrying in ${delay}ms (attempt ${attempt}/${VERIFY_MAX_ATTEMPTS})`
1013: );
1014: await setTimeout(delay);
1015: }
1016: throw new UpgradeError(
1017: "execution_failed",
1018: `Downloaded binary is missing or empty at ${path}. ` +
1019: "This is usually transient — rerun `sentry cli upgrade` to retry."
1020: );
1021: }
1022:
1023: /**
1024: * Download the new binary to a temporary path and return its location.
1025: * Used by the upgrade command to download before spawning setup --install. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
850: function getNightlyGzFilename(): string {
851: return `${getPlatformBinaryName()}.gz`;
852: }
853:
854: /**
855: * Download a nightly binary from GHCR and decompress it to `destPath`.
856: *
857: * Fetches an anonymous token, retrieves the OCI manifest, finds the layer
858: * matching this platform's `.gz` filename, then downloads and decompresses
859: * the blob in-stream.
860: *
861: * When `version` is provided, fetches the pinned versioned tag
862: * (`nightly-{version}`). Otherwise fetches the rolling `:nightly` tag. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
190: // belongs to the old channel and would install the wrong binary type.
191: if (resolveOpts.channelChanged && !versionArg) {
192: throw new UpgradeError(
193: "unsupported_operation",
194: "Cannot switch channels in offline mode — the cached version belongs to the current channel. " +
195: "Run 'sentry cli upgrade' with network access to switch channels."
196: );
197: }
198: // Read the cached version BEFORE persisting the channel — setReleaseChannel
199: // clears the version cache on channel changes.
200: const target = resolveOfflineTarget(versionArg);
201: persistChannelFn();
202: log.info(`Offline mode: using cached target ${target}`);
203: return { kind: "target", target, offline: "explicit" };
204: }
205:
206: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts</path>
<type>file</type>
<content>
819: /**
820: * Resolve the channel, version arg, method, and channel-changed flag from
821: * the positional version argument and flags. Extracted to keep `func()`
822: * complexity under the biome limit.
823: */
824: async function resolveContext(
825: version: string | undefined,
826: flags: UpgradeFlags
827: ): Promise<{
828: channel: ReleaseChannel;
829: versionArg: string | undefined;
830: channelChanged: boolean;
831: method: InstallationMethod;
832: }> {
833: const { channel, versionArg } = resolveChannelAndVersion(version);
834: const currentChannel = getReleaseChannel();
835: const channelChanged = channel !== currentChannel;
836:
837: const method = flags.method ?? (await detectInstallationMethod());
838: validateMethod(method, versionArg, channel, ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade</path> <type>directory</type> <entries> .craft.yml .git .github/ .gitignore .lore.md .nojekyll .npmrc AGENTS.md apps/ CHANGELOG.md codemods/ docs/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md (19 entries) </entries>
File not found: /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/.cursor/rules/ultracite.mdc
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. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/AGENTS.md</path> <type>file</type> <content> 1: # AGENTS.md 2: 3: Guidelines for AI agents working in this codebase. 4: 5: ## Project Overview 6: 7: **Sentry CLI** is a command-line interface for [Sentry](https://sentry.io), built with Node.js, [pnpm](https://pnpm.io), and [Stricli](https://bloomberg.github.io/stricli/). It lives in `packages/cli` of a pnpm workspace; the docs site lives in `apps/cli-docs`. ...
StatusCode: non 2xx status code (404 GET https://raw.githubusercontent.com/BYK/binpatch/9ba6bbb8227fcbd2521852d2311c82afac5e9573/src/github-release.ts)
{
"sha": "9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"url": "https://api.github.com/repos/BYK/binpatch/git/trees/9ba6bbb8227fcbd2521852d2311c82afac5e9573",
"tree": [
{
"path": ".craft.yml",
"mode": "100644",
"type": "blob",
"sha": "36f34fdd754de842419fe5a5cb2844a8c98f80df",
"size": 1143,
"url": "https://api.github.com/repos/BYK/binpatch/git/blobs/36f34fdd754de842419fe5a5cb2844a8c98f80df"
},
{
"path": ".github",
"mode": "040000",
"type": "tree",
"sha": "dc6a71d7d4d393c0e072cb45ac745fc2a61f60ef",
"url": "https://api.github.com/repos/BYK/binpatch/git/trees/dc6a71d7d4d393c0e072cb45ac745fc2a61f60ef"
},
{
"path": ".github/workflows",
"mode": "040000",
"type": "tree",
"sha": "da820a4798f068f6531c69b3544f97601baa4cfa",
"url": "https://api.github.com/repos/BYK/binpatch/git/trees/da820a4798f068f6531c69b3544f97601baa4cfa"
},
{
"path": ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
I have enough evidence to close the review. I’m checking the current patch once more so the report reflects the latest source rather than an earlier snapshot.
(no output)
## feat/toolkit-bridge-upgrade...origin/feat/toolkit-bridge-upgrade 4094ae9a7 (HEAD -> feat/toolkit-bridge-upgrade, origin/feat/toolkit-bridge-upgrade) feat(cli): add toolkit upgrade bridge bd065083c (origin/main, origin/HEAD) feat(local): Add Vercel Analytics (#1563) 4ca8818d1 feat(local): Add browser viewer for local telemetry (#1560) 0e661a5f5 fix(org): log region URL parse failures in org list (#1539) 9d0901b10 feat(local): Add agent debugging stream (#1538) .github/workflows/ci.yml | 1 + package.json | 3 +- packages/cli/install | 192 +++++++++++--- packages/cli/package.json | 3 +- packages/cli/src/commands/cli/upgrade.ts | 114 ++++++--- packages/cli/src/lib/binary.ts | 146 ++++++++++- packages/cli/src/lib/delta-upgrade.ts | 81 +++--- packages/cli/src/lib/ghcr.ts | 48 ++-- packages/cli/src/lib/release-notes.ts ...
<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/custom-ca.ts</path> <type>file</type> <content> 1: /** 2: * Custom CA certificate loading for corporate TLS proxies. 3: * 4: * Reads CA bundles from (in priority order): 5: * 1. `sentry cli defaults ca-cert` (stored path in SQLite) 6: * 2. `NODE_EXTRA_CA_CERTS` env var 7: * 8: * Returns a `tls` options object for Bun's `fetch()`. On the Node.js npm 9: * distribution, Node natively honors `NODE_EXTRA_CA_CERTS` so the extra 10: * `tls.ca` option is harmless (ignored by Node's fetch). 11: * 12: * Security model: When the CA source is an env var (not a stored default) 13: * AND the target is SaaS (`*.sentry.io`), a one-time warning is logged. 14: * `sentry cli defaults ca-cert` silences the warning — the user has 15: * explicitly acknowledged the custom CA. See CLI-1K6 plan for the full 16: * threat model discussion. ...
Found 1 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts: Line 305: export function customFetch(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts</path>
<type>file</type>
<content>
285: * Get the combined CA certificate PEM string for Node.js `http.request()`.
286: * Returns undefined when no custom CAs are configured.
287: *
288: * Unlike {@link getCustomTlsOptions} (which returns Bun's `{ tls: { ca } }` shape),
289: * this returns the raw PEM string suitable for Node's `https.RequestOptions.ca`
290: * and the Sentry SDK's `NodeTransportOptions.caCerts`.
291: */
292: export function getCustomCaCerts(): string | undefined {
293: resolve();
294: return resolved?.tls.ca;
295: }
296:
297: /**
298: * Drop-in replacement for `fetch()` that injects custom CA certificates
299: * when configured. All non-authenticated fetch call sites should use this
300: * instead of bare `fetch()`.
301: *
302: * Authenticated API calls go through `fetchWithTimeout()` in sentry-client.ts
303: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
790: ]);
791: const result = validateChainStep(manifest, {
792: expectedFrom: "0.0.9",
793: patchLayerName: PATCH_LAYER_NAME,
794: sizeLimit: 100_000,
795: });
796: expect(result).toEqual({
797: ok: true,
798: digest: `sha256:${PATCH_LAYER_NAME.replace(/\W/g, "")}`,
799: size: 500,
800: });
801: });
802: });
803:
804: // ===================================================================
805: // Async functions (fetch-mocked)
806: // ===================================================================
807:
808: /** Helper to mock globalThis.fetch */
809: function mockFetch(
810: fn: (url: string | URL | Request, init?: RequestInit) => Promise<Response>
811: ): void {
812: globalThis.fetch = fn as typeof globalThis.fetch;
813: }
814: ...
/**
* binpatch — reusable binary delta-update engine.
*
* Two things, joined by one wire contract (see README):
* - **apply core** — parse + apply a TRDIFF10/bsdiff patch chain to a binary.
* - **discovery** — resolve a patch chain from a pluggable `SourceStrategy`
* (OCI/GHCR tags or GitHub Release assets), then apply + verify it.
*
* Pure Node (`node:*` builtins only), zero product coupling — the consumer
* injects the cache directory, the download source, version comparison,
* progress handling, and telemetry.
*/
export {
addDiffChunk,
applyPatch,
applyPatchChainInMemory,
applyPatchToMemory,
MAX_OUTPUT_SIZE,
offtin,
parsePatchHeader,
type PatchHeader,
} from "./bspatch";
export {
type ChainMeta,
chainFileName,
makeCache,
type PatchCache,
patchFileName,
type PatchStepMeta,
} from "./patch-cache";
// Wire-contract constants + shared chain types. ...
No files found
Found 7 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 28: fetchWithUpgradeError,
Line 476: const response = await fetchWithUpgradeError(
Line 677: await fetchWithUpgradeError(
Line 709: const response = await fetchWithUpgradeError(
Line 919: const gzResponse = await fetchWithUpgradeError(
Line 933: const response = await fetchWithUpgradeError(url, { headers }, "GitHub");
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 482: export async function fetchWithUpgradeError(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
450:
451: for (const dir of candidates) {
452: if (existsSync(dir) && pathDirs.some((p) => samePath(p, dir))) {
453: return dir;
454: }
455: }
456:
457: // 5. XDG-aligned fallback — setup will handle adding this to PATH
458: return join(homeDir, ".local", "bin");
459: }
460:
461: /**
462: * Build headers for GitHub API requests.
463: */
464: export function getGitHubHeaders(): Record<string, string> {
465: return {
466: Accept: "application/vnd.github.v3+json",
467: "User-Agent": getUserAgent(),
468: };
469: }
470:
471: /**
472: * Fetch wrapper that converts network errors to UpgradeError.
473: * Handles DNS failures, timeouts, and other connection issues. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts</path>
<type>file</type>
<content>
560: sections.push({ category, markdown });
561: }
562: }
563:
564: return sections;
565: }
566:
567: // ────────────────────────────── Fetch Functions ────────────────────────────
568:
569: /**
570: * Max releases to fetch for changelog purposes.
571: *
572: * Higher than the delta-upgrade cap (12) to cover larger version jumps.
573: * GitHub API max per_page is 100; 30 covers ~6+ months of weekly releases.
574: */
575: const CHANGELOG_MAX_RELEASES = 30;
576:
577: /**
578: * Fetch recent releases from GitHub for changelog building.
579: *
580: * Uses a higher `per_page` than `fetchRecentReleases()` in delta-upgrade
581: * (which is capped at 12 for patch chain resolution) to cover larger
582: * version jumps without silent truncation. ...
<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()`. ...
Found 7 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts:
Line 427: function buildChangelogSummaryForSource(
Line 435: let tagName = release.tag_name;
Line 436: if (source?.tagPrefix) {
Line 437: if (!tagName.startsWith(source.tagPrefix)) {
Line 440: tagName = tagName.slice(source.tagPrefix.length);
Line 477: return buildChangelogSummaryForSource(releases, fromVersion, toVersion, {
Line 637: return buildChangelogSummaryForSource(releases, fromVersion, toVersion, {
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts</path>
<type>file</type>
<content>
390: function mergeSectionsByCategory(releases: GitHubRelease[]): ChangeSection[] {
391: const sectionsByCategory = new Map<ChangeCategory, string[]>();
392:
393: for (const release of releases) {
394: if (!release.body) {
395: continue;
396: }
397: const sections = extractSections(release.body);
398: for (const section of sections) {
399: const stripped = stripAttributions(section.markdown);
400: const existing = sectionsByCategory.get(section.category) ?? [];
401: existing.push(stripped);
402: sectionsByCategory.set(section.category, existing);
403: }
404: }
405:
406: // Build merged sections in display order
407: const merged: ChangeSection[] = [];
408: for (const category of CATEGORY_ORDER) {
409: const markdowns = ...
Found 6 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts: Line 843: const result = await fetchRecentReleases(); Line 855: await fetchRecentReleases(undefined, LEGACY_UPGRADE_SOURCE); Line 865: const result = await fetchRecentReleases(); Line 874: const result = await fetchRecentReleases(); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts: Line 580: * Uses a higher `per_page` than `fetchRecentReleases()` in delta-upgrade /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts: Line 160: export async function fetchRecentReleases(
Found 23 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts:
Line 601: await expect(versionExists("curl", "1.0.0")).resolves.toBe(true);
Line 616: await expect(versionExists("curl", "1.0.0")).resolves.toBe(true);
Line 631: versionExists("curl", "1.0.0", UPGRADE_SOURCES[0])
Line 641: const exists = await versionExists("curl", "1.0.0");
Line 648: const exists = await versionExists("curl", "99.99.99");
Line 655: const exists = await versionExists("npm", "1.0.0");
Line 662: const exists = await versionExists("npm", "99.99.99");
Line 669: const exists = await versionExists("pnpm", "1.0.0");
Line 676: const exists = await versionExists("bun", "1.0.0");
Line 683: const exists = await versionExists("brew", "1.0.0");
Line 690: const exists = await versionExists("brew", "99.99.99");
Line 697: const exists = await ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/upgrade.test.ts</path>
<type>file</type>
<content>
580: new Response(JSON.stringify([{ tag_name: "cli@v3.0.0" }]), {
581: status: 200,
582: headers: { "Content-Type": "application/json" },
583: })
584: );
585:
586: const version = await fetchLatestVersion("curl");
587: expect(version).toBe("3.0.0");
588: });
589: });
590:
591: describe("versionExists", () => {
592: test("probes prefixed Toolkit tags and retains the selected source", async () => {
593: const requests: string[] = [];
594: mockFetch(async (url) => {
595: requests.push(String(url));
596: return new Response(JSON.stringify({ tag_name: "cli@1.0.0" }), {
597: status: 200,
598: });
599: });
600:
601: await expect(versionExists("curl", "1.0.0")).resolves.toBe(true);
602: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
1850: };
1851:
1852: setupFullNightlyMocks({
1853: targetVersion: "0.14.0-dev.200",
1854: targetManifest,
1855: patchTags: ["patch-0.14.0-dev.200"],
1856: patchManifests: new Map(),
1857: blobs: new Map(),
1858: });
1859:
1860: const result = await resolveNightlyDelta(
1861: "0.14.0-dev.200",
1862: "/tmp/fake-old",
1863: "/tmp/fake-out"
1864: );
1865: expect(result).toBeNull();
1866: });
1867: });
1868:
1869: // attemptDeltaUpgrade (top-level orchestrator)
1870:
1871: describe("attemptDeltaUpgrade", () => {
1872: test("returns null when canAttemptDelta is false (dev version)", async () => {
1873: const result = await attemptDeltaUpgrade(
1874: "0.14.0",
1875: "/tmp/fake-old",
1876: ...
Found 1 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts: Line 105: function extractReleaseVersions(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path> <type>file</type> <content> 75: type PackageManager = "npm" | "pnpm" | "bun" | "yarn"; 76: 77: /** 78: * How the current upgrade reached the offline code path. 79: * 80: * - `false` — online upgrade (network available) 81: * - `"explicit"` — user passed `--offline` flag 82: * - `"network-fallback"` — network failed, auto-fell back to cache 83: */ 84: export type OfflineMode = false | "explicit" | "network-fallback"; 85: 86: // Constants 87: 88: /** The git tag used for the rolling nightly GitHub release (stable fallback only). */ 89: export const NIGHTLY_TAG = "nightly"; 90: 91: /** npm registry base URL */ 92: const NPM_REGISTRY_URL = "https://registry.npmjs.org/sentry"; 93: 94: /** Regex to strip 'v' prefix from version strings */ 95: export const VERSION_PREFIX_REGEX = /^v/; 96: 97: /** A resolved standalone-binary version ...
Found 15 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts:
Line 32: fetchLatestFromGitHubWithSource,
Line 292: : await fetchLatestFromGitHubWithSource(signal);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 98: export type ResolvedUpgradeVersion = {
Line 433: export async function fetchLatestFromGitHubWithSource(
Line 436: ): Promise<ResolvedUpgradeVersion> {
Line 462: await fetchLatestFromGitHubWithSource(
Line 512: ): Promise<ResolvedUpgradeVersion> {
Line 609: ): Promise<ResolvedUpgradeVersion> {
Line 612: : fetchLatestFromGitHubWithSource(signal);
Line 618: ): Promise<ResolvedUpgradeVersion | null> ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
400: return stored.method;
401: }
402:
403: // Legacy detection for existing installs (pre-setup command)
404: const legacyMethod = await detectLegacyInstallationMethod();
405:
406: // Auto-save detected method for future runs (best-effort —
407: // a read-only or broken DB shouldn't block detection)
408: if (legacyMethod !== "unknown") {
409: try {
410: setInstallInfo({
411: method: legacyMethod,
412: path: process.execPath,
413: version: CLI_VERSION,
414: });
415: } catch {
416: log.debug("Failed to persist install info (DB may be read-only)");
417: }
418: }
419:
420: return legacyMethod;
421: }
422:
423: // Version Fetching
424:
425: /**
426: * Fetch the latest version from GitHub releases. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
85: return LEGACY_INSTALL_SUBDIRS.map((dir) => join(homeDir, dir));
86: }
87:
88: /**
89: * How the CLI was installed. Determines the upgrade strategy.
90: *
91: * Defined here (alongside other installation constants like
92: * {@link KNOWN_CURL_DIRS}) so that both `upgrade.ts` and
93: * `db/install-info.ts` can import it without creating a circular
94: * dependency.
95: */
96: export type InstallationMethod =
97: | "curl"
98: | "brew"
99: | "npm"
100: | "pnpm"
101: | "bun"
102: | "yarn"
103: | "unknown";
104:
105: /** A repository pair that hosts CLI stable releases and nightly OCI images. */
106: export type UpgradeSource = {
107: /** GitHub `owner/repository` containing CLI release assets. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
285: /** Configuration for selecting the first available upgrade source. */
286: export type ResolveUpgradeSourceOptions = {
287: /** Build the source-specific URL whose response proves source availability. */
288: readonly getProbeUrl: (source: UpgradeSource) => string;
289: /** Fetch implementation used for the probe. Defaults to the CLI CA-aware fetch. */
290: readonly fetch?: typeof fetch;
291: /** Optional cancellation signal shared by every source probe. */
292: readonly signal?: AbortSignal;
293: /** Ordered sources to probe. Defaults to all configured upgrade sources. */
294: readonly sources?: readonly UpgradeSource[];
295: };
296:
297: async function fetchUpgradeProbe(
298: source: UpgradeSource,
299: options: ResolveUpgradeSourceOptions
300: ): Promise<Response> {
301: try ...
Found 22 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts:
Line 837: "api.github.com/repos/getsentry/toolkit/releases"
Line 848: test("uses the selected legacy GitHub repository", async () => {
Line 858: "https://api.github.com/repos/getsentry/cli/releases?per_page=12",
Line 950: const patchUrl = `https://github.com/getsentry/cli/releases/download/0.14.0/${binaryName}.patch`;
Line 980: test("keeps stable resolution on the selected legacy source", async () => {
Line 991: "https://api.github.com/repos/getsentry/cli/releases?per_page=12",
Line 993: expect(urls.every((url) => !url.includes("getsentry/toolkit"))).toBe(true);
Line 1223: test("keeps nightly resolution on the selected legacy source", async () => {
Line 1239: expect(urls).toEqual(["https://ghcr.io/v2/getsentry/cli/tags/list?n=100"]);
Line 1240: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/package.json</path> <type>file</type> <content> 95: "@sentry/api": "^0.256.0", 96: "@sentry/core": "10.63.0", 97: "@sentry/node": "10.65.0", 98: "@sentry/node-core": "10.63.0", 99: "@sentry/sqlish": "^1.0.1", 100: "@sentry/symbolic": "13.7.0", 101: "@spotlightjs/spotlight": "^4.11.7", 102: "@stricli/auto-complete": "^1.2.8", 103: "@stricli/core": "1.2.8", 104: "@types/http-cache-semantics": "^4.2.0", 105: "@types/node": "^22.20.0", 106: "@types/picomatch": "^4.0.3", 107: "@types/pngjs": "^6.0.5", 108: "@types/qrcode-terminal": "^0.12.2", 109: "@types/react": "^19.2.17", 110: "@types/semver": "^7.7.1", 111: "@vitest/coverage-v8": "^4.1.9", 112: "binpatch": "^0.4.2", 113: "chalk": "^5.6.2", 114: "cli-highlight": "^2.1.11", 115: "consola": "^3.4.2", 116: "esbuild": ...
diff --git a/packages/cli/src/lib/delta-upgrade.ts b/packages/cli/src/lib/delta-upgrade.ts
index ec709b8c8..d7f2e3bfa 100644
--- a/packages/cli/src/lib/delta-upgrade.ts
+++ b/packages/cli/src/lib/delta-upgrade.ts
@@ -32,16 +32,17 @@ import {
} from "binpatch";
import {
compareVersions,
- GITHUB_RELEASES_URL,
+ getGitHubReleasesUrl,
getPlatformBinaryName,
isDowngrade,
isNightlyVersion,
+ PRIMARY_UPGRADE_SOURCE,
+ type UpgradeSource,
} from "./binary.js";
import { CLI_VERSION } from "./constants.js";
import { customFetch } from "./custom-ca.js";
import { getConfigDir } from "./db/index.js";
import { formatBytes } from "./formatters/numbers.js";
-import { GHCR_REPO } from "./ghcr.js";
import { logger } from "./logger.js";
import { makeByteProgress, type SetMessage } from "./progress.js";
import { withTracing, withTracingSpan } from "./telemetry.js";
@@ -68,11 +69,15 @@ export type DeltaResult = {
chainLength: number;
};
-// GHCR publishes nightlies to ...
Found 4 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts:
Line 575: const CHANGELOG_MAX_RELEASES = 30;
Line 592: `${getGitHubReleasesUrl(source)}?per_page=${CHANGELOG_MAX_RELEASES}`,
Line 692: const url = `https://api.github.com/repos/${source.githubRepo}/commits?sha=main&since=${sinceDate}&until=${untilDate}&per_page=100`;
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts:
Line 263: ? `${getGitHubReleasesUrl(source)}?per_page=100`
Found 34 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts:
Line 29: * Mock constants.js to pretend we're running a real stable version.
Line 93: test("resolves and applies a stable delta patch", async () => {
Line 99: // Set up fetch mocks — releases API + patch download
Line 102: const patchUrl = `https://github.com/getsentry/cli/releases/download/0.14.0/${BINARY_NAME}.patch`;
Line 103: const releases = [
Line 105: tag_name: "0.14.0",
Line 110: digest: `sha256:${versionHex("0.14.0")}`,
Line 116: browser_download_url: patchUrl,
Line 148: return new Response(JSON.stringify(releases), { status: 200 });
Line 150: if (urlStr === patchUrl) {
Line 160: // 1. Fetch releases (success)
Line 166: resolveStableDelta("0.14.0", oldBinaryPath, destPath)
Line 183: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.mocked.test.ts</path> <type>file</type> <content> 1: /** 2: * Integration tests for delta upgrade orchestration with a non-dev CLI_VERSION. 3: * 4: * These tests use `vi.mock()` to override `CLI_VERSION` from constants.js 5: * so that `canAttemptDelta()` passes its dev-build guard (the real `CLI_VERSION` 6: * is "0.0.0-dev" in test mode, which short-circuits the orchestrator). 7: * 8: * Kept as a sibling file to `delta-upgrade.test.ts` because its 9: * `vi.mock()` would invert the assumptions of the dev-mode null-return 10: * tests in that file. Under `bun test --isolate` each file gets a fresh 11: * module graph, so the mocks here don't leak. ...
No files found
<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: ...
/**
* GitHub Release-asset patch source (the "stable" channel).
*
* Resolves a patch chain from GitHub Release assets. Each release for the
* target platform publishes three assets:
* - `<binaryName>` — the binary (its digest → expected SHA-256)
* - `<binaryName>.gz` — gzipped binary (its size → the ratio gate)
* - `<binaryName>.patch` — the delta patch from the previous release
*
* The chain is the releases between current and target, oldest-first, capped
* at {@link MAX_STABLE_CHAIN_DEPTH} and by {@link SIZE_THRESHOLD_RATIO}.
*
* All product specifics (owner/repo, binary name, user-agent, fetch) are
* injected. Generalized from Lore's stable-channel resolver.
*/
import {
type InstrumentHook,
MAX_STABLE_CHAIN_DEPTH,
type PatchChain,
type PatchLink,
SIZE_THRESHOLD_RATIO,
} from "../contract";
import type { SourceStrategy } from "../discover";
const SHA256_DIGEST_PATTERN = /^sha256:([0-9a-f]+)$/i;
export type GitHubAsset = {
name: string;
...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts</path> <type>file</type> <content> 1: /** 2: * Custom CA certificate loading for corporate TLS proxies. 3: * 4: * Reads CA bundles from (in priority order): 5: * 1. `sentry cli defaults ca-cert` (stored path in SQLite) 6: * 2. `NODE_EXTRA_CA_CERTS` env var 7: * 8: * Returns a `tls` options object for Bun's `fetch()`. On the Node.js npm 9: * distribution, Node natively honors `NODE_EXTRA_CA_CERTS` so the extra 10: * `tls.ca` option is harmless (ignored by Node's fetch). 11: * 12: * Security model: When the CA source is an env var (not a stored default) 13: * AND the target is SaaS (`*.sentry.io`), a one-time warning is logged. 14: * `sentry cli defaults ca-cert` silences the warning — the user has 15: * explicitly acknowledged the custom CA. See CLI-1K6 plan for the full 16: * threat model discussion. ...
Found 1 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts: Line 305: export function customFetch(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/custom-ca.ts</path>
<type>file</type>
<content>
275: " This usually means your network uses a TLS-intercepting proxy\n" +
276: " (corporate firewall, VPN) with a private certificate authority.\n\n" +
277: " To fix this, point the CLI to your CA certificate bundle:\n" +
278: " sentry cli defaults ca-cert /path/to/corporate-ca.pem\n\n" +
279: " Or set the NODE_EXTRA_CA_CERTS environment variable:\n" +
280: " export NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem"
281: );
282: }
283:
284: /**
285: * Get the combined CA certificate PEM string for Node.js `http.request()`.
286: * Returns undefined when no custom CAs are configured.
287: *
288: * Unlike {@link getCustomTlsOptions} (which returns Bun's `{ tls: { ca } }` shape),
289: * this returns the raw PEM string suitable for Node's `https.RequestOptions.ca`
290: * and ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts</path>
<type>file</type>
<content>
270: budget: opts.sizeLimit,
271: },
272: }
273: : {
274: ok: false,
275: failure: { reason: "missing-layer", layerName: opts.patchLayerName },
276: };
277: }
278:
279: export function resolveStableChain(
280: currentVersion: string,
281: targetVersion: string,
282: signal?: AbortSignal,
283: source: UpgradeSource = getPrimaryUpgradeSource()
284: ): Promise<PatchChain | null> {
285: return stableSource(source).resolveChain(
286: currentVersion,
287: targetVersion,
288: signal
289: );
290: }
291:
292: export async function resolveNightlyChain(opts: {
293: token: string;
294: currentVersion: string;
295: targetVersion: string;
296: fullGzSize: number;
297: preloadedTags?: string[];
298: signal?: AbortSignal;
299: ...
Found 6 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts: Line 843: const result = await fetchRecentReleases(); Line 855: await fetchRecentReleases(undefined, LEGACY_UPGRADE_SOURCE); Line 865: const result = await fetchRecentReleases(); Line 874: const result = await fetchRecentReleases(); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts: Line 580: * Uses a higher `per_page` than `fetchRecentReleases()` in delta-upgrade /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts: Line 160: export async function fetchRecentReleases(
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts</path>
<type>file</type>
<content>
760: sizeLimit: 100_000,
761: });
762: expect(result).toEqual({
763: ok: false,
764: failure: { reason: "missing-layer", layerName: PATCH_LAYER_NAME },
765: });
766: });
767:
768: test("returns size-exceeded when layer exceeds budget", () => {
769: const manifest = makePatchManifest("0.0.9", {}, [
770: makeLayer(PATCH_LAYER_NAME, 200_000),
771: ]);
772: const result = validateChainStep(manifest, {
773: expectedFrom: "0.0.9",
774: patchLayerName: PATCH_LAYER_NAME,
775: sizeLimit: 100_000,
776: });
777: expect(result).toEqual({
778: ok: false,
779: failure: {
780: reason: "size-exceeded",
781: layerSize: 200_000,
782: budget: 100_000,
783: },
784: });
785: });
786:
787: ...
I found the key incompatibility: source affinity is threaded through, but Toolkit stable deltas still feed raw cli@… tags to binpatch, which only compares unprefixed versions. I’m checking every stable-delta entry point and test gap before writing the final read-only report.
Found 25 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/version-check.ts:
Line 244: await prefetchStablePatches(latestVersion, signal, source);
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts:
Line 1149: return await attemptDeltaUpgrade(
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts:
Line 970: const chain = await resolveStableChain("0.13.0", "0.14.0");
Line 988: resolveStableChain("0.13.0", "0.14.0", undefined, LEGACY_UPGRADE_SOURCE)
Line 1039: const chain = await resolveStableChain("0.13.0", "0.15.0");
Line 1057: const chain = await resolveStableChain("0.12.0", "0.14.0");
Line 1064: const chain = await resolveStableChain("0.12.0", "0.13.0");
Line 1089: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts</path>
<type>file</type>
<content>
1110: log.debug(`Binary verified (${formatBytes(verifiedSize)})`);
1111:
1112: // Clear consumed patch cache — patches for the old version are useless
1113: // after the binary has been updated (whether via delta or full download).
1114: // biome-ignore lint/plugin: grandfathered silent catch — see #1531; drain by adding log.debug()/log.warn() or re-throwing.
1115: clearPatchCache().catch(() => {
1116: /* best-effort — don't fail the upgrade if cache cleanup fails */
1117: });
1118:
1119: // Set executable permission (Unix only)
1120: if (process.platform !== "win32") {
1121: chmodSync(tempPath, 0o755);
1122: }
1123:
1124: return { tempBinaryPath: tempPath, lockPath, patchBytes };
1125: } catch (error) {
1126: releaseLock(lockPath);
1127: throw ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/release-notes.ts</path>
<type>file</type>
<content>
560: sections.push({ category, markdown });
561: }
562: }
563:
564: return sections;
565: }
566:
567: // ────────────────────────────── Fetch Functions ────────────────────────────
568:
569: /**
570: * Max releases to fetch for changelog purposes.
571: *
572: * Higher than the delta-upgrade cap (12) to cover larger version jumps.
573: * GitHub API max per_page is 100; 30 covers ~6+ months of weekly releases.
574: */
575: const CHANGELOG_MAX_RELEASES = 30;
576:
577: /**
578: * Fetch recent releases from GitHub for changelog building.
579: *
580: * Uses a higher `per_page` than `fetchRecentReleases()` in delta-upgrade
581: * (which is capped at 12 for patch chain resolution) to cover larger
582: * version jumps without silent truncation. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade</path> <type>directory</type> <entries> .craft.yml .git .github/ .gitignore .lore.md .nojekyll .npmrc AGENTS.md apps/ CHANGELOG.md codemods/ docs/ LICENSE.md node_modules/ package.json packages/ pnpm-lock.yaml pnpm-workspace.yaml README.md (19 entries) </entries>
<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: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
180: return cachedIsMusl;
181: }
182:
183: // Heuristic 1: Check for musl dynamic linker
184: const muslArch = process.arch === "x64" ? "x86_64" : "aarch64";
185: if (existsSync(`/lib/ld-musl-${muslArch}.so.1`)) {
186: cachedIsMusl = true;
187: return true;
188: }
189:
190: // Heuristic 2: ldd --version output (musl ldd writes "musl libc" to stderr)
191: try {
192: const result = spawnSync("ldd", ["--version"], {
193: stdio: ["ignore", "pipe", "pipe"],
194: });
195: const output =
196: Buffer.from(result.stdout).toString() +
197: Buffer.from(result.stderr).toString();
198: cachedIsMusl = output.toLowerCase().includes("musl");
199: return cachedIsMusl;
200: } catch {
201: // ldd not found or failed — assume glibc (the common case)
202: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts</path>
<type>file</type>
<content>
95: */
96: export type InstallationMethod =
97: | "curl"
98: | "brew"
99: | "npm"
100: | "pnpm"
101: | "bun"
102: | "yarn"
103: | "unknown";
104:
105: /** A repository pair that hosts CLI stable releases and nightly OCI images. */
106: export type UpgradeSource = {
107: /** GitHub `owner/repository` containing CLI release assets. */
108: readonly githubRepo: string;
109: /** GHCR `owner/package` containing CLI nightly images and delta patches. */
110: readonly ghcrRepo: string;
111: /** Prefix attached to CLI release tags in this repository. */
112: readonly tagPrefix: string;
113: };
114:
115: /** Ordered CLI release sources. The resolver falls through only on HTTP 404. ...
- 🔴 (14:38) `packages/cli/src/lib/release-notes.ts` defines `CHANGELOG_MAX_RELEASES = 30`, requests `${getGitHubReleasesUrl(source)}?per_page=${CHANGELOG_MAX_RELEASES}`, and builds commit-history URLs as `https://api.github.com/repos/${source.githubRepo}/commits?sha=main&since=${sinceDate}&until=${untilDate}&per_page=100`. - 🔴 (14:39) `packages/cli/test/lib/delta-upgrade.mocked.test.ts` is isol…
- 🔴 (14:28) `packages/cli/src/lib/upgrade.ts` lines 433–454 define `fetchLatestFromGitHubWithSource(signal?, sources = UPGRADE_SOURCES): Promise<ResolvedUpgradeVersion>`: it calls `resolveUpgradeSource({ getProbeUrl: getGitHubLatestReleaseUrl, signal, sources })`, parses the successful response with `extractReleaseVersions(data, source)`, strips `VERSION_PREFIX_REGEX` from the first tag, throws …
- 🔴 (14:25) `packages/cli/test/lib/upgrade.test.ts` lines 591–710 test `versionExists()`: for `"curl"` version `"1.0.0"`, it first requests `https://api.github.com/repos/getsentry/toolkit/releases/tags/cli%401.0.0` and returns `true` on HTTP 200. - 🔴 (14:25) `versionExists("curl", "1.0.0")` falls back after a Toolkit HTTP 404 from `https://api.github.com/repos/getsentry/toolkit/releases/tags/cl…
- 🔴 (14:18) The `binpatch` public entrypoint describes a reusable, pure-Node (`node:*` built-ins only), zero-product-coupling binary delta-update engine with two components joined by one README wire contract: (1) an apply core that parses/applies a `TRDIFF10`/bsdiff patch chain to a binary; (2) discovery that resolves a patch chain through a pluggable `SourceStrategy` using OCI/GHCR tags or GitH…
- 🔴 (14:16) `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts` lines 808–824 define `mockFetch(fn)` by assigning `globalThis.fetch`, save the original fetch in `beforeEach()`, and restore it in `afterEach()`. - 🔴 (14:16) `fetchRecentReleases()` tests verify the default GitHub API URL contains `ap…
### September 9, 2026 - 🔴 (14:11) BYK/binpatch `src/sources/github-release.ts` implements the stable-channel `githubReleaseSource()` using GitHub Release assets named `<binaryName>`, `<binaryName>.gz`, and `<binaryName>.patch`; owner/repository URL, binary name, user agent, fetch implementation, and instrumentation are injected through `GitHubReleaseSourceConfig`. - 🔴 (14:11) `extractSha256(ass…
### September 9, 2026 - 🔴 (14:07) In `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts`, `resolveContext(version, flags)` resolves `{ channel, versionArg }` through `resolveChannelAndVersion(version)`, compares against `getReleaseChannel()` to derive `channelChanged`, selects `flags.method ?? (await …
### September 9, 2026 - 🔴 (14:05) In `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts`, `getNightlyGzFilename()` returns `${getPlatformBinaryName()}.gz`. - 🔴 (14:05) `downloadNightlyToPath(destPath, version?, setMessage?, source = PRIMARY_UPGRADE_SOURCE)` gets an anonymous token for the selected `UpgradeSou…
### September 9, 2026 - 🔴 (13:56) The reviewed chain orchestration module defines `SourceStrategy.resolveChain(currentVersion, targetVersion, signal?, report?): Promise<PatchChain | null>`; a `null` result always falls back to a full download, and `report` classifications are telemetry-only and never change control flow. - 🔴 (13:56) `DeltaUnavailableReason` has exactly 5 values: `"no_patches"` …
### September 9, 2026 - 🔴 (13:44) `packages/cli/test/lib/delta-upgrade.test.ts` was 2013 lines. Its `"selected source affinity"` suite uses `importDeltaUpgradeWithVersion(version)` with `vi.resetModules()`/`vi.doMock("../../src/lib/constants.js")` and restores state via `vi.doUnmock()` plus `vi.resetModules()`. - 🔴 (13:44) Exact legacy-affinity expectations in `packages/cli/test/lib/delta-upgra…
### Current State - **Date:** September 9, 2026. - **Repository/worktree:** `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade` - **Branch:** `feat/toolkit-bridge-upgrade`; at 09:33 it was behind `origin/main` by 2 commits. - **Task:** Read-only review of Toolkit/legacy dual-source upgrade compatibility, focused on: - `packages/cli/src/lib/…
* 🔴 (13:40) Working tree contained 18 modified files with 1,931 insertions and 325 deletions: `.github/workflows/ci.yml`, `packages/cli/install`, `packages/cli/package.json`, `packages/cli/src/commands/cli/upgrade.ts`, `packages/cli/src/lib/binary.ts`, `packages/cli/src/lib/delta-upgrade.ts`, `packages/cli/src/lib/ghcr.ts`, `packages/cli/src/lib/release-notes.ts`, `packages/cli/src/lib/upgrade.t…
* 🔴 (13:37) In `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts`, the `method` flag is parsed by `parseInstallationMethod`, is optional, uses placeholder `"method"`, and is documented as supporting `curl`, `brew`, `npm`, `pnpm`, `bun`, and `yarn`. * 🔴 (13:37) The upgrade command’s `func()` calls `r…
* 🔴 (13:33) The `githubReleaseSource` stable-channel strategy models each GitHub release with three platform assets: `<binaryName>` for the expected SHA-256 digest, `<binaryName>.gz` for the full-download size ratio gate, and `<binaryName>.patch` for the delta from the previous release. * 🔴 (13:33) `extractSha256(asset)` accepts case-insensitive `sha256:([0-9a-f]+)` digests and returns lowercas…
* 🔴 (13:32) `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts` is a 648-line delta-upgrade implementation backed by `binpatch`. * 🔴 (13:32) `src/lib/delta-upgrade.ts` imports `applyPatchChainInMemory`, `extractStableChain`, `filterAndSortChainTags`, `validateChainStep`, `getPatchFromVersion`, `getPatch…
* 🔴 (13:30) In `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/version-check.test.ts`, lines 402–416 define `describe("abortPendingVersionCheck", ...)` with tests confirming `abortPendingVersionCheck()` does not throw when no check is pending and when called 3 times. * 🔴 (13:30) In `test/lib/version-check.test.ts`, …
* 🔴 (13:27) User’s search found exactly 12 matches for `LEGACY_UPGRADE_SOURCE`, legacy-source affinity, and related tests in `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/test/lib/delta-upgrade.test.ts`. * 🔴 (13:27) In `test/lib/delta-upgrade.test.ts`, line 46 defines `const LEGACY_UPGRADE_SOURCE = UPGRADE_SOURCES[1];`, an…
* 🔴 (13:23) User’s search found exactly 47 matches for delta-upgrade resolution, execution, and prefetch APIs across 5 files under `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/`. * 🔴 (13:23) In `src/lib/version-check.ts`, line 242 calls `await prefetchNightlyPatches(latestVersion, signal, source)`, while line 244 calls `a…
* 🔴 (13:14) User showed `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/binary.ts` lines 90–279. `InstallationMethod` is `"curl" | "brew" | "npm" | "pnpm" | "bun" | "yarn" | "unknown"`, while `VALID_METHODS` accepts only `curl`, `brew`, `npm`, `pnpm`, `bun`, and `yarn`. * 🔴 (13:14) User showed `parseInstallationMetho…
* 🔴 (13:10) User showed `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/delta-upgrade.ts`, a 648-line CLI adapter around `binpatch` that preserves the existing public API while delegating chain extraction, source resolution, caching, patch application, and telemetry. * 🔴 (13:10) User showed `getPrimaryUpgradeSource()…
* 🔴 (13:08) User showed Vitest coverage for `extractSha256()`: it accepts case-insensitive `sha256:` digests and returns lowercase hex (for example, `sha256:ABCDEF01` → `abcdef01`), while missing digests and non-SHA-256 values such as `md5:deadbeef` return `null`. * 🔴 (13:08) User showed `getStableTargetSha256()` locating the exact binary asset by `name === binaryName`, extracting its SHA-256 d…
* 🔴 (13:00) User showed `packages/cli/src/commands/cli/upgrade.ts` threading optional `source?: UpgradeSource` through target resolution and upgrade execution, including `resolveExistingUpgradeVersion()`, `resolveLatestUpgradeVersion()`, `executeUpgrade()`, and returned target/done result types. * 🔴 (13:00) User showed a comment in `packages/cli/src/commands/cli/setup.ts` stating that current t…
* 🔴 (12:59) User showed source-affinity changes in `packages/cli/src/lib/delta-upgrade.ts`: `fetchRecentReleases()`, `resolveStableChain()`, `resolveNightlyChain()`, `resolveStableDelta()`, `resolveNightlyDelta()`, `attemptDeltaUpgrade()`, `prefetchNightlyPatches()`, and `prefetchStablePatches()` now accept an `UpgradeSource`, defaulting through `getPrimaryUpgradeSource()` or `PRIMARY_UPGRADE_SO…
* 🔴 (12:55) User showed `packages/cli/src/lib/delta-upgrade.ts`, a 648-line sentry-cli adapter around `binpatch` that preserves the existing public API while injecting Sentry tracing, custom CA fetch, logging, cache location, version comparison, upgrade-source configuration, and CLI progress rendering. * 🔴 (12:55) User showed `getPrimaryUpgradeSource()` returning `PRIMARY_UPGRADE_SOURCE` or thr…
* 🔴 (10:29) User showed a chain-discovery and resolve/apply orchestration module that combines a product-agnostic `SourceStrategy` with `PatchCache`, `applyPatchChainInMemory`, SHA-256 verification, and progress events; product-specific concerns such as version, telemetry, logging, and cache location are injected. * 🔴 (10:29) User defined `SourceStrategy.resolveChain(currentVersion, targetVersi…
* 🔴 (10:27) User requires `detectInstallationMethod()` in `packages/cli/src/lib/upgrade.ts` to always check Homebrew first because stored install information may be stale; `isHomebrewInstall()` is a cheap, authoritative realpath check that overrides stored data, including when a user previously had curl recorded and switched to Homebrew. * 🔴 (10:27) User showed `detectInstallationMethod()` prio…
Date: Sep 9, 2026 * 🔴 (10:22) User showed GitHub issue comment `4978828102` (`IC_kwDOQm6jAs8AAAABKMLjRg`) at `https://github.com/getsentry/cli/issues/1244#issuecomment-4978828102`: BYK, a repository MEMBER, wrote “Master tracking issue: https://github.com/getsentry/cli/issues/1248”; created and updated July 15, 2026 at 09:05:00Z, with 0 reactions. * 🔴 (10:22) User showed an in-progress change t…
Date: Sep 9, 2026 * 🔴 (10:18) User showed BYK/binpatch tags: `0.4.2` at commit `9ba6bbb8227fcbd2521852d2311c82afac5e9573`, `0.4.1` at `d0593cdd89eb720edddf9644e0753613e4a8e622`, and `0.4.0` at `2446f4cbecca92eba775e8ef52dff01fd20a9326`. * 🔴 (10:19) User showed a search with exactly 84 matches across `packages/cli/test/lib/delta-upgrade.test.ts`, `packages/cli/test/lib/delta-upgrade.mocked.test.…
* 🔴 (10:16) User showed `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts`, totaling exactly 1144 lines. * 🔴 (10:16) User showed `getNightlyGzFilename()` returns `${getPlatformBinaryName()}.gz`; nightly layers use that value as the `org.opencontainers.image.title` annotation, including `sentry-windows-x64.ex…
Date: September 9, 2026 * 🔴 (10:13) User stated that a listed patch-manifest tag failing to fetch is almost always transient (`5xx` / timeout / connection reset), whereas a poisoned tag fetches successfully with HTTP 200 and is rejected by `validateNightlyChain`. * 🔴 (10:13) User stated manifest-fetch failures must be classified as `"network"` so they never trigger a false `"malformed_chain"` p…
Date: September 9, 2026 * 🔴 (10:08) User showed exactly 3 `fetchLatestFromGitHub` references: call site `packages/cli/src/lib/version-check.ts:287`, definition `packages/cli/src/lib/upgrade.ts:399`, and another call site `packages/cli/src/lib/upgrade.ts:506`. * 🔴 (10:09) User showed `packages/cli/test/lib/binary.test.ts` imports and tests `resolveUpgradeSource`, `UPGRADE_SOURCES`, and source-aw…
Date: September 9, 2026 * 🔴 (10:05) User showed the `binpatch` package is a reusable binary delta-update engine with two parts joined by one wire contract: an apply core for parsing/applying `TRDIFF10`/bsdiff patch chains, and discovery via pluggable `SourceStrategy` implementations for OCI/GHCR tags or GitHub Release assets; it uses only `node:*` built-ins and has zero product coupling. * 🔴 (1…
Date: September 9, 2026 * 🔴 (10:03) User showed `SourceStrategy.resolveChain(currentVersion, targetVersion, signal?, report?)` returns `Promise<PatchChain | null>` containing an ordered oldest-hop-first patch chain and expected final SHA-256; `null` means no usable chain and always falls back to a full download. * 🔴 (10:03) User stated `UnavailableReporter` classification is telemetry-only and …
Date: September 9, 2026 * 🔴 (10:02) User showed `InstallationMethod` in `packages/cli/src/lib/binary.ts` as the exact union `"curl" | "brew" | "npm" | "pnpm" | "bun" | "yarn" | "unknown"`; `VALID_METHODS` excludes `"unknown"`, and `parseInstallationMethod()` lowercases input and throws `Invalid method: ${value}. Must be one of: ${VALID_METHODS.join(", ")}` for an unsupported method. * 🔴 (10:02)…
Date: September 9, 2026 * 🔴 (10:01) User showed additional `resolveStableChain()` coverage in `packages/cli/test/lib/delta-upgrade.test.ts`: resolving `"0.13.0"` → `"0.14.0"` returns `null`; a generated sequence of 15 releases representing 14 hops from `"0.1.0"` → `"0.15.0"` returns `null` because it exceeds `MAX_STABLE_CHAIN_DEPTH (10)`. * 🔴 (10:01) User showed `setupNightlyMocks()` in `packag…
Date: September 9, 2026 * 🔴 (09:58) User stated the Sentry CLI project is built with Node.js, pnpm, and Stricli, lives in `packages/cli` within a pnpm workspace, and has its docs site in `apps/cli-docs`. * 🔴 (09:58) User stated project goals: zero-config project-context detection from DSNs in source and env files; Seer AI-powered root-cause analysis and fix plans; developer-friendly UX followin…
* 🔴 (09:56) User showed `packages/cli/src/lib/delta-upgrade.ts` as a 627-line binpatch-backed delta-upgrade adapter importing `applyPatchChainInMemory`, `resolveAndApply`, `ghcrSource`, `githubReleaseSource`, `OciClient`, cache/discovery helpers, telemetry types, chain validators, and constants from `"binpatch"`, while preserving existing public exports such as `extractSha256`, `getPatchFromVers…
* 🔴 (09:54) User showed a diff in `packages/cli/src/lib/ghcr.ts` importing `PRIMARY_UPGRADE_SOURCE` and `type UpgradeSource` from `./binary.js`, changing `GHCR_REPO` from hard-coded `"getsentry/cli"` to `PRIMARY_UPGRADE_SOURCE.ghcrRepo`, and making GHCR token, manifest, blob, tag-listing, and layer-download helpers source-aware. * 🔴 (09:54) User showed `getAnonymousToken(sourceOrSignal, signal)…
* 🔴 (09:50) User showed GitHub comment `getsentry/cli#1244#issuecomment-4978828102` (`id: 4978828102`) by `BYK`, created and last updated `2026-07-15T09:05:00Z`, whose body is `Master tracking issue: https://github.com/getsentry/cli/issues/1248`. * 🔴 (09:51) User showed tests for `extractSha256`: a binary asset digest `sha256:ABCDEF01` becomes lowercase `abcdef01`; a missing digest or non-SHA-2…
* 🔴 (09:49) User showed a code change in `packages/cli/src/lib/binary.ts` adding `UpgradeSource = { readonly githubRepo: string; readonly ghcrRepo: string; readonly tagPrefix: string }` and the shared ordered `UPGRADE_SOURCES`: 1. `{ githubRepo: "getsentry/toolkit", ghcrRepo: "getsentry/toolkit", tagPrefix: "cli@" }`; 2. `{ githubRepo: "getsentry/cli", ghcrRepo: "getsentry/cli", tagPrefix: "" }`…
* 🔴 (09:47) User showed binpatch wire-contract constants that must agree between the generator/publishing side and library: `MAX_STABLE_CHAIN_DEPTH = 10`, `MAX_NIGHTLY_CHAIN_DEPTH = 30`, `SIZE_THRESHOLD_RATIO = 0.6` for abandoning a patch chain when its total size exceeds 60% of the full gzipped download, and GHCR manifest tag prefix `PATCH_TAG_PREFIX = "patch-"`. * 🔴 (09:47) User showed shared…
* 🔴 (09:43) User showed `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/commands/cli/upgrade.ts:562-603`: `resolveUpdatedCliPath()` resolves `whichSync("sentry", { PATH: pathEnv }) ?? entryPath ?? execPath`; `resolveUpgradeInstallDir()` normally retains `currentInstallDir`, but relocates legacy `~/.sentry/bin` to the XDG …
* 🔴 (09:41) User specified installation-method detection in `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts` must always check Homebrew first because stored install information may be stale; the Homebrew-first check appears at line 356, before the stored-info path at line 363. * 🔴 (09:42) User stated packa…
* 🟡 (09:38) Search found exactly 5 matches in `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/toolkit-bridge-upgrade/packages/cli/src/lib/upgrade.ts`: line 399 exports `fetchLatestFromGitHub(`, line 433 exports `fetchLatestFromNpm(): Promise<string>`, line 467 exports `fetchLatestNightlyVersion(`, line 503 returns `fetchLatestNightlyVersion()`, and line 506 con…
* 🔴 (09:37) User stated the binpatch library never renders progress UI; it only emits progress events. * 🟡 (09:37) The binpatch public barrel exports apply-core APIs from `./bspatch`: `addDiffChunk`, `applyPatch`, `applyPatchChainInMemory`, `applyPatchToMemory`, `MAX_OUTPUT_SIZE`, `offtin`, `parsePatchHeader`, and type `PatchHeader`. * 🟡 (09:37) The binpatch public barrel exports cache APIs fr…
* 🟡 (09:36) `src/sources/github-release.ts` defines the stable-channel `githubReleaseSource`: each GitHub release is expected to publish `<binaryName>`, `<binaryName>.gz`, and `<binaryName>.patch`; product details (`releasesUrl`, `binaryName`, `userAgent`, injectable `fetch`, and optional `InstrumentHook`) remain consumer-injected. * 🟡 (09:36) Stable SHA-256 extraction uses `SHA256_DIGEST_PATTE…
Date: Sep 9, 2026 * 🟡 (09:34) `packages/cli/test/lib/delta-upgrade.mocked.test.ts` is a 500-line integration-test file that uses `vi.mock("../../src/lib/constants.js", ...)` to set `CLI_VERSION: "0.13.0"` before importing `attemptDeltaUpgrade`, `resolveNightlyDelta`, and `resolveStableDelta`; it is separate from `delta-upgrade.test.ts` because `bun test --isolate` gives each file a fresh module …
Date: Sep 9, 2026 * 🔴 (09:33) User specified that the caller receives the successful upgrade-source probe response so it never repeats the request; only HTTP 404 advances to the next source, while every other HTTP or network failure aborts immediately. * 🔴 (09:34) User specified that the in-memory patch chain never creates scratch files on disk. * 🟡 (09:32) `downloadBinaryToTemp(version, downl…
* 🟡 (09:31) Repository search for the broader `source`/`resource` terms returned 100 matches with more available; notable upgrade-related matches were in `packages/cli/src/lib/binary.ts` and `packages/cli/src/lib/delta-upgrade.ts`. * 🟡 (09:31) Two separate file searches returned `No files found`. * 🔴 (09:32) User specified that trailing path separators may be stripped, but never from a bare ro…
Date: Sep 9, 2026 * 🟡 (09:31) Repository search found 94 matches related to `binpatch` and prefetching. * 🟡 (09:31) `packages/cli/package.json` line 111 declares `"binpatch": "^0.4.2"`. * 🟡 (09:31) `packages/cli/src/lib/delta-upgrade.ts` imports `githubReleaseSource` from `binpatch`; `githubReleaseSource({ ... })` is called around line 123. * 🟡 (09:31) Delta resolution is centralized in `reso…