@preventive/triage 1.0.0-alpha.17 → 1.0.0-alpha.19
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.
- package/api/reap.ts +13 -75
- package/common/server-info.ts +6 -4
- package/out/client-managed-import.js +81 -0
- package/out/client-managed.js +68 -41
- package/out/client-sync.js +14 -14
- package/out/graph.js +10 -10
- package/out/index.html +1 -0
- package/out/view.css +1 -1
- package/out/view.js +179 -142
- package/package.json +16 -6
- package/report/index.js +2 -1
- package/report/src/finding.js +12 -0
- package/report/src/security.js +63 -0
- package/server-common/database-config.ts +16 -0
- package/server-common/initialize.ts +18 -0
- package/server-common/npm-advisories.ts +101 -0
- package/server-common/reap.ts +48 -0
- package/server-common/standalone.ts +29 -0
- package/server-common/storage-log.ts +34 -0
- package/server-common/vercel-blob.ts +110 -0
- package/server-e2e/app.ts +485 -0
- package/server-e2e/cli.js +7 -2
- package/server-e2e/config.ts +36 -40
- package/server-e2e/db-neon.ts +1 -1
- package/server-e2e/db.ts +1 -1
- package/server-e2e/http.ts +12 -2
- package/server-e2e/index.ts +12 -481
- package/server-e2e/lifecycle.ts +59 -172
- package/server-e2e/neon-driver.ts +2 -2
- package/server-e2e/npm-proxy.ts +10 -143
- package/server-e2e/objstore/blob-vercel.ts +4 -108
- package/server-e2e/objstore/init.ts +15 -23
- package/server-e2e/objstore/store-neon.ts +5 -9
- package/server-e2e/static.ts +11 -17
- package/out/provider-icons/claude.svg +0 -1
- package/out/provider-icons/deepseek.svg +0 -1
- package/out/provider-icons/google.svg +0 -1
- package/out/provider-icons/grok.svg +0 -1
- package/out/provider-icons/moonshot.svg +0 -1
- package/out/provider-icons/nvidia.svg +0 -1
- package/out/provider-icons/openai.svg +0 -1
- package/out/provider-icons/openrouter.svg +0 -1
- package/out/provider-icons/qwen.svg +0 -1
- package/out/provider-icons/zai.svg +0 -1
|
@@ -18,9 +18,9 @@ export type ObjstoreInitDeps = {
|
|
|
18
18
|
// the workspace_revision handle in server-e2e/db.ts.
|
|
19
19
|
handle: Handle
|
|
20
20
|
reapIntervalMs: number
|
|
21
|
-
//
|
|
21
|
+
// Automatic-sweep switch (OBJSTORE_REAP_DISABLED). When true, NEITHER the boot
|
|
22
22
|
// sweep nor the periodic timer runs: `startupReap` resolves immediately
|
|
23
|
-
// and
|
|
23
|
+
// and no timer is installed. Orphaned/superseded blobs and stale
|
|
24
24
|
// staging rows then accumulate unbounded — only safe if an external job
|
|
25
25
|
// handles GC. Omitted/false → reaper runs (the default). See config.ts.
|
|
26
26
|
reapDisabled?: boolean
|
|
@@ -59,6 +59,7 @@ export type ObjstoreInitDeps = {
|
|
|
59
59
|
export type ObjstoreInit = {
|
|
60
60
|
handlers: ObjstoreHandlers
|
|
61
61
|
restDeps: ObjstoreRestDeps
|
|
62
|
+
reap: () => Promise<void>
|
|
62
63
|
startupReap: Promise<void>
|
|
63
64
|
// Cancels the periodic timer AND resolves only after any
|
|
64
65
|
// currently-in-flight sweep has finished, so shutdown can safely
|
|
@@ -102,31 +103,22 @@ export function initObjstore(deps: ObjstoreInitDeps): ObjstoreInit {
|
|
|
102
103
|
let inFlight: Promise<void> | null = null
|
|
103
104
|
function enqueueSweep(): Promise<void> {
|
|
104
105
|
if (inFlight) return inFlight
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
// cleaned, and operators need to see it. Inner catch makes the
|
|
108
|
-
// promise resolve so callers (startupReap awaiter + setInterval)
|
|
109
|
-
// don't have to handle rejection.
|
|
110
|
-
const p = reapOrphans(handle).catch((err) => {
|
|
111
|
-
console.warn('objstore reaper error:', errStack(err))
|
|
112
|
-
}).finally(() => { if (inFlight === p) inFlight = null })
|
|
106
|
+
// Keep failures visible to explicit callers; automatic sweeps log them.
|
|
107
|
+
const p = reapOrphans(handle).finally(() => { if (inFlight === p) inFlight = null })
|
|
113
108
|
inFlight = p
|
|
114
109
|
return p
|
|
115
110
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
//
|
|
119
|
-
// nothing to clear or drain. Loud, unconditional warning — with GC off,
|
|
120
|
-
// orphaned/superseded blobs and stale staging rows are never reclaimed
|
|
121
|
-
// (they accumulate until an external job, if any, collects them).
|
|
111
|
+
const drain = async () => { if (inFlight) await inFlight.catch(() => {}) }
|
|
112
|
+
const automaticSweep = () => enqueueSweep().catch(err => console.warn('objstore reaper error:', errStack(err)))
|
|
113
|
+
// Explicit cleanup remains available when automatic sweeps are disabled.
|
|
122
114
|
if (deps.reapDisabled) {
|
|
123
|
-
console.warn('objstore: reaper DISABLED (OBJSTORE_REAP_DISABLED) —
|
|
124
|
-
return { handlers, restDeps, startupReap: Promise.resolve(), stopReaper:
|
|
115
|
+
console.warn('objstore: automatic reaper DISABLED (OBJSTORE_REAP_DISABLED) — use /api/reap or an external cleanup job')
|
|
116
|
+
return { handlers, restDeps, reap: enqueueSweep, startupReap: Promise.resolve(), stopReaper: drain }
|
|
125
117
|
}
|
|
126
118
|
// Caller awaits this before accepting traffic so a fresh boot
|
|
127
119
|
// can't hand out list / fetch / put-begin against a tag whose
|
|
128
120
|
// on-disk state still has stranded files from a prior crash.
|
|
129
|
-
const startupReap =
|
|
121
|
+
const startupReap = automaticSweep()
|
|
130
122
|
// Jittered start of the periodic timer. Multi-replica deploys
|
|
131
123
|
// (Neon + Vercel Blob) commonly boot N replicas in tight lock-step
|
|
132
124
|
// (deploy rollout, cluster restart), which would otherwise sync every
|
|
@@ -139,20 +131,20 @@ export function initObjstore(deps: ObjstoreInitDeps): ObjstoreInit {
|
|
|
139
131
|
let reapTimer: ReturnType<typeof setInterval> | null = null
|
|
140
132
|
const jitterMs = Math.floor(Math.random() * deps.reapIntervalMs)
|
|
141
133
|
const firstTimer = setTimeout(() => {
|
|
142
|
-
|
|
143
|
-
reapTimer = setInterval(
|
|
134
|
+
void automaticSweep()
|
|
135
|
+
reapTimer = setInterval(automaticSweep, deps.reapIntervalMs)
|
|
144
136
|
reapTimer.unref?.()
|
|
145
137
|
}, deps.reapIntervalMs + jitterMs)
|
|
146
138
|
firstTimer.unref?.()
|
|
147
139
|
return {
|
|
148
|
-
handlers, restDeps, startupReap,
|
|
140
|
+
handlers, restDeps, reap: enqueueSweep, startupReap,
|
|
149
141
|
stopReaper: async () => {
|
|
150
142
|
clearTimeout(firstTimer)
|
|
151
143
|
if (reapTimer) clearInterval(reapTimer)
|
|
152
144
|
// Drain whichever sweep is currently running (startup or
|
|
153
145
|
// periodic) — either could be mid-readdir/unlink at SIGTERM
|
|
154
146
|
// time and would otherwise outlive `handle.close()`.
|
|
155
|
-
|
|
147
|
+
await drain()
|
|
156
148
|
},
|
|
157
149
|
}
|
|
158
150
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// dialect on the wire.
|
|
5
5
|
//
|
|
6
6
|
// `@neondatabase/serverless` is an OPTIONAL peer dep — selected by
|
|
7
|
-
// the
|
|
7
|
+
// the configured database URL branch in `server-e2e/index.ts`. The peer dep
|
|
8
8
|
// itself is loaded lazily inside `openNeonObjstore` below. A single
|
|
9
9
|
// Neon project / database holds both `workspace_revision` and the
|
|
10
10
|
// two objstore tables; each plane opens its own stateless
|
|
@@ -13,14 +13,10 @@
|
|
|
13
13
|
// release.
|
|
14
14
|
//
|
|
15
15
|
// Byte plane: passed in as a `BlobBackend` (./blob.ts). The
|
|
16
|
-
// supported
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// alongside DATABASE_URL.
|
|
21
|
-
// - Neon + local FS (development / operator escape hatch — bytes
|
|
22
|
-
// still need to live on a shared filesystem if you run more
|
|
23
|
-
// than one replica).
|
|
16
|
+
// supported Neon pairing selected by server-e2e/index.ts is Vercel
|
|
17
|
+
// Blob Private Storage. DATABASE_URL or E2E_DATABASE_URL plus BLOB_READ_WRITE_TOKEN
|
|
18
|
+
// is required; the launcher never selects Neon + local FS. Tests
|
|
19
|
+
// can inject a local-FS backend directly through this adapter.
|
|
24
20
|
|
|
25
21
|
import type { BlobBackend } from './blob.ts'
|
|
26
22
|
import type { AllStmt, GetStmt, RunStmt } from '../db-stmt.ts'
|
package/server-e2e/static.ts
CHANGED
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
// request URL is only used as a Map key, never joined with the
|
|
8
8
|
// filesystem — so the handler has no path-traversal surface at all:
|
|
9
9
|
// `..`, percent-encoded slashes and absolute-form URIs all just
|
|
10
|
-
// produce a key that isn't in the map and 404.
|
|
11
|
-
// the one explicitly allowed asset subdirectory.
|
|
10
|
+
// produce a key that isn't in the map and 404.
|
|
12
11
|
//
|
|
13
12
|
// Compression: every entry whose extension is in COMPRESSIBLE gets
|
|
14
13
|
// pre-computed brotli + gzip at boot. The handler picks brotli over
|
|
@@ -104,8 +103,10 @@ export type StaticHandler = (req: HttpRequest, res: ServerResponse) => boolean
|
|
|
104
103
|
// caller falls through to its next route. Missing `staticDir`
|
|
105
104
|
// (pre-build case) logs a warning and returns a handler that always
|
|
106
105
|
// answers false; the API/WS planes are unaffected.
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
type StaticOptions = { transformIndex?: (html: string) => string, indexOnly?: boolean }
|
|
107
|
+
|
|
108
|
+
export function loadStatic(staticDir: string, deepviewScanServer: string | null = null, options: StaticOptions = {}): StaticHandler {
|
|
109
|
+
const files = readStaticFiles(staticDir, deepviewScanServer, options)
|
|
109
110
|
return function handleStatic(req: HttpRequest, res: ServerResponse): boolean {
|
|
110
111
|
if (req.method !== 'GET' && req.method !== 'HEAD') return false
|
|
111
112
|
if (typeof req.url !== 'string') return false
|
|
@@ -153,7 +154,7 @@ export function loadStatic(staticDir: string, deepviewScanServer: string | null
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
function readStaticFiles(staticDir: string, deepviewScanServer: string | null): ReadonlyMap<string, StaticEntry> {
|
|
157
|
+
function readStaticFiles(staticDir: string, deepviewScanServer: string | null, options: StaticOptions): ReadonlyMap<string, StaticEntry> {
|
|
157
158
|
const files = new Map<string, StaticEntry>()
|
|
158
159
|
let entries
|
|
159
160
|
try { entries = readdirSync(staticDir, { withFileTypes: true }) } catch (err) {
|
|
@@ -167,24 +168,17 @@ function readStaticFiles(staticDir: string, deepviewScanServer: string | null):
|
|
|
167
168
|
throw err
|
|
168
169
|
}
|
|
169
170
|
for (const entry of entries) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const name = `${entry.name}/${icon.name}`
|
|
174
|
-
files.set(name, buildEntry(staticDir, name))
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
// Exclude other subdirectories, symlinks and non-file entries.
|
|
178
|
-
if (!entry.isFile()) continue
|
|
179
|
-
files.set(entry.name, buildEntry(staticDir, entry.name, deepviewScanServer))
|
|
171
|
+
// Exclude subdirectories, symlinks and non-file entries.
|
|
172
|
+
if (!entry.isFile() || (options.indexOnly && entry.name !== 'index.html')) continue
|
|
173
|
+
files.set(entry.name, buildEntry(staticDir, entry.name, deepviewScanServer, options.transformIndex))
|
|
180
174
|
}
|
|
181
175
|
return files
|
|
182
176
|
}
|
|
183
177
|
|
|
184
|
-
function buildEntry(staticDir: string, name: string, deepviewScanServer: string | null = null): StaticEntry {
|
|
178
|
+
function buildEntry(staticDir: string, name: string, deepviewScanServer: string | null = null, transformIndex: (html: string) => string = html => html): StaticEntry {
|
|
185
179
|
const ext = extname(name)
|
|
186
180
|
const source = readFileSync(join(staticDir, name))
|
|
187
|
-
const raw = name === 'index.html' ? Buffer.from(scanServerHtml(source.toString('utf8'), deepviewScanServer)) : source
|
|
181
|
+
const raw = name === 'index.html' ? Buffer.from(transformIndex(scanServerHtml(source.toString('utf8'), deepviewScanServer))) : source
|
|
188
182
|
const type = CONTENT_TYPE[ext] ?? 'application/octet-stream'
|
|
189
183
|
// HTML: lift `<link rel="(module)preload" …>` into a Link header and
|
|
190
184
|
// drop the tags from the served body. ETag + compression run against
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>DeepSeek</title><path d="M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Google</title><path d="M23 12.245c0-.905-.075-1.565-.236-2.25h-10.54v4.083h6.186c-.124 1.014-.797 2.542-2.294 3.569l-.021.136 3.332 2.53.23.022C21.779 18.417 23 15.593 23 12.245z"></path><path d="M12.225 23c3.03 0 5.574-.978 7.433-2.665l-3.542-2.688c-.948.648-2.22 1.1-3.891 1.1a6.745 6.745 0 01-6.386-4.572l-.132.011-3.465 2.628-.045.124C4.043 20.531 7.835 23 12.225 23z"></path><path d="M5.84 14.175A6.65 6.65 0 015.463 12c0-.758.138-1.491.361-2.175l-.006-.147-3.508-2.67-.115.054A10.831 10.831 0 001 12c0 1.772.436 3.447 1.197 4.938l3.642-2.763z"></path><path d="M12.225 5.253c2.108 0 3.529.892 4.34 1.638l3.167-3.031C17.787 2.088 15.255 1 12.225 1 7.834 1 4.043 3.469 2.197 7.062l3.63 2.763a6.77 6.77 0 016.398-4.572z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Grok</title><path d="M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>MoonshotAI</title><path d="M1.052 16.916l9.539 2.552a21.007 21.007 0 00.06 2.033l5.956 1.593a11.997 11.997 0 01-5.586.865l-.18-.016-.044-.004-.084-.009-.094-.01a11.605 11.605 0 01-.157-.02l-.107-.014-.11-.016a11.962 11.962 0 01-.32-.051l-.042-.008-.075-.013-.107-.02-.07-.015-.093-.019-.075-.016-.095-.02-.097-.023-.094-.022-.068-.017-.088-.022-.09-.024-.095-.025-.082-.023-.109-.03-.062-.02-.084-.025-.093-.028-.105-.034-.058-.019-.08-.026-.09-.031-.066-.024a6.293 6.293 0 01-.044-.015l-.068-.025-.101-.037-.057-.022-.08-.03-.087-.035-.088-.035-.079-.032-.095-.04-.063-.028-.063-.027a5.655 5.655 0 01-.041-.018l-.066-.03-.103-.047-.052-.024-.096-.046-.062-.03-.084-.04-.086-.044-.093-.047-.052-.027-.103-.055-.057-.03-.058-.032a6.49 6.49 0 01-.046-.026l-.094-.053-.06-.034-.051-.03-.072-.041-.082-.05-.093-.056-.052-.032-.084-.053-.061-.039-.079-.05-.07-.047-.053-.035a7.785 7.785 0 01-.054-.036l-.044-.03-.044-.03a6.066 6.066 0 01-.04-.028l-.057-.04-.076-.054-.069-.05-.074-.054-.056-.042-.076-.057-.076-.059-.086-.067-.045-.035-.064-.052-.074-.06-.089-.073-.046-.039-.046-.039a7.516 7.516 0 01-.043-.037l-.045-.04-.061-.053-.07-.062-.068-.06-.062-.058-.067-.062-.053-.05-.088-.084a13.28 13.28 0 01-.099-.097l-.029-.028-.041-.042-.069-.07-.05-.051-.05-.053a6.457 6.457 0 01-.168-.179l-.08-.088-.062-.07-.071-.08-.042-.049-.053-.062-.058-.068-.046-.056a7.175 7.175 0 01-.027-.033l-.045-.055-.066-.082-.041-.052-.05-.064-.02-.025a11.99 11.99 0 01-1.44-2.402zm-1.02-5.794l11.353 3.037a20.468 20.468 0 00-.469 2.011l10.817 2.894a12.076 12.076 0 01-1.845 2.005L.657 15.923l-.016-.046-.035-.104a11.965 11.965 0 01-.05-.153l-.007-.023a11.896 11.896 0 01-.207-.741l-.03-.126-.018-.08-.021-.097-.018-.081-.018-.09-.017-.084-.018-.094c-.026-.141-.05-.283-.071-.426l-.017-.118-.011-.083-.013-.102a12.01 12.01 0 01-.019-.161l-.005-.047a12.12 12.12 0 01-.034-2.145zm1.593-5.15l11.948 3.196c-.368.605-.705 1.231-1.01 1.875l11.295 3.022c-.142.82-.368 1.612-.668 2.365l-11.55-3.09L.124 10.26l.015-.1.008-.049.01-.067.015-.087.018-.098c.026-.148.056-.295.088-.442l.028-.124.02-.085.024-.097c.022-.09.045-.18.07-.268l.028-.102.023-.083.03-.1.025-.082.03-.096.026-.082.031-.095a11.896 11.896 0 011.01-2.232zm4.442-4.4L17.352 4.59a20.77 20.77 0 00-1.688 1.721l7.823 2.093c.267.852.442 1.744.513 2.665L2.106 5.213l.045-.065.027-.04.04-.055.046-.065.055-.076.054-.072.064-.086.05-.065.057-.073.055-.07.06-.074.055-.069.065-.077.054-.066.066-.077.053-.06.072-.082.053-.06.067-.074.054-.058.073-.078.058-.06.063-.067.168-.17.1-.098.059-.056.076-.071a12.084 12.084 0 012.272-1.677zM12.017 0h.097l.082.001.069.001.054.002.068.002.046.001.076.003.047.002.06.003.054.002.087.005.105.007.144.011.088.007.044.004.077.008.082.008.047.005.102.012.05.006.108.014.081.01.042.006.065.01.207.032.07.012.065.011.14.026.092.018.11.022.046.01.075.016.041.01L14.7.3l.042.01.065.015.049.012.071.017.096.024.112.03.113.03.113.032.05.015.07.02.078.024.073.023.05.016.05.016.076.025.099.033.102.036.048.017.064.023.093.034.11.041.116.045.1.04.047.02.06.024.041.018.063.026.04.018.057.025.11.048.1.046.074.035.075.036.06.028.092.046.091.045.102.052.053.028.049.026.046.024.06.033.041.022.052.029.088.05.106.06.087.051.057.034.053.032.096.059.088.055.098.062.036.024.064.041.084.056.04.027.062.042.062.043.023.017c.054.037.108.075.161.114l.083.06.065.048.056.043.086.065.082.064.04.03.05.041.086.069.079.065.085.071c.712.6 1.353 1.283 1.909 2.031L7.222.994l.062-.027.065-.028.081-.034.086-.035c.113-.045.227-.09.341-.131l.096-.035.093-.033.084-.03.096-.031c.087-.03.176-.058.264-.085l.091-.027.086-.025.102-.03.085-.023.1-.026L9.04.37l.09-.023.091-.022.095-.022.09-.02.098-.021.091-.02.095-.018.092-.018.1-.018.091-.016.098-.017.092-.014.097-.015.092-.013.102-.013.091-.012.105-.012.09-.01.105-.01c.093-.01.186-.018.28-.024l.106-.008.09-.005.11-.006.093-.004.1-.004.097-.002.099-.002.197-.002z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Nvidia</title><path d="M10.212 8.976V7.62c.127-.01.256-.017.388-.021 3.596-.117 5.957 3.184 5.957 3.184s-2.548 3.647-5.282 3.647a3.227 3.227 0 01-1.063-.175v-4.109c1.4.174 1.681.812 2.523 2.258l1.873-1.627a4.905 4.905 0 00-3.67-1.846 6.594 6.594 0 00-.729.044m0-4.476v2.025c.13-.01.259-.019.388-.024 5.002-.174 8.261 4.226 8.261 4.226s-3.743 4.69-7.643 4.69c-.338 0-.675-.031-1.007-.092v1.25c.278.038.558.057.838.057 3.629 0 6.253-1.91 8.794-4.169.421.347 2.146 1.193 2.501 1.564-2.416 2.083-8.048 3.763-11.24 3.763-.308 0-.603-.02-.894-.048V19.5H24v-15H10.21zm0 9.756v1.068c-3.356-.616-4.287-4.21-4.287-4.21a7.173 7.173 0 014.287-2.138v1.172h-.005a3.182 3.182 0 00-2.502 1.178s.615 2.276 2.507 2.931m-5.961-3.3c1.436-1.935 3.604-3.148 5.961-3.336V6.523C5.81 6.887 2 10.723 2 10.723s2.158 6.427 8.21 7.015v-1.166C5.77 16 4.25 10.958 4.25 10.958h-.002z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenAI</title><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenRouter</title><path d="M18.654 3.87a5.087 5.087 0 110 10.174L23.7 19.09c.64.641.187 1.737-.72 1.737H8.48a8.479 8.479 0 010-16.958h10.175zM8.479 7.26a5.087 5.087 0 100 10.176 5.087 5.087 0 000-10.175z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Qwen</title><path d="M12.604 1.34c.393.69.784 1.382 1.174 2.075a.18.18 0 00.157.091h5.552c.174 0 .322.11.446.327l1.454 2.57c.19.337.24.478.024.837-.26.43-.513.864-.76 1.3l-.367.658c-.106.196-.223.28-.04.512l2.652 4.637c.172.301.111.494-.043.77-.437.785-.882 1.564-1.335 2.34-.159.272-.352.375-.68.37-.777-.016-1.552-.01-2.327.016a.099.099 0 00-.081.05 575.097 575.097 0 01-2.705 4.74c-.169.293-.38.363-.725.364-.997.003-2.002.004-3.017.002a.537.537 0 01-.465-.271l-1.335-2.323a.09.09 0 00-.083-.049H4.982c-.285.03-.553-.001-.805-.092l-1.603-2.77a.543.543 0 01-.002-.54l1.207-2.12a.198.198 0 000-.197 550.951 550.951 0 01-1.875-3.272l-.79-1.395c-.16-.31-.173-.496.095-.965.465-.813.927-1.625 1.387-2.436.132-.234.304-.334.584-.335a338.3 338.3 0 012.589-.001.124.124 0 00.107-.063l2.806-4.895a.488.488 0 01.422-.246c.524-.001 1.053 0 1.583-.006L11.704 1c.341-.003.724.032.9.34zm-3.432.403a.06.06 0 00-.052.03L6.254 6.788a.157.157 0 01-.135.078H3.253c-.056 0-.07.025-.041.074l5.81 10.156c.025.042.013.062-.034.063l-2.795.015a.218.218 0 00-.2.116l-1.32 2.31c-.044.078-.021.118.068.118l5.716.008c.046 0 .08.02.104.061l1.403 2.454c.046.081.092.082.139 0l5.006-8.76.783-1.382a.055.055 0 01.096 0l1.424 2.53a.122.122 0 00.107.062l2.763-.02a.04.04 0 00.035-.02.041.041 0 000-.04l-2.9-5.086a.108.108 0 010-.113l.293-.507 1.12-1.977c.024-.041.012-.062-.035-.062H9.2c-.059 0-.073-.026-.043-.077l1.434-2.505a.107.107 0 000-.114L9.225 1.774a.06.06 0 00-.053-.031zm6.29 8.02c.046 0 .058.02.034.06l-.832 1.465-2.613 4.585a.056.056 0 01-.05.029.058.058 0 01-.05-.029L8.498 9.841c-.02-.034-.01-.052.028-.054l.216-.012 6.722-.012z"></path></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Z.ai</title><path d="M12.105 2L9.927 4.953H.653L2.83 2h9.276zM23.254 19.048L21.078 22h-9.242l2.174-2.952h9.244zM24 2L9.264 22H0L14.736 2H24z"></path></svg>
|