@manishbht/helpcode 0.2.3 → 0.3.5
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/bin/helpcode.js +0 -0
- package/dist/src/commands/ask.js +15 -1
- package/dist/src/commands/ask.js.map +1 -1
- package/dist/src/commands/cockpit.d.ts +13 -0
- package/dist/src/commands/cockpit.js +33 -0
- package/dist/src/commands/cockpit.js.map +1 -0
- package/dist/src/commands/plan.d.ts +14 -0
- package/dist/src/commands/plan.js +113 -0
- package/dist/src/commands/plan.js.map +1 -0
- package/dist/src/commands/run.js +51 -4
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/core/cockpit.d.ts +27 -0
- package/dist/src/core/cockpit.js +109 -0
- package/dist/src/core/cockpit.js.map +1 -0
- package/dist/src/core/cockpitHtml.d.ts +52 -0
- package/dist/src/core/cockpitHtml.js +395 -0
- package/dist/src/core/cockpitHtml.js.map +1 -0
- package/dist/src/core/consent.d.ts +20 -0
- package/dist/src/core/consent.js +34 -0
- package/dist/src/core/consent.js.map +1 -0
- package/dist/src/core/decompose.d.ts +45 -0
- package/dist/src/core/decompose.js +86 -0
- package/dist/src/core/decompose.js.map +1 -0
- package/dist/src/core/gemini.d.ts +41 -0
- package/dist/src/core/gemini.js +91 -0
- package/dist/src/core/gemini.js.map +1 -0
- package/dist/src/core/keys.d.ts +29 -0
- package/dist/src/core/keys.js +92 -0
- package/dist/src/core/keys.js.map +1 -0
- package/dist/src/core/llmSelector.d.ts +6 -0
- package/dist/src/core/llmSelector.js +22 -7
- package/dist/src/core/llmSelector.js.map +1 -1
- package/dist/src/core/providers.d.ts +60 -0
- package/dist/src/core/providers.js +117 -0
- package/dist/src/core/providers.js.map +1 -0
- package/dist/src/core/remoteRouter.d.ts +27 -0
- package/dist/src/core/remoteRouter.js +71 -0
- package/dist/src/core/remoteRouter.js.map +1 -0
- package/dist/src/core/selector.d.ts +9 -4
- package/dist/src/core/selector.js +85 -29
- package/dist/src/core/selector.js.map +1 -1
- package/dist/src/core/souschef.d.ts +63 -0
- package/dist/src/core/souschef.js +55 -0
- package/dist/src/core/souschef.js.map +1 -0
- package/dist/src/core/state.d.ts +13 -1
- package/dist/src/core/state.js +47 -5
- package/dist/src/core/state.js.map +1 -1
- package/dist/src/core/triage.d.ts +14 -1
- package/dist/src/core/triage.js +23 -5
- package/dist/src/core/triage.js.map +1 -1
- package/dist/src/index.d.ts +8 -7
- package/dist/src/index.js +21 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/types.d.ts +70 -1
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal client for the Google Gemini API (free tier), via REST.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Ollama client's discipline:
|
|
5
|
+
* - Zero runtime dependencies: plain fetch, no SDK.
|
|
6
|
+
* - fetch is injectable so tests never hit the live API and CI passes offline.
|
|
7
|
+
* - Every failure becomes a GeminiError; callers fall back to a cheaper
|
|
8
|
+
* worker (local) or deterministic path. The remote path can NEVER break the
|
|
9
|
+
* core flow.
|
|
10
|
+
*
|
|
11
|
+
* PRIVACY: the free tier may use inputs/outputs to train Google's models. The
|
|
12
|
+
* sous-chef privacy gate (core/souschef.ts) ensures only non-code task input
|
|
13
|
+
* (decomposition) reaches here unless the user opts into allowRemoteCode. This
|
|
14
|
+
* client does not enforce that — it's enforced upstream at routing time.
|
|
15
|
+
*/
|
|
16
|
+
export declare class GeminiError extends Error {
|
|
17
|
+
/** True if the failure was a 429 RESOURCE_EXHAUSTED (free quota used up). */
|
|
18
|
+
readonly quotaExhausted: boolean;
|
|
19
|
+
constructor(message: string, quotaExhausted?: boolean);
|
|
20
|
+
}
|
|
21
|
+
type FetchImpl = (url: string, init?: RequestInit) => Promise<Response>;
|
|
22
|
+
export interface GeminiCallOptions {
|
|
23
|
+
fetchImpl?: FetchImpl;
|
|
24
|
+
}
|
|
25
|
+
export interface GeminiConfig {
|
|
26
|
+
apiKey: string;
|
|
27
|
+
/** Model id, e.g. "gemini-2.5-flash-lite". */
|
|
28
|
+
model: string;
|
|
29
|
+
timeoutMs: number;
|
|
30
|
+
}
|
|
31
|
+
/** Build the generateContent endpoint URL for a model + key. */
|
|
32
|
+
export declare function buildGeminiUrl(model: string, apiKey: string): string;
|
|
33
|
+
/** Extract concatenated text from a generateContent response body. */
|
|
34
|
+
export declare function parseGeminiResponse(body: any): string;
|
|
35
|
+
/**
|
|
36
|
+
* Generate text from Gemini. Returns the model's text on success; throws a
|
|
37
|
+
* GeminiError on any failure (with quotaExhausted set for 429s so the router
|
|
38
|
+
* can mark the provider throttled).
|
|
39
|
+
*/
|
|
40
|
+
export declare function geminiGenerate(prompt: string, config: GeminiConfig, opts?: GeminiCallOptions): Promise<string>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal client for the Google Gemini API (free tier), via REST.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Ollama client's discipline:
|
|
5
|
+
* - Zero runtime dependencies: plain fetch, no SDK.
|
|
6
|
+
* - fetch is injectable so tests never hit the live API and CI passes offline.
|
|
7
|
+
* - Every failure becomes a GeminiError; callers fall back to a cheaper
|
|
8
|
+
* worker (local) or deterministic path. The remote path can NEVER break the
|
|
9
|
+
* core flow.
|
|
10
|
+
*
|
|
11
|
+
* PRIVACY: the free tier may use inputs/outputs to train Google's models. The
|
|
12
|
+
* sous-chef privacy gate (core/souschef.ts) ensures only non-code task input
|
|
13
|
+
* (decomposition) reaches here unless the user opts into allowRemoteCode. This
|
|
14
|
+
* client does not enforce that — it's enforced upstream at routing time.
|
|
15
|
+
*/
|
|
16
|
+
export class GeminiError extends Error {
|
|
17
|
+
/** True if the failure was a 429 RESOURCE_EXHAUSTED (free quota used up). */
|
|
18
|
+
quotaExhausted;
|
|
19
|
+
constructor(message, quotaExhausted = false) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = 'GeminiError';
|
|
22
|
+
this.quotaExhausted = quotaExhausted;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const DEFAULT_GENERATE_TIMEOUT = 20000;
|
|
26
|
+
const API_BASE = 'https://generativelanguage.googleapis.com/v1beta/models';
|
|
27
|
+
/** Build the generateContent endpoint URL for a model + key. */
|
|
28
|
+
export function buildGeminiUrl(model, apiKey) {
|
|
29
|
+
return `${API_BASE}/${model}:generateContent?key=${apiKey}`;
|
|
30
|
+
}
|
|
31
|
+
/** Extract concatenated text from a generateContent response body. */
|
|
32
|
+
export function parseGeminiResponse(body) {
|
|
33
|
+
const cand = body?.candidates?.[0];
|
|
34
|
+
const parts = cand?.content?.parts;
|
|
35
|
+
if (!Array.isArray(parts))
|
|
36
|
+
return '';
|
|
37
|
+
return parts.map((p) => (typeof p?.text === 'string' ? p.text : '')).join('');
|
|
38
|
+
}
|
|
39
|
+
function getFetch(opts) {
|
|
40
|
+
return opts?.fetchImpl ?? globalThis.fetch;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Generate text from Gemini. Returns the model's text on success; throws a
|
|
44
|
+
* GeminiError on any failure (with quotaExhausted set for 429s so the router
|
|
45
|
+
* can mark the provider throttled).
|
|
46
|
+
*/
|
|
47
|
+
export async function geminiGenerate(prompt, config, opts) {
|
|
48
|
+
const fetchImpl = getFetch(opts);
|
|
49
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_GENERATE_TIMEOUT;
|
|
50
|
+
const url = buildGeminiUrl(config.model, config.apiKey);
|
|
51
|
+
const requestBody = {
|
|
52
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
53
|
+
};
|
|
54
|
+
const controller = new AbortController();
|
|
55
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
56
|
+
let response;
|
|
57
|
+
try {
|
|
58
|
+
response = await fetchImpl(url, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: { 'content-type': 'application/json' },
|
|
61
|
+
body: JSON.stringify(requestBody),
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
const why = e?.name === 'AbortError' ? 'timed out' : e.message;
|
|
68
|
+
throw new GeminiError(`request failed: ${why}`);
|
|
69
|
+
}
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
// Parse the body (may be an error envelope).
|
|
72
|
+
let body;
|
|
73
|
+
try {
|
|
74
|
+
body = await response.json();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new GeminiError(`bad response (status ${response.status}, non-JSON body)`);
|
|
78
|
+
}
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
const status = body?.error?.status ?? '';
|
|
81
|
+
const msg = body?.error?.message ?? `HTTP ${response.status}`;
|
|
82
|
+
const isQuota = response.status === 429 || status === 'RESOURCE_EXHAUSTED';
|
|
83
|
+
throw new GeminiError(`Gemini error: ${msg}`, isQuota);
|
|
84
|
+
}
|
|
85
|
+
const text = parseGeminiResponse(body).trim();
|
|
86
|
+
if (!text) {
|
|
87
|
+
throw new GeminiError('Gemini returned no usable text');
|
|
88
|
+
}
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/core/gemini.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API key loading for remote sous-chefs (v0.3.2).
|
|
3
|
+
*
|
|
4
|
+
* Keys are secrets and must never touch project.json (which is committed).
|
|
5
|
+
* Resolution order:
|
|
6
|
+
* 1. GEMINI_API_KEY environment variable (precedence; nothing on disk)
|
|
7
|
+
* 2. .helpcode/keys.json { "gemini": "..." } (gitignored by init)
|
|
8
|
+
*
|
|
9
|
+
* Returns null if no key is configured — in which case the remote sous-chef
|
|
10
|
+
* simply doesn't exist and helpcode behaves exactly as v0.3.1 (local only).
|
|
11
|
+
* Never throws: a missing or malformed keys.json yields null, not an error.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the Gemini API key. `env` is injectable for testing (defaults to
|
|
15
|
+
* process.env). Returns the key string, or null if none is configured.
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadGeminiKey(cwd?: string, env?: Record<string, string | undefined>): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve an API key for any provider, by its env var name, with the same
|
|
20
|
+
* precedence: env var first, then .helpcode/keys.json (keyed by a short name).
|
|
21
|
+
* `envVar` is e.g. "XAI_API_KEY"; `fileKey` is the keys.json field, e.g. "grok".
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadProviderKey(envVar: string, fileKey: string, cwd?: string, env?: Record<string, string | undefined>): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Whether a keys.json exists but is NOT gitignored — a footgun worth warning
|
|
26
|
+
* about (the user could commit their key). Best-effort: checks for a literal
|
|
27
|
+
* keys.json or .helpcode/ entry in .gitignore.
|
|
28
|
+
*/
|
|
29
|
+
export declare function keysFileAtRiskOfCommit(cwd?: string): boolean;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API key loading for remote sous-chefs (v0.3.2).
|
|
3
|
+
*
|
|
4
|
+
* Keys are secrets and must never touch project.json (which is committed).
|
|
5
|
+
* Resolution order:
|
|
6
|
+
* 1. GEMINI_API_KEY environment variable (precedence; nothing on disk)
|
|
7
|
+
* 2. .helpcode/keys.json { "gemini": "..." } (gitignored by init)
|
|
8
|
+
*
|
|
9
|
+
* Returns null if no key is configured — in which case the remote sous-chef
|
|
10
|
+
* simply doesn't exist and helpcode behaves exactly as v0.3.1 (local only).
|
|
11
|
+
* Never throws: a missing or malformed keys.json yields null, not an error.
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
const KEYS_FILE = path.join('.helpcode', 'keys.json');
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the Gemini API key. `env` is injectable for testing (defaults to
|
|
18
|
+
* process.env). Returns the key string, or null if none is configured.
|
|
19
|
+
*/
|
|
20
|
+
export function loadGeminiKey(cwd = process.cwd(), env = process.env) {
|
|
21
|
+
// 1. Environment variable wins (and leaves nothing on disk).
|
|
22
|
+
const fromEnv = env.GEMINI_API_KEY;
|
|
23
|
+
if (typeof fromEnv === 'string' && fromEnv.trim().length > 0) {
|
|
24
|
+
return fromEnv.trim();
|
|
25
|
+
}
|
|
26
|
+
// 2. .helpcode/keys.json
|
|
27
|
+
const file = path.join(cwd, KEYS_FILE);
|
|
28
|
+
if (!fs.existsSync(file))
|
|
29
|
+
return null;
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
32
|
+
const k = parsed?.gemini;
|
|
33
|
+
if (typeof k === 'string' && k.trim().length > 0)
|
|
34
|
+
return k.trim();
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Malformed file: behave as if no key (never throw).
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve an API key for any provider, by its env var name, with the same
|
|
44
|
+
* precedence: env var first, then .helpcode/keys.json (keyed by a short name).
|
|
45
|
+
* `envVar` is e.g. "XAI_API_KEY"; `fileKey` is the keys.json field, e.g. "grok".
|
|
46
|
+
*/
|
|
47
|
+
export function loadProviderKey(envVar, fileKey, cwd = process.cwd(), env = process.env) {
|
|
48
|
+
const fromEnv = env[envVar];
|
|
49
|
+
if (typeof fromEnv === 'string' && fromEnv.trim().length > 0) {
|
|
50
|
+
return fromEnv.trim();
|
|
51
|
+
}
|
|
52
|
+
const file = path.join(cwd, KEYS_FILE);
|
|
53
|
+
if (!fs.existsSync(file))
|
|
54
|
+
return null;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
57
|
+
const k = parsed?.[fileKey];
|
|
58
|
+
if (typeof k === 'string' && k.trim().length > 0)
|
|
59
|
+
return k.trim();
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Whether a keys.json exists but is NOT gitignored — a footgun worth warning
|
|
68
|
+
* about (the user could commit their key). Best-effort: checks for a literal
|
|
69
|
+
* keys.json or .helpcode/ entry in .gitignore.
|
|
70
|
+
*/
|
|
71
|
+
export function keysFileAtRiskOfCommit(cwd = process.cwd()) {
|
|
72
|
+
const keysPath = path.join(cwd, KEYS_FILE);
|
|
73
|
+
if (!fs.existsSync(keysPath))
|
|
74
|
+
return false;
|
|
75
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
76
|
+
if (!fs.existsSync(gitignorePath))
|
|
77
|
+
return true; // exists, nothing ignoring it
|
|
78
|
+
try {
|
|
79
|
+
const ignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
80
|
+
const lines = ignore.split(/\r?\n/).map(l => l.trim());
|
|
81
|
+
const covered = lines.some(l => l === '.helpcode/' ||
|
|
82
|
+
l === '.helpcode' ||
|
|
83
|
+
l === '.helpcode/keys.json' ||
|
|
84
|
+
l === 'keys.json' ||
|
|
85
|
+
l === '.helpcode/*');
|
|
86
|
+
return !covered;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../src/core/keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,6 +56,12 @@ export declare function parseSelectionResponse(response: string, candidates: Can
|
|
|
56
56
|
* "model ran but found nothing" (empty array) from "couldn't reach model"
|
|
57
57
|
* (throw) — both lead to fallback, but the caller may log them differently.
|
|
58
58
|
*/
|
|
59
|
+
/**
|
|
60
|
+
* Backend-agnostic file selection: builds the prompt, calls the provided
|
|
61
|
+
* generate function (Ollama or Gemini or any text model), parses + validates.
|
|
62
|
+
* The empty-file filter and hallucination guard apply regardless of backend.
|
|
63
|
+
*/
|
|
64
|
+
export declare function selectFilesWithGenerate(task: string, candidatePaths: string[], projectRoot: string, count: number, generateFn: (prompt: string) => Promise<string>): Promise<Selection[]>;
|
|
59
65
|
export declare function llmSelectFiles(task: string, candidatePaths: string[], projectRoot: string, opts: {
|
|
60
66
|
host: string;
|
|
61
67
|
model: string;
|
|
@@ -71,7 +71,8 @@ export function buildSelectionPrompt(task, candidates, count) {
|
|
|
71
71
|
lines.push(`- ${c.path}: ${c.signature}`);
|
|
72
72
|
}
|
|
73
73
|
lines.push('');
|
|
74
|
-
lines.push(`Return
|
|
74
|
+
lines.push(`Return UP TO ${count} files that are genuinely relevant to the task, most relevant first.`);
|
|
75
|
+
lines.push('Include FEWER than ' + count + ' if fewer are truly relevant — do not pad the list with files that are empty or unrelated.');
|
|
75
76
|
lines.push('Format each line exactly as:');
|
|
76
77
|
lines.push(' PATH | one-line reason');
|
|
77
78
|
lines.push('Only use paths from the candidate list above. No prose, no other text.');
|
|
@@ -118,17 +119,31 @@ export function parseSelectionResponse(response, candidates) {
|
|
|
118
119
|
* "model ran but found nothing" (empty array) from "couldn't reach model"
|
|
119
120
|
* (throw) — both lead to fallback, but the caller may log them differently.
|
|
120
121
|
*/
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Backend-agnostic file selection: builds the prompt, calls the provided
|
|
124
|
+
* generate function (Ollama or Gemini or any text model), parses + validates.
|
|
125
|
+
* The empty-file filter and hallucination guard apply regardless of backend.
|
|
126
|
+
*/
|
|
127
|
+
export async function selectFilesWithGenerate(task, candidatePaths, projectRoot, count, generateFn) {
|
|
128
|
+
const meaningful = candidatePaths.filter(p => {
|
|
129
|
+
try {
|
|
130
|
+
return fs.readFileSync(p, 'utf-8').trim().length >= 10;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
const candidates = meaningful.map(p => ({
|
|
123
137
|
path: path.relative(projectRoot, p),
|
|
124
138
|
signature: buildSignature(p),
|
|
125
139
|
}));
|
|
126
|
-
const prompt = buildSelectionPrompt(task, candidates,
|
|
127
|
-
const response = await
|
|
128
|
-
timeoutMs: opts.timeoutMs,
|
|
129
|
-
});
|
|
140
|
+
const prompt = buildSelectionPrompt(task, candidates, count);
|
|
141
|
+
const response = await generateFn(prompt);
|
|
130
142
|
return parseSelectionResponse(response, candidates);
|
|
131
143
|
}
|
|
144
|
+
export async function llmSelectFiles(task, candidatePaths, projectRoot, opts) {
|
|
145
|
+
return selectFilesWithGenerate(task, candidatePaths, projectRoot, opts.count, (prompt) => generate(opts.host, opts.model, prompt, { timeoutMs: opts.timeoutMs }));
|
|
146
|
+
}
|
|
132
147
|
// Re-export for callers that want to detect transport errors specifically.
|
|
133
148
|
export { OllamaError };
|
|
134
149
|
//# sourceMappingURL=llmSelector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llmSelector.js","sourceRoot":"","sources":["../../../src/core/llmSelector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAcpD,MAAM,mBAAmB,GAAG,CAAC,CAAC,CAAK,mCAAmC;AACtE,MAAM,4BAA4B,GAAG,CAAC,CAAC,CAAE,2BAA2B;AAEpE;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,MAAM,GAAG,0HAA0H,CAAC;IAC1I,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,kEAAkE;YAClE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnE,IAAI,OAAO;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACjC,IAAI,KAAK,CAAC,MAAM,IAAI,mBAAmB;gBAAE,MAAM;QACjD,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,mDAAmD;IACnD,MAAM,UAAU,GAAG,KAAK;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;SACtE,KAAK,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;IAC1C,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,UAAuB,EACvB,KAAa;IAEb,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"llmSelector.js","sourceRoot":"","sources":["../../../src/core/llmSelector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-compatible remote sous-chef providers (v0.3.5).
|
|
3
|
+
*
|
|
4
|
+
* Kimi (Moonshot), Grok (xAI), and ChatGPT (OpenAI) all expose the same
|
|
5
|
+
* OpenAI chat-completions API shape, so they share ONE client
|
|
6
|
+
* (openaiCompatGenerate) and differ only in configuration: base URL, default
|
|
7
|
+
* model, env var, and free-tier data-policy note. To users they're three
|
|
8
|
+
* distinct providers (three panels, three keys); under the hood, one code path.
|
|
9
|
+
*
|
|
10
|
+
* Gemini stays separate (core/gemini.ts) because its REST shape differs.
|
|
11
|
+
*
|
|
12
|
+
* PRIVACY: every provider here is a free tier that MAY train on inputs (Grok's
|
|
13
|
+
* free credits are explicitly a data-sharing program; Gemini likewise; Kimi
|
|
14
|
+
* verify per current terms). So all are governed by the same privacy gate in
|
|
15
|
+
* core/souschef.ts — decomposition by default, code only with allowRemoteCode.
|
|
16
|
+
* The freeTierNote is surfaced so the user sees the tradeoff per provider.
|
|
17
|
+
*/
|
|
18
|
+
export interface ProviderConfig {
|
|
19
|
+
id: string;
|
|
20
|
+
/** Human label for the cockpit. */
|
|
21
|
+
label: string;
|
|
22
|
+
/** OpenAI-compatible base URL (without the /chat/completions suffix). */
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
/** Default model id for this provider's free/cheap tier. */
|
|
25
|
+
defaultModel: string;
|
|
26
|
+
/** Env var that holds this provider's API key. */
|
|
27
|
+
envVar: string;
|
|
28
|
+
/** One-line note on the free-tier data/training policy. */
|
|
29
|
+
freeTierNote: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The registry. Models/URLs verified around mid-2026; they drift, so they're
|
|
33
|
+
* config, not hardcoded logic — easy to bump. Pick exact models at use time if
|
|
34
|
+
* a default is deprecated.
|
|
35
|
+
*/
|
|
36
|
+
export declare const PROVIDERS: ProviderConfig[];
|
|
37
|
+
export declare function getProvider(id: string): ProviderConfig | null;
|
|
38
|
+
export declare class OpenAICompatError extends Error {
|
|
39
|
+
readonly quotaExhausted: boolean;
|
|
40
|
+
constructor(message: string, quotaExhausted?: boolean);
|
|
41
|
+
}
|
|
42
|
+
type FetchImpl = (url: string, init?: RequestInit) => Promise<Response>;
|
|
43
|
+
export interface OpenAICompatCall {
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
model: string;
|
|
46
|
+
apiKey: string;
|
|
47
|
+
timeoutMs: number;
|
|
48
|
+
}
|
|
49
|
+
export interface OpenAICompatDeps {
|
|
50
|
+
fetchImpl?: FetchImpl;
|
|
51
|
+
}
|
|
52
|
+
/** Extract the assistant message content from a chat-completions body. */
|
|
53
|
+
export declare function parseChatCompletion(body: any): string;
|
|
54
|
+
/**
|
|
55
|
+
* Call any OpenAI-compatible chat-completions endpoint. Returns the text on
|
|
56
|
+
* success; throws OpenAICompatError on any failure (quotaExhausted set for
|
|
57
|
+
* 429s) so callers fall back to a cheaper worker.
|
|
58
|
+
*/
|
|
59
|
+
export declare function openaiCompatGenerate(prompt: string, call: OpenAICompatCall, deps?: OpenAICompatDeps): Promise<string>;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-compatible remote sous-chef providers (v0.3.5).
|
|
3
|
+
*
|
|
4
|
+
* Kimi (Moonshot), Grok (xAI), and ChatGPT (OpenAI) all expose the same
|
|
5
|
+
* OpenAI chat-completions API shape, so they share ONE client
|
|
6
|
+
* (openaiCompatGenerate) and differ only in configuration: base URL, default
|
|
7
|
+
* model, env var, and free-tier data-policy note. To users they're three
|
|
8
|
+
* distinct providers (three panels, three keys); under the hood, one code path.
|
|
9
|
+
*
|
|
10
|
+
* Gemini stays separate (core/gemini.ts) because its REST shape differs.
|
|
11
|
+
*
|
|
12
|
+
* PRIVACY: every provider here is a free tier that MAY train on inputs (Grok's
|
|
13
|
+
* free credits are explicitly a data-sharing program; Gemini likewise; Kimi
|
|
14
|
+
* verify per current terms). So all are governed by the same privacy gate in
|
|
15
|
+
* core/souschef.ts — decomposition by default, code only with allowRemoteCode.
|
|
16
|
+
* The freeTierNote is surfaced so the user sees the tradeoff per provider.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* The registry. Models/URLs verified around mid-2026; they drift, so they're
|
|
20
|
+
* config, not hardcoded logic — easy to bump. Pick exact models at use time if
|
|
21
|
+
* a default is deprecated.
|
|
22
|
+
*/
|
|
23
|
+
export const PROVIDERS = [
|
|
24
|
+
{
|
|
25
|
+
id: 'kimi',
|
|
26
|
+
label: 'Kimi',
|
|
27
|
+
baseUrl: 'https://api.moonshot.ai/v1',
|
|
28
|
+
defaultModel: 'kimi-k2.5',
|
|
29
|
+
envVar: 'MOONSHOT_API_KEY',
|
|
30
|
+
freeTierNote: 'Moonshot free tier (~1000 req/day); verify current training policy.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'grok',
|
|
34
|
+
label: 'Grok',
|
|
35
|
+
baseUrl: 'https://api.x.ai/v1',
|
|
36
|
+
defaultModel: 'grok-4.1-fast',
|
|
37
|
+
envVar: 'XAI_API_KEY',
|
|
38
|
+
freeTierNote: 'xAI free credits via data-sharing — inputs MAY train xAI models.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'openai',
|
|
42
|
+
label: 'ChatGPT',
|
|
43
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
44
|
+
defaultModel: 'gpt-5.4-mini',
|
|
45
|
+
envVar: 'OPENAI_API_KEY',
|
|
46
|
+
freeTierNote: 'OpenAI API — check whether your account/tier trains on inputs.',
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
export function getProvider(id) {
|
|
50
|
+
return PROVIDERS.find(p => p.id === id) ?? null;
|
|
51
|
+
}
|
|
52
|
+
// --- the shared OpenAI-compatible client ---------------------------------
|
|
53
|
+
export class OpenAICompatError extends Error {
|
|
54
|
+
quotaExhausted;
|
|
55
|
+
constructor(message, quotaExhausted = false) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = 'OpenAICompatError';
|
|
58
|
+
this.quotaExhausted = quotaExhausted;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const DEFAULT_TIMEOUT = 30000;
|
|
62
|
+
/** Extract the assistant message content from a chat-completions body. */
|
|
63
|
+
export function parseChatCompletion(body) {
|
|
64
|
+
const choice = body?.choices?.[0];
|
|
65
|
+
const content = choice?.message?.content;
|
|
66
|
+
return typeof content === 'string' ? content : '';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Call any OpenAI-compatible chat-completions endpoint. Returns the text on
|
|
70
|
+
* success; throws OpenAICompatError on any failure (quotaExhausted set for
|
|
71
|
+
* 429s) so callers fall back to a cheaper worker.
|
|
72
|
+
*/
|
|
73
|
+
export async function openaiCompatGenerate(prompt, call, deps = {}) {
|
|
74
|
+
const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
|
|
75
|
+
const timeoutMs = call.timeoutMs ?? DEFAULT_TIMEOUT;
|
|
76
|
+
const url = `${call.baseUrl.replace(/\/$/, '')}/chat/completions`;
|
|
77
|
+
const controller = new AbortController();
|
|
78
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
79
|
+
let response;
|
|
80
|
+
try {
|
|
81
|
+
response = await fetchImpl(url, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: {
|
|
84
|
+
'content-type': 'application/json',
|
|
85
|
+
authorization: `Bearer ${call.apiKey}`,
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
model: call.model,
|
|
89
|
+
messages: [{ role: 'user', content: prompt }],
|
|
90
|
+
}),
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
const why = e?.name === 'AbortError' ? 'timed out' : e.message;
|
|
97
|
+
throw new OpenAICompatError(`request failed: ${why}`);
|
|
98
|
+
}
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
let body;
|
|
101
|
+
try {
|
|
102
|
+
body = await response.json();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new OpenAICompatError(`bad response (status ${response.status}, non-JSON)`);
|
|
106
|
+
}
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const msg = body?.error?.message ?? `HTTP ${response.status}`;
|
|
109
|
+
const isQuota = response.status === 429;
|
|
110
|
+
throw new OpenAICompatError(`API error: ${msg}`, isQuota);
|
|
111
|
+
}
|
|
112
|
+
const text = parseChatCompletion(body).trim();
|
|
113
|
+
if (!text)
|
|
114
|
+
throw new OpenAICompatError('provider returned no usable text');
|
|
115
|
+
return text;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../src/core/providers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote provider routing (v0.3.5).
|
|
3
|
+
*
|
|
4
|
+
* Picks which remote sous-chef to use among the configured providers, based on
|
|
5
|
+
* which one has a key available. Unifies the two client shapes — Gemini (its
|
|
6
|
+
* own REST) and the OpenAI-compatible trio (Kimi, Grok, ChatGPT) — behind one
|
|
7
|
+
* `generate(prompt)` function so callers (plan, selection, triage) don't care
|
|
8
|
+
* which provider answered.
|
|
9
|
+
*
|
|
10
|
+
* Priority order: Gemini first (the original, most-tested), then Kimi, Grok,
|
|
11
|
+
* ChatGPT. A caller may pass a preferred id to override the order when that
|
|
12
|
+
* provider has a key.
|
|
13
|
+
*/
|
|
14
|
+
export interface ResolvedProvider {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
model: string;
|
|
18
|
+
key: string;
|
|
19
|
+
freeTierNote: string;
|
|
20
|
+
/** Run a prompt through this provider's client. Throws on failure. */
|
|
21
|
+
generate: (prompt: string, timeoutMs?: number) => Promise<string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Find the first remote provider that has a key. If `preferred` is given and
|
|
25
|
+
* that provider has a key, it wins; otherwise fall back to priority order.
|
|
26
|
+
*/
|
|
27
|
+
export declare function firstAvailableProvider(env?: Record<string, string | undefined>, preferred?: string, cwd?: string): ResolvedProvider | null;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote provider routing (v0.3.5).
|
|
3
|
+
*
|
|
4
|
+
* Picks which remote sous-chef to use among the configured providers, based on
|
|
5
|
+
* which one has a key available. Unifies the two client shapes — Gemini (its
|
|
6
|
+
* own REST) and the OpenAI-compatible trio (Kimi, Grok, ChatGPT) — behind one
|
|
7
|
+
* `generate(prompt)` function so callers (plan, selection, triage) don't care
|
|
8
|
+
* which provider answered.
|
|
9
|
+
*
|
|
10
|
+
* Priority order: Gemini first (the original, most-tested), then Kimi, Grok,
|
|
11
|
+
* ChatGPT. A caller may pass a preferred id to override the order when that
|
|
12
|
+
* provider has a key.
|
|
13
|
+
*/
|
|
14
|
+
import { PROVIDERS, openaiCompatGenerate } from './providers.js';
|
|
15
|
+
import { geminiGenerate } from './gemini.js';
|
|
16
|
+
import { loadGeminiKey, loadProviderKey } from './keys.js';
|
|
17
|
+
const GEMINI_MODEL = 'gemini-2.5-flash-lite';
|
|
18
|
+
/** Priority order for auto-selection (Gemini first, then the OAI-compat trio). */
|
|
19
|
+
const PRIORITY = ['gemini', 'kimi', 'grok', 'openai'];
|
|
20
|
+
function makeGemini(key) {
|
|
21
|
+
return {
|
|
22
|
+
id: 'gemini',
|
|
23
|
+
label: 'Gemini',
|
|
24
|
+
model: GEMINI_MODEL,
|
|
25
|
+
key,
|
|
26
|
+
freeTierNote: 'Gemini free tier — inputs may train Google models.',
|
|
27
|
+
generate: (prompt, timeoutMs = 30000) => geminiGenerate(prompt, { apiKey: key, model: GEMINI_MODEL, timeoutMs }),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function makeOpenAICompat(p, key) {
|
|
31
|
+
return {
|
|
32
|
+
id: p.id,
|
|
33
|
+
label: p.label,
|
|
34
|
+
model: p.defaultModel,
|
|
35
|
+
key,
|
|
36
|
+
freeTierNote: p.freeTierNote,
|
|
37
|
+
generate: (prompt, timeoutMs = 30000) => openaiCompatGenerate(prompt, {
|
|
38
|
+
baseUrl: p.baseUrl, model: p.defaultModel, apiKey: key, timeoutMs,
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Resolve a single provider by id, if it has a key. */
|
|
43
|
+
function resolveById(id, env, cwd) {
|
|
44
|
+
if (id === 'gemini') {
|
|
45
|
+
const key = loadGeminiKey(cwd, env);
|
|
46
|
+
return key ? makeGemini(key) : null;
|
|
47
|
+
}
|
|
48
|
+
const p = PROVIDERS.find(x => x.id === id);
|
|
49
|
+
if (!p)
|
|
50
|
+
return null;
|
|
51
|
+
const key = loadProviderKey(p.envVar, p.id, cwd, env);
|
|
52
|
+
return key ? makeOpenAICompat(p, key) : null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Find the first remote provider that has a key. If `preferred` is given and
|
|
56
|
+
* that provider has a key, it wins; otherwise fall back to priority order.
|
|
57
|
+
*/
|
|
58
|
+
export function firstAvailableProvider(env = process.env, preferred, cwd = process.cwd()) {
|
|
59
|
+
if (preferred) {
|
|
60
|
+
const p = resolveById(preferred, env, cwd);
|
|
61
|
+
if (p)
|
|
62
|
+
return p;
|
|
63
|
+
}
|
|
64
|
+
for (const id of PRIORITY) {
|
|
65
|
+
const p = resolveById(id, env, cwd);
|
|
66
|
+
if (p)
|
|
67
|
+
return p;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=remoteRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remoteRouter.js","sourceRoot":"","sources":["../../../src/core/remoteRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAkB,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAY3D,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAE7C,kFAAkF;AAClF,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEtD,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO;QACL,EAAE,EAAE,QAAQ;QACZ,KAAK,EAAE,QAAQ;QACf,KAAK,EAAE,YAAY;QACnB,GAAG;QACH,YAAY,EAAE,oDAAoD;QAClE,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,EAAE,CACtC,cAAc,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAiB,EAAE,GAAW;IACtD,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,YAAY;QACrB,GAAG;QACH,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,EAAE,CACtC,oBAAoB,CAAC,MAAM,EAAE;YAC3B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS;SAClE,CAAC;KACL,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,SAAS,WAAW,CAClB,EAAU,EACV,GAAuC,EACvC,GAAW;IAEX,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC;IACD,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAA0C,OAAO,CAAC,GAAG,EACrD,SAAkB,EAClB,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAClB,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|