@melaya/runner 1.0.73 → 1.0.74
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/dist/detect.js +37 -21
- package/package.json +1 -1
package/dist/detect.js
CHANGED
|
@@ -4,32 +4,48 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { execFile } from "child_process";
|
|
6
6
|
import { promisify } from "util";
|
|
7
|
+
import { readFile } from "fs/promises";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { join } from "path";
|
|
7
10
|
const execFileAsync = promisify(execFile);
|
|
8
|
-
/** Claude Code is a subscription CLI — when it's
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
11
|
+
/** Claude Code is a subscription CLI — when it's logged in on this machine,
|
|
12
|
+
* report its model aliases so the platform's model picker shows TRUE
|
|
13
|
+
* availability for local runs (claude_code pipelines execute HERE).
|
|
14
|
+
*
|
|
15
|
+
* We read the CLI's OAuth credentials FILE directly rather than spawning
|
|
16
|
+
* `claude auth status`. That subprocess flashed a console window on Windows
|
|
17
|
+
* every time the runner started (`windowsHide` is unreliable through the
|
|
18
|
+
* `.cmd` shell wrapper, which spawns its own conhost). The file is the source
|
|
19
|
+
* of truth on Windows/Linux; macOS keeps the grant in the Keychain, where
|
|
20
|
+
* `security` is a subprocess but pops NO window. Zero windows, faster, and
|
|
21
|
+
* it mirrors exactly what the runtime (model.py `_read_claude_oauth`) reads. */
|
|
12
22
|
async function detectClaudeCode() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
let raw = null;
|
|
24
|
+
try {
|
|
25
|
+
raw = await readFile(join(homedir(), ".claude", ".credentials.json"), "utf8");
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
raw = null;
|
|
29
|
+
}
|
|
30
|
+
if (!raw && process.platform === "darwin") {
|
|
17
31
|
try {
|
|
18
|
-
const { stdout } = await execFileAsync(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
const { stdout } = await execFileAsync("security", ["find-generic-password", "-s", "Claude Code-credentials", "-w"], { timeout: 8000 });
|
|
33
|
+
if (stdout && stdout.trim())
|
|
34
|
+
raw = stdout.trim();
|
|
35
|
+
}
|
|
36
|
+
catch { /* not in keychain */ }
|
|
37
|
+
}
|
|
38
|
+
if (!raw)
|
|
39
|
+
return [];
|
|
40
|
+
try {
|
|
41
|
+
const oauth = (JSON.parse(raw)?.claudeAiOauth ?? {});
|
|
42
|
+
const expiresAt = Number(oauth.expiresAt ?? 0);
|
|
43
|
+
if (oauth.accessToken && (!expiresAt || Date.now() < expiresAt)) {
|
|
44
|
+
return ["sonnet", "opus", "haiku"].map((name) => ({ provider: "claude_code", name }));
|
|
29
45
|
}
|
|
30
|
-
catch { /* not installed / not on PATH / non-JSON — try next candidate */ }
|
|
31
46
|
}
|
|
32
|
-
|
|
47
|
+
catch { /* malformed creds → treat as logged out */ }
|
|
48
|
+
return []; // not logged in / expired → don't advertise models
|
|
33
49
|
}
|
|
34
50
|
export async function detectModels() {
|
|
35
51
|
const models = [];
|