Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 15 additions & 30 deletions packages/core/src/oauth/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
// offline and drop into any transport (`res.end(...)`, Effect `response.end`,
// etc.).
//
// The visual language mirrors the OpenCode app: the design tokens are a curated
// subset of the OC-2 semantic tokens in `packages/ui/src/styles/theme.css`, and
// the wordmark is the same geometry as `packages/ui/src/components/logo.tsx`.
// The design tokens are a curated subset of the OC-2 semantic tokens in
// `packages/ui/src/styles/theme.css`; the pages are branded as DevPass Code.
// Keep this file in sync with those sources when the brand changes.

export interface CallbackPageOptions {
Expand All @@ -25,7 +24,9 @@ export function success(options?: CallbackPageOptions) {
body: renderCard({
status: "success",
headline: "Authorization successful",
message: provider ? `OpenCode is now connected to ${escapeHtml(provider)}.` : "OpenCode is now authorized.",
message: provider
? `DevPass Code is now connected to ${escapeHtml(provider)}.`
: "DevPass Code is now authorized.",
footnote: "You can close this window.",
}),
script: options?.autoClose === false ? undefined : AUTO_CLOSE_SCRIPT,
Expand All @@ -40,10 +41,10 @@ export function error(detail: string, options?: CallbackPageOptions) {
status: "error",
headline: "Authorization failed",
message: provider
? `OpenCode couldn't finish connecting to ${escapeHtml(provider)}.`
: "OpenCode couldn't complete authorization.",
? `DevPass Code couldn't finish connecting to ${escapeHtml(provider)}.`
: "DevPass Code couldn't complete authorization.",
detail,
footnote: "Close this window and try again from OpenCode.",
footnote: "Close this window and try again from DevPass Code.",
}),
})
}
Expand Down Expand Up @@ -100,7 +101,7 @@ function renderDocument(input: { title: string; body: string; script?: string })
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex" />
<title>${escapeHtml(input.title)} · OpenCode</title>
<title>${escapeHtml(input.title)} · DevPass Code</title>
<style>${STYLES}</style>
</head>
<body>
Expand All @@ -116,8 +117,8 @@ function bootstrapScript(options: BootstrapOptions) {
var TOKEN_URL=new URL(${scriptString(options.tokenPath)},window.location.origin).href;
(function(){
var card=document.getElementById("oc-card"),headline=document.getElementById("oc-headline"),message=document.getElementById("oc-message"),detail=document.getElementById("oc-detail"),footnote=document.getElementById("oc-footnote");
function fail(text){card.dataset.status="error";headline.textContent="Authorization failed";message.textContent=PROVIDER?("OpenCode couldn't finish connecting to "+PROVIDER+"."):"OpenCode couldn't complete authorization.";if(text){detail.textContent=text;detail.hidden=false}footnote.textContent="Close this window and try again from OpenCode."}
function ok(){card.dataset.status="success";headline.textContent="Authorization successful";message.textContent=PROVIDER?("OpenCode is now connected to "+PROVIDER+"."):"OpenCode is now authorized.";detail.hidden=true;footnote.textContent="You can close this window.";setTimeout(function(){try{window.close()}catch(e){}},2500)}
function fail(text){card.dataset.status="error";headline.textContent="Authorization failed";message.textContent=PROVIDER?("DevPass Code couldn't finish connecting to "+PROVIDER+"."):"DevPass Code couldn't complete authorization.";if(text){detail.textContent=text;detail.hidden=false}footnote.textContent="Close this window and try again from DevPass Code."}
function ok(){card.dataset.status="success";headline.textContent="Authorization successful";message.textContent=PROVIDER?("DevPass Code is now connected to "+PROVIDER+"."):"DevPass Code is now authorized.";detail.hidden=true;footnote.textContent="You can close this window.";setTimeout(function(){try{window.close()}catch(e){}},2500)}
try{
var hash=new URLSearchParams((window.location.hash||"").slice(1));
var search=new URLSearchParams(window.location.search||"");
Expand Down Expand Up @@ -214,7 +215,8 @@ const STYLES = `
text-align: center;
}
.brand { display: flex; justify-content: center; margin-bottom: 1.75rem; }
.brand svg { height: 19px; width: auto; }
.brand .wordmark { font-size: 1.0625rem; font-weight: 500; letter-spacing: -0.01em; color: var(--oc-text-strong); }
.brand .wordmark b { font-weight: 700; }
.status { display: flex; justify-content: center; margin-bottom: 1.125rem; }
.icon { display: none; line-height: 0; }
.icon svg { display: block; }
Expand Down Expand Up @@ -249,25 +251,8 @@ const STYLES = `
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
`

// OpenCode wordmark — same path geometry as packages/ui/src/components/logo.tsx (Logo).
const WORDMARK = `<svg class="wordmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234 42" fill="none" aria-label="OpenCode" role="img">
<path d="M18 30H6V18H18V30Z" fill="var(--oc-icon-weak)" />
<path d="M18 12H6V30H18V12ZM24 36H0V6H24V36Z" fill="var(--oc-icon-base)" />
<path d="M48 30H36V18H48V30Z" fill="var(--oc-icon-weak)" />
<path d="M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z" fill="var(--oc-icon-base)" />
<path d="M84 24V30H66V24H84Z" fill="var(--oc-icon-weak)" />
<path d="M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z" fill="var(--oc-icon-base)" />
<path d="M108 36H96V18H108V36Z" fill="var(--oc-icon-weak)" />
<path d="M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z" fill="var(--oc-icon-base)" />
<path d="M144 30H126V18H144V30Z" fill="var(--oc-icon-weak)" />
<path d="M144 12H126V30H144V36H120V6H144V12Z" fill="var(--oc-icon-strong)" />
<path d="M168 30H156V18H168V30Z" fill="var(--oc-icon-weak)" />
<path d="M168 12H156V30H168V12ZM174 36H150V6H174V36Z" fill="var(--oc-icon-strong)" />
<path d="M198 30H186V18H198V30Z" fill="var(--oc-icon-weak)" />
<path d="M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z" fill="var(--oc-icon-strong)" />
<path d="M234 24V30H216V24H234Z" fill="var(--oc-icon-weak)" />
<path d="M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z" fill="var(--oc-icon-strong)" />
</svg>`
// DevPass Code wordmark — text-based, mirrors the TUI footer brand.
const WORDMARK = `<span class="wordmark" role="img" aria-label="DevPass Code">DevPass <b>Code</b></span>`

const ICON_CHECK = `<svg viewBox="0 0 24 24" width="30" height="30" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" /><path d="m8.5 12.5 2.4 2.4 4.6-5.4" /></svg>`

Expand Down
13 changes: 11 additions & 2 deletions packages/devpass-code/src/plugin/llmgateway/llmgateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface LoopbackLogin {
wait: () => Promise<string>
}

async function startLoopbackLogin(source: string): Promise<LoopbackLogin> {
async function startLoopbackLogin(source: string, org: "default" | "devpass"): Promise<LoopbackLogin> {
let resolveKey!: (key: string) => void
let rejectKey!: (error: Error) => void
const keyPromise = new Promise<string>((resolve, reject) => {
Expand Down Expand Up @@ -90,6 +90,7 @@ async function startLoopbackLogin(source: string): Promise<LoopbackLogin> {
callback,
state,
source,
org,
name: "DevPass Code CLI",
})
const url = `${appUrl()}/connect/cli?${params.toString()}`
Expand All @@ -114,6 +115,12 @@ interface LlmGatewayPluginConfig {
providerID: string
label: string
source: string
/**
* Which LLM Gateway org the minted key lives in: "devpass" bills the DevPass
* subscription (personal org), "default" bills pay-as-you-go credits on the
* user's default dashboard org.
*/
org: "default" | "devpass"
}

export function makeLlmGatewayPlugin(config: LlmGatewayPluginConfig) {
Expand All @@ -126,7 +133,7 @@ export function makeLlmGatewayPlugin(config: LlmGatewayPluginConfig) {
type: "oauth",
label: "Log in with browser",
authorize: async () => {
const { url, wait } = await startLoopbackLogin(config.source)
const { url, wait } = await startLoopbackLogin(config.source, config.org)
open(url).catch(() => {})
return {
url,
Expand Down Expand Up @@ -163,10 +170,12 @@ export const LlmGatewayAuthPlugin = makeLlmGatewayPlugin({
providerID: "llmgateway",
label: "LLM Gateway",
source: "devpass-code",
org: "default",
})

export const LlmGatewayDevPassAuthPlugin = makeLlmGatewayPlugin({
providerID: "llmgateway-devpass",
label: "LLM Gateway DevPass",
source: "devpass-code",
org: "devpass",
})
Loading