Vendor opencode source for docker build

This commit is contained in:
southseact-3d
2026-02-07 20:54:46 +00:00
parent b30ff1cfa4
commit efda260214
3195 changed files with 387717 additions and 1 deletions

View File

@@ -0,0 +1,146 @@
import { query } from "@solidjs/router"
type Release = {
tag_name: string
name: string
body: string
published_at: string
html_url: string
}
export type HighlightMedia =
| { type: "video"; src: string }
| { type: "image"; src: string; width: string; height: string }
export type HighlightItem = {
title: string
description: string
shortDescription?: string
media: HighlightMedia
}
export type HighlightGroup = {
source: string
items: HighlightItem[]
}
export type ChangelogRelease = {
tag: string
name: string
date: string
url: string
highlights: HighlightGroup[]
sections: { title: string; items: string[] }[]
}
export type ChangelogData = {
ok: boolean
releases: ChangelogRelease[]
}
export async function loadChangelog(): Promise<ChangelogData> {
const response = await fetch("https://api.github.com/repos/anomalyco/opencode/releases?per_page=20", {
headers: {
Accept: "application/vnd.github.v3+json",
"User-Agent": "OpenCode-Console",
},
cf: {
// best-effort edge caching (ignored outside Cloudflare)
cacheTtl: 60 * 5,
cacheEverything: true,
},
} as RequestInit).catch(() => undefined)
if (!response?.ok) return { ok: false, releases: [] }
const data = await response.json().catch(() => undefined)
if (!Array.isArray(data)) return { ok: false, releases: [] }
const releases = (data as Release[]).map((release) => {
const parsed = parseMarkdown(release.body || "")
return {
tag: release.tag_name,
name: release.name,
date: release.published_at,
url: release.html_url,
highlights: parsed.highlights,
sections: parsed.sections,
}
})
return { ok: true, releases }
}
export const changelog = query(async () => {
"use server"
const result = await loadChangelog()
return result.releases
}, "changelog")
function parseHighlights(body: string): HighlightGroup[] {
const groups = new Map<string, HighlightItem[]>()
const regex = /<highlight\s+source="([^"]+)">([\s\S]*?)<\/highlight>/g
let match
while ((match = regex.exec(body)) !== null) {
const source = match[1]
const content = match[2]
const titleMatch = content.match(/<h2>([^<]+)<\/h2>/)
const pMatch = content.match(/<p(?:\s+short="([^"]*)")?>([^<]+)<\/p>/)
const imgMatch = content.match(/<img\s+width="([^"]+)"\s+height="([^"]+)"\s+alt="[^"]*"\s+src="([^"]+)"/)
const videoMatch = content.match(/^\s*(https:\/\/github\.com\/user-attachments\/assets\/[a-f0-9-]+)\s*$/m)
const media = (() => {
if (videoMatch) return { type: "video", src: videoMatch[1] } satisfies HighlightMedia
if (imgMatch) {
return {
type: "image",
src: imgMatch[3],
width: imgMatch[1],
height: imgMatch[2],
} satisfies HighlightMedia
}
})()
if (!titleMatch || !media) continue
const item: HighlightItem = {
title: titleMatch[1],
description: pMatch?.[2] || "",
shortDescription: pMatch?.[1],
media,
}
if (!groups.has(source)) groups.set(source, [])
groups.get(source)!.push(item)
}
return Array.from(groups.entries()).map(([source, items]) => ({ source, items }))
}
function parseMarkdown(body: string) {
const lines = body.split("\n")
const sections: { title: string; items: string[] }[] = []
let current: { title: string; items: string[] } | null = null
let skip = false
for (const line of lines) {
if (line.startsWith("## ")) {
if (current) sections.push(current)
current = { title: line.slice(3).trim(), items: [] }
skip = false
continue
}
if (line.startsWith("**Thank you")) {
skip = true
continue
}
if (line.startsWith("- ") && !skip) current?.items.push(line.slice(2).trim())
}
if (current) sections.push(current)
return { sections, highlights: parseHighlights(body) }
}

View File

@@ -0,0 +1,83 @@
import type { Key } from "~/i18n"
export const formError = {
invalidPlan: "error.invalidPlan",
workspaceRequired: "error.workspaceRequired",
alreadySubscribed: "error.alreadySubscribed",
limitRequired: "error.limitRequired",
monthlyLimitInvalid: "error.monthlyLimitInvalid",
workspaceNameRequired: "error.workspaceNameRequired",
nameTooLong: "error.nameTooLong",
emailRequired: "error.emailRequired",
roleRequired: "error.roleRequired",
idRequired: "error.idRequired",
nameRequired: "error.nameRequired",
providerRequired: "error.providerRequired",
apiKeyRequired: "error.apiKeyRequired",
modelRequired: "error.modelRequired",
} as const
const map = {
[formError.invalidPlan]: "error.invalidPlan",
[formError.workspaceRequired]: "error.workspaceRequired",
[formError.alreadySubscribed]: "error.alreadySubscribed",
[formError.limitRequired]: "error.limitRequired",
[formError.monthlyLimitInvalid]: "error.monthlyLimitInvalid",
[formError.workspaceNameRequired]: "error.workspaceNameRequired",
[formError.nameTooLong]: "error.nameTooLong",
[formError.emailRequired]: "error.emailRequired",
[formError.roleRequired]: "error.roleRequired",
[formError.idRequired]: "error.idRequired",
[formError.nameRequired]: "error.nameRequired",
[formError.providerRequired]: "error.providerRequired",
[formError.apiKeyRequired]: "error.apiKeyRequired",
[formError.modelRequired]: "error.modelRequired",
"Invalid plan": "error.invalidPlan",
"Workspace ID is required": "error.workspaceRequired",
"Workspace ID is required.": "error.workspaceRequired",
"This workspace already has a subscription": "error.alreadySubscribed",
"Limit is required.": "error.limitRequired",
"Set a valid monthly limit": "error.monthlyLimitInvalid",
"Set a valid monthly limit.": "error.monthlyLimitInvalid",
"Workspace name is required.": "error.workspaceNameRequired",
"Name must be 255 characters or less.": "error.nameTooLong",
"Email is required": "error.emailRequired",
"Role is required": "error.roleRequired",
"ID is required": "error.idRequired",
"Name is required": "error.nameRequired",
"Provider is required": "error.providerRequired",
"API key is required": "error.apiKeyRequired",
"Model is required": "error.modelRequired",
} as const satisfies Record<string, Key>
export function formErrorReloadAmountMin(amount: number) {
return `error.reloadAmountMin:${amount}`
}
export function formErrorReloadTriggerMin(amount: number) {
return `error.reloadTriggerMin:${amount}`
}
export function localizeError(t: (key: Key, params?: Record<string, string | number>) => string, error?: string) {
if (!error) return ""
if (error.startsWith("error.reloadAmountMin:")) {
const amount = Number(error.split(":")[1] ?? 0)
return t("error.reloadAmountMin", { amount })
}
if (error.startsWith("error.reloadTriggerMin:")) {
const amount = Number(error.split(":")[1] ?? 0)
return t("error.reloadTriggerMin", { amount })
}
const amount = error.match(/^Reload amount must be at least \$(\d+)$/)
if (amount) return t("error.reloadAmountMin", { amount: Number(amount[1]) })
const trigger = error.match(/^Balance trigger must be at least \$(\d+)$/)
if (trigger) return t("error.reloadTriggerMin", { amount: Number(trigger[1]) })
const key = map[error as keyof typeof map]
if (key) return t(key)
return error
}

View File

@@ -0,0 +1,38 @@
import { query } from "@solidjs/router"
import { config } from "~/config"
export const github = query(async () => {
"use server"
const headers = {
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
}
const apiBaseUrl = config.github.repoUrl.replace("https://github.com/", "https://api.github.com/repos/")
try {
const [meta, releases, contributors] = await Promise.all([
fetch(apiBaseUrl, { headers }).then((res) => res.json()),
fetch(`${apiBaseUrl}/releases`, { headers }).then((res) => res.json()),
fetch(`${apiBaseUrl}/contributors?per_page=1`, { headers }),
])
if (!Array.isArray(releases) || releases.length === 0) {
return undefined
}
const [release] = releases
const linkHeader = contributors.headers.get("Link")
const contributorCount = linkHeader
? Number.parseInt(linkHeader.match(/&page=(\d+)>; rel="last"/)?.at(1) ?? "0")
: 0
return {
stars: meta.stargazers_count,
release: {
name: release.name,
url: release.html_url,
tag_name: release.tag_name,
},
contributors: contributorCount,
}
} catch (e) {
console.error(e)
}
return undefined
}, "github")

View File

@@ -0,0 +1,211 @@
export const LOCALES = [
"en",
"zh",
"zht",
"ko",
"de",
"es",
"fr",
"it",
"da",
"ja",
"pl",
"ru",
"ar",
"no",
"br",
"th",
"tr",
] as const
export type Locale = (typeof LOCALES)[number]
export const LOCALE_COOKIE = "oc_locale" as const
export const LOCALE_HEADER = "x-opencode-locale" as const
function fix(pathname: string) {
if (pathname.startsWith("/")) return pathname
return `/${pathname}`
}
const LABEL = {
en: "English",
zh: "简体中文",
zht: "繁體中文",
ko: "한국어",
de: "Deutsch",
es: "Español",
fr: "Français",
it: "Italiano",
da: "Dansk",
ja: "日本語",
pl: "Polski",
ru: "Русский",
ar: "العربية",
no: "Norsk",
br: "Português (Brasil)",
th: "ไทย",
tr: "Türkçe",
} satisfies Record<Locale, string>
const TAG = {
en: "en",
zh: "zh-Hans",
zht: "zh-Hant",
ko: "ko",
de: "de",
es: "es",
fr: "fr",
it: "it",
da: "da",
ja: "ja",
pl: "pl",
ru: "ru",
ar: "ar",
no: "no",
br: "pt-BR",
th: "th",
tr: "tr",
} satisfies Record<Locale, string>
export function parseLocale(value: unknown): Locale | null {
if (typeof value !== "string") return null
if ((LOCALES as readonly string[]).includes(value)) return value as Locale
return null
}
export function fromPathname(pathname: string) {
return parseLocale(fix(pathname).split("/")[1])
}
export function strip(pathname: string) {
const locale = fromPathname(pathname)
if (!locale) return fix(pathname)
const next = fix(pathname).slice(locale.length + 1)
if (!next) return "/"
if (next.startsWith("/")) return next
return `/${next}`
}
export function route(locale: Locale, pathname: string) {
const next = strip(pathname)
if (next.startsWith("/docs")) return next
if (next.startsWith("/auth")) return next
if (next.startsWith("/workspace")) return next
if (locale === "en") return next
if (next === "/") return `/${locale}`
return `/${locale}${next}`
}
export function label(locale: Locale) {
return LABEL[locale]
}
export function tag(locale: Locale) {
return TAG[locale]
}
export function dir(locale: Locale) {
if (locale === "ar") return "rtl"
return "ltr"
}
function match(input: string): Locale | null {
const value = input.trim().toLowerCase()
if (!value) return null
if (value.startsWith("zh")) {
if (value.includes("hant") || value.includes("-tw") || value.includes("-hk") || value.includes("-mo")) return "zht"
return "zh"
}
if (value.startsWith("ko")) return "ko"
if (value.startsWith("de")) return "de"
if (value.startsWith("es")) return "es"
if (value.startsWith("fr")) return "fr"
if (value.startsWith("it")) return "it"
if (value.startsWith("da")) return "da"
if (value.startsWith("ja")) return "ja"
if (value.startsWith("pl")) return "pl"
if (value.startsWith("ru")) return "ru"
if (value.startsWith("ar")) return "ar"
if (value.startsWith("tr")) return "tr"
if (value.startsWith("th")) return "th"
if (value.startsWith("pt")) return "br"
if (value.startsWith("no") || value.startsWith("nb") || value.startsWith("nn")) return "no"
if (value.startsWith("en")) return "en"
return null
}
export function detectFromLanguages(languages: readonly string[]) {
for (const language of languages) {
const locale = match(language)
if (locale) return locale
}
return "en" satisfies Locale
}
export function detectFromAcceptLanguage(header: string | null) {
if (!header) return "en" satisfies Locale
const items = header
.split(",")
.map((raw) => raw.trim())
.filter(Boolean)
.map((raw) => {
const parts = raw.split(";").map((x) => x.trim())
const lang = parts[0] ?? ""
const q = parts
.slice(1)
.find((x) => x.startsWith("q="))
?.slice(2)
return {
lang,
q: q ? Number.parseFloat(q) : 1,
}
})
.sort((a, b) => b.q - a.q)
for (const item of items) {
if (!item.lang || item.lang === "*") continue
const locale = match(item.lang)
if (locale) return locale
}
return "en" satisfies Locale
}
export function localeFromCookieHeader(header: string | null) {
if (!header) return null
const raw = header
.split(";")
.map((x) => x.trim())
.find((x) => x.startsWith(`${LOCALE_COOKIE}=`))
?.slice(`${LOCALE_COOKIE}=`.length)
if (!raw) return null
return parseLocale(decodeURIComponent(raw))
}
export function localeFromRequest(request: Request) {
const fromHeader = parseLocale(request.headers.get(LOCALE_HEADER))
if (fromHeader) return fromHeader
const fromPath = fromPathname(new URL(request.url).pathname)
if (fromPath) return fromPath
return (
localeFromCookieHeader(request.headers.get("cookie")) ??
detectFromAcceptLanguage(request.headers.get("accept-language"))
)
}
export function cookie(locale: Locale) {
return `${LOCALE_COOKIE}=${encodeURIComponent(locale)}; Path=/; Max-Age=31536000; SameSite=Lax`
}
export function clearCookie() {
return `${LOCALE_COOKIE}=; Path=/; Max-Age=0; SameSite=Lax`
}