@slkiser/opencode-quota 1.2.0 → 1.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.
- package/dist/lib/api-key-resolver.d.ts +83 -0
- package/dist/lib/api-key-resolver.d.ts.map +1 -0
- package/dist/lib/api-key-resolver.js +113 -0
- package/dist/lib/api-key-resolver.js.map +1 -0
- package/dist/lib/chutes-config.d.ts +8 -7
- package/dist/lib/chutes-config.d.ts.map +1 -1
- package/dist/lib/chutes-config.js +32 -128
- package/dist/lib/chutes-config.js.map +1 -1
- package/dist/lib/chutes.d.ts.map +1 -1
- package/dist/lib/chutes.js +1 -17
- package/dist/lib/chutes.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -48
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/copilot.d.ts.map +1 -1
- package/dist/lib/copilot.js +1 -24
- package/dist/lib/copilot.js.map +1 -1
- package/dist/lib/env-template.d.ts +25 -0
- package/dist/lib/env-template.d.ts.map +1 -0
- package/dist/lib/env-template.js +32 -0
- package/dist/lib/env-template.js.map +1 -0
- package/dist/lib/firmware-config.d.ts +1 -7
- package/dist/lib/firmware-config.d.ts.map +1 -1
- package/dist/lib/firmware-config.js +26 -148
- package/dist/lib/firmware-config.js.map +1 -1
- package/dist/lib/firmware.d.ts.map +1 -1
- package/dist/lib/firmware.js +1 -17
- package/dist/lib/firmware.js.map +1 -1
- package/dist/lib/format-utils.d.ts +56 -0
- package/dist/lib/format-utils.d.ts.map +1 -0
- package/dist/lib/format-utils.js +101 -0
- package/dist/lib/format-utils.js.map +1 -0
- package/dist/lib/format.d.ts.map +1 -1
- package/dist/lib/format.js +2 -67
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/google.d.ts.map +1 -1
- package/dist/lib/google.js +2 -24
- package/dist/lib/google.js.map +1 -1
- package/dist/lib/http.d.ts +14 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +34 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/jsonc.d.ts +25 -0
- package/dist/lib/jsonc.d.ts.map +1 -0
- package/dist/lib/jsonc.js +73 -0
- package/dist/lib/jsonc.js.map +1 -0
- package/dist/lib/openai.d.ts.map +1 -1
- package/dist/lib/openai.js +1 -17
- package/dist/lib/openai.js.map +1 -1
- package/dist/lib/opencode-storage.d.ts +27 -0
- package/dist/lib/opencode-storage.d.ts.map +1 -1
- package/dist/lib/opencode-storage.js +67 -0
- package/dist/lib/opencode-storage.js.map +1 -1
- package/dist/lib/quota-command-format.d.ts.map +1 -1
- package/dist/lib/quota-command-format.js +5 -50
- package/dist/lib/quota-command-format.js.map +1 -1
- package/dist/lib/quota-stats.d.ts +1 -0
- package/dist/lib/quota-stats.d.ts.map +1 -1
- package/dist/lib/quota-stats.js +15 -5
- package/dist/lib/quota-stats.js.map +1 -1
- package/dist/lib/quota-status.d.ts +7 -0
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +10 -0
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/toast-format-grouped.d.ts.map +1 -1
- package/dist/lib/toast-format-grouped.js +1 -66
- package/dist/lib/toast-format-grouped.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +40 -5
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic API key resolution from env vars, config files, and auth.json.
|
|
3
|
+
*
|
|
4
|
+
* Used by provider-specific config modules (firmware-config, chutes-config)
|
|
5
|
+
* to resolve API keys with consistent priority and behavior.
|
|
6
|
+
*/
|
|
7
|
+
/** A candidate config file path with its format */
|
|
8
|
+
export interface ConfigCandidate {
|
|
9
|
+
path: string;
|
|
10
|
+
isJsonc: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get candidate paths for opencode.json/opencode.jsonc files.
|
|
14
|
+
*
|
|
15
|
+
* Order: local (cwd) first, then global (~/.config/opencode).
|
|
16
|
+
* Within each location, .jsonc takes precedence over .json.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getOpencodeConfigCandidatePaths(): ConfigCandidate[];
|
|
19
|
+
/**
|
|
20
|
+
* Read and parse an opencode config file.
|
|
21
|
+
*
|
|
22
|
+
* @returns Parsed config with metadata, or null if file doesn't exist or is invalid
|
|
23
|
+
*/
|
|
24
|
+
export declare function readOpencodeConfig(filePath: string, isJsonc: boolean): Promise<{
|
|
25
|
+
config: unknown;
|
|
26
|
+
path: string;
|
|
27
|
+
isJsonc: boolean;
|
|
28
|
+
} | null>;
|
|
29
|
+
/** Result of API key resolution */
|
|
30
|
+
export interface ApiKeyResult<Source extends string> {
|
|
31
|
+
key: string;
|
|
32
|
+
source: Source;
|
|
33
|
+
}
|
|
34
|
+
/** Environment variable definition for key resolution */
|
|
35
|
+
export interface EnvVarDef<Source extends string> {
|
|
36
|
+
name: string;
|
|
37
|
+
source: Source;
|
|
38
|
+
}
|
|
39
|
+
/** Configuration for resolving an API key from multiple sources */
|
|
40
|
+
export interface ResolveApiKeyConfig<Source extends string> {
|
|
41
|
+
/** Environment variables to check (in order) */
|
|
42
|
+
envVars: EnvVarDef<Source>[];
|
|
43
|
+
/** Extract API key from parsed config object. Returns null if not found. */
|
|
44
|
+
extractFromConfig: (config: unknown) => string | null;
|
|
45
|
+
/** Source label for opencode.json */
|
|
46
|
+
configJsonSource: Source;
|
|
47
|
+
/** Source label for opencode.jsonc */
|
|
48
|
+
configJsoncSource: Source;
|
|
49
|
+
/** Extract API key from auth.json data. Returns null if not found. */
|
|
50
|
+
extractFromAuth: (auth: unknown) => string | null;
|
|
51
|
+
/** Source label for auth.json */
|
|
52
|
+
authSource: Source;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve an API key from multiple sources with consistent priority.
|
|
56
|
+
*
|
|
57
|
+
* Priority (first wins):
|
|
58
|
+
* 1. Environment variables (in order specified)
|
|
59
|
+
* 2. opencode.json/opencode.jsonc (local first, then global)
|
|
60
|
+
* 3. auth.json
|
|
61
|
+
*
|
|
62
|
+
* @returns API key and source, or null if not found
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveApiKey<Source extends string>(config: ResolveApiKeyConfig<Source>, readAuth: () => Promise<unknown | null>): Promise<ApiKeyResult<Source> | null>;
|
|
65
|
+
/** Configuration for API key diagnostics */
|
|
66
|
+
export interface DiagnosticsConfig<Source extends string> {
|
|
67
|
+
/** Environment variable names to check */
|
|
68
|
+
envVarNames: string[];
|
|
69
|
+
/** Resolver function to get the current key result */
|
|
70
|
+
resolve: () => Promise<ApiKeyResult<Source> | null>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get diagnostic info about API key configuration.
|
|
74
|
+
*
|
|
75
|
+
* Reports which sources were checked (env vars that exist, config files that exist)
|
|
76
|
+
* and whether a key was found.
|
|
77
|
+
*/
|
|
78
|
+
export declare function getApiKeyDiagnostics<Source extends string>(config: DiagnosticsConfig<Source>): Promise<{
|
|
79
|
+
configured: boolean;
|
|
80
|
+
source: Source | null;
|
|
81
|
+
checkedPaths: string[];
|
|
82
|
+
}>;
|
|
83
|
+
//# sourceMappingURL=api-key-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-resolver.d.ts","sourceRoot":"","sources":["../../src/lib/api-key-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,IAAI,eAAe,EAAE,CAUnE;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC,CASrE;AAED,mCAAmC;AACnC,MAAM,WAAW,YAAY,CAAC,MAAM,SAAS,MAAM;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,yDAAyD;AACzD,MAAM,WAAW,SAAS,CAAC,MAAM,SAAS,MAAM;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mEAAmE;AACnE,MAAM,WAAW,mBAAmB,CAAC,MAAM,SAAS,MAAM;IACxD,gDAAgD;IAChD,OAAO,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IAE7B,4EAA4E;IAC5E,iBAAiB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;IAEtD,qCAAqC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,sCAAsC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAE1B,sEAAsE;IACtE,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;IAElD,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,MAAM,SAAS,MAAM,EACvD,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,EACnC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GACtC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAgCtC;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB,CAAC,MAAM,SAAS,MAAM;IACtD,0CAA0C;IAC1C,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,sDAAsD;IACtD,OAAO,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;CACrD;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,SAAS,MAAM,EAC9D,MAAM,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAChC,OAAO,CAAC;IACT,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC,CAyBD"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic API key resolution from env vars, config files, and auth.json.
|
|
3
|
+
*
|
|
4
|
+
* Used by provider-specific config modules (firmware-config, chutes-config)
|
|
5
|
+
* to resolve API keys with consistent priority and behavior.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from "fs";
|
|
8
|
+
import { readFile } from "fs/promises";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { parseJsonOrJsonc } from "./jsonc.js";
|
|
12
|
+
/**
|
|
13
|
+
* Get candidate paths for opencode.json/opencode.jsonc files.
|
|
14
|
+
*
|
|
15
|
+
* Order: local (cwd) first, then global (~/.config/opencode).
|
|
16
|
+
* Within each location, .jsonc takes precedence over .json.
|
|
17
|
+
*/
|
|
18
|
+
export function getOpencodeConfigCandidatePaths() {
|
|
19
|
+
const cwd = process.cwd();
|
|
20
|
+
const configBaseDir = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
21
|
+
return [
|
|
22
|
+
{ path: join(cwd, "opencode.jsonc"), isJsonc: true },
|
|
23
|
+
{ path: join(cwd, "opencode.json"), isJsonc: false },
|
|
24
|
+
{ path: join(configBaseDir, "opencode", "opencode.jsonc"), isJsonc: true },
|
|
25
|
+
{ path: join(configBaseDir, "opencode", "opencode.json"), isJsonc: false },
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Read and parse an opencode config file.
|
|
30
|
+
*
|
|
31
|
+
* @returns Parsed config with metadata, or null if file doesn't exist or is invalid
|
|
32
|
+
*/
|
|
33
|
+
export async function readOpencodeConfig(filePath, isJsonc) {
|
|
34
|
+
try {
|
|
35
|
+
if (!existsSync(filePath))
|
|
36
|
+
return null;
|
|
37
|
+
const content = await readFile(filePath, "utf-8");
|
|
38
|
+
const config = parseJsonOrJsonc(content, isJsonc);
|
|
39
|
+
return { config, path: filePath, isJsonc };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve an API key from multiple sources with consistent priority.
|
|
47
|
+
*
|
|
48
|
+
* Priority (first wins):
|
|
49
|
+
* 1. Environment variables (in order specified)
|
|
50
|
+
* 2. opencode.json/opencode.jsonc (local first, then global)
|
|
51
|
+
* 3. auth.json
|
|
52
|
+
*
|
|
53
|
+
* @returns API key and source, or null if not found
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveApiKey(config, readAuth) {
|
|
56
|
+
// 1. Check environment variables (highest priority)
|
|
57
|
+
for (const envVar of config.envVars) {
|
|
58
|
+
const value = process.env[envVar.name]?.trim();
|
|
59
|
+
if (value && value.length > 0) {
|
|
60
|
+
return { key: value, source: envVar.source };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// 2. Check opencode.json/opencode.jsonc files
|
|
64
|
+
const candidates = getOpencodeConfigCandidatePaths();
|
|
65
|
+
for (const candidate of candidates) {
|
|
66
|
+
const result = await readOpencodeConfig(candidate.path, candidate.isJsonc);
|
|
67
|
+
if (!result)
|
|
68
|
+
continue;
|
|
69
|
+
const key = config.extractFromConfig(result.config);
|
|
70
|
+
if (key) {
|
|
71
|
+
return {
|
|
72
|
+
key,
|
|
73
|
+
source: result.isJsonc ? config.configJsoncSource : config.configJsonSource,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// 3. Fallback to auth.json
|
|
78
|
+
const auth = await readAuth();
|
|
79
|
+
const key = config.extractFromAuth(auth);
|
|
80
|
+
if (key) {
|
|
81
|
+
return { key, source: config.authSource };
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get diagnostic info about API key configuration.
|
|
87
|
+
*
|
|
88
|
+
* Reports which sources were checked (env vars that exist, config files that exist)
|
|
89
|
+
* and whether a key was found.
|
|
90
|
+
*/
|
|
91
|
+
export async function getApiKeyDiagnostics(config) {
|
|
92
|
+
const checkedPaths = [];
|
|
93
|
+
// Track env vars checked (only if they exist, even if empty)
|
|
94
|
+
for (const envVarName of config.envVarNames) {
|
|
95
|
+
if (process.env[envVarName] !== undefined) {
|
|
96
|
+
checkedPaths.push(`env:${envVarName}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Track config files checked (only if they exist)
|
|
100
|
+
const candidates = getOpencodeConfigCandidatePaths();
|
|
101
|
+
for (const candidate of candidates) {
|
|
102
|
+
if (existsSync(candidate.path)) {
|
|
103
|
+
checkedPaths.push(candidate.path);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const result = await config.resolve();
|
|
107
|
+
return {
|
|
108
|
+
configured: result !== null,
|
|
109
|
+
source: result?.source ?? null,
|
|
110
|
+
checkedPaths,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=api-key-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-resolver.js","sourceRoot":"","sources":["../../src/lib/api-key-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,15 +14,16 @@ export interface ChutesApiKeyResult {
|
|
|
14
14
|
}
|
|
15
15
|
/** Source of the resolved API key */
|
|
16
16
|
export type ChutesKeySource = "env:CHUTES_API_KEY" | "opencode.json" | "opencode.jsonc" | "auth.json";
|
|
17
|
-
|
|
18
|
-
* Get candidate paths for opencode.json/opencode.jsonc files
|
|
19
|
-
*/
|
|
20
|
-
export declare function getOpencodeConfigCandidatePaths(): Array<{
|
|
21
|
-
path: string;
|
|
22
|
-
isJsonc: boolean;
|
|
23
|
-
}>;
|
|
17
|
+
export { getOpencodeConfigCandidatePaths } from "./api-key-resolver.js";
|
|
24
18
|
/**
|
|
25
19
|
* Resolve Chutes API key from all available sources.
|
|
20
|
+
*
|
|
21
|
+
* Priority (first wins):
|
|
22
|
+
* 1. Environment variable: CHUTES_API_KEY
|
|
23
|
+
* 2. opencode.json/opencode.jsonc: provider.chutes.options.apiKey
|
|
24
|
+
* 3. auth.json: chutes.key
|
|
25
|
+
*
|
|
26
|
+
* @returns API key and source, or null if not found
|
|
26
27
|
*/
|
|
27
28
|
export declare function resolveChutesApiKey(): Promise<ChutesApiKeyResult | null>;
|
|
28
29
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chutes-config.d.ts","sourceRoot":"","sources":["../../src/lib/chutes-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"chutes-config.d.ts","sourceRoot":"","sources":["../../src/lib/chutes-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,0CAA0C;AAC1C,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,qCAAqC;AACrC,MAAM,MAAM,eAAe,GACvB,oBAAoB,GACpB,eAAe,GACf,gBAAgB,GAChB,WAAW,CAAC;AAyChB,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AAExE;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAY9E;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC;IACvD,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC,CAKD"}
|
|
@@ -7,75 +7,13 @@
|
|
|
7
7
|
* - Supports {env:VAR_NAME} syntax for environment variable references
|
|
8
8
|
* 3. auth.json: chutes.key (legacy/fallback)
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
11
|
-
import { readFile } from "fs/promises";
|
|
12
|
-
import { homedir } from "os";
|
|
13
|
-
import { join } from "path";
|
|
10
|
+
import { resolveEnvTemplate } from "./env-template.js";
|
|
14
11
|
import { readAuthFile } from "./opencode-auth.js";
|
|
15
|
-
|
|
16
|
-
* Strip JSONC comments (// and /* ... */) from a string.
|
|
17
|
-
*/
|
|
18
|
-
function stripJsonComments(content) {
|
|
19
|
-
let result = "";
|
|
20
|
-
let i = 0;
|
|
21
|
-
let inString = false;
|
|
22
|
-
let stringChar = "";
|
|
23
|
-
while (i < content.length) {
|
|
24
|
-
const char = content[i];
|
|
25
|
-
const nextChar = content[i + 1];
|
|
26
|
-
if ((char === '"' || char === "'") && (i === 0 || content[i - 1] !== "\\")) {
|
|
27
|
-
if (!inString) {
|
|
28
|
-
inString = true;
|
|
29
|
-
stringChar = char;
|
|
30
|
-
}
|
|
31
|
-
else if (char === stringChar) {
|
|
32
|
-
inString = false;
|
|
33
|
-
}
|
|
34
|
-
result += char;
|
|
35
|
-
i++;
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (!inString) {
|
|
39
|
-
if (char === "/" && nextChar === "/") {
|
|
40
|
-
while (i < content.length && content[i] !== "\n") {
|
|
41
|
-
i++;
|
|
42
|
-
}
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (char === "/" && nextChar === "*") {
|
|
46
|
-
i += 2;
|
|
47
|
-
while (i < content.length - 1 && !(content[i] === "*" && content[i + 1] === "/")) {
|
|
48
|
-
i++;
|
|
49
|
-
}
|
|
50
|
-
i += 2;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
result += char;
|
|
55
|
-
i++;
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Parse JSON or JSONC content
|
|
61
|
-
*/
|
|
62
|
-
function parseJsonOrJsonc(content, isJsonc) {
|
|
63
|
-
const toParse = isJsonc ? stripJsonComments(content) : content;
|
|
64
|
-
return JSON.parse(toParse);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Resolve {env:VAR_NAME} syntax in a string value
|
|
68
|
-
*/
|
|
69
|
-
function resolveEnvTemplate(value) {
|
|
70
|
-
const match = value.match(/^\{env:([^}]+)\}$/);
|
|
71
|
-
if (!match)
|
|
72
|
-
return value;
|
|
73
|
-
const envVar = match[1];
|
|
74
|
-
const envValue = process.env[envVar];
|
|
75
|
-
return envValue && envValue.trim().length > 0 ? envValue.trim() : null;
|
|
76
|
-
}
|
|
12
|
+
import { resolveApiKey, getApiKeyDiagnostics, } from "./api-key-resolver.js";
|
|
77
13
|
/**
|
|
78
14
|
* Extract Chutes API key from opencode config object
|
|
15
|
+
*
|
|
16
|
+
* Looks for: provider.chutes.options.apiKey
|
|
79
17
|
*/
|
|
80
18
|
function extractChutesKeyFromConfig(config) {
|
|
81
19
|
if (!config || typeof config !== "object")
|
|
@@ -96,60 +34,38 @@ function extractChutesKeyFromConfig(config) {
|
|
|
96
34
|
return resolveEnvTemplate(apiKey.trim());
|
|
97
35
|
}
|
|
98
36
|
/**
|
|
99
|
-
*
|
|
37
|
+
* Extract Chutes API key from auth.json
|
|
100
38
|
*/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const configBaseDir = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
104
|
-
return [
|
|
105
|
-
{ path: join(cwd, "opencode.jsonc"), isJsonc: true },
|
|
106
|
-
{ path: join(cwd, "opencode.json"), isJsonc: false },
|
|
107
|
-
{ path: join(configBaseDir, "opencode", "opencode.jsonc"), isJsonc: true },
|
|
108
|
-
{ path: join(configBaseDir, "opencode", "opencode.json"), isJsonc: false },
|
|
109
|
-
];
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Read and parse opencode config file
|
|
113
|
-
*/
|
|
114
|
-
async function readOpencodeConfig(filePath, isJsonc) {
|
|
115
|
-
try {
|
|
116
|
-
if (!existsSync(filePath))
|
|
117
|
-
return null;
|
|
118
|
-
const content = await readFile(filePath, "utf-8");
|
|
119
|
-
const config = parseJsonOrJsonc(content, isJsonc);
|
|
120
|
-
return { config, path: filePath, isJsonc };
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
39
|
+
function extractChutesKeyFromAuth(auth) {
|
|
40
|
+
if (!auth || typeof auth !== "object")
|
|
123
41
|
return null;
|
|
42
|
+
const chutes = auth.chutes;
|
|
43
|
+
if (chutes && chutes.type === "api" && chutes.key && chutes.key.trim().length > 0) {
|
|
44
|
+
return chutes.key.trim();
|
|
124
45
|
}
|
|
46
|
+
return null;
|
|
125
47
|
}
|
|
48
|
+
// Re-export for consumers that need path info
|
|
49
|
+
export { getOpencodeConfigCandidatePaths } from "./api-key-resolver.js";
|
|
126
50
|
/**
|
|
127
51
|
* Resolve Chutes API key from all available sources.
|
|
52
|
+
*
|
|
53
|
+
* Priority (first wins):
|
|
54
|
+
* 1. Environment variable: CHUTES_API_KEY
|
|
55
|
+
* 2. opencode.json/opencode.jsonc: provider.chutes.options.apiKey
|
|
56
|
+
* 3. auth.json: chutes.key
|
|
57
|
+
*
|
|
58
|
+
* @returns API key and source, or null if not found
|
|
128
59
|
*/
|
|
129
60
|
export async function resolveChutesApiKey() {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
continue;
|
|
139
|
-
const key = extractChutesKeyFromConfig(result.config);
|
|
140
|
-
if (key) {
|
|
141
|
-
return {
|
|
142
|
-
key,
|
|
143
|
-
source: result.isJsonc ? "opencode.jsonc" : "opencode.json",
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const auth = await readAuthFile();
|
|
148
|
-
const chutes = auth?.chutes;
|
|
149
|
-
if (chutes && chutes.type === "api" && chutes.key && chutes.key.trim().length > 0) {
|
|
150
|
-
return { key: chutes.key.trim(), source: "auth.json" };
|
|
151
|
-
}
|
|
152
|
-
return null;
|
|
61
|
+
return resolveApiKey({
|
|
62
|
+
envVars: [{ name: "CHUTES_API_KEY", source: "env:CHUTES_API_KEY" }],
|
|
63
|
+
extractFromConfig: extractChutesKeyFromConfig,
|
|
64
|
+
configJsonSource: "opencode.json",
|
|
65
|
+
configJsoncSource: "opencode.jsonc",
|
|
66
|
+
extractFromAuth: extractChutesKeyFromAuth,
|
|
67
|
+
authSource: "auth.json",
|
|
68
|
+
}, readAuthFile);
|
|
153
69
|
}
|
|
154
70
|
/**
|
|
155
71
|
* Check if a Chutes API key is configured
|
|
@@ -162,21 +78,9 @@ export async function hasChutesApiKey() {
|
|
|
162
78
|
* Get diagnostic info about Chutes API key configuration
|
|
163
79
|
*/
|
|
164
80
|
export async function getChutesKeyDiagnostics() {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
const candidates = getOpencodeConfigCandidatePaths();
|
|
170
|
-
for (const candidate of candidates) {
|
|
171
|
-
if (existsSync(candidate.path)) {
|
|
172
|
-
checkedPaths.push(candidate.path);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
const result = await resolveChutesApiKey();
|
|
176
|
-
return {
|
|
177
|
-
configured: result !== null,
|
|
178
|
-
source: result?.source ?? null,
|
|
179
|
-
checkedPaths,
|
|
180
|
-
};
|
|
81
|
+
return getApiKeyDiagnostics({
|
|
82
|
+
envVarNames: ["CHUTES_API_KEY"],
|
|
83
|
+
resolve: resolveChutesApiKey,
|
|
84
|
+
});
|
|
181
85
|
}
|
|
182
86
|
//# sourceMappingURL=chutes-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chutes-config.js","sourceRoot":"","sources":["../../src/lib/chutes-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"chutes-config.js","sourceRoot":"","sources":["../../src/lib/chutes-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EACL,aAAa,EACb,oBAAoB,GAGrB,MAAM,uBAAuB,CAAC;AAe/B;;;;GAIG;AACH,SAAS,0BAA0B,CAAC,MAAe;IACjD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEvD,MAAM,IAAI,GAAG,MAAiC,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC/B,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3D,MAAM,MAAM,GAAI,QAAoC,CAAC,MAAM,CAAC;IAC5D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEvD,MAAM,OAAO,GAAI,MAAkC,CAAC,OAAO,CAAC;IAC5D,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAEzD,MAAM,MAAM,GAAI,OAAmC,CAAC,MAAM,CAAC;IAC3D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1E,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,IAAa;IAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,MAAM,GAAI,IAAgC,CAAC,MAEpC,CAAC;IACd,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClF,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8CAA8C;AAC9C,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AAExE;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,OAAO,aAAa,CAClB;QACE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;QACnE,iBAAiB,EAAE,0BAA0B;QAC7C,gBAAgB,EAAE,eAAe;QACjC,iBAAiB,EAAE,gBAAgB;QACnC,eAAe,EAAE,wBAAwB;QACzC,UAAU,EAAE,WAAW;KACxB,EACD,YAAY,CACb,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,MAAM,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAC3C,OAAO,MAAM,KAAK,IAAI,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAK3C,OAAO,oBAAoB,CAAkB;QAC3C,WAAW,EAAE,CAAC,gBAAgB,CAAC;QAC/B,OAAO,EAAE,mBAAmB;KAC7B,CAAC,CAAC;AACL,CAAC"}
|
package/dist/lib/chutes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chutes.d.ts","sourceRoot":"","sources":["../../src/lib/chutes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"chutes.d.ts","sourceRoot":"","sources":["../../src/lib/chutes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAyC/C,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC,CAElE;AAED,OAAO,EAAE,uBAAuB,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEnF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,CAAC,CAwC9D"}
|
package/dist/lib/chutes.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Resolves API key from multiple sources and queries:
|
|
5
5
|
* https://api.chutes.ai/users/me/quota_usage/me
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { fetchWithTimeout } from "./http.js";
|
|
8
8
|
import { resolveChutesApiKey, hasChutesApiKey, } from "./chutes-config.js";
|
|
9
9
|
function clampPercent(n) {
|
|
10
10
|
if (!Number.isFinite(n))
|
|
@@ -16,22 +16,6 @@ function getNextDailyResetUtc() {
|
|
|
16
16
|
const reset = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1, 0, 0, 0, 0));
|
|
17
17
|
return reset.toISOString();
|
|
18
18
|
}
|
|
19
|
-
async function fetchWithTimeout(url, options) {
|
|
20
|
-
const controller = new AbortController();
|
|
21
|
-
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
22
|
-
try {
|
|
23
|
-
return await fetch(url, { ...options, signal: controller.signal });
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
27
|
-
throw new Error(`Request timeout after ${Math.round(REQUEST_TIMEOUT_MS / 1000)}s`);
|
|
28
|
-
}
|
|
29
|
-
throw err;
|
|
30
|
-
}
|
|
31
|
-
finally {
|
|
32
|
-
clearTimeout(timeoutId);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
19
|
async function readChutesAuth() {
|
|
36
20
|
const result = await resolveChutesApiKey();
|
|
37
21
|
if (!result)
|
package/dist/lib/chutes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chutes.js","sourceRoot":"","sources":["../../src/lib/chutes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"chutes.js","sourceRoot":"","sources":["../../src/lib/chutes.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,YAAY,CAAC;AASlE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC;IACrC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AASD;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE;IACN,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,YAAY,CAAC,EAAE;oBAAE,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAC9F,CAAC;CACH,EACD,IAAI,CAAC,EAAE,cAAc,GACpB,OAAO,CAAC,gBAAgB,CAAC,CA2K3B"}
|
package/dist/lib/config.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Fallback: reads local config files directly.
|
|
6
6
|
*/
|
|
7
7
|
import { DEFAULT_CONFIG } from "./types.js";
|
|
8
|
+
import { stripJsonComments } from "./jsonc.js";
|
|
8
9
|
import { existsSync } from "fs";
|
|
9
10
|
import { readFile } from "fs/promises";
|
|
10
11
|
import { homedir } from "os";
|
|
@@ -90,54 +91,6 @@ export async function loadConfig(client, meta) {
|
|
|
90
91
|
}
|
|
91
92
|
return config;
|
|
92
93
|
}
|
|
93
|
-
/**
|
|
94
|
-
* Strip JSONC comments (// and /* ... */) from a string.
|
|
95
|
-
*/
|
|
96
|
-
function stripJsonComments(content) {
|
|
97
|
-
let result = "";
|
|
98
|
-
let i = 0;
|
|
99
|
-
let inString = false;
|
|
100
|
-
let stringChar = "";
|
|
101
|
-
while (i < content.length) {
|
|
102
|
-
const char = content[i];
|
|
103
|
-
const nextChar = content[i + 1];
|
|
104
|
-
// Handle string boundaries
|
|
105
|
-
if ((char === '"' || char === "'") && (i === 0 || content[i - 1] !== "\\")) {
|
|
106
|
-
if (!inString) {
|
|
107
|
-
inString = true;
|
|
108
|
-
stringChar = char;
|
|
109
|
-
}
|
|
110
|
-
else if (char === stringChar) {
|
|
111
|
-
inString = false;
|
|
112
|
-
}
|
|
113
|
-
result += char;
|
|
114
|
-
i++;
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
// Skip comments only when not in a string
|
|
118
|
-
if (!inString) {
|
|
119
|
-
// Single-line comment
|
|
120
|
-
if (char === "/" && nextChar === "/") {
|
|
121
|
-
while (i < content.length && content[i] !== "\n") {
|
|
122
|
-
i++;
|
|
123
|
-
}
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
// Multi-line comment
|
|
127
|
-
if (char === "/" && nextChar === "*") {
|
|
128
|
-
i += 2;
|
|
129
|
-
while (i < content.length - 1 && !(content[i] === "*" && content[i + 1] === "/")) {
|
|
130
|
-
i++;
|
|
131
|
-
}
|
|
132
|
-
i += 2;
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
result += char;
|
|
137
|
-
i++;
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
94
|
async function readJson(path) {
|
|
142
95
|
try {
|
|
143
96
|
const content = await readFile(path, "utf-8");
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copilot.d.ts","sourceRoot":"","sources":["../../src/lib/copilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAOV,aAAa,EACd,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"copilot.d.ts","sourceRoot":"","sources":["../../src/lib/copilot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAOV,aAAa,EACd,MAAM,YAAY,CAAC;AA2QpB;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,CAAC,CA2DhE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAevE"}
|
package/dist/lib/copilot.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 2) Best-effort: internal endpoint using OpenCode's stored OAuth token
|
|
9
9
|
* (legacy formats or via token exchange).
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { fetchWithTimeout } from "./http.js";
|
|
12
12
|
import { readAuthFile } from "./opencode-auth.js";
|
|
13
13
|
import { existsSync, readFileSync } from "fs";
|
|
14
14
|
import { homedir } from "os";
|
|
@@ -28,29 +28,6 @@ const COPILOT_QUOTA_CONFIG_PATH = join(process.env.XDG_CONFIG_HOME || join(homed
|
|
|
28
28
|
// =============================================================================
|
|
29
29
|
// Helpers
|
|
30
30
|
// =============================================================================
|
|
31
|
-
/**
|
|
32
|
-
* Fetch with timeout
|
|
33
|
-
*/
|
|
34
|
-
async function fetchWithTimeout(url, options, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
35
|
-
const controller = new AbortController();
|
|
36
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
37
|
-
try {
|
|
38
|
-
const response = await fetch(url, {
|
|
39
|
-
...options,
|
|
40
|
-
signal: controller.signal,
|
|
41
|
-
});
|
|
42
|
-
return response;
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
46
|
-
throw new Error(`Request timeout after ${Math.round(timeoutMs / 1000)}s`);
|
|
47
|
-
}
|
|
48
|
-
throw err;
|
|
49
|
-
}
|
|
50
|
-
finally {
|
|
51
|
-
clearTimeout(timeoutId);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
31
|
/**
|
|
55
32
|
* Build headers for GitHub API requests
|
|
56
33
|
*/
|