Files
OmniRoute/scripts/raycast/extract-credentials.mjs
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

101 lines
3.1 KiB
JavaScript

#!/usr/bin/env node
/**
* @file extract-credentials.mjs
* @description Print Raycast Pro credentials from local macOS install (redacted preview).
*
* Usage: node scripts/raycast/extract-credentials.mjs
*
* @changes
* - [2026-07-27] [Composer] - CLI credential extractor for local Raycast
*/
import { execFileSync } from "node:child_process";
import { createHash } from "node:crypto";
import { copyFileSync, existsSync, mkdtempSync, readFileSync, rmdirSync, unlinkSync } from "node:fs";
import { homedir, tmpdir } from "node:os";
import { join } from "node:path";
const RAYCAST_SALT = "yvkwWXzxPPBAqY2tmaKrB*DvYjjMaeEf";
const RAYCAST_SUPPORT = join(homedir(), "Library", "Application Support", "com.raycast.macos");
const RAYCAST_DB = join(RAYCAST_SUPPORT, "raycast-enc.sqlite");
function redact(s, keep = 8) {
if (!s || s.length <= keep * 2) return "***";
return `${s.slice(0, keep)}${s.slice(-4)}`;
}
function readKeychain(account) {
return JSON.parse(
execFileSync("security", ["find-generic-password", "-s", "Raycast", "-a", account, "-w"], {
encoding: "utf-8",
}).trim()
);
}
function dbPassphrase() {
const keyHex = execFileSync(
"security",
["find-generic-password", "-s", "Raycast", "-a", "database_key", "-w"],
{ encoding: "utf-8" }
).trim();
return createHash("sha256")
.update(keyHex + RAYCAST_SALT)
.digest("hex");
}
function queryDb(sql) {
const tmpDir = mkdtempSync(join(tmpdir(), "raycast-extract-"));
const tmpDb = join(tmpDir, "db.sqlite");
copyFileSync(RAYCAST_DB, tmpDb);
for (const ext of ["-wal", "-shm"]) {
const src = RAYCAST_DB + ext;
if (existsSync(src)) copyFileSync(src, tmpDb + ext);
}
const passphrase = dbPassphrase();
const input = `PRAGMA key = '${passphrase}';\n.mode json\n${sql}`;
const out = execFileSync("sqlcipher", [tmpDb], { input, encoding: "utf-8" });
for (const ext of ["", "-wal", "-shm"]) {
try {
unlinkSync(tmpDb + ext);
} catch {}
}
try {
rmdirSync(tmpDir);
} catch {}
const jsonStr = out.startsWith("ok\n") ? out.slice(3) : out;
return JSON.parse(jsonStr.trim() || "[]");
}
if (process.platform !== "darwin") {
console.error("macOS only");
process.exit(1);
}
const store = readKeychain("raycast-store_credentials");
const token = store?.oauth?.access_token;
if (!token) {
console.error("No Raycast bearer token in Keychain — open Raycast and sign in");
process.exit(1);
}
const users = queryDb("SELECT analyticsId, email, username, hasProFeatures, hasBetterAI FROM user LIMIT 1;");
const user = users[0] || {};
const deviceId =
user.analyticsId ||
JSON.parse(readFileSync(join(RAYCAST_SUPPORT, "posthog.distinctId"), "utf-8"))["posthog.distinctId"];
console.log(JSON.stringify({
accessTokenPreview: redact(token),
accessToken: token,
deviceId,
aid: deviceId,
email: user.email || store?.user?.email,
username: user.username || store?.user?.username,
hasProFeatures: !!user.hasProFeatures,
hasBetterAI: !!user.hasBetterAI,
sources: {
bearer: "Keychain Raycast / raycast-store_credentials",
deviceId: "raycast-enc.sqlite user.analyticsId",
},
}, null, 2));