offrouter-cli 0.2.1 → 0.3.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,31 +0,0 @@
1
- import { ConfigError } from "offrouter-core";
2
-
3
- export interface CliConfigError {
4
- name: string;
5
- message: string;
6
- filePath?: string;
7
- issues?: string[];
8
- }
9
-
10
- export function formatConfigError(error: unknown): CliConfigError {
11
- if (error instanceof ConfigError) {
12
- return {
13
- name: error.name,
14
- message: error.message,
15
- filePath: error.filePath,
16
- issues: error.issues,
17
- };
18
- }
19
-
20
- if (error instanceof Error) {
21
- return {
22
- name: error.name,
23
- message: error.message,
24
- };
25
- }
26
-
27
- return {
28
- name: "Error",
29
- message: String(error),
30
- };
31
- }
@@ -1,209 +0,0 @@
1
- /**
2
- * Readiness detection for CLI doctor/init/status.
3
- * Never reads secret values - only boolean presence / opaque health signals.
4
- */
5
- import { access, constants } from "node:fs/promises";
6
- import { homedir as osHomedir } from "node:os";
7
- import { join } from "node:path";
8
-
9
- export const V1_HONESTY_LINE =
10
- "Claude Code's primary model is unchanged in V1. OffRouter routes delegated work." as const;
11
-
12
- export const V1_CODEX_HONESTY_LINE =
13
- "Codex's primary model is unchanged in V1. OffRouter routes delegated work." as const;
14
-
15
- export const V1_GEMINI_HONESTY_LINE =
16
- "Gemini CLI's primary model is unchanged in V1. OffRouter routes delegated work." as const;
17
-
18
- export const V1_GROK_HONESTY_LINE =
19
- "Grok Build's primary model is unchanged in V1. OffRouter routes delegated work." as const;
20
-
21
- export function honestyForHarness(
22
- kind: "claude" | "codex" | "gemini" | "grok",
23
- ): string {
24
- if (kind === "codex") return V1_CODEX_HONESTY_LINE;
25
- if (kind === "gemini") return V1_GEMINI_HONESTY_LINE;
26
- if (kind === "grok") return V1_GROK_HONESTY_LINE;
27
- return V1_HONESTY_LINE;
28
- }
29
-
30
- /** Env keys that indicate API-key readiness (presence only). */
31
- const API_KEY_ENV_FLAGS = [
32
- "ANTHROPIC_API_KEY",
33
- "OPENAI_API_KEY",
34
- "OPENROUTER_API_KEY",
35
- "XAI_API_KEY",
36
- "GOOGLE_API_KEY",
37
- "GEMINI_API_KEY",
38
- "OFFROUTER_API_KEY",
39
- ] as const;
40
-
41
- export interface HarnessProfileDetection {
42
- kind: string;
43
- profileHint: string;
44
- detected: boolean;
45
- pathChecked?: string;
46
- }
47
-
48
- export interface AuthTierReadiness {
49
- subscription: boolean;
50
- local: boolean;
51
- "api-key": boolean;
52
- }
53
-
54
- export interface SubscriptionDetection {
55
- status: "unconfigured" | "unknown" | "active";
56
- /** Which first-party subscription surfaces appear installed (no credentials). */
57
- surfaces: string[];
58
- }
59
-
60
- export interface ApiKeyReadiness {
61
- anyReady: boolean;
62
- /** Env var names that are set (values never included). */
63
- envPresent: string[];
64
- }
65
-
66
- export interface LocalRuntimeHealth {
67
- health: "unconfigured" | "unknown" | "healthy";
68
- ollamaHostConfigured: boolean;
69
- /** True only if a common local binary path exists on disk (no spawn). */
70
- localBinaryPresent: boolean;
71
- }
72
-
73
- export interface OpaqueLimitStatus {
74
- /** Opaque summary only - no quota remaining figures from live APIs. */
75
- status: "unavailable" | "unknown";
76
- detail: string;
77
- }
78
-
79
- export interface DetectionSnapshot {
80
- harnessProfiles: HarnessProfileDetection[];
81
- authTiers: AuthTierReadiness;
82
- subscription: SubscriptionDetection;
83
- apiKeyReadiness: ApiKeyReadiness;
84
- localRuntime: LocalRuntimeHealth;
85
- limits: OpaqueLimitStatus;
86
- /** Last provider error summary; null when none known. Never includes secrets. */
87
- lastProviderError: string | null;
88
- honesty: typeof V1_HONESTY_LINE;
89
- }
90
-
91
- export interface DetectionOptions {
92
- env?: NodeJS.ProcessEnv;
93
- homedir?: () => string;
94
- cwd?: string;
95
- }
96
-
97
- async function pathExists(path: string): Promise<boolean> {
98
- try {
99
- await access(path, constants.F_OK);
100
- return true;
101
- } catch {
102
- return false;
103
- }
104
- }
105
-
106
- function envPresent(env: NodeJS.ProcessEnv, key: string): boolean {
107
- const v = env[key];
108
- return typeof v === "string" && v.trim().length > 0;
109
- }
110
-
111
- export async function detectEnvironment(
112
- options: DetectionOptions = {},
113
- ): Promise<DetectionSnapshot> {
114
- const env = options.env ?? process.env;
115
- const home = (options.homedir ?? osHomedir)();
116
-
117
- const claudePath = join(home, ".claude");
118
- const codexPath = join(home, ".codex");
119
- const geminiPath = join(home, ".gemini");
120
- const piPath = join(home, ".pi");
121
-
122
- const [claude, codex, gemini, pi] = await Promise.all([
123
- pathExists(claudePath),
124
- pathExists(codexPath),
125
- pathExists(geminiPath),
126
- pathExists(piPath),
127
- ]);
128
-
129
- const harnessProfiles: HarnessProfileDetection[] = [
130
- {
131
- kind: "claude",
132
- profileHint: "claude-personal",
133
- detected: claude,
134
- pathChecked: claudePath,
135
- },
136
- {
137
- kind: "codex",
138
- profileHint: "codex-personal",
139
- detected: codex,
140
- pathChecked: codexPath,
141
- },
142
- {
143
- kind: "gemini",
144
- profileHint: "gemini-personal",
145
- detected: gemini,
146
- pathChecked: geminiPath,
147
- },
148
- {
149
- kind: "pi",
150
- profileHint: "pi-personal",
151
- detected: pi,
152
- pathChecked: piPath,
153
- },
154
- ];
155
-
156
- const surfaces: string[] = [];
157
- if (claude) surfaces.push("claude");
158
- if (codex) surfaces.push("codex");
159
- if (gemini) surfaces.push("gemini");
160
- if (pi) surfaces.push("pi");
161
-
162
- // Subscription readiness: directory presence only - never parse creds.
163
- const subscription: SubscriptionDetection = {
164
- status: surfaces.length > 0 ? "unknown" : "unconfigured",
165
- surfaces,
166
- };
167
-
168
- const envPresentKeys = API_KEY_ENV_FLAGS.filter((k) => envPresent(env, k));
169
- const apiKeyReadiness: ApiKeyReadiness = {
170
- anyReady: envPresentKeys.length > 0,
171
- envPresent: [...envPresentKeys],
172
- };
173
-
174
- const ollamaHostConfigured = envPresent(env, "OLLAMA_HOST");
175
- const localBinaryPresent =
176
- (await pathExists("/usr/local/bin/ollama")) ||
177
- (await pathExists("/opt/homebrew/bin/ollama")) ||
178
- (await pathExists(join(home, ".ollama")));
179
-
180
- const localRuntime: LocalRuntimeHealth = {
181
- health:
182
- ollamaHostConfigured || localBinaryPresent ? "unknown" : "unconfigured",
183
- ollamaHostConfigured,
184
- localBinaryPresent,
185
- };
186
-
187
- const authTiers: AuthTierReadiness = {
188
- subscription: subscription.status !== "unconfigured",
189
- local: localRuntime.health !== "unconfigured",
190
- "api-key": apiKeyReadiness.anyReady,
191
- };
192
-
193
- const limits: OpaqueLimitStatus = {
194
- status: "unavailable",
195
- detail:
196
- "Live limit queries are not run by the CLI shell; configure providers and re-run doctor after adapters are available.",
197
- };
198
-
199
- return {
200
- harnessProfiles,
201
- authTiers,
202
- subscription,
203
- apiKeyReadiness,
204
- localRuntime,
205
- limits,
206
- lastProviderError: null,
207
- honesty: V1_HONESTY_LINE,
208
- };
209
- }