diff --git a/packages/gittensory-miner/lib/ams-policy.js b/packages/gittensory-miner/lib/ams-policy.js index 0340651849..4cf0bbde7e 100644 --- a/packages/gittensory-miner/lib/ams-policy.js +++ b/packages/gittensory-miner/lib/ams-policy.js @@ -58,7 +58,7 @@ async function fetchRepoAmsPolicyContent(target, resolved) { for (const path of AMS_POLICY_SPEC_FILENAMES) { const url = `${resolved.rawContentBaseUrl}/${encodeURIComponent(target.owner)}/${encodeURIComponent(target.repo)}/HEAD/${path}`; try { - const response = await resolved.fetchImpl(url, { method: "GET", headers: { accept: "application/json", "user-agent": "gittensory-miner" } }); + const response = await resolved.fetchImpl(url, { method: "GET", headers: { accept: "application/json", "user-agent": "loopover-miner" } }); if (response.ok) { const text = await response.text(); if (typeof text === "string") return text; diff --git a/packages/gittensory-miner/lib/ci-poller.js b/packages/gittensory-miner/lib/ci-poller.js index b37fbb41da..db3eb2ca6e 100644 --- a/packages/gittensory-miner/lib/ci-poller.js +++ b/packages/gittensory-miner/lib/ci-poller.js @@ -60,7 +60,7 @@ function normalizePullNumber(value) { function githubHeaders(githubToken) { const headers = { accept: "application/vnd.github+json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": githubApiVersion, }; if (githubToken) headers.authorization = `Bearer ${githubToken}`; diff --git a/packages/gittensory-miner/lib/laptop-init.js b/packages/gittensory-miner/lib/laptop-init.js index 0bfe2d112c..b416e577ad 100644 --- a/packages/gittensory-miner/lib/laptop-init.js +++ b/packages/gittensory-miner/lib/laptop-init.js @@ -114,7 +114,7 @@ function resolveCodexAuthPath(env = process.env) { function githubHeaders(githubToken) { const headers = { accept: "application/vnd.github+json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": githubApiVersion, }; const token = typeof githubToken === "string" ? githubToken.trim() : ""; diff --git a/packages/gittensory-miner/lib/live-issue-snapshot.js b/packages/gittensory-miner/lib/live-issue-snapshot.js index bea4410071..c3d38a7f73 100644 --- a/packages/gittensory-miner/lib/live-issue-snapshot.js +++ b/packages/gittensory-miner/lib/live-issue-snapshot.js @@ -32,7 +32,7 @@ function githubGraphqlHeaders(githubToken) { const headers = { accept: "application/vnd.github+json", "content-type": "application/json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": GITHUB_API_VERSION, }; const token = typeof githubToken === "string" ? githubToken.trim() : ""; diff --git a/packages/gittensory-miner/lib/opportunity-fanout.js b/packages/gittensory-miner/lib/opportunity-fanout.js index 915e18b598..e1d141a506 100644 --- a/packages/gittensory-miner/lib/opportunity-fanout.js +++ b/packages/gittensory-miner/lib/opportunity-fanout.js @@ -68,7 +68,7 @@ function targetFromSearchIssue(issue) { function githubHeaders(githubToken) { const headers = { accept: "application/vnd.github+json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": githubApiVersion, }; const token = typeof githubToken === "string" ? githubToken.trim() : ""; diff --git a/packages/gittensory-miner/lib/pr-disposition-poller.js b/packages/gittensory-miner/lib/pr-disposition-poller.js index 1b6d302036..a89534a13d 100644 --- a/packages/gittensory-miner/lib/pr-disposition-poller.js +++ b/packages/gittensory-miner/lib/pr-disposition-poller.js @@ -71,7 +71,7 @@ function normalizePullNumber(value) { function githubHeaders(githubToken) { const headers = { accept: "application/vnd.github+json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": githubApiVersion, }; if (githubToken) headers.authorization = `Bearer ${githubToken}`; diff --git a/packages/gittensory-miner/lib/rejection-signal.js b/packages/gittensory-miner/lib/rejection-signal.js index 2dfa4a24bb..3ebfec8adb 100644 --- a/packages/gittensory-miner/lib/rejection-signal.js +++ b/packages/gittensory-miner/lib/rejection-signal.js @@ -36,7 +36,7 @@ function normalizeOptions(options = {}) { async function fetchPolicyDoc(target, path, resolved) { const url = `${resolved.rawContentBaseUrl}/${encodeURIComponent(target.owner)}/${encodeURIComponent(target.repo)}/HEAD/${path}`; try { - const response = await resolved.fetchImpl(url, { method: "GET", headers: { accept: "application/json", "user-agent": "gittensory-miner" } }); + const response = await resolved.fetchImpl(url, { method: "GET", headers: { accept: "application/json", "user-agent": "loopover-miner" } }); if (!response.ok) return null; const text = await response.text(); return typeof text === "string" ? text : null; diff --git a/packages/gittensory-miner/lib/self-review-context.js b/packages/gittensory-miner/lib/self-review-context.js index fbab889e3f..e9b29de406 100644 --- a/packages/gittensory-miner/lib/self-review-context.js +++ b/packages/gittensory-miner/lib/self-review-context.js @@ -38,7 +38,7 @@ function parseRepoFullName(repoFullName) { function githubHeaders(githubToken) { const headers = { accept: "application/vnd.github+json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": GITHUB_API_VERSION, }; const token = typeof githubToken === "string" ? githubToken.trim() : ""; @@ -216,7 +216,7 @@ async function fetchManifestContent(target, resolved) { for (const path of MANIFEST_FILE_CANDIDATES) { const url = `${resolved.rawContentBaseUrl}/${encodeURIComponent(target.owner)}/${encodeURIComponent(target.repo)}/HEAD/${path}`; try { - const response = await resolved.fetchImpl(url, { method: "GET", headers: { accept: "application/json", "user-agent": "gittensory-miner" } }); + const response = await resolved.fetchImpl(url, { method: "GET", headers: { accept: "application/json", "user-agent": "loopover-miner" } }); if (response.ok) { const text = await response.text(); if (typeof text === "string") return text; diff --git a/scripts/check-mcp-release-due.mjs b/scripts/check-mcp-release-due.mjs index 11eb369177..7ebd99d57a 100644 --- a/scripts/check-mcp-release-due.mjs +++ b/scripts/check-mcp-release-due.mjs @@ -140,7 +140,7 @@ async function githubRequest({ token, method, path, body }) { accept: "application/vnd.github+json", authorization: `Bearer ${token}`, "content-type": "application/json", - "user-agent": "gittensory-mcp-release-watch", + "user-agent": "loopover-mcp-release-watch", "x-github-api-version": "2022-11-28", }, body: body ? JSON.stringify(body) : undefined, diff --git a/scripts/smoke-production.mjs b/scripts/smoke-production.mjs index c978e6e8a3..3487d805a0 100644 --- a/scripts/smoke-production.mjs +++ b/scripts/smoke-production.mjs @@ -106,7 +106,7 @@ async function fetchWithTimeout(url, init = {}) { return await fetch(url, { ...init, headers: { - "user-agent": "gittensory-production-smoke", + "user-agent": "loopover-production-smoke", ...(init.headers ?? {}), }, signal: controller.signal, diff --git a/src/auth/github-oauth.ts b/src/auth/github-oauth.ts index 46f0ae931d..74bab5cf22 100644 --- a/src/auth/github-oauth.ts +++ b/src/auth/github-oauth.ts @@ -43,7 +43,7 @@ export async function startGitHubDeviceFlow(env: Env): Promise { return { accept: "application/vnd.github+json", - "user-agent": "gittensory/0.1", + "user-agent": PRODUCT_USER_AGENT, "x-github-api-version": "2022-11-28", ...(token ? { authorization: `Bearer ${token}` } : {}), }; diff --git a/src/github/public.ts b/src/github/public.ts index 0db90a5a5d..3b01448ecd 100644 --- a/src/github/public.ts +++ b/src/github/public.ts @@ -1,4 +1,4 @@ -import { githubRateLimitAdmissionKeyForPublicToken, timeoutFetch, type GitHubRateLimitAdmissionKey } from "./client"; +import { githubRateLimitAdmissionKeyForPublicToken, PRODUCT_USER_AGENT, timeoutFetch, type GitHubRateLimitAdmissionKey } from "./client"; export type PublicContributorProfile = { login: string; @@ -66,7 +66,7 @@ export async function fetchPublicContributorProfile(login: string, env?: Pick, r const response = await timeoutFetch(`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`, { headers: { accept: "application/vnd.github+json", - "user-agent": "gittensory/0.1", + "user-agent": PRODUCT_USER_AGENT, "x-github-api-version": "2022-11-28", ...(env.GITHUB_PUBLIC_TOKEN ? { authorization: `Bearer ${env.GITHUB_PUBLIC_TOKEN}` } : {}), }, diff --git a/src/gittensor/api.ts b/src/gittensor/api.ts index 83c666211f..4f5bff8868 100644 --- a/src/gittensor/api.ts +++ b/src/gittensor/api.ts @@ -1,4 +1,5 @@ import type { ContributorRepoStatRecord } from "../types"; +import { PRODUCT_USER_AGENT } from "../github/client"; import { errorMessage } from "../utils/json"; const GITTENSOR_API_BASE = "https://api.gittensor.io"; @@ -282,7 +283,7 @@ async function fetchJson(url: string): Promise { const response = await fetch(url, { headers: { accept: "application/json", - "user-agent": "gittensory/0.1", + "user-agent": PRODUCT_USER_AGENT, }, signal: AbortSignal.timeout(GITTENSOR_FETCH_TIMEOUT_MS), }); diff --git a/src/orb/app-auth.ts b/src/orb/app-auth.ts index 8608e83658..70fceea51f 100644 --- a/src/orb/app-auth.ts +++ b/src/orb/app-auth.ts @@ -11,7 +11,7 @@ function orbHeaders(jwt: string): HeadersInit { accept: "application/vnd.github+json", authorization: `Bearer ${jwt}`, "content-type": "application/json", - "user-agent": "gittensory-orb/0.1", + "user-agent": "loopover-orb/0.1", "x-github-api-version": "2022-11-28", }; } diff --git a/src/orb/oauth.ts b/src/orb/oauth.ts index a1746482de..124719c782 100644 --- a/src/orb/oauth.ts +++ b/src/orb/oauth.ts @@ -13,7 +13,7 @@ // (read back at token-exchange, never from a request). No request input is echoed into the markup (no injection // surface). import type { Context } from "hono"; -import { timeoutFetch } from "../github/client"; +import { PRODUCT_USER_AGENT, timeoutFetch } from "../github/client"; import { GITTENSORY_SITE_URL } from "../github/footer"; import { isOrbBrokerEnabled, issueOrbEnrollment } from "./broker"; @@ -36,7 +36,7 @@ export async function exchangeOrbOAuthCode(env: Env, code: string, fetchImpl: ty /** Identify the authenticated maintainer (GET /user with their token). Null on any non-OK / loginless response. */ export async function fetchOrbOAuthUser(token: string, fetchImpl: typeof fetch = timeoutFetch): Promise { const res = await fetchImpl("https://api.github.com/user", { - headers: { authorization: `Bearer ${token}`, accept: "application/vnd.github+json", "user-agent": "gittensory/0.1" }, + headers: { authorization: `Bearer ${token}`, accept: "application/vnd.github+json", "user-agent": PRODUCT_USER_AGENT }, }); const user = (await res.json().catch(() => ({}))) as GitHubUser; return res.ok && user.login ? user : null; @@ -60,7 +60,7 @@ export async function verifyInstallationAdmin( return userId === accountId && userLogin.toLowerCase() === accountLogin.toLowerCase(); } const res = await fetchImpl(`https://api.github.com/user/memberships/orgs/${encodeURIComponent(accountLogin)}`, { - headers: { authorization: `Bearer ${token}`, accept: "application/vnd.github+json", "user-agent": "gittensory/0.1" }, + headers: { authorization: `Bearer ${token}`, accept: "application/vnd.github+json", "user-agent": PRODUCT_USER_AGENT }, }); if (!res.ok) return false; const body = (await res.json().catch(() => ({}))) as GitHubOrgMembership; diff --git a/src/orb/relay.ts b/src/orb/relay.ts index 0184954d7b..a3328aa1c3 100644 --- a/src/orb/relay.ts +++ b/src/orb/relay.ts @@ -465,7 +465,7 @@ export async function forwardOrbEvent( "x-github-event": args.eventName, "x-github-delivery": args.deliveryId, "x-orb-signature-256": `sha256=${signature}`, - "user-agent": "gittensory-orb/0.1", + "user-agent": "loopover-orb/0.1", }, body: args.rawBody, signal: AbortSignal.timeout(10_000), diff --git a/src/registry/sync.ts b/src/registry/sync.ts index 0a0a419c06..32b4817560 100644 --- a/src/registry/sync.ts +++ b/src/registry/sync.ts @@ -1,6 +1,7 @@ import { and, desc, eq, inArray } from "drizzle-orm"; import { getDb } from "../db/client"; import { registrySnapshots, repositories, syncRuns } from "../db/schema"; +import { PRODUCT_USER_AGENT } from "../github/client"; import type { RegistrySnapshot } from "../types"; import { errorMessage, jsonString, nowIso, repoParts } from "../utils/json"; import { normalizeRegistryPayload } from "./normalize"; @@ -35,7 +36,7 @@ export async function refreshRegistry(env: Env): Promise { const response = await fetch(url, { headers: { accept: "application/json", - "user-agent": "gittensory/0.1", + "user-agent": PRODUCT_USER_AGENT, }, }); if (!response.ok) { diff --git a/src/review/content-lane/netuid-verification.ts b/src/review/content-lane/netuid-verification.ts index acced697f2..bdc1a3de79 100644 --- a/src/review/content-lane/netuid-verification.ts +++ b/src/review/content-lane/netuid-verification.ts @@ -86,7 +86,7 @@ export async function fetchSubnetRecord( try { const res = await fetchWithRetry( `${base}/subnets/${netuid}`, - { headers: { accept: "application/json", "user-agent": "gittensory-content-lane" } }, + { headers: { accept: "application/json", "user-agent": "loopover-content-lane" } }, fetchImpl, ); if (res.status === 404) return { status: "missing", record: null }; diff --git a/src/review/enrichment-wire.ts b/src/review/enrichment-wire.ts index f76c969a6f..07a1006b8a 100644 --- a/src/review/enrichment-wire.ts +++ b/src/review/enrichment-wire.ts @@ -77,7 +77,7 @@ async function fetchReesPingWithRetry(url: string, secret: string): Promise { return { accept, - "user-agent": "gittensory/0.1", + "user-agent": PRODUCT_USER_AGENT, "x-github-api-version": "2022-11-28", ...(token ? { authorization: `Bearer ${token}` } : {}), }; diff --git a/src/review/visual/actions-fallback.ts b/src/review/visual/actions-fallback.ts index 22feb1fe0f..84ab57d5b0 100644 --- a/src/review/visual/actions-fallback.ts +++ b/src/review/visual/actions-fallback.ts @@ -32,7 +32,7 @@ // dispatch inputs and surfaces the result as `workflow_run.display_title` in the completion webhook. // parseFallbackRunCorrelation reads it back; a run whose title doesn't match this exact shape is ignored // (fail-safe -- never guesses a PR from an unrelated run). -import { timeoutFetch, type GitHubRateLimitAdmissionKey } from "../../github/client"; +import { PRODUCT_USER_AGENT, timeoutFetch, type GitHubRateLimitAdmissionKey } from "../../github/client"; import { sha256Hex } from "../../utils/crypto"; import { isSafeHttpUrl } from "../content-lane/safe-url"; import type { GitHubRepo } from "./preview-url"; @@ -97,7 +97,7 @@ export async function dispatchVisualCaptureFallback(params: { const headers = new Headers(); headers.set("accept", "application/vnd.github+json"); headers.set("content-type", "application/json"); - headers.set("user-agent", "gittensory/0.1"); + headers.set("user-agent", PRODUCT_USER_AGENT); headers.set("x-github-api-version", API_VERSION); headers.set("authorization", `Bearer ${params.token}`); const response = await timeoutFetch(`${base}/actions/workflows/${FALLBACK_WORKFLOW_FILE}/dispatches`, { @@ -358,7 +358,7 @@ const MAX_FALLBACK_SHOTS = 24; function githubApiHeaders(token: string): Headers { const headers = new Headers(); headers.set("accept", "application/vnd.github+json"); - headers.set("user-agent", "gittensory/0.1"); + headers.set("user-agent", PRODUCT_USER_AGENT); headers.set("x-github-api-version", API_VERSION); headers.set("authorization", `Bearer ${token}`); return headers; diff --git a/src/review/visual/preview-url.ts b/src/review/visual/preview-url.ts index 2d8c6f5e4c..4b11136f3f 100644 --- a/src/review/visual/preview-url.ts +++ b/src/review/visual/preview-url.ts @@ -15,7 +15,7 @@ // (resolved via createInstallationToken). Every helper degrades to null/absent on failure — preview // discovery must NEVER sink a review. -import { timeoutFetch, type GitHubRateLimitAdmissionKey } from "../../github/client"; +import { PRODUCT_USER_AGENT, timeoutFetch, type GitHubRateLimitAdmissionKey } from "../../github/client"; const DEFAULT_GITHUB_TIMEOUT_MS = 20_000; @@ -46,7 +46,7 @@ async function githubJson( ): Promise { const headers = new Headers(); headers.set("accept", "application/vnd.github+json"); - headers.set("user-agent", "gittensory/0.1"); + headers.set("user-agent", PRODUCT_USER_AGENT); headers.set("x-github-api-version", init.apiVersion || "2022-11-28"); if (init.token) headers.set("authorization", `Bearer ${init.token}`); const response = await timeoutFetch(url, { diff --git a/src/selfhost/setup-wizard.ts b/src/selfhost/setup-wizard.ts index 86e8108ee8..41d48f8f8f 100644 --- a/src/selfhost/setup-wizard.ts +++ b/src/selfhost/setup-wizard.ts @@ -133,7 +133,7 @@ ${error}
export async function exchangeManifestCode(code: string, fetchImpl: typeof fetch = timeoutFetch): Promise { const res = await fetchImpl(`https://api.github.com/app-manifests/${encodeURIComponent(code)}/conversions`, { method: "POST", - headers: { accept: "application/vnd.github+json", "user-agent": "gittensory-selfhost" }, + headers: { accept: "application/vnd.github+json", "user-agent": "loopover-selfhost" }, }); if (!res.ok) throw new Error(`manifest_exchange_http_${res.status}`); return (await res.json()) as AppCredentials; diff --git a/src/services/draft.ts b/src/services/draft.ts index a55ae07927..1d12b1122f 100644 --- a/src/services/draft.ts +++ b/src/services/draft.ts @@ -352,7 +352,7 @@ class GitHubUserApiError extends Error { async function githubUserJson(url: string, init: RequestInit & { token: string } = { token: "" }): Promise { const headers = new Headers(init.headers); headers.set("accept", "application/vnd.github+json"); - headers.set("user-agent", "gittensory-api"); + headers.set("user-agent", "loopover-api"); headers.set("x-github-api-version", GITHUB_API_VERSION); /* v8 ignore next -- token-absent arm is unreachable: every caller passes a decrypted user token; the { token: "" } default only guards the type. */ if (init.token) headers.set("authorization", `Bearer ${init.token}`); diff --git a/src/signals/focus-manifest-loader.ts b/src/signals/focus-manifest-loader.ts index 592579892c..a879b658f6 100644 --- a/src/signals/focus-manifest-loader.ts +++ b/src/signals/focus-manifest-loader.ts @@ -77,7 +77,7 @@ export async function fetchRepoFocusManifestFile(repoFullName: string): Promise< for (const path of MANIFEST_FILE_CANDIDATES) { const url = `https://raw.githubusercontent.com/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/HEAD/${path}`; try { - const response = await fetch(url, { headers: { Accept: "application/json", "User-Agent": "gittensory" } }); + const response = await fetch(url, { headers: { Accept: "application/json", "User-Agent": "loopover" } }); if (response.ok) { const text = await readBoundedResponseText(response); if (text !== null) return text; diff --git a/src/upstream/commit.ts b/src/upstream/commit.ts index bba6bf1035..0b3036ceee 100644 --- a/src/upstream/commit.ts +++ b/src/upstream/commit.ts @@ -1,10 +1,10 @@ -import { githubRateLimitAdmissionKeyForPublicToken, timeoutFetch } from "../github/client"; +import { githubRateLimitAdmissionKeyForPublicToken, PRODUCT_USER_AGENT, timeoutFetch } from "../github/client"; import { LOW_REST_RATE_LIMIT_REMAINING, shouldWaitForGitHubRateLimit } from "../github/rate-limit"; function upstreamCommitHeaders(token: string | undefined): Record { return { accept: "application/vnd.github+json", - "user-agent": "gittensory/0.1", + "user-agent": PRODUCT_USER_AGENT, "x-github-api-version": "2022-11-28", ...(token ? { authorization: `Bearer ${token}` } : {}), }; diff --git a/test/unit/enrichment-wire.test.ts b/test/unit/enrichment-wire.test.ts index be62961a7e..87772a8170 100644 --- a/test/unit/enrichment-wire.test.ts +++ b/test/unit/enrichment-wire.test.ts @@ -246,7 +246,7 @@ describe("buildReviewEnrichment", () => { ).toBe("Bearer sek"); expect( (calls[0]!.init.headers as Record)["user-agent"], - ).toBe("gittensory-selfhost/1.0"); + ).toBe("loopover-selfhost/1.0"); expect( (calls[0]!.init.headers as Record)["x-gittensory-request-id"], ).toMatch(/^[-0-9a-fA-Fa-z]+$/); diff --git a/test/unit/github-client.test.ts b/test/unit/github-client.test.ts index 1b40ba2d27..816e5eb1e4 100644 --- a/test/unit/github-client.test.ts +++ b/test/unit/github-client.test.ts @@ -190,7 +190,7 @@ describe("githubHeaders — the single shared GitHub REST header-builder (#4610, it("with no options, defaults to the standard accept + pinned api-version and omits content-type/authorization", () => { expect(githubHeaders()).toEqual({ accept: "application/vnd.github+json", - "user-agent": "gittensory/0.1", + "user-agent": "loopover/0.1", "x-github-api-version": "2022-11-28", }); }); diff --git a/test/unit/miner-init-verify-token.test.ts b/test/unit/miner-init-verify-token.test.ts index 6204ff333f..220126db62 100644 --- a/test/unit/miner-init-verify-token.test.ts +++ b/test/unit/miner-init-verify-token.test.ts @@ -61,7 +61,7 @@ describe("verifyGithubToken", () => { url: "https://example.com/user", headers: { accept: "application/vnd.github+json", - "user-agent": "gittensory-miner", + "user-agent": "loopover-miner", "x-github-api-version": "2022-11-28", }, },