@ai-ecoverse/slicc-agent 6.15.2 → 6.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/settings.ts"],
4
- "sourcesContent": ["import { type Context, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, ModelsStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\nimport {\n ADOBE,\n ADOBE_PROXY,\n adobeConfig,\n adobeIdentity,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nimport { abortableBedrock } from './bedrock.ts';\nimport type { McpAccounts } from './mcp/index.ts';\nimport { MCP_ACCOUNT } from './mcp/label.ts';\nimport type { Reach } from './net.ts';\nimport { BEDROCK, preferredModel } from './preferred.ts';\nimport {\n ADDED_FIRST,\n DEFAULT_REGION,\n type FieldSpec,\n KEY_PROVIDERS,\n LISTINGS,\n type Listing,\n} from './providers.ts';\nimport type { KeysMoved } from './secrets/legacy.ts';\nimport type { VaultRecords } from './secrets/records.ts';\nimport type { PlainStore } from './secrets/store.ts';\nimport type {\n AccountField,\n AccountState,\n AgentSettings,\n ModelChoice,\n ProviderOption,\n SettingsState,\n} from './services.ts';\n\nexport { BEDROCK, PREFERRED_MODELS, preferredModel } from './preferred.ts';\n\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\nexport const DEFAULT_REGIONS: Readonly<Record<string, string>> = { [BEDROCK]: DEFAULT_REGION };\n\nconst specs = (providerId: string): readonly FieldSpec[] => LISTINGS.get(providerId)?.fields ?? [];\n\nexport const ACCOUNT_FIELDS: Readonly<Record<string, readonly AccountField[]>> = Object.fromEntries(\n [...LISTINGS.keys()]\n .filter((id) => specs(id).length)\n .map((id) => [id, specs(id).map(({ env: _env, ...field }) => field)])\n);\nexport const SIGN_IN_NEEDS_VAULT = \"Adobe sign-in needs seven's vault: update seven\";\nexport const KEY_NEEDS_VAULT = \"API keys are kept in seven's vault: update seven\";\n\nexport async function resolveDefaultModel(\n credentials: CredentialStore,\n providers: Provider[],\n models: MutableModels\n): Promise<{ provider: string; modelId: string }> {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n for (const provider of providers) {\n if (!stored.has(provider.id)) continue;\n if (!models.getModels(provider.id).length && provider.refreshModels) {\n await models.refresh({ providers: [provider.id] }).catch(() => undefined);\n }\n const chosen = preferredModel(provider.id, models.getModels(provider.id));\n if (chosen) return { provider: provider.id, modelId: chosen.id };\n }\n return DEFAULT_MODEL;\n}\n\nconst signIn = new Set([ADOBE]);\nconst BUDGET_EVERY = 5 * 60 * 1000;\n\nexport function sliccProviders(version?: string): Provider[] {\n return [\n amazonBedrockProvider() as Provider,\n adobeProvider({ version }),\n ...KEY_PROVIDERS.map((entry) => entry.make()),\n ];\n}\n\nexport function withDefaultRegions(credentials: CredentialStore): CredentialStore {\n return {\n async read(providerId, options) {\n const credential = await credentials.read(providerId, options);\n const region = DEFAULT_REGIONS[providerId];\n if (credential?.type !== 'api_key' || !region || credential.env?.AWS_REGION) {\n return credential;\n }\n return { ...credential, env: { ...credential.env, AWS_REGION: region } };\n },\n list: (options) => credentials.list(options),\n modify: (providerId, fn, options) => credentials.modify(providerId, fn, options),\n delete: (providerId, options) => credentials.delete(providerId, options),\n };\n}\n\nexport function catalogStore(store: PlainStore): ModelsStore {\n return {\n read: async (providerId) =>\n ((await store.get(providerId)) as Awaited<ReturnType<ModelsStore['read']>>) ?? undefined,\n write: (providerId, entry) => store.set(providerId, entry),\n delete: (providerId) => store.set(providerId, undefined),\n };\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders(),\n catalog?: ModelsStore\n): MutableModels {\n const models = createModels({\n credentials: withDefaultRegions(credentials),\n ...(catalog ? { modelsStore: catalog } : {}),\n });\n for (const provider of providers) models.setProvider(abortableBedrock(provider));\n return models;\n}\n\nconst SHORT: Record<string, string> = { [BEDROCK]: 'Bedrock', [ADOBE]: 'Adobe' };\n\nfunction labels(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): Record<string, string> {\n return Object.fromEntries(\n providers\n .filter((provider) => !stored.has(provider.id))\n .flatMap((provider) =>\n models\n .getModels(provider.id)\n .map((model) => [\n `${provider.id}/${model.id}`,\n `${model.name} on ${SHORT[provider.id] ?? provider.name ?? provider.id}`,\n ])\n )\n );\n}\n\nfunction choices(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): ModelChoice[] {\n return providers\n .filter((provider) => stored.has(provider.id))\n .flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n images: model.input.includes('image'),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nfunction listed(\n records: Pick<VaultRecords, 'model'>,\n fields: Pick<ProviderFields, 'get' | 'added'>\n): (providerId: string) => boolean {\n const added = new Set(fields.added() ?? ADDED_FIRST);\n return (providerId) =>\n !LISTINGS.has(providerId) ||\n added.has(providerId) ||\n records.model(providerId) !== undefined ||\n fields.get(providerId) !== undefined;\n}\n\nfunction filled(\n fields: readonly AccountField[],\n stored: Readonly<Record<string, string>> | undefined\n): AccountField[] {\n return fields.map((field) => {\n const value = stored?.[field.name]?.trim() || field.value;\n const options =\n field.options && value && !field.options.some((option) => option.value === value)\n ? [{ value, label: value }, ...field.options]\n : field.options;\n return { ...field, ...(options ? { options: [...options] } : {}), ...(value ? { value } : {}) };\n });\n}\n\nfunction accounts(\n records: Pick<VaultRecords, 'model'>,\n providers: Provider[],\n given: Pick<ProviderFields, 'ready' | 'get'>,\n blocked: (providerId: string) => boolean\n): AccountState[] {\n return providers.map((provider) => {\n const record = given.ready(provider.id) ? records.model(provider.id) : undefined;\n const fields = ACCOUNT_FIELDS[provider.id];\n const listing = LISTINGS.get(provider.id);\n return {\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: record ? (signIn.has(provider.id) ? 'Adobe ID' : 'API key') : '',\n status: !record ? 'disconnected' : record.state === 'expired' ? 'expired' : 'connected',\n auth: signIn.has(provider.id) ? 'oauth' : 'api-key',\n needs: listing?.corsFree ? 'cors-free-transport' : null,\n ...(blocked(provider.id) ? { blocked: 'cors-free-transport' as const } : {}),\n group: 'providers',\n store: 'vault',\n ...(fields ? { fields: filled(fields, given.get(provider.id)) } : {}),\n ...about(listing),\n };\n });\n}\n\nfunction about(listing: Listing | undefined) {\n if (!listing) return {};\n return {\n description: listing.description,\n vaultName: listing.vaultName,\n ...(listing.keyUrl ? { keyUrl: listing.keyUrl } : {}),\n };\n}\n\nfunction offered(\n providers: Provider[],\n blocked: (providerId: string) => boolean\n): ProviderOption[] {\n return providers\n .flatMap((provider): ProviderOption[] => {\n const listing = LISTINGS.get(provider.id);\n if (!listing) return [];\n const fields = ACCOUNT_FIELDS[provider.id];\n return [\n {\n id: provider.id,\n name: provider.name,\n description: listing.description,\n auth: listing.auth,\n vaultName: listing.vaultName,\n ...(fields ? { fields: filled(fields, undefined) } : {}),\n ...(listing.keyUrl ? { keyUrl: listing.keyUrl } : {}),\n ...(listing.corsFree ? { needs: 'cors-free-transport' as const } : {}),\n ...(blocked(provider.id) ? { blocked: 'cors-free-transport' as const } : {}),\n },\n ];\n })\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport interface ProviderFields {\n get(providerId: string): Readonly<Record<string, string>> | undefined;\n env(providerId: string): Readonly<Record<string, string>> | undefined;\n set(providerId: string, fields: Record<string, string> | undefined): Promise<void>;\n ready(providerId: string): boolean;\n added(): readonly string[] | undefined;\n add(providerId: string): Promise<void>;\n forget(providerId: string): Promise<void>;\n}\n\nconst ADDED = 'providers';\n\nexport async function providerFields(\n store: PlainStore,\n providers: readonly Provider[]\n): Promise<ProviderFields> {\n const known = new Map<string, Record<string, string>>();\n for (const provider of providers) {\n const saved = (await store.get(`model:${provider.id}`)) as Record<string, string> | undefined;\n if (saved && typeof saved === 'object') known.set(provider.id, saved);\n }\n const saved = await store.get(ADDED);\n let added = Array.isArray(saved)\n ? saved.filter((id): id is string => typeof id === 'string')\n : undefined;\n const keep = async (next: string[]) => {\n added = next;\n await store.set(ADDED, next);\n };\n return {\n ready: (providerId) =>\n specs(providerId).every((spec) => {\n const value = known.get(providerId)?.[spec.name];\n if (value === undefined) return !spec.required;\n return typeof spec.env(value.trim()) !== 'string';\n }),\n added: () => added,\n async add(providerId) {\n const now = added ?? ADDED_FIRST;\n if (added && now.includes(providerId)) return;\n await keep([...new Set([...now, providerId])]);\n },\n async forget(providerId) {\n await keep((added ?? ADDED_FIRST).filter((id) => id !== providerId));\n known.delete(providerId);\n await store.set(`model:${providerId}`, undefined);\n },\n get: (providerId) => known.get(providerId),\n env(providerId) {\n const fields = known.get(providerId);\n if (!fields) return undefined;\n return Object.assign(\n {},\n ...specs(providerId).flatMap((spec) => {\n const value = fields[spec.name];\n const env = value === undefined ? '' : spec.env(value.trim());\n return typeof env === 'string' ? [] : [env];\n })\n );\n },\n async set(providerId, fields) {\n const kept: Record<string, string> = {};\n for (const spec of specs(providerId)) {\n const given = fields?.[spec.name];\n const value = typeof given === 'string' ? given.trim() : '';\n const stored = known.get(providerId)?.[spec.name];\n if (!value && spec.required && fields && stored) kept[spec.name] = stored;\n else if (!value && spec.required && fields)\n throw new Error(`${spec.label} can\u2019t be empty.`);\n else if (value) {\n const problem = spec.env(value);\n if (typeof problem === 'string') throw new Error(problem);\n kept[spec.name] = value;\n }\n }\n const next = Object.keys(kept).length ? kept : undefined;\n if (next) known.set(providerId, next);\n else known.delete(providerId);\n await store.set(`model:${providerId}`, next);\n },\n };\n}\n\nexport type UsageReader = (token: string) => Promise<Budget | null>;\n\nasync function budget(records: Pick<VaultRecords, 'model'>, usage: UsageReader) {\n const key = records.model(ADOBE)?.placeholder;\n const found = key ? await usage(key).catch(() => null) : null;\n return found ? { provider: ADOBE, ...found } : null;\n}\n\nexport interface SettingsSources {\n records: VaultRecords;\n fields: ProviderFields;\n}\n\nfunction blockedBy(reach: Reach | undefined): (providerId: string) => boolean {\n return (providerId) => Boolean(LISTINGS.get(providerId)?.corsFree) && reach?.free() === false;\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n sources: SettingsSources,\n providers = sliccProviders(),\n options: {\n usage?: UsageReader;\n every?: number;\n mcp?: McpAccounts;\n moved?: KeysMoved;\n reach?: Reach;\n } = {}\n): Promise<AgentSettings> {\n const { mcp, moved, reach } = options;\n const blocked = blockedBy(reach);\n const { records, fields } = sources;\n const routed = (providerId: string) => (providerId.startsWith(MCP_ACCOUNT) ? mcp : undefined);\n const adobe = providers.find((provider) => provider.id === ADOBE);\n const endpoint = adobe?.baseUrl ?? ADOBE_PROXY;\n const identity = (adobe?.headers as Record<string, string> | undefined) ?? adobeIdentity();\n const usage = options.usage ?? ((token: string) => adobeUsage(token, { endpoint, identity }));\n const snapshot = async (): Promise<SettingsState> => {\n const stored = new Set(\n providers\n .filter((provider) => records.model(provider.id) && fields.ready(provider.id))\n .map((provider) => provider.id)\n );\n const show = listed(records, fields);\n const shown = providers.filter((provider) => show(provider.id));\n const open = (list: Provider[]) => list.filter((provider) => !blocked(provider.id));\n return {\n models: choices(models, open(providers), stored),\n labels: labels(models, open(shown), stored),\n accounts: [...accounts(records, shown, fields, blocked), ...((await mcp?.accounts()) ?? [])],\n providers: offered(providers, blocked),\n budget: await budget(records, usage),\n ...(moved?.state.value?.length\n ? { moved: moved.state.value.map((name) => ({ ...name })) }\n : {}),\n };\n };\n const state = replicatedState<SettingsState>(await snapshot());\n let latest = Promise.resolve();\n const refresh = (context: Context) => {\n const next = latest.then(async () => state.replace(context, await snapshot()));\n latest = next.catch(() => undefined);\n return next;\n };\n const signedIn = providers\n .filter((provider) => signIn.has(provider.id))\n .map((provider) => provider.id);\n const discover = (ids: string[]) =>\n models.refresh({ providers: ids }).then(\n () => undefined,\n () => undefined\n );\n if (signedIn.length) {\n const cycle = () =>\n void discover(signedIn)\n .then(() => refresh(BACKGROUND_CONTEXT))\n .catch(() => undefined);\n cycle();\n const timer: unknown = setInterval(cycle, options.every ?? BUDGET_EVERY);\n (timer as { unref?: () => void }).unref?.();\n }\n mcp?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n reach?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n moved?.state.subscribe((_value, context) => void refresh(context).catch(() => undefined));\n const held = () => signedIn.filter((id) => records.model(id)).join(' ');\n let seen = held();\n records.state.subscribe(() => {\n const now = held();\n const added = now !== seen;\n seen = now;\n const discovered = added ? discover(signedIn) : Promise.resolve();\n void discovered.then(() => refresh(BACKGROUND_CONTEXT)).catch(() => undefined);\n });\n const reread = (context: Context) => records.refresh(context).catch(() => undefined);\n return {\n state,\n async connect(providerId, secret, given, context) {\n const server = routed(providerId);\n if (server) {\n await server.connect(providerId, secret);\n await refresh(context);\n return;\n }\n if (secret !== null)\n throw new Error(signIn.has(providerId) ? SIGN_IN_NEEDS_VAULT : KEY_NEEDS_VAULT);\n if (given !== null) await fields.set(providerId, given);\n if (LISTINGS.has(providerId)) await fields.add(providerId);\n records.reconnected(providerId);\n await reread(context);\n if (signIn.has(providerId)) await discover([providerId]);\n await refresh(context);\n },\n async signIn(providerId) {\n const server = routed(providerId);\n if (server) return server.signIn(providerId);\n if (providerId !== ADOBE) return null;\n const { clientId, scopes, imsEnvironment } = await adobeConfig(\n endpoint,\n (input, init) => globalThis.fetch(input, init),\n identity\n );\n return { clientId, scopes, imsEnvironment: imsEnvironment || 'prod' };\n },\n async dismissMoved(context) {\n await moved?.dismiss(context);\n await refresh(context);\n },\n async disconnect(providerId, context) {\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else if (LISTINGS.has(providerId)) await fields.add(providerId);\n else await fields.set(providerId, undefined);\n await reread(context);\n await refresh(context);\n },\n async serverUrl(providerId) {\n return (await routed(providerId)?.serverUrl(providerId)) ?? null;\n },\n async remove(providerId, context) {\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else await fields.forget(providerId);\n await reread(context);\n await refresh(context);\n },\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { type Context, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, ModelsStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\nimport {\n ADOBE,\n ADOBE_PROXY,\n adobeConfig,\n adobeIdentity,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nimport { abortableBedrock } from './bedrock.ts';\nimport { codexProvider } from './codex.ts';\nimport { type DeviceFlows, deviceFlows } from './device.ts';\nimport type { McpAccounts } from './mcp/index.ts';\nimport { MCP_ACCOUNT } from './mcp/label.ts';\nimport type { Reach } from './net.ts';\nimport { BEDROCK, preferredModel } from './preferred.ts';\nimport {\n ADDED_FIRST,\n DEFAULT_REGION,\n type FieldSpec,\n KEY_PROVIDERS,\n LISTINGS,\n type Listing,\n} from './providers.ts';\nimport { absent } from './secrets/fetch.ts';\nimport type { KeysMoved } from './secrets/legacy.ts';\nimport type { VaultRecords } from './secrets/records.ts';\nimport type { PlainStore } from './secrets/store.ts';\nimport type { Vault } from './secrets/vault.ts';\nimport type {\n AccountField,\n AccountState,\n AgentSettings,\n ModelChoice,\n ProviderOption,\n SettingsState,\n} from './services.ts';\nimport { DEVICE_NEEDS_VAULT, DEVICE_SIGN_INS } from './sign-ins.ts';\n\nexport { BEDROCK, PREFERRED_MODELS, preferredModel } from './preferred.ts';\n\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\nexport const DEFAULT_REGIONS: Readonly<Record<string, string>> = { [BEDROCK]: DEFAULT_REGION };\n\nconst specs = (providerId: string): readonly FieldSpec[] => LISTINGS.get(providerId)?.fields ?? [];\n\nexport const ACCOUNT_FIELDS: Readonly<Record<string, readonly AccountField[]>> = Object.fromEntries(\n [...LISTINGS.keys()]\n .filter((id) => specs(id).length)\n .map((id) => [id, specs(id).map(({ env: _env, ...field }) => field)])\n);\nexport const SIGN_IN_NEEDS_VAULT = \"Adobe sign-in needs seven's vault: update seven\";\nexport const KEY_NEEDS_VAULT = \"API keys are kept in seven's vault: update seven\";\n\nexport async function resolveDefaultModel(\n credentials: CredentialStore,\n providers: Provider[],\n models: MutableModels\n): Promise<{ provider: string; modelId: string }> {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n for (const provider of providers) {\n if (!stored.has(provider.id)) continue;\n if (!models.getModels(provider.id).length && provider.refreshModels) {\n await models.refresh({ providers: [provider.id] }).catch(() => undefined);\n }\n const chosen = preferredModel(provider.id, models.getModels(provider.id));\n if (chosen) return { provider: provider.id, modelId: chosen.id };\n }\n return DEFAULT_MODEL;\n}\n\nconst signIn = new Set([ADOBE]);\nconst oauth = (providerId: string) => signIn.has(providerId) || DEVICE_SIGN_INS.has(providerId);\nconst SIGN_IN_CORS_FREE = new Set(['xai']);\nconst BUDGET_EVERY = 5 * 60 * 1000;\n\nexport function sliccProviders(version?: string): Provider[] {\n return [\n amazonBedrockProvider() as Provider,\n adobeProvider({ version }),\n ...KEY_PROVIDERS.map((entry) => entry.make()),\n codexProvider(),\n ];\n}\n\nexport function withDefaultRegions(credentials: CredentialStore): CredentialStore {\n return {\n async read(providerId, options) {\n const credential = await credentials.read(providerId, options);\n const region = DEFAULT_REGIONS[providerId];\n if (credential?.type !== 'api_key' || !region || credential.env?.AWS_REGION) {\n return credential;\n }\n return { ...credential, env: { ...credential.env, AWS_REGION: region } };\n },\n list: (options) => credentials.list(options),\n modify: (providerId, fn, options) => credentials.modify(providerId, fn, options),\n delete: (providerId, options) => credentials.delete(providerId, options),\n };\n}\n\nexport function catalogStore(store: PlainStore): ModelsStore {\n return {\n read: async (providerId) =>\n ((await store.get(providerId)) as Awaited<ReturnType<ModelsStore['read']>>) ?? undefined,\n write: (providerId, entry) => store.set(providerId, entry),\n delete: (providerId) => store.set(providerId, undefined),\n };\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders(),\n catalog?: ModelsStore\n): MutableModels {\n const models = createModels({\n credentials: withDefaultRegions(credentials),\n ...(catalog ? { modelsStore: catalog } : {}),\n });\n for (const provider of providers) models.setProvider(abortableBedrock(provider));\n return models;\n}\n\nconst SHORT: Record<string, string> = { [BEDROCK]: 'Bedrock', [ADOBE]: 'Adobe' };\n\nfunction labels(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): Record<string, string> {\n return Object.fromEntries(\n providers\n .filter((provider) => !stored.has(provider.id))\n .flatMap((provider) =>\n models\n .getModels(provider.id)\n .map((model) => [\n `${provider.id}/${model.id}`,\n `${model.name} on ${SHORT[provider.id] ?? provider.name ?? provider.id}`,\n ])\n )\n );\n}\n\nfunction choices(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): ModelChoice[] {\n return providers\n .filter((provider) => stored.has(provider.id))\n .flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n images: model.input.includes('image'),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nfunction listed(\n records: Pick<VaultRecords, 'model'>,\n fields: Pick<ProviderFields, 'get' | 'added'>\n): (providerId: string) => boolean {\n const added = new Set(fields.added() ?? ADDED_FIRST);\n return (providerId) =>\n !LISTINGS.has(providerId) ||\n added.has(providerId) ||\n records.model(providerId) !== undefined ||\n fields.get(providerId) !== undefined;\n}\n\nfunction filled(\n fields: readonly AccountField[],\n stored: Readonly<Record<string, string>> | undefined\n): AccountField[] {\n return fields.map((field) => {\n const value = stored?.[field.name]?.trim() || field.value;\n const options =\n field.options && value && !field.options.some((option) => option.value === value)\n ? [{ value, label: value }, ...field.options]\n : field.options;\n return { ...field, ...(options ? { options: [...options] } : {}), ...(value ? { value } : {}) };\n });\n}\n\nfunction accounts(\n records: Pick<VaultRecords, 'model'>,\n providers: Provider[],\n given: Pick<ProviderFields, 'ready' | 'get'>,\n blocked: (providerId: string) => boolean\n): AccountState[] {\n return providers.map((provider) => {\n const record = given.ready(provider.id) ? records.model(provider.id) : undefined;\n const fields = ACCOUNT_FIELDS[provider.id];\n const listing = LISTINGS.get(provider.id);\n return {\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: record ? identityOf(provider.id, record) : '',\n status: !record ? 'disconnected' : record.state === 'expired' ? 'expired' : 'connected',\n auth: oauth(provider.id) ? 'oauth' : 'api-key',\n ...(DEVICE_SIGN_INS.has(provider.id) && listing?.keyUrl\n ? { secret: 'api-key' as const }\n : {}),\n needs: listing?.corsFree ? 'cors-free-transport' : null,\n ...(blocked(provider.id) ? { blocked: 'cors-free-transport' as const } : {}),\n group: 'providers',\n store: 'vault',\n ...(fields ? { fields: filled(fields, given.get(provider.id)) } : {}),\n ...about(listing),\n };\n });\n}\n\nfunction identityOf(providerId: string, record: { expiresAt?: number }): string {\n if (signIn.has(providerId)) return 'Adobe ID';\n return DEVICE_SIGN_INS.has(providerId) && record.expiresAt !== undefined\n ? 'Signed in'\n : 'API key';\n}\n\nfunction about(listing: Listing | undefined) {\n if (!listing) return {};\n return {\n description: listing.description,\n vaultName: listing.vaultName,\n ...(listing.keyUrl ? { keyUrl: listing.keyUrl } : {}),\n };\n}\n\nfunction offered(\n providers: Provider[],\n blocked: (providerId: string) => boolean\n): ProviderOption[] {\n return providers\n .flatMap((provider): ProviderOption[] => {\n const listing = LISTINGS.get(provider.id);\n if (!listing) return [];\n const fields = ACCOUNT_FIELDS[provider.id];\n return [\n {\n id: provider.id,\n name: provider.name,\n description: listing.description,\n auth: listing.auth,\n vaultName: listing.vaultName,\n ...(fields ? { fields: filled(fields, undefined) } : {}),\n ...(listing.keyUrl ? { keyUrl: listing.keyUrl } : {}),\n ...(listing.corsFree ? { needs: 'cors-free-transport' as const } : {}),\n ...(blocked(provider.id) ? { blocked: 'cors-free-transport' as const } : {}),\n },\n ];\n })\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport interface ProviderFields {\n get(providerId: string): Readonly<Record<string, string>> | undefined;\n env(providerId: string): Readonly<Record<string, string>> | undefined;\n set(providerId: string, fields: Record<string, string> | undefined): Promise<void>;\n ready(providerId: string): boolean;\n added(): readonly string[] | undefined;\n add(providerId: string): Promise<void>;\n forget(providerId: string): Promise<void>;\n}\n\nconst ADDED = 'providers';\n\nexport async function providerFields(\n store: PlainStore,\n providers: readonly Provider[]\n): Promise<ProviderFields> {\n const known = new Map<string, Record<string, string>>();\n for (const provider of providers) {\n const saved = (await store.get(`model:${provider.id}`)) as Record<string, string> | undefined;\n if (saved && typeof saved === 'object') known.set(provider.id, saved);\n }\n const saved = await store.get(ADDED);\n let added = Array.isArray(saved)\n ? saved.filter((id): id is string => typeof id === 'string')\n : undefined;\n const keep = async (next: string[]) => {\n added = next;\n await store.set(ADDED, next);\n };\n return {\n ready: (providerId) =>\n specs(providerId).every((spec) => {\n const value = known.get(providerId)?.[spec.name];\n if (value === undefined) return !spec.required;\n return typeof spec.env(value.trim()) !== 'string';\n }),\n added: () => added,\n async add(providerId) {\n const now = added ?? ADDED_FIRST;\n if (added && now.includes(providerId)) return;\n await keep([...new Set([...now, providerId])]);\n },\n async forget(providerId) {\n await keep((added ?? ADDED_FIRST).filter((id) => id !== providerId));\n known.delete(providerId);\n await store.set(`model:${providerId}`, undefined);\n },\n get: (providerId) => known.get(providerId),\n env(providerId) {\n const fields = known.get(providerId);\n if (!fields) return undefined;\n return Object.assign(\n {},\n ...specs(providerId).flatMap((spec) => {\n const value = fields[spec.name];\n const env = value === undefined ? '' : spec.env(value.trim());\n return typeof env === 'string' ? [] : [env];\n })\n );\n },\n async set(providerId, fields) {\n const kept: Record<string, string> = {};\n for (const spec of specs(providerId)) {\n const given = fields?.[spec.name];\n const value = typeof given === 'string' ? given.trim() : '';\n const stored = known.get(providerId)?.[spec.name];\n if (!value && spec.required && fields && stored) kept[spec.name] = stored;\n else if (!value && spec.required && fields)\n throw new Error(`${spec.label} can\u2019t be empty.`);\n else if (value) {\n const problem = spec.env(value);\n if (typeof problem === 'string') throw new Error(problem);\n kept[spec.name] = value;\n }\n }\n const next = Object.keys(kept).length ? kept : undefined;\n if (next) known.set(providerId, next);\n else known.delete(providerId);\n await store.set(`model:${providerId}`, next);\n },\n };\n}\n\nexport type UsageReader = (token: string) => Promise<Budget | null>;\n\nasync function budget(records: Pick<VaultRecords, 'model'>, usage: UsageReader) {\n const key = records.model(ADOBE)?.placeholder;\n const found = key ? await usage(key).catch(() => null) : null;\n return found ? { provider: ADOBE, ...found } : null;\n}\n\nexport interface SettingsSources {\n records: VaultRecords;\n fields: ProviderFields;\n}\n\nfunction blockedBy(reach: Reach | undefined): (providerId: string) => boolean {\n return (providerId) => Boolean(LISTINGS.get(providerId)?.corsFree) && reach?.free() === false;\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n sources: SettingsSources,\n providers = sliccProviders(),\n options: {\n usage?: UsageReader;\n every?: number;\n mcp?: McpAccounts;\n moved?: KeysMoved;\n reach?: Reach;\n vault?: Pick<Vault, 'connected' | 'needed' | 'grantProvider'>;\n flows?: DeviceFlows;\n } = {}\n): Promise<AgentSettings> {\n const { mcp, moved, reach, vault } = options;\n const blocked = blockedBy(reach);\n const flows =\n options.flows ??\n deviceFlows((grant) => (vault as Pick<Vault, 'grantProvider'>).grantProvider(grant));\n const device = (providerId: string, context: Context) => {\n const provider = providers.find((candidate) => candidate.id === providerId);\n const name = LISTINGS.get(providerId)?.vaultName;\n if (!provider || !name) return Promise.resolve(null);\n if (!vault || absent(vault)) return Promise.reject(new Error(DEVICE_NEEDS_VAULT));\n if (blocked(providerId) || (SIGN_IN_CORS_FREE.has(providerId) && reach?.free() === false))\n return Promise.reject(new Error(`${provider.name} sign-in needs the cors-free transport.`));\n return fields\n .add(providerId)\n .then(() => refresh(context))\n .then(() => flows.start(provider, name, context));\n };\n const { records, fields } = sources;\n const routed = (providerId: string) => (providerId.startsWith(MCP_ACCOUNT) ? mcp : undefined);\n const adobe = providers.find((provider) => provider.id === ADOBE);\n const endpoint = adobe?.baseUrl ?? ADOBE_PROXY;\n const identity = (adobe?.headers as Record<string, string> | undefined) ?? adobeIdentity();\n const usage = options.usage ?? ((token: string) => adobeUsage(token, { endpoint, identity }));\n const snapshot = async (): Promise<SettingsState> => {\n const stored = new Set(\n providers\n .filter((provider) => records.model(provider.id) && fields.ready(provider.id))\n .map((provider) => provider.id)\n );\n const show = listed(records, fields);\n const shown = providers.filter((provider) => show(provider.id));\n const open = (list: Provider[]) => list.filter((provider) => !blocked(provider.id));\n return {\n models: choices(models, open(providers), stored),\n labels: labels(models, open(shown), stored),\n accounts: [...accounts(records, shown, fields, blocked), ...((await mcp?.accounts()) ?? [])],\n providers: offered(providers, blocked),\n budget: await budget(records, usage),\n ...(moved?.state.value?.length\n ? { moved: moved.state.value.map((name) => ({ ...name })) }\n : {}),\n };\n };\n const state = replicatedState<SettingsState>(await snapshot());\n let latest = Promise.resolve();\n const refresh = (context: Context) => {\n const next = latest.then(async () => state.replace(context, await snapshot()));\n latest = next.catch(() => undefined);\n return next;\n };\n const signedIn = providers\n .filter((provider) => signIn.has(provider.id))\n .map((provider) => provider.id);\n const discover = (ids: string[]) =>\n models.refresh({ providers: ids }).then(\n () => undefined,\n () => undefined\n );\n if (signedIn.length) {\n const cycle = () =>\n void discover(signedIn)\n .then(() => refresh(BACKGROUND_CONTEXT))\n .catch(() => undefined);\n cycle();\n const timer: unknown = setInterval(cycle, options.every ?? BUDGET_EVERY);\n (timer as { unref?: () => void }).unref?.();\n }\n mcp?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n reach?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n moved?.state.subscribe((_value, context) => void refresh(context).catch(() => undefined));\n const held = () => signedIn.filter((id) => records.model(id)).join(' ');\n let seen = held();\n records.state.subscribe(() => {\n const now = held();\n const added = now !== seen;\n seen = now;\n const discovered = added ? discover(signedIn) : Promise.resolve();\n void discovered.then(() => refresh(BACKGROUND_CONTEXT)).catch(() => undefined);\n });\n const reread = (context: Context) => records.refresh(context).catch(() => undefined);\n return {\n state,\n async connect(providerId, secret, given, context) {\n const server = routed(providerId);\n if (server) {\n await server.connect(providerId, secret);\n await refresh(context);\n return;\n }\n if (secret !== null)\n throw new Error(signIn.has(providerId) ? SIGN_IN_NEEDS_VAULT : KEY_NEEDS_VAULT);\n if (flows.has(providerId)) await flows.finish(providerId, context);\n if (given !== null) await fields.set(providerId, given);\n if (LISTINGS.has(providerId)) await fields.add(providerId);\n records.reconnected(providerId);\n await reread(context);\n if (signIn.has(providerId)) await discover([providerId]);\n await refresh(context);\n },\n async signIn(providerId, context) {\n const server = routed(providerId);\n if (server) return server.signIn(providerId);\n if (DEVICE_SIGN_INS.has(providerId)) return device(providerId, context);\n if (providerId !== ADOBE) return null;\n const { clientId, scopes, imsEnvironment } = await adobeConfig(\n endpoint,\n (input, init) => globalThis.fetch(input, init),\n identity\n );\n return { clientId, scopes, imsEnvironment: imsEnvironment || 'prod' };\n },\n async dismissMoved(context) {\n await moved?.dismiss(context);\n await refresh(context);\n },\n async disconnect(providerId, context) {\n flows.stop(providerId);\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else if (LISTINGS.has(providerId)) await fields.add(providerId);\n else await fields.set(providerId, undefined);\n await reread(context);\n await refresh(context);\n },\n async serverUrl(providerId) {\n return (await routed(providerId)?.serverUrl(providerId)) ?? null;\n },\n async remove(providerId, context) {\n flows.stop(providerId);\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else await fields.forget(providerId);\n await reread(context);\n await refresh(context);\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["BEDROCK", "preferredModel", "saved"]
7
7
  }
@@ -0,0 +1,25 @@
1
+ const CODEX = "openai-codex";
2
+ const CODEX_ACCOUNT = "CHATGPT_ACCOUNT_ID";
3
+ const DEVICE_SIGN_INS = /* @__PURE__ */ new Set(["xai", "kimi-coding", CODEX]);
4
+ const SIGN_IN_REFUSED = "The sign-in was refused.";
5
+ const SIGN_IN_UNFINISHED = "The sign-in didn't finish. Try again.";
6
+ const NAME_TAKEN = "This name holds another provider's key.";
7
+ const SIGN_IN_LOCKED = "Unlock the vault to sign in.";
8
+ const SIGN_IN_UNKEPT = "The vault didn't keep the sign-in. Try again.";
9
+ const DEVICE_NEEDS_VAULT = "Signing in needs seven's vault: update seven";
10
+ function httpsUrl(value) {
11
+ return typeof value === "string" && URL.parse(value)?.protocol === "https:";
12
+ }
13
+ export {
14
+ CODEX,
15
+ CODEX_ACCOUNT,
16
+ DEVICE_NEEDS_VAULT,
17
+ DEVICE_SIGN_INS,
18
+ NAME_TAKEN,
19
+ SIGN_IN_LOCKED,
20
+ SIGN_IN_REFUSED,
21
+ SIGN_IN_UNFINISHED,
22
+ SIGN_IN_UNKEPT,
23
+ httpsUrl
24
+ };
25
+ //# sourceMappingURL=sign-ins.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/sign-ins.ts"],
4
+ "sourcesContent": ["export const CODEX = 'openai-codex';\nexport const CODEX_ACCOUNT = 'CHATGPT_ACCOUNT_ID';\n\nexport const DEVICE_SIGN_INS: ReadonlySet<string> = new Set(['xai', 'kimi-coding', CODEX]);\n\nexport const SIGN_IN_REFUSED = 'The sign-in was refused.';\nexport const SIGN_IN_UNFINISHED = \"The sign-in didn't finish. Try again.\";\nexport const NAME_TAKEN = \"This name holds another provider's key.\";\nexport const SIGN_IN_LOCKED = 'Unlock the vault to sign in.';\nexport const SIGN_IN_UNKEPT = \"The vault didn't keep the sign-in. Try again.\";\nexport const DEVICE_NEEDS_VAULT = \"Signing in needs seven's vault: update seven\";\n\nexport interface DeviceSignIn {\n url: string;\n code?: string;\n}\n\nexport interface ConnectOptions {\n method?: 'sign-in' | 'key';\n}\n\nexport function httpsUrl(value: unknown): value is string {\n return typeof value === 'string' && URL.parse(value)?.protocol === 'https:';\n}\n"],
5
+ "mappings": "AAAO,MAAM,QAAQ;AACd,MAAM,gBAAgB;AAEtB,MAAM,kBAAuC,oBAAI,IAAI,CAAC,OAAO,eAAe,KAAK,CAAC;AAElF,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,aAAa;AACnB,MAAM,iBAAiB;AACvB,MAAM,iBAAiB;AACvB,MAAM,qBAAqB;AAW3B,SAAS,SAAS,OAAiC;AACxD,SAAO,OAAO,UAAU,YAAY,IAAI,MAAM,KAAK,GAAG,aAAa;AACrE;",
6
+ "names": []
7
+ }
@@ -75,6 +75,7 @@ export {
75
75
  MCP_NAME_KEY,
76
76
  SIGN_IN_TIMEOUT_MS,
77
77
  mcpLogin,
78
- safeAuthorizationUrl
78
+ safeAuthorizationUrl,
79
+ untilAborted
79
80
  };
80
81
  //# sourceMappingURL=mcp-login.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/spectrum/mcp-login.ts"],
4
- "sourcesContent": ["import type { McpSignIn, SignIn } from '../services.ts';\n\nexport const MCP_CHANNEL = 'slicc-mcp-oauth';\nexport const MCP_NAME_KEY = 'slicc-mcp-oauth:';\nexport const SIGN_IN_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface Popup {\n location: { href: string };\n close(): void;\n}\n\nexport interface Channel {\n onmessage: ((event: { data: unknown }) => void) | null;\n close(): void;\n}\n\nexport interface McpLoginHost {\n open(): Popup | null;\n channel(): Channel;\n remember?(state: string, name: string | null): void;\n timeoutMs?: number;\n}\n\nconst browser: McpLoginHost = {\n open: () =>\n globalThis.open?.('about:blank', 'slicc-mcp-oauth', 'popup,width=520,height=720') ?? null,\n channel: () => new BroadcastChannel(MCP_CHANNEL) as unknown as Channel,\n remember: (state, name) => {\n const key = `${MCP_NAME_KEY}${state}`;\n if (name === null) globalThis.localStorage?.removeItem(key);\n else globalThis.localStorage?.setItem(key, name);\n },\n};\n\nconst LOOPBACK = new Set(['localhost', '127.0.0.1', '[::1]']);\n\nexport function safeAuthorizationUrl(value: string): boolean {\n if (!URL.canParse(value)) return false;\n const url = new URL(value);\n return url.protocol === 'https:' || (url.protocol === 'http:' && LOOPBACK.has(url.hostname));\n}\n\nfunction answered(channel: Channel, state: string, signal: AbortSignal, timeoutMs: number) {\n return new Promise<string>((resolve, reject) => {\n const done = () => {\n clearTimeout(timer);\n signal.removeEventListener('abort', stop);\n };\n const stop = () => {\n done();\n reject(signal.reason);\n };\n const timer = setTimeout(() => {\n done();\n reject(new Error('The sign-in window gave no answer. Try again.'));\n }, timeoutMs);\n signal.addEventListener('abort', stop, { once: true });\n channel.onmessage = ({ data }) => {\n const answer = data as { state?: unknown } | null;\n if (answer?.state !== state) return;\n done();\n resolve(JSON.stringify(answer));\n };\n });\n}\n\nfunction untilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n signal.throwIfAborted();\n return new Promise<T>((resolve, reject) => {\n const stop = () => reject(signal.reason);\n signal.addEventListener('abort', stop, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', stop));\n });\n}\n\nexport function mcpLogin(host: McpLoginHost = browser) {\n return async (\n providerId: string,\n signIn: () => Promise<SignIn | McpSignIn | null>,\n options: { signal: AbortSignal }\n ): Promise<string> => {\n const popup = host.open();\n const channel = host.channel();\n let state: string | undefined;\n try {\n const started = (await untilAborted(signIn(), options.signal)) as McpSignIn | null;\n if (!started?.url) throw new Error('This MCP server has no sign-in.');\n if (!safeAuthorizationUrl(started.url))\n throw new Error(\"The authorization server gave a sign-in address that isn't https.\");\n if (!popup)\n throw new Error('The browser blocked the sign-in window. Allow pop-ups for SLICC.');\n state = started.state;\n host.remember?.(state, providerId.replace(/^mcp:/, ''));\n popup.location.href = started.url;\n return await answered(channel, state, options.signal, host.timeoutMs ?? SIGN_IN_TIMEOUT_MS);\n } finally {\n if (state) host.remember?.(state, null);\n channel.close();\n popup?.close();\n }\n };\n}\n"],
5
- "mappings": "AAEO,MAAM,cAAc;AACpB,MAAM,eAAe;AACrB,MAAM,qBAAqB,IAAI,KAAK;AAmB3C,MAAM,UAAwB;AAAA,EAC5B,MAAM,MACJ,WAAW,OAAO,eAAe,mBAAmB,4BAA4B,KAAK;AAAA,EACvF,SAAS,MAAM,IAAI,iBAAiB,WAAW;AAAA,EAC/C,UAAU,CAAC,OAAO,SAAS;AACzB,UAAM,MAAM,GAAG,YAAY,GAAG,KAAK;AACnC,QAAI,SAAS,KAAM,YAAW,cAAc,WAAW,GAAG;AAAA,QACrD,YAAW,cAAc,QAAQ,KAAK,IAAI;AAAA,EACjD;AACF;AAEA,MAAM,WAAW,oBAAI,IAAI,CAAC,aAAa,aAAa,OAAO,CAAC;AAErD,SAAS,qBAAqB,OAAwB;AAC3D,MAAI,CAAC,IAAI,SAAS,KAAK,EAAG,QAAO;AACjC,QAAM,MAAM,IAAI,IAAI,KAAK;AACzB,SAAO,IAAI,aAAa,YAAa,IAAI,aAAa,WAAW,SAAS,IAAI,IAAI,QAAQ;AAC5F;AAEA,SAAS,SAAS,SAAkB,OAAe,QAAqB,WAAmB;AACzF,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,UAAM,OAAO,MAAM;AACjB,mBAAa,KAAK;AAClB,aAAO,oBAAoB,SAAS,IAAI;AAAA,IAC1C;AACA,UAAM,OAAO,MAAM;AACjB,WAAK;AACL,aAAO,OAAO,MAAM;AAAA,IACtB;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,WAAK;AACL,aAAO,IAAI,MAAM,+CAA+C,CAAC;AAAA,IACnE,GAAG,SAAS;AACZ,WAAO,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AACrD,YAAQ,YAAY,CAAC,EAAE,KAAK,MAAM;AAChC,YAAM,SAAS;AACf,UAAI,QAAQ,UAAU,MAAO;AAC7B,WAAK;AACL,cAAQ,KAAK,UAAU,MAAM,CAAC;AAAA,IAChC;AAAA,EACF,CAAC;AACH;AAEA,SAAS,aAAgB,SAAqB,QAAiC;AAC7E,SAAO,eAAe;AACtB,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,UAAM,OAAO,MAAM,OAAO,OAAO,MAAM;AACvC,WAAO,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AACrD,YAAQ,KAAK,SAAS,MAAM,EAAE,QAAQ,MAAM,OAAO,oBAAoB,SAAS,IAAI,CAAC;AAAA,EACvF,CAAC;AACH;AAEO,SAAS,SAAS,OAAqB,SAAS;AACrD,SAAO,OACL,YACA,QACA,YACoB;AACpB,UAAM,QAAQ,KAAK,KAAK;AACxB,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI;AACJ,QAAI;AACF,YAAM,UAAW,MAAM,aAAa,OAAO,GAAG,QAAQ,MAAM;AAC5D,UAAI,CAAC,SAAS,IAAK,OAAM,IAAI,MAAM,iCAAiC;AACpE,UAAI,CAAC,qBAAqB,QAAQ,GAAG;AACnC,cAAM,IAAI,MAAM,mEAAmE;AACrF,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,kEAAkE;AACpF,cAAQ,QAAQ;AAChB,WAAK,WAAW,OAAO,WAAW,QAAQ,SAAS,EAAE,CAAC;AACtD,YAAM,SAAS,OAAO,QAAQ;AAC9B,aAAO,MAAM,SAAS,SAAS,OAAO,QAAQ,QAAQ,KAAK,aAAa,kBAAkB;AAAA,IAC5F,UAAE;AACA,UAAI,MAAO,MAAK,WAAW,OAAO,IAAI;AACtC,cAAQ,MAAM;AACd,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import type { McpSignIn, SignIn } from '../services.ts';\n\nexport const MCP_CHANNEL = 'slicc-mcp-oauth';\nexport const MCP_NAME_KEY = 'slicc-mcp-oauth:';\nexport const SIGN_IN_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface Popup {\n location: { href: string };\n close(): void;\n}\n\nexport interface Channel {\n onmessage: ((event: { data: unknown }) => void) | null;\n close(): void;\n}\n\nexport interface McpLoginHost {\n open(): Popup | null;\n channel(): Channel;\n remember?(state: string, name: string | null): void;\n timeoutMs?: number;\n}\n\nconst browser: McpLoginHost = {\n open: () =>\n globalThis.open?.('about:blank', 'slicc-mcp-oauth', 'popup,width=520,height=720') ?? null,\n channel: () => new BroadcastChannel(MCP_CHANNEL) as unknown as Channel,\n remember: (state, name) => {\n const key = `${MCP_NAME_KEY}${state}`;\n if (name === null) globalThis.localStorage?.removeItem(key);\n else globalThis.localStorage?.setItem(key, name);\n },\n};\n\nconst LOOPBACK = new Set(['localhost', '127.0.0.1', '[::1]']);\n\nexport function safeAuthorizationUrl(value: string): boolean {\n if (!URL.canParse(value)) return false;\n const url = new URL(value);\n return url.protocol === 'https:' || (url.protocol === 'http:' && LOOPBACK.has(url.hostname));\n}\n\nfunction answered(channel: Channel, state: string, signal: AbortSignal, timeoutMs: number) {\n return new Promise<string>((resolve, reject) => {\n const done = () => {\n clearTimeout(timer);\n signal.removeEventListener('abort', stop);\n };\n const stop = () => {\n done();\n reject(signal.reason);\n };\n const timer = setTimeout(() => {\n done();\n reject(new Error('The sign-in window gave no answer. Try again.'));\n }, timeoutMs);\n signal.addEventListener('abort', stop, { once: true });\n channel.onmessage = ({ data }) => {\n const answer = data as { state?: unknown } | null;\n if (answer?.state !== state) return;\n done();\n resolve(JSON.stringify(answer));\n };\n });\n}\n\nexport function untilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<T> {\n signal.throwIfAborted();\n return new Promise<T>((resolve, reject) => {\n const stop = () => reject(signal.reason);\n signal.addEventListener('abort', stop, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', stop));\n });\n}\n\nexport function mcpLogin(host: McpLoginHost = browser) {\n return async (\n providerId: string,\n signIn: () => Promise<SignIn | McpSignIn | null>,\n options: { signal: AbortSignal }\n ): Promise<string> => {\n const popup = host.open();\n const channel = host.channel();\n let state: string | undefined;\n try {\n const started = (await untilAborted(signIn(), options.signal)) as McpSignIn | null;\n if (!started?.url) throw new Error('This MCP server has no sign-in.');\n if (!safeAuthorizationUrl(started.url))\n throw new Error(\"The authorization server gave a sign-in address that isn't https.\");\n if (!popup)\n throw new Error('The browser blocked the sign-in window. Allow pop-ups for SLICC.');\n state = started.state;\n host.remember?.(state, providerId.replace(/^mcp:/, ''));\n popup.location.href = started.url;\n return await answered(channel, state, options.signal, host.timeoutMs ?? SIGN_IN_TIMEOUT_MS);\n } finally {\n if (state) host.remember?.(state, null);\n channel.close();\n popup?.close();\n }\n };\n}\n"],
5
+ "mappings": "AAEO,MAAM,cAAc;AACpB,MAAM,eAAe;AACrB,MAAM,qBAAqB,IAAI,KAAK;AAmB3C,MAAM,UAAwB;AAAA,EAC5B,MAAM,MACJ,WAAW,OAAO,eAAe,mBAAmB,4BAA4B,KAAK;AAAA,EACvF,SAAS,MAAM,IAAI,iBAAiB,WAAW;AAAA,EAC/C,UAAU,CAAC,OAAO,SAAS;AACzB,UAAM,MAAM,GAAG,YAAY,GAAG,KAAK;AACnC,QAAI,SAAS,KAAM,YAAW,cAAc,WAAW,GAAG;AAAA,QACrD,YAAW,cAAc,QAAQ,KAAK,IAAI;AAAA,EACjD;AACF;AAEA,MAAM,WAAW,oBAAI,IAAI,CAAC,aAAa,aAAa,OAAO,CAAC;AAErD,SAAS,qBAAqB,OAAwB;AAC3D,MAAI,CAAC,IAAI,SAAS,KAAK,EAAG,QAAO;AACjC,QAAM,MAAM,IAAI,IAAI,KAAK;AACzB,SAAO,IAAI,aAAa,YAAa,IAAI,aAAa,WAAW,SAAS,IAAI,IAAI,QAAQ;AAC5F;AAEA,SAAS,SAAS,SAAkB,OAAe,QAAqB,WAAmB;AACzF,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,UAAM,OAAO,MAAM;AACjB,mBAAa,KAAK;AAClB,aAAO,oBAAoB,SAAS,IAAI;AAAA,IAC1C;AACA,UAAM,OAAO,MAAM;AACjB,WAAK;AACL,aAAO,OAAO,MAAM;AAAA,IACtB;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,WAAK;AACL,aAAO,IAAI,MAAM,+CAA+C,CAAC;AAAA,IACnE,GAAG,SAAS;AACZ,WAAO,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AACrD,YAAQ,YAAY,CAAC,EAAE,KAAK,MAAM;AAChC,YAAM,SAAS;AACf,UAAI,QAAQ,UAAU,MAAO;AAC7B,WAAK;AACL,cAAQ,KAAK,UAAU,MAAM,CAAC;AAAA,IAChC;AAAA,EACF,CAAC;AACH;AAEO,SAAS,aAAgB,SAAqB,QAAiC;AACpF,SAAO,eAAe;AACtB,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,UAAM,OAAO,MAAM,OAAO,OAAO,MAAM;AACvC,WAAO,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AACrD,YAAQ,KAAK,SAAS,MAAM,EAAE,QAAQ,MAAM,OAAO,oBAAoB,SAAS,IAAI,CAAC;AAAA,EACvF,CAAC;AACH;AAEO,SAAS,SAAS,OAAqB,SAAS;AACrD,SAAO,OACL,YACA,QACA,YACoB;AACpB,UAAM,QAAQ,KAAK,KAAK;AACxB,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI;AACJ,QAAI;AACF,YAAM,UAAW,MAAM,aAAa,OAAO,GAAG,QAAQ,MAAM;AAC5D,UAAI,CAAC,SAAS,IAAK,OAAM,IAAI,MAAM,iCAAiC;AACpE,UAAI,CAAC,qBAAqB,QAAQ,GAAG;AACnC,cAAM,IAAI,MAAM,mEAAmE;AACrF,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,kEAAkE;AACpF,cAAQ,QAAQ;AAChB,WAAK,WAAW,OAAO,WAAW,QAAQ,SAAS,EAAE,CAAC;AACtD,YAAM,SAAS,OAAO,QAAQ;AAC9B,aAAO,MAAM,SAAS,SAAS,OAAO,QAAQ,QAAQ,KAAK,aAAa,kBAAkB;AAAA,IAC5F,UAAE;AACA,UAAI,MAAO,MAAK,WAAW,OAAO,IAAI;AACtC,cAAQ,MAAM;AACd,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,13 @@
1
- import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
1
+ import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
2
2
  import { preferredModel } from "../preferred.js";
3
+ import {
4
+ DEVICE_SIGN_INS,
5
+ httpsUrl,
6
+ SIGN_IN_UNFINISHED
7
+ } from "../sign-ins.js";
3
8
  import { attempt } from "./attempt.js";
4
9
  import { Emitter } from "./emitter.js";
5
- import { mcpLogin } from "./mcp-login.js";
10
+ import { mcpLogin, untilAborted } from "./mcp-login.js";
6
11
  const SETTINGS_KEY = "slicc-agent.settings";
7
12
  const defaults = {
8
13
  color: "system",
@@ -13,7 +18,8 @@ const defaults = {
13
18
  diffStyle: "unified"
14
19
  };
15
20
  const SIGN_IN_NEEDS_VAULT = "Adobe sign-in needs seven's vault: update seven";
16
- const UNFINISHED = "The sign-in didn't finish. Try again.";
21
+ const UNFINISHED = SIGN_IN_UNFINISHED;
22
+ const openPopup = () => globalThis.open?.("about:blank", "slicc-sign-in", "popup,width=520,height=720") ?? null;
17
23
  function readable(error) {
18
24
  if (error instanceof DOMException && error.name === "AbortError") return error;
19
25
  const text = (error instanceof Error ? error.message : String(error ?? "")).trim();
@@ -28,12 +34,15 @@ class SettingsAdapter extends Emitter {
28
34
  #login;
29
35
  #mcpLogin;
30
36
  #signing = /* @__PURE__ */ new Map();
37
+ #prompts = /* @__PURE__ */ new Map();
38
+ #open;
31
39
  #local;
32
40
  #offered = "";
33
41
  #urls = /* @__PURE__ */ new Map();
34
- constructor(settings, agent, storage, login = null, mcp = mcpLogin()) {
42
+ constructor(settings, agent, storage, login = null, mcp = mcpLogin(), open = openPopup) {
35
43
  super();
36
44
  this.#mcpLogin = mcp;
45
+ this.#open = open;
37
46
  this.#settings = settings;
38
47
  this.#agent = agent;
39
48
  this.#storage = storage;
@@ -126,20 +135,29 @@ class SettingsAdapter extends Emitter {
126
135
  return this.#state().accounts.map(({ needs, ...account }) => {
127
136
  const url = this.#urls.get(account.id);
128
137
  const located = url ? { ...account, url } : account;
129
- const shown = this.#signing.has(account.id) ? { ...located, status: "signing-in" } : located;
138
+ const prompt = this.#prompts.get(account.id);
139
+ const shown = this.#signing.has(account.id) ? {
140
+ ...located,
141
+ status: "signing-in",
142
+ ...prompt ? { signIn: { ...prompt } } : {}
143
+ } : located;
130
144
  return needs ? { ...shown, needs } : shown;
131
145
  });
132
146
  }
133
- async connect(id, secret, fields) {
147
+ async connect(id, secret, fields, options) {
134
148
  const account = this.#state().accounts.find((candidate) => candidate.id === id) ?? this.#offer(id);
135
149
  const mcp = account?.group === "mcp";
136
- const login = account?.auth !== "oauth" ? null : mcp ? this.#mcpLogin : this.#login;
137
150
  const given = fields ? { ...fields } : null;
151
+ const keyed = options?.method === "key";
152
+ if (account?.auth === "oauth" && DEVICE_SIGN_INS.has(id) && secret === void 0 && !keyed)
153
+ return this.#device(id, given);
154
+ const login = account?.auth !== "oauth" || keyed ? null : mcp ? this.#mcpLogin : this.#login;
155
+ if (keyed) this.cancel(id);
138
156
  if (secret !== void 0) {
139
157
  await this.#settings.connect(id, secret, given, BACKGROUND_CONTEXT);
140
158
  return;
141
159
  }
142
- if (account?.auth === "oauth" && !login) throw new Error(`${id} needs a sign-in`);
160
+ if (account?.auth === "oauth" && !login && !keyed) throw new Error(`${id} needs a sign-in`);
143
161
  if (!login) {
144
162
  if (account?.store !== "vault") throw new Error(`${id} needs an API key`);
145
163
  await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);
@@ -154,11 +172,47 @@ class SettingsAdapter extends Emitter {
154
172
  if (answer?.sealed !== true) throw new Error(UNFINISHED);
155
173
  await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);
156
174
  }
157
- async #signIn(id, login) {
175
+ #begin(id) {
158
176
  const controller = new AbortController();
159
177
  this.#signing.get(id)?.abort(new DOMException("A newer sign-in replaced this one.", "AbortError"));
160
178
  this.#signing.set(id, controller);
179
+ this.#prompts.delete(id);
180
+ this.emit("accounts", this.accounts());
181
+ return controller;
182
+ }
183
+ #end(id, controller) {
184
+ if (this.#signing.get(id) === controller) {
185
+ this.#signing.delete(id);
186
+ this.#prompts.delete(id);
187
+ }
161
188
  this.emit("accounts", this.accounts());
189
+ }
190
+ async #device(id, given) {
191
+ const popup = this.#open();
192
+ const controller = this.#begin(id);
193
+ const { signal } = controller;
194
+ const context = withAbortSignal(signal, BACKGROUND_CONTEXT);
195
+ try {
196
+ const started = await untilAborted(
197
+ this.#settings.signIn(id, context),
198
+ signal
199
+ );
200
+ if (!started || !httpsUrl(started.url)) throw new Error(UNFINISHED);
201
+ const code = typeof started.code === "string" && started.code ? started.code : void 0;
202
+ this.#prompts.set(id, { url: started.url, ...code ? { code } : {} });
203
+ this.emit("accounts", this.accounts());
204
+ if (popup) popup.location.href = started.url;
205
+ await untilAborted(this.#settings.connect(id, null, given, context), signal);
206
+ } catch (error) {
207
+ signal.throwIfAborted();
208
+ throw readable(error);
209
+ } finally {
210
+ popup?.close();
211
+ this.#end(id, controller);
212
+ }
213
+ }
214
+ async #signIn(id, login) {
215
+ const controller = this.#begin(id);
162
216
  try {
163
217
  const key = await login(
164
218
  id,
@@ -173,14 +227,14 @@ class SettingsAdapter extends Emitter {
173
227
  controller.signal.throwIfAborted();
174
228
  return key;
175
229
  } finally {
176
- if (this.#signing.get(id) === controller) this.#signing.delete(id);
177
- this.emit("accounts", this.accounts());
230
+ this.#end(id, controller);
178
231
  }
179
232
  }
180
233
  cancel(id) {
181
234
  const controller = this.#signing.get(id);
182
235
  if (!controller) return;
183
236
  this.#signing.delete(id);
237
+ this.#prompts.delete(id);
184
238
  controller.abort(new DOMException("The sign-in was cancelled.", "AbortError"));
185
239
  this.emit("accounts", this.accounts());
186
240
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/spectrum/settings-port.ts"],
4
- "sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { preferredModel } from '../preferred.ts';\nimport type { AgentSettings, ProviderOption, SettingsState, SignIn } from '../services.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { attempt } from './attempt.ts';\nimport { Emitter } from './emitter.ts';\nimport { mcpLogin } from './mcp-login.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Sealed = { sealed: true };\n\nexport type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string | Sealed>;\n\nexport const SIGN_IN_NEEDS_VAULT = \"Adobe sign-in needs seven's vault: update seven\";\nexport const UNFINISHED = \"The sign-in didn't finish. Try again.\";\n\nexport function readable(error: unknown): Error {\n if (error instanceof DOMException && error.name === 'AbortError') return error;\n const text = (error instanceof Error ? error.message : String(error ?? '')).trim();\n if (!text) return new Error(UNFINISHED);\n const lead = /^[a-z]+\\b(?![-.@/])/.test(text) ? text[0].toUpperCase() + text.slice(1) : text;\n return new Error(/[.!?]$/.test(lead) ? lead : `${lead}.`);\n}\n\ntype Events = SettingsEvents & { providers: readonly ProviderOption[] };\n\nexport class SettingsAdapter extends Emitter<Events> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n readonly #mcpLogin: Login;\n readonly #signing = new Map<string, AbortController>();\n #local: Local;\n #offered = '';\n readonly #urls = new Map<string, string>();\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null,\n mcp: Login = mcpLogin() as Login\n ) {\n super();\n this.#mcpLogin = mcp;\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n this.#offered = JSON.stringify(this.providers());\n this.#locate();\n settings.state.subscribe(() => {\n this.#locate();\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n const offered = JSON.stringify(this.providers());\n if (offered === this.#offered) return;\n this.#offered = offered;\n this.emit('providers', this.providers());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #locate(): void {\n const servers = this.#state()\n .accounts.filter(({ group }) => group === 'mcp')\n .map(({ id }) => id);\n for (const id of this.#urls.keys()) if (!servers.includes(id)) this.#urls.delete(id);\n for (const id of servers) {\n void this.#settings\n .serverUrl?.(id, BACKGROUND_CONTEXT)\n .then((url) => {\n if ((url ?? undefined) === this.#urls.get(id)) return;\n if (url) this.#urls.set(id, url);\n else this.#urls.delete(id);\n this.emit('accounts', this.accounts());\n })\n .catch(() => undefined);\n }\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n const choices = this.#state().models;\n const groups = Map.groupBy(choices, ({ id }) => id.slice(0, id.indexOf('/')));\n const chosen = new Set(\n [...groups].map(\n ([providerId, group]) =>\n preferredModel(\n providerId,\n group.map((choice) => ({ id: choice.id.slice(providerId.length + 1), choice }))\n )?.choice\n )\n );\n return choices.map((choice) => {\n const { id, label, provider, kind, reasoning, images } = choice;\n return {\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n ...(chosen.has(choice) ? { default: true } : {}),\n };\n });\n }\n\n #offer(id: string) {\n const option = this.providers().find((candidate) => candidate.id === id);\n if (!option) return undefined;\n return {\n auth: option.auth === 'oauth' ? ('oauth' as const) : ('api-key' as const),\n store: 'vault' as const,\n group: 'providers' as const,\n };\n }\n\n providers(): readonly ProviderOption[] {\n return this.#state().providers ?? [];\n }\n\n async remove(id: string): Promise<void> {\n this.cancel(id);\n await this.#settings.remove(id, BACKGROUND_CONTEXT);\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const url = this.#urls.get(account.id);\n const located = url ? { ...account, url } : account;\n const shown = this.#signing.has(account.id)\n ? { ...located, status: 'signing-in' as const }\n : located;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(id: string, secret?: string, fields?: Record<string, string>): Promise<void> {\n const account =\n this.#state().accounts.find((candidate) => candidate.id === id) ?? this.#offer(id);\n const mcp = account?.group === 'mcp';\n const login = account?.auth !== 'oauth' ? null : mcp ? this.#mcpLogin : this.#login;\n const given = fields ? { ...fields } : null;\n if (secret !== undefined) {\n await this.#settings.connect(id, secret, given, BACKGROUND_CONTEXT);\n return;\n }\n if (account?.auth === 'oauth' && !login) throw new Error(`${id} needs a sign-in`);\n if (!login) {\n if (account?.store !== 'vault') throw new Error(`${id} needs an API key`);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n return;\n }\n const answer = await this.#signIn(id, login);\n if (typeof answer === 'string') {\n if (!mcp) throw new Error(SIGN_IN_NEEDS_VAULT);\n await this.#settings.connect(id, answer, given, BACKGROUND_CONTEXT);\n return;\n }\n if (answer?.sealed !== true) throw new Error(UNFINISHED);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n }\n\n async #signIn(id: string, login: Login): Promise<string | Sealed> {\n const controller = new AbortController();\n this.#signing\n .get(id)\n ?.abort(new DOMException('A newer sign-in replaced this one.', 'AbortError'));\n this.#signing.set(id, controller);\n this.emit('accounts', this.accounts());\n try {\n const key = await login(\n id,\n () => this.#settings.signIn(id, BACKGROUND_CONTEXT) as Promise<SignIn | null>,\n {\n signal: controller.signal,\n }\n ).catch((error: unknown) => {\n controller.signal.throwIfAborted();\n throw readable(error);\n });\n controller.signal.throwIfAborted();\n return key;\n } finally {\n if (this.#signing.get(id) === controller) this.#signing.delete(id);\n this.emit('accounts', this.accounts());\n }\n }\n\n cancel(id: string): void {\n const controller = this.#signing.get(id);\n if (!controller) return;\n this.#signing.delete(id);\n controller.abort(new DOMException('The sign-in was cancelled.', 'AbortError'));\n this.emit('accounts', this.accounts());\n }\n\n disconnect(id: string): void {\n attempt(this.#settings.disconnect(id, BACKGROUND_CONTEXT), 'disconnect accounts', (text) =>\n this.#agent.notify(text)\n );\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT, withAbortSignal } from '@earendil-works/chord/context';\nimport { preferredModel } from '../preferred.ts';\nimport type { AgentSettings, ProviderOption, SettingsState, SignIn } from '../services.ts';\nimport {\n type ConnectOptions,\n DEVICE_SIGN_INS,\n type DeviceSignIn,\n httpsUrl,\n SIGN_IN_UNFINISHED,\n} from '../sign-ins.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { attempt } from './attempt.ts';\nimport { Emitter } from './emitter.ts';\nimport { mcpLogin, type Popup, untilAborted } from './mcp-login.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Sealed = { sealed: true };\n\nexport type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string | Sealed>;\n\nexport const SIGN_IN_NEEDS_VAULT = \"Adobe sign-in needs seven's vault: update seven\";\nexport const UNFINISHED = SIGN_IN_UNFINISHED;\n\nexport type OpenPopup = () => Popup | null;\n\nconst openPopup: OpenPopup = () =>\n globalThis.open?.('about:blank', 'slicc-sign-in', 'popup,width=520,height=720') ?? null;\n\nexport function readable(error: unknown): Error {\n if (error instanceof DOMException && error.name === 'AbortError') return error;\n const text = (error instanceof Error ? error.message : String(error ?? '')).trim();\n if (!text) return new Error(UNFINISHED);\n const lead = /^[a-z]+\\b(?![-.@/])/.test(text) ? text[0].toUpperCase() + text.slice(1) : text;\n return new Error(/[.!?]$/.test(lead) ? lead : `${lead}.`);\n}\n\ntype Events = SettingsEvents & { providers: readonly ProviderOption[] };\n\nexport class SettingsAdapter extends Emitter<Events> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n readonly #mcpLogin: Login;\n readonly #signing = new Map<string, AbortController>();\n readonly #prompts = new Map<string, DeviceSignIn>();\n readonly #open: OpenPopup;\n #local: Local;\n #offered = '';\n readonly #urls = new Map<string, string>();\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null,\n mcp: Login = mcpLogin() as Login,\n open: OpenPopup = openPopup\n ) {\n super();\n this.#mcpLogin = mcp;\n this.#open = open;\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n this.#offered = JSON.stringify(this.providers());\n this.#locate();\n settings.state.subscribe(() => {\n this.#locate();\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n const offered = JSON.stringify(this.providers());\n if (offered === this.#offered) return;\n this.#offered = offered;\n this.emit('providers', this.providers());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #locate(): void {\n const servers = this.#state()\n .accounts.filter(({ group }) => group === 'mcp')\n .map(({ id }) => id);\n for (const id of this.#urls.keys()) if (!servers.includes(id)) this.#urls.delete(id);\n for (const id of servers) {\n void this.#settings\n .serverUrl?.(id, BACKGROUND_CONTEXT)\n .then((url) => {\n if ((url ?? undefined) === this.#urls.get(id)) return;\n if (url) this.#urls.set(id, url);\n else this.#urls.delete(id);\n this.emit('accounts', this.accounts());\n })\n .catch(() => undefined);\n }\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n const choices = this.#state().models;\n const groups = Map.groupBy(choices, ({ id }) => id.slice(0, id.indexOf('/')));\n const chosen = new Set(\n [...groups].map(\n ([providerId, group]) =>\n preferredModel(\n providerId,\n group.map((choice) => ({ id: choice.id.slice(providerId.length + 1), choice }))\n )?.choice\n )\n );\n return choices.map((choice) => {\n const { id, label, provider, kind, reasoning, images } = choice;\n return {\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n ...(chosen.has(choice) ? { default: true } : {}),\n };\n });\n }\n\n #offer(id: string) {\n const option = this.providers().find((candidate) => candidate.id === id);\n if (!option) return undefined;\n return {\n auth: option.auth === 'oauth' ? ('oauth' as const) : ('api-key' as const),\n store: 'vault' as const,\n group: 'providers' as const,\n };\n }\n\n providers(): readonly ProviderOption[] {\n return this.#state().providers ?? [];\n }\n\n async remove(id: string): Promise<void> {\n this.cancel(id);\n await this.#settings.remove(id, BACKGROUND_CONTEXT);\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const url = this.#urls.get(account.id);\n const located = url ? { ...account, url } : account;\n const prompt = this.#prompts.get(account.id);\n const shown = this.#signing.has(account.id)\n ? {\n ...located,\n status: 'signing-in' as const,\n ...(prompt ? { signIn: { ...prompt } } : {}),\n }\n : located;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(\n id: string,\n secret?: string,\n fields?: Record<string, string>,\n options?: ConnectOptions\n ): Promise<void> {\n const account =\n this.#state().accounts.find((candidate) => candidate.id === id) ?? this.#offer(id);\n const mcp = account?.group === 'mcp';\n const given = fields ? { ...fields } : null;\n const keyed = options?.method === 'key';\n if (account?.auth === 'oauth' && DEVICE_SIGN_INS.has(id) && secret === undefined && !keyed)\n return this.#device(id, given);\n const login = account?.auth !== 'oauth' || keyed ? null : mcp ? this.#mcpLogin : this.#login;\n if (keyed) this.cancel(id);\n if (secret !== undefined) {\n await this.#settings.connect(id, secret, given, BACKGROUND_CONTEXT);\n return;\n }\n if (account?.auth === 'oauth' && !login && !keyed) throw new Error(`${id} needs a sign-in`);\n if (!login) {\n if (account?.store !== 'vault') throw new Error(`${id} needs an API key`);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n return;\n }\n const answer = await this.#signIn(id, login);\n if (typeof answer === 'string') {\n if (!mcp) throw new Error(SIGN_IN_NEEDS_VAULT);\n await this.#settings.connect(id, answer, given, BACKGROUND_CONTEXT);\n return;\n }\n if (answer?.sealed !== true) throw new Error(UNFINISHED);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n }\n\n #begin(id: string): AbortController {\n const controller = new AbortController();\n this.#signing\n .get(id)\n ?.abort(new DOMException('A newer sign-in replaced this one.', 'AbortError'));\n this.#signing.set(id, controller);\n this.#prompts.delete(id);\n this.emit('accounts', this.accounts());\n return controller;\n }\n\n #end(id: string, controller: AbortController): void {\n if (this.#signing.get(id) === controller) {\n this.#signing.delete(id);\n this.#prompts.delete(id);\n }\n this.emit('accounts', this.accounts());\n }\n\n async #device(id: string, given: Record<string, string> | null): Promise<void> {\n const popup = this.#open();\n const controller = this.#begin(id);\n const { signal } = controller;\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n try {\n const started = (await untilAborted(\n this.#settings.signIn(id, context),\n signal\n )) as DeviceSignIn | null;\n if (!started || !httpsUrl(started.url)) throw new Error(UNFINISHED);\n const code = typeof started.code === 'string' && started.code ? started.code : undefined;\n this.#prompts.set(id, { url: started.url, ...(code ? { code } : {}) });\n this.emit('accounts', this.accounts());\n if (popup) popup.location.href = started.url;\n await untilAborted(this.#settings.connect(id, null, given, context), signal);\n } catch (error) {\n signal.throwIfAborted();\n throw readable(error);\n } finally {\n popup?.close();\n this.#end(id, controller);\n }\n }\n\n async #signIn(id: string, login: Login): Promise<string | Sealed> {\n const controller = this.#begin(id);\n try {\n const key = await login(\n id,\n () => this.#settings.signIn(id, BACKGROUND_CONTEXT) as Promise<SignIn | null>,\n {\n signal: controller.signal,\n }\n ).catch((error: unknown) => {\n controller.signal.throwIfAborted();\n throw readable(error);\n });\n controller.signal.throwIfAborted();\n return key;\n } finally {\n this.#end(id, controller);\n }\n }\n\n cancel(id: string): void {\n const controller = this.#signing.get(id);\n if (!controller) return;\n this.#signing.delete(id);\n this.#prompts.delete(id);\n controller.abort(new DOMException('The sign-in was cancelled.', 'AbortError'));\n this.emit('accounts', this.accounts());\n }\n\n disconnect(id: string): void {\n attempt(this.#settings.disconnect(id, BACKGROUND_CONTEXT), 'disconnect accounts', (text) =>\n this.#agent.notify(text)\n );\n }\n}\n"],
5
+ "mappings": "AAOA,SAAS,oBAAoB,uBAAuB;AACpD,SAAS,sBAAsB;AAE/B;AAAA,EAEE;AAAA,EAEA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,UAAsB,oBAAoB;AAE5C,MAAM,eAAe;AAE5B,MAAM,WAAqB;AAAA,EACzB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AACb;AAYO,MAAM,sBAAsB;AAC5B,MAAM,aAAa;AAI1B,MAAM,YAAuB,MAC3B,WAAW,OAAO,eAAe,iBAAiB,4BAA4B,KAAK;AAE9E,SAAS,SAAS,OAAuB;AAC9C,MAAI,iBAAiB,gBAAgB,MAAM,SAAS,aAAc,QAAO;AACzE,QAAM,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,EAAE,GAAG,KAAK;AACjF,MAAI,CAAC,KAAM,QAAO,IAAI,MAAM,UAAU;AACtC,QAAM,OAAO,sBAAsB,KAAK,IAAI,IAAI,KAAK,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,IAAI;AACxF,SAAO,IAAI,MAAM,SAAS,KAAK,IAAI,IAAI,OAAO,GAAG,IAAI,GAAG;AAC1D;AAIO,MAAM,wBAAwB,QAAwC;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW,oBAAI,IAA6B;AAAA,EAC5C,WAAW,oBAAI,IAA0B;AAAA,EACzC;AAAA,EACT;AAAA,EACA,WAAW;AAAA,EACF,QAAQ,oBAAI,IAAoB;AAAA,EAEzC,YACE,UACA,OACA,SACA,QAAsB,MACtB,MAAa,SAAS,GACtB,OAAkB,WAClB;AACA,UAAM;AACN,SAAK,YAAY;AACjB,SAAK,QAAQ;AACb,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,UAAM,QAAQ,KAAK,MAAM,SAAS,QAAQ,YAAY,KAAK,IAAI;AAC/D,UAAM,EAAE,OAAO,QAAQ,UAAU,WAAW,GAAG,MAAM,IAAI,EAAE,GAAG,UAAU,GAAG,MAAM;AACjF,SAAK,SAAS;AACd,SAAK,WAAW,KAAK,UAAU,KAAK,UAAU,CAAC;AAC/C,SAAK,QAAQ;AACb,aAAS,MAAM,UAAU,MAAM;AAC7B,WAAK,QAAQ;AACb,WAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AACrC,WAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAChC,YAAM,UAAU,KAAK,UAAU,KAAK,UAAU,CAAC;AAC/C,UAAI,YAAY,KAAK,SAAU;AAC/B,WAAK,WAAW;AAChB,WAAK,KAAK,aAAa,KAAK,UAAU,CAAC;AAAA,IACzC,CAAC;AACD,UAAM,GAAG,UAAU,MAAM,KAAK,KAAK,YAAY,KAAK,IAAI,CAAC,CAAC;AAAA,EAC5D;AAAA,EAEA,UAAgB;AACd,UAAM,UAAU,KAAK,OAAO,EACzB,SAAS,OAAO,CAAC,EAAE,MAAM,MAAM,UAAU,KAAK,EAC9C,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE;AACrB,eAAW,MAAM,KAAK,MAAM,KAAK,EAAG,KAAI,CAAC,QAAQ,SAAS,EAAE,EAAG,MAAK,MAAM,OAAO,EAAE;AACnF,eAAW,MAAM,SAAS;AACxB,WAAK,KAAK,UACP,YAAY,IAAI,kBAAkB,EAClC,KAAK,CAAC,QAAQ;AACb,aAAK,OAAO,YAAe,KAAK,MAAM,IAAI,EAAE,EAAG;AAC/C,YAAI,IAAK,MAAK,MAAM,IAAI,IAAI,GAAG;AAAA,YAC1B,MAAK,MAAM,OAAO,EAAE;AACzB,aAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,MACvC,CAAC,EACA,MAAM,MAAM,MAAS;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,SAAwB;AACtB,WAAO,KAAK,UAAU,MAAM,SAAS,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,EAClE;AAAA,EAEA,MAAgB;AACd,UAAM,OAAO,KAAK,OAAO,KAAK,EAAE,CAAC;AACjC,WAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,MAAM,SAAS,IAAI,UAAU,MAAM,YAAY,MAAM;AAAA,EACvF;AAAA,EAEA,OAAO,OAAgC;AACrC,UAAM,EAAE,OAAO,UAAU,GAAG,MAAM,IAAI;AACtC,UAAM,KAAK,KAAK,OAAO,OAAO;AAC9B,QAAI,UAAU,OAAW,MAAK,OAAO,SAAS,IAAI,KAAK;AACvD,QAAI,aAAa,OAAW,MAAK,OAAO,YAAY,IAAI,QAAQ;AAChE,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,MAAM;AACzC,SAAK,UAAU,QAAQ,cAAc,KAAK,UAAU,KAAK,MAAM,CAAC;AAChE,SAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,EAClC;AAAA,EAEA,SAAiC;AAC/B,UAAM,UAAU,KAAK,OAAO,EAAE;AAC9B,UAAM,SAAS,IAAI,QAAQ,SAAS,CAAC,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC;AAC5E,UAAM,SAAS,IAAI;AAAA,MACjB,CAAC,GAAG,MAAM,EAAE;AAAA,QACV,CAAC,CAAC,YAAY,KAAK,MACjB;AAAA,UACE;AAAA,UACA,MAAM,IAAI,CAAC,YAAY,EAAE,IAAI,OAAO,GAAG,MAAM,WAAW,SAAS,CAAC,GAAG,OAAO,EAAE;AAAA,QAChF,GAAG;AAAA,MACP;AAAA,IACF;AACA,WAAO,QAAQ,IAAI,CAAC,WAAW;AAC7B,YAAM,EAAE,IAAI,OAAO,UAAU,MAAM,WAAW,OAAO,IAAI;AACzD,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,QACzC,GAAI,OAAO,IAAI,MAAM,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,MAChD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,IAAY;AACjB,UAAM,SAAS,KAAK,UAAU,EAAE,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE;AACvE,QAAI,CAAC,OAAQ,QAAO;AACpB,WAAO;AAAA,MACL,MAAM,OAAO,SAAS,UAAW,UAAqB;AAAA,MACtD,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,YAAuC;AACrC,WAAO,KAAK,OAAO,EAAE,aAAa,CAAC;AAAA,EACrC;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,SAAK,OAAO,EAAE;AACd,UAAM,KAAK,UAAU,OAAO,IAAI,kBAAkB;AAAA,EACpD;AAAA,EAEA,WAA+B;AAC7B,WAAO,KAAK,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,MAAM;AAC3D,YAAM,MAAM,KAAK,MAAM,IAAI,QAAQ,EAAE;AACrC,YAAM,UAAU,MAAM,EAAE,GAAG,SAAS,IAAI,IAAI;AAC5C,YAAM,SAAS,KAAK,SAAS,IAAI,QAAQ,EAAE;AAC3C,YAAM,QAAQ,KAAK,SAAS,IAAI,QAAQ,EAAE,IACtC;AAAA,QACE,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,GAAI,SAAS,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC;AAAA,MAC5C,IACA;AACJ,aAAO,QAAQ,EAAE,GAAG,OAAO,MAAM,IAAI;AAAA,IACvC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QACJ,IACA,QACA,QACA,SACe;AACf,UAAM,UACJ,KAAK,OAAO,EAAE,SAAS,KAAK,CAAC,cAAc,UAAU,OAAO,EAAE,KAAK,KAAK,OAAO,EAAE;AACnF,UAAM,MAAM,SAAS,UAAU;AAC/B,UAAM,QAAQ,SAAS,EAAE,GAAG,OAAO,IAAI;AACvC,UAAM,QAAQ,SAAS,WAAW;AAClC,QAAI,SAAS,SAAS,WAAW,gBAAgB,IAAI,EAAE,KAAK,WAAW,UAAa,CAAC;AACnF,aAAO,KAAK,QAAQ,IAAI,KAAK;AAC/B,UAAM,QAAQ,SAAS,SAAS,WAAW,QAAQ,OAAO,MAAM,KAAK,YAAY,KAAK;AACtF,QAAI,MAAO,MAAK,OAAO,EAAE;AACzB,QAAI,WAAW,QAAW;AACxB,YAAM,KAAK,UAAU,QAAQ,IAAI,QAAQ,OAAO,kBAAkB;AAClE;AAAA,IACF;AACA,QAAI,SAAS,SAAS,WAAW,CAAC,SAAS,CAAC,MAAO,OAAM,IAAI,MAAM,GAAG,EAAE,kBAAkB;AAC1F,QAAI,CAAC,OAAO;AACV,UAAI,SAAS,UAAU,QAAS,OAAM,IAAI,MAAM,GAAG,EAAE,mBAAmB;AACxE,YAAM,KAAK,UAAU,QAAQ,IAAI,MAAM,OAAO,kBAAkB;AAChE;AAAA,IACF;AACA,UAAM,SAAS,MAAM,KAAK,QAAQ,IAAI,KAAK;AAC3C,QAAI,OAAO,WAAW,UAAU;AAC9B,UAAI,CAAC,IAAK,OAAM,IAAI,MAAM,mBAAmB;AAC7C,YAAM,KAAK,UAAU,QAAQ,IAAI,QAAQ,OAAO,kBAAkB;AAClE;AAAA,IACF;AACA,QAAI,QAAQ,WAAW,KAAM,OAAM,IAAI,MAAM,UAAU;AACvD,UAAM,KAAK,UAAU,QAAQ,IAAI,MAAM,OAAO,kBAAkB;AAAA,EAClE;AAAA,EAEA,OAAO,IAA6B;AAClC,UAAM,aAAa,IAAI,gBAAgB;AACvC,SAAK,SACF,IAAI,EAAE,GACL,MAAM,IAAI,aAAa,sCAAsC,YAAY,CAAC;AAC9E,SAAK,SAAS,IAAI,IAAI,UAAU;AAChC,SAAK,SAAS,OAAO,EAAE;AACvB,SAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,IAAY,YAAmC;AAClD,QAAI,KAAK,SAAS,IAAI,EAAE,MAAM,YAAY;AACxC,WAAK,SAAS,OAAO,EAAE;AACvB,WAAK,SAAS,OAAO,EAAE;AAAA,IACzB;AACA,SAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,EACvC;AAAA,EAEA,MAAM,QAAQ,IAAY,OAAqD;AAC7E,UAAM,QAAQ,KAAK,MAAM;AACzB,UAAM,aAAa,KAAK,OAAO,EAAE;AACjC,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,gBAAgB,QAAQ,kBAAkB;AAC1D,QAAI;AACF,YAAM,UAAW,MAAM;AAAA,QACrB,KAAK,UAAU,OAAO,IAAI,OAAO;AAAA,QACjC;AAAA,MACF;AACA,UAAI,CAAC,WAAW,CAAC,SAAS,QAAQ,GAAG,EAAG,OAAM,IAAI,MAAM,UAAU;AAClE,YAAM,OAAO,OAAO,QAAQ,SAAS,YAAY,QAAQ,OAAO,QAAQ,OAAO;AAC/E,WAAK,SAAS,IAAI,IAAI,EAAE,KAAK,QAAQ,KAAK,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC,EAAG,CAAC;AACrE,WAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AACrC,UAAI,MAAO,OAAM,SAAS,OAAO,QAAQ;AACzC,YAAM,aAAa,KAAK,UAAU,QAAQ,IAAI,MAAM,OAAO,OAAO,GAAG,MAAM;AAAA,IAC7E,SAAS,OAAO;AACd,aAAO,eAAe;AACtB,YAAM,SAAS,KAAK;AAAA,IACtB,UAAE;AACA,aAAO,MAAM;AACb,WAAK,KAAK,IAAI,UAAU;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,IAAY,OAAwC;AAChE,UAAM,aAAa,KAAK,OAAO,EAAE;AACjC,QAAI;AACF,YAAM,MAAM,MAAM;AAAA,QAChB;AAAA,QACA,MAAM,KAAK,UAAU,OAAO,IAAI,kBAAkB;AAAA,QAClD;AAAA,UACE,QAAQ,WAAW;AAAA,QACrB;AAAA,MACF,EAAE,MAAM,CAAC,UAAmB;AAC1B,mBAAW,OAAO,eAAe;AACjC,cAAM,SAAS,KAAK;AAAA,MACtB,CAAC;AACD,iBAAW,OAAO,eAAe;AACjC,aAAO;AAAA,IACT,UAAE;AACA,WAAK,KAAK,IAAI,UAAU;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,OAAO,IAAkB;AACvB,UAAM,aAAa,KAAK,SAAS,IAAI,EAAE;AACvC,QAAI,CAAC,WAAY;AACjB,SAAK,SAAS,OAAO,EAAE;AACvB,SAAK,SAAS,OAAO,EAAE;AACvB,eAAW,MAAM,IAAI,aAAa,8BAA8B,YAAY,CAAC;AAC7E,SAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AAAA,EACvC;AAAA,EAEA,WAAW,IAAkB;AAC3B;AAAA,MAAQ,KAAK,UAAU,WAAW,IAAI,kBAAkB;AAAA,MAAG;AAAA,MAAuB,CAAC,SACjF,KAAK,OAAO,OAAO,IAAI;AAAA,IACzB;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,4 @@
1
+ import type { Provider } from '@earendil-works/pi-ai';
2
+ export declare function codexKey(placeholder: string, account: string): string;
3
+ export declare function codexProvider(): Provider;
4
+ export declare function codexFetch(inner: typeof fetch): typeof fetch;
@@ -0,0 +1,24 @@
1
+ import type { Context } from '@earendil-works/chord';
2
+ import type { OAuthCredential, Provider } from '@earendil-works/pi-ai';
3
+ import { type DeviceSignIn } from './sign-ins.ts';
4
+ export declare const ATTACH_MS = 60000;
5
+ export interface ProviderGrant {
6
+ provider: string;
7
+ name: string;
8
+ response: Uint8Array;
9
+ settings?: Record<string, string>;
10
+ }
11
+ export type Grant = (grant: ProviderGrant) => Promise<unknown>;
12
+ export interface DeviceFlows {
13
+ has(providerId: string): boolean;
14
+ start(provider: Provider, name: string, context: Context): Promise<DeviceSignIn>;
15
+ finish(providerId: string, context: Context): Promise<void>;
16
+ stop(providerId: string): void;
17
+ }
18
+ export declare function keptError(error: unknown): Error;
19
+ export declare function flowError(error: unknown): Error;
20
+ export declare function tokenResponse(credential: OAuthCredential, now: number): Uint8Array;
21
+ export declare function deviceFlows(grant: Grant, options?: {
22
+ attachMs?: number;
23
+ now?: () => number;
24
+ }): DeviceFlows;
@@ -24,6 +24,7 @@ export interface KeyProvider {
24
24
  description: string;
25
25
  keyUrl: string;
26
26
  cors: boolean;
27
+ signIn?: true;
27
28
  fields?: readonly FieldSpec[];
28
29
  }
29
30
  export declare function httpsBase(value: string): URL | undefined;
@@ -49,6 +49,12 @@ export declare class Vault implements Scrub {
49
49
  mcp(server: string, request: OutgoingRequest): Promise<OutgoingRequest>;
50
50
  records(): Promise<AgentRecord[]>;
51
51
  grant(server: string, response: string | Uint8Array, oauth: OAuthConfig, name?: string): Promise<Granted>;
52
+ grantProvider(grant: {
53
+ provider: string;
54
+ name: string;
55
+ response: Uint8Array;
56
+ settings?: Record<string, string>;
57
+ }): Promise<Omit<Granted, 'response'>>;
52
58
  refresh(target: RefreshTarget, name?: string): Promise<string>;
53
59
  endpoints(set: EndpointSet): Promise<void>;
54
60
  stream(): ScrubStream;
@@ -11,6 +11,7 @@ import type { GuestDraft, GuestGates, GuestSeat } from './guests/seats.ts';
11
11
  import type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';
12
12
  import type { AgentRemote } from './remote/host.ts';
13
13
  import type { VaultState } from './secrets/vault.ts';
14
+ import type { DeviceSignIn } from './sign-ins.ts';
14
15
  import type { SkillPackage, SkillSource } from './skills/skills.ts';
15
16
  import type { Sprinkle } from './sprinkles/kind.ts';
16
17
  export type SendMode = 'steer' | 'followUp' | 'reject';
@@ -409,7 +410,7 @@ export interface AgentSettings {
409
410
  disconnect(providerId: string, context: Context): Promise<void>;
410
411
  remove(providerId: string, context: Context): Promise<void>;
411
412
  serverUrl(providerId: string, context: Context): Promise<string | null>;
412
- signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;
413
+ signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | DeviceSignIn | null>;
413
414
  dismissMoved(context: Context): Promise<void>;
414
415
  }
415
416
  export declare const SETTINGS_METHODS: ("connect" | "disconnect" | "dismissMoved" | "remove" | "serverUrl" | "signIn")[];
@@ -1,11 +1,13 @@
1
1
  import type { CredentialStore, ModelsStore, Provider } from '@earendil-works/pi-ai';
2
2
  import { type MutableModels } from '@earendil-works/pi-ai/models';
3
3
  import { type Budget } from './adobe.ts';
4
+ import { type DeviceFlows } from './device.ts';
4
5
  import type { McpAccounts } from './mcp/index.ts';
5
6
  import type { Reach } from './net.ts';
6
7
  import type { KeysMoved } from './secrets/legacy.ts';
7
8
  import type { VaultRecords } from './secrets/records.ts';
8
9
  import type { PlainStore } from './secrets/store.ts';
10
+ import type { Vault } from './secrets/vault.ts';
9
11
  import type { AccountField, AgentSettings } from './services.ts';
10
12
  export { BEDROCK, PREFERRED_MODELS, preferredModel } from './preferred.ts';
11
13
  export declare const DEFAULT_MODEL: {
@@ -45,4 +47,6 @@ export declare function createAgentSettings(models: MutableModels, sources: Sett
45
47
  mcp?: McpAccounts;
46
48
  moved?: KeysMoved;
47
49
  reach?: Reach;
50
+ vault?: Pick<Vault, 'connected' | 'needed' | 'grantProvider'>;
51
+ flows?: DeviceFlows;
48
52
  }): Promise<AgentSettings>;
@@ -0,0 +1,17 @@
1
+ export declare const CODEX = "openai-codex";
2
+ export declare const CODEX_ACCOUNT = "CHATGPT_ACCOUNT_ID";
3
+ export declare const DEVICE_SIGN_INS: ReadonlySet<string>;
4
+ export declare const SIGN_IN_REFUSED = "The sign-in was refused.";
5
+ export declare const SIGN_IN_UNFINISHED = "The sign-in didn't finish. Try again.";
6
+ export declare const NAME_TAKEN = "This name holds another provider's key.";
7
+ export declare const SIGN_IN_LOCKED = "Unlock the vault to sign in.";
8
+ export declare const SIGN_IN_UNKEPT = "The vault didn't keep the sign-in. Try again.";
9
+ export declare const DEVICE_NEEDS_VAULT = "Signing in needs seven's vault: update seven";
10
+ export interface DeviceSignIn {
11
+ url: string;
12
+ code?: string;
13
+ }
14
+ export interface ConnectOptions {
15
+ method?: 'sign-in' | 'key';
16
+ }
17
+ export declare function httpsUrl(value: unknown): value is string;
@@ -21,6 +21,7 @@ export interface McpLoginHost {
21
21
  timeoutMs?: number;
22
22
  }
23
23
  export declare function safeAuthorizationUrl(value: string): boolean;
24
+ export declare function untilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<T>;
24
25
  export declare function mcpLogin(host?: McpLoginHost): (providerId: string, signIn: () => Promise<SignIn | McpSignIn | null>, options: {
25
26
  signal: AbortSignal;
26
27
  }) => Promise<string>;
@@ -1,7 +1,9 @@
1
1
  import type { Account, ModelOption, Settings, SettingsEvents, SettingsPort } from '@ai-ecoverse/slicc-spectrum/ui';
2
2
  import type { AgentSettings, ProviderOption, SignIn } from '../services.ts';
3
+ import { type ConnectOptions } from '../sign-ins.ts';
3
4
  import type { AgentAdapter } from './agent-port.ts';
4
5
  import { Emitter } from './emitter.ts';
6
+ import { type Popup } from './mcp-login.ts';
5
7
  export declare const SETTINGS_KEY = "slicc-agent.settings";
6
8
  export type Sealed = {
7
9
  sealed: true;
@@ -11,20 +13,21 @@ export type Login = (providerId: string, signIn: () => Promise<SignIn | null>, o
11
13
  }) => Promise<string | Sealed>;
12
14
  export declare const SIGN_IN_NEEDS_VAULT = "Adobe sign-in needs seven's vault: update seven";
13
15
  export declare const UNFINISHED = "The sign-in didn't finish. Try again.";
16
+ export type OpenPopup = () => Popup | null;
14
17
  export declare function readable(error: unknown): Error;
15
18
  type Events = SettingsEvents & {
16
19
  providers: readonly ProviderOption[];
17
20
  };
18
21
  export declare class SettingsAdapter extends Emitter<Events> implements SettingsPort {
19
22
  #private;
20
- constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null, login?: Login | null, mcp?: Login);
23
+ constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null, login?: Login | null, mcp?: Login, open?: OpenPopup);
21
24
  get(): Settings;
22
25
  update(patch: Partial<Settings>): void;
23
26
  models(): readonly ModelOption[];
24
27
  providers(): readonly ProviderOption[];
25
28
  remove(id: string): Promise<void>;
26
29
  accounts(): readonly Account[];
27
- connect(id: string, secret?: string, fields?: Record<string, string>): Promise<void>;
30
+ connect(id: string, secret?: string, fields?: Record<string, string>, options?: ConnectOptions): Promise<void>;
28
31
  cancel(id: string): void;
29
32
  disconnect(id: string): void;
30
33
  }