scoutline 0.10.2 → 0.12.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/README.md +99 -44
- package/dist/capabilities/diagnostics.d.ts +75 -0
- package/dist/capabilities/diagnostics.d.ts.map +1 -1
- package/dist/capabilities/diagnostics.js.map +1 -1
- package/dist/capabilities/quota.d.ts +64 -1
- package/dist/capabilities/quota.d.ts.map +1 -1
- package/dist/capabilities/quota.js.map +1 -1
- package/dist/capabilities/vision.d.ts +4 -3
- package/dist/capabilities/vision.d.ts.map +1 -1
- package/dist/capabilities/vision.js +7 -5
- package/dist/capabilities/vision.js.map +1 -1
- package/dist/commands/code.d.ts +9 -1
- package/dist/commands/code.d.ts.map +1 -1
- package/dist/commands/code.js +4 -4
- package/dist/commands/code.js.map +1 -1
- package/dist/commands/crawl.d.ts.map +1 -1
- package/dist/commands/crawl.js +14 -3
- package/dist/commands/crawl.js.map +1 -1
- package/dist/commands/doctor.d.ts +71 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +96 -15
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +186 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1221 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/map.d.ts.map +1 -1
- package/dist/commands/map.js +16 -3
- package/dist/commands/map.js.map +1 -1
- package/dist/commands/quota.d.ts +32 -0
- package/dist/commands/quota.d.ts.map +1 -1
- package/dist/commands/quota.js +165 -24
- package/dist/commands/quota.js.map +1 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +9 -3
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/repo.d.ts.map +1 -1
- package/dist/commands/repo.js +5 -3
- package/dist/commands/repo.js.map +1 -1
- package/dist/commands/research.d.ts +35 -7
- package/dist/commands/research.d.ts.map +1 -1
- package/dist/commands/research.js +93 -15
- package/dist/commands/research.js.map +1 -1
- package/dist/commands/tools.d.ts +8 -0
- package/dist/commands/tools.d.ts.map +1 -1
- package/dist/commands/tools.js +4 -4
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/vision.d.ts +10 -0
- package/dist/commands/vision.d.ts.map +1 -1
- package/dist/commands/vision.js +25 -2
- package/dist/commands/vision.js.map +1 -1
- package/dist/index.d.ts +136 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +894 -298
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +1 -1
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +6 -2
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/cache.d.ts +9 -2
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +9 -2
- package/dist/lib/cache.js.map +1 -1
- package/dist/lib/code-mode.d.ts +8 -0
- package/dist/lib/code-mode.d.ts.map +1 -1
- package/dist/lib/code-mode.js +3 -1
- package/dist/lib/code-mode.js.map +1 -1
- package/dist/lib/config-store.d.ts +165 -0
- package/dist/lib/config-store.d.ts.map +1 -0
- package/dist/lib/config-store.js +332 -0
- package/dist/lib/config-store.js.map +1 -0
- package/dist/lib/config.d.ts +2 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +19 -11
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/consumption.d.ts +144 -0
- package/dist/lib/consumption.d.ts.map +1 -0
- package/dist/lib/consumption.js +161 -0
- package/dist/lib/consumption.js.map +1 -0
- package/dist/lib/errors.d.ts +11 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +14 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/execution.d.ts +32 -4
- package/dist/lib/execution.d.ts.map +1 -1
- package/dist/lib/execution.js +156 -13
- package/dist/lib/execution.js.map +1 -1
- package/dist/lib/mcp-client.d.ts +12 -0
- package/dist/lib/mcp-client.d.ts.map +1 -1
- package/dist/lib/mcp-client.js +16 -7
- package/dist/lib/mcp-client.js.map +1 -1
- package/dist/lib/mcp-config.d.ts +10 -0
- package/dist/lib/mcp-config.d.ts.map +1 -1
- package/dist/lib/mcp-config.js +13 -7
- package/dist/lib/mcp-config.js.map +1 -1
- package/dist/lib/monitor-client.d.ts +19 -3
- package/dist/lib/monitor-client.d.ts.map +1 -1
- package/dist/lib/monitor-client.js +21 -5
- package/dist/lib/monitor-client.js.map +1 -1
- package/dist/lib/provider-fallback.d.ts +150 -0
- package/dist/lib/provider-fallback.d.ts.map +1 -0
- package/dist/lib/provider-fallback.js +510 -0
- package/dist/lib/provider-fallback.js.map +1 -0
- package/dist/lib/quota-mapping.d.ts +402 -0
- package/dist/lib/quota-mapping.d.ts.map +1 -0
- package/dist/lib/quota-mapping.js +539 -0
- package/dist/lib/quota-mapping.js.map +1 -0
- package/dist/lib/quota-store.d.ts +271 -0
- package/dist/lib/quota-store.d.ts.map +1 -0
- package/dist/lib/quota-store.js +540 -0
- package/dist/lib/quota-store.js.map +1 -0
- package/dist/lib/trigger-detection.d.ts +149 -0
- package/dist/lib/trigger-detection.d.ts.map +1 -0
- package/dist/lib/trigger-detection.js +149 -0
- package/dist/lib/trigger-detection.js.map +1 -0
- package/dist/lib/tty.d.ts +8 -1
- package/dist/lib/tty.d.ts.map +1 -1
- package/dist/lib/tty.js +53 -1
- package/dist/lib/tty.js.map +1 -1
- package/dist/providers/brave/adapter.d.ts +26 -0
- package/dist/providers/brave/adapter.d.ts.map +1 -1
- package/dist/providers/brave/adapter.js +66 -4
- package/dist/providers/brave/adapter.js.map +1 -1
- package/dist/providers/brave/client.d.ts +46 -2
- package/dist/providers/brave/client.d.ts.map +1 -1
- package/dist/providers/brave/client.js +55 -3
- package/dist/providers/brave/client.js.map +1 -1
- package/dist/providers/exa/adapter.d.ts.map +1 -1
- package/dist/providers/exa/adapter.js +10 -1
- package/dist/providers/exa/adapter.js.map +1 -1
- package/dist/providers/firecrawl/adapter.d.ts.map +1 -1
- package/dist/providers/firecrawl/adapter.js +13 -3
- package/dist/providers/firecrawl/adapter.js.map +1 -1
- package/dist/providers/minimax/adapter.d.ts.map +1 -1
- package/dist/providers/minimax/adapter.js +4 -0
- package/dist/providers/minimax/adapter.js.map +1 -1
- package/dist/providers/selection.d.ts +114 -1
- package/dist/providers/selection.d.ts.map +1 -1
- package/dist/providers/selection.js +99 -3
- package/dist/providers/selection.js.map +1 -1
- package/dist/providers/tavily/adapter.d.ts.map +1 -1
- package/dist/providers/tavily/adapter.js +2 -0
- package/dist/providers/tavily/adapter.js.map +1 -1
- package/dist/providers/types.d.ts +33 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +8 -0
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/zai/adapter.d.ts.map +1 -1
- package/dist/providers/zai/adapter.js +18 -5
- package/dist/providers/zai/adapter.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/lib/config-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { PROVIDER_IDS } from "../providers/types.js";
|
|
6
|
+
import { ConfigurationError } from "./errors.js";
|
|
7
|
+
export const CONFIG_VERSION = 1;
|
|
8
|
+
export function resolveConfigRootPure(env, platform) {
|
|
9
|
+
return env.SCOUTLINE_CONFIG_DIR || path.join(platform.homedir, ".scoutline");
|
|
10
|
+
}
|
|
11
|
+
export function resolveConfigRoot() {
|
|
12
|
+
return resolveConfigRootPure({ SCOUTLINE_CONFIG_DIR: process.env.SCOUTLINE_CONFIG_DIR }, { homedir: os.homedir() });
|
|
13
|
+
}
|
|
14
|
+
export function configFilePath(root = resolveConfigRoot()) {
|
|
15
|
+
return path.join(root, "config.json");
|
|
16
|
+
}
|
|
17
|
+
function emptyConfig() {
|
|
18
|
+
return { version: CONFIG_VERSION, providers: {} };
|
|
19
|
+
}
|
|
20
|
+
function corruptConfig() {
|
|
21
|
+
return new ConfigurationError("config.json is corrupt", "Run `scoutline init` to reconfigure, or fix/remove the file.");
|
|
22
|
+
}
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
function parseVerification(value) {
|
|
27
|
+
if (value === undefined)
|
|
28
|
+
return undefined;
|
|
29
|
+
if (!isRecord(value))
|
|
30
|
+
throw corruptConfig();
|
|
31
|
+
const { status, checkedAt, reason } = value;
|
|
32
|
+
if ((status !== "verified" && status !== "unverified") ||
|
|
33
|
+
typeof checkedAt !== "number" ||
|
|
34
|
+
!Number.isFinite(checkedAt) ||
|
|
35
|
+
checkedAt < 0 ||
|
|
36
|
+
(reason !== undefined && typeof reason !== "string")) {
|
|
37
|
+
throw corruptConfig();
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
status,
|
|
41
|
+
checkedAt,
|
|
42
|
+
...(reason?.trim() ? { reason: reason.trim() } : {}),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function parseProviderConfig(value) {
|
|
46
|
+
if (!isRecord(value))
|
|
47
|
+
throw corruptConfig();
|
|
48
|
+
const { apiKey, onboarded } = value;
|
|
49
|
+
if ((apiKey !== undefined && typeof apiKey !== "string") ||
|
|
50
|
+
(onboarded !== undefined && typeof onboarded !== "boolean")) {
|
|
51
|
+
throw corruptConfig();
|
|
52
|
+
}
|
|
53
|
+
const verification = parseVerification(value.verification);
|
|
54
|
+
return {
|
|
55
|
+
...(apiKey?.trim() ? { apiKey } : {}),
|
|
56
|
+
...(onboarded !== undefined ? { onboarded } : {}),
|
|
57
|
+
...(verification ? { verification } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function parseConfig(contents) {
|
|
61
|
+
let parsed;
|
|
62
|
+
try {
|
|
63
|
+
parsed = JSON.parse(contents);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
throw corruptConfig();
|
|
67
|
+
}
|
|
68
|
+
if (!isRecord(parsed))
|
|
69
|
+
throw corruptConfig();
|
|
70
|
+
const version = parsed.version;
|
|
71
|
+
if (version !== CONFIG_VERSION) {
|
|
72
|
+
throw new ConfigurationError(`Unsupported config version ${String(version)}`, "Upgrade Scoutline to read this config file.");
|
|
73
|
+
}
|
|
74
|
+
if ((parsed.fallbackEnabled !== undefined && typeof parsed.fallbackEnabled !== "boolean") ||
|
|
75
|
+
(parsed.hintShown !== undefined && typeof parsed.hintShown !== "boolean") ||
|
|
76
|
+
(parsed.providers !== undefined && !isRecord(parsed.providers))) {
|
|
77
|
+
throw corruptConfig();
|
|
78
|
+
}
|
|
79
|
+
const providers = {};
|
|
80
|
+
const warnings = [];
|
|
81
|
+
for (const [providerId, value] of Object.entries(parsed.providers ?? {})) {
|
|
82
|
+
if (!PROVIDER_IDS.includes(providerId)) {
|
|
83
|
+
warnings.push({
|
|
84
|
+
code: "UNKNOWN_PROVIDER",
|
|
85
|
+
providerId,
|
|
86
|
+
message: `Ignoring unknown provider "${providerId}" in config.json.`,
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
providers[providerId] = parseProviderConfig(value);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
config: {
|
|
94
|
+
version: CONFIG_VERSION,
|
|
95
|
+
...(parsed.fallbackEnabled !== undefined
|
|
96
|
+
? { fallbackEnabled: parsed.fallbackEnabled }
|
|
97
|
+
: {}),
|
|
98
|
+
providers,
|
|
99
|
+
...(parsed.hintShown !== undefined ? { hintShown: parsed.hintShown } : {}),
|
|
100
|
+
},
|
|
101
|
+
warnings,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export async function readConfig(options = {}) {
|
|
105
|
+
const file = options.filePath ?? configFilePath();
|
|
106
|
+
let contents;
|
|
107
|
+
try {
|
|
108
|
+
contents = await fs.readFile(file, "utf8");
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error.code === "ENOENT")
|
|
112
|
+
return emptyConfig();
|
|
113
|
+
throw new ConfigurationError("Unable to read config.json", "Run `scoutline init` to reconfigure, or fix/remove the file.");
|
|
114
|
+
}
|
|
115
|
+
const parsed = parseConfig(contents);
|
|
116
|
+
const onWarning = options.onWarning ??
|
|
117
|
+
((warning) => process.stderr.write(`Warning: ${warning.message}\n`));
|
|
118
|
+
for (const warning of parsed.warnings)
|
|
119
|
+
onWarning(warning);
|
|
120
|
+
return parsed.config;
|
|
121
|
+
}
|
|
122
|
+
export async function inspectConfig(options = {}) {
|
|
123
|
+
const filePath = options.filePath ?? configFilePath();
|
|
124
|
+
let contents;
|
|
125
|
+
try {
|
|
126
|
+
contents = await fs.readFile(filePath, "utf8");
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error.code === "ENOENT") {
|
|
130
|
+
return { status: "absent", filePath };
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
status: "corrupt",
|
|
134
|
+
filePath,
|
|
135
|
+
error: new ConfigurationError("Unable to read config.json", "Run `scoutline init` to reconfigure, or fix/remove the file."),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const parsed = parseConfig(contents);
|
|
140
|
+
return { status: "valid", filePath, config: parsed.config, warnings: parsed.warnings };
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return {
|
|
144
|
+
status: "corrupt",
|
|
145
|
+
filePath,
|
|
146
|
+
error: error,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export async function atomicReplaceFile(filePath, contents, options = {}) {
|
|
151
|
+
const platform = options.platform ?? process.platform;
|
|
152
|
+
const root = path.dirname(filePath);
|
|
153
|
+
await fs.mkdir(root, { recursive: true, mode: 0o700 });
|
|
154
|
+
if (platform !== "win32")
|
|
155
|
+
await fs.chmod(root, 0o700);
|
|
156
|
+
const randomId = options.randomId ?? randomUUID;
|
|
157
|
+
let tempPath;
|
|
158
|
+
let handle;
|
|
159
|
+
for (let attempt = 0; attempt < 16; attempt += 1) {
|
|
160
|
+
tempPath = path.join(root, `.${path.basename(filePath)}.${process.pid}.${randomId()}.tmp`);
|
|
161
|
+
try {
|
|
162
|
+
handle = await fs.open(tempPath, "wx", 0o600);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error.code !== "EEXIST")
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!handle || !tempPath) {
|
|
171
|
+
throw new Error("Unable to allocate a unique atomic-write temp file");
|
|
172
|
+
}
|
|
173
|
+
let renamed = false;
|
|
174
|
+
try {
|
|
175
|
+
await handle.writeFile(contents);
|
|
176
|
+
await handle.sync();
|
|
177
|
+
await handle.close();
|
|
178
|
+
handle = undefined;
|
|
179
|
+
// Node's rename maps to an atomic replacing rename on supported Windows
|
|
180
|
+
// filesystems. If that guarantee is unavailable, fail closed: never unlink
|
|
181
|
+
// the live config as a non-atomic fallback.
|
|
182
|
+
await (options.rename ?? fs.rename)(tempPath, filePath);
|
|
183
|
+
renamed = true;
|
|
184
|
+
if (platform !== "win32") {
|
|
185
|
+
const directory = await fs.open(root, "r");
|
|
186
|
+
try {
|
|
187
|
+
await directory.sync();
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
await directory.close();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
await handle?.close().catch(() => { });
|
|
196
|
+
if (!renamed)
|
|
197
|
+
await fs.unlink(tempPath).catch(() => { });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export async function writeConfig(config, options = {}) {
|
|
201
|
+
const parsed = parseConfig(JSON.stringify(config));
|
|
202
|
+
const onWarning = options.onWarning ??
|
|
203
|
+
((warning) => process.stderr.write(`Warning: ${warning.message}\n`));
|
|
204
|
+
for (const warning of parsed.warnings)
|
|
205
|
+
onWarning(warning);
|
|
206
|
+
const payload = `${JSON.stringify(parsed.config, null, 2)}\n`;
|
|
207
|
+
try {
|
|
208
|
+
await atomicReplaceFile(options.filePath ?? configFilePath(), payload, options.atomic);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
throw new ConfigurationError("Unable to write config.json", "Check the config directory permissions and try again.");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Build the resolved environment view that shared commands see: the
|
|
216
|
+
* injected `env` with file-configured API keys layered in for any
|
|
217
|
+
* Provider that is NOT already configured via `env`.
|
|
218
|
+
*
|
|
219
|
+
* Precedence rules (Plan A — T2a):
|
|
220
|
+
* - **Env overrides file.** A non-blank key already present in `env`
|
|
221
|
+
* (including aliases like `ZAI_API_KEY`) wins; the file key for that
|
|
222
|
+
* Provider is not written. This preserves the documented alias
|
|
223
|
+
* precedence (`Z_AI_API_KEY` > `ZAI_API_KEY` > file key).
|
|
224
|
+
* - **`process.env` is never mutated.** The returned object is a fresh
|
|
225
|
+
* shallow copy; the caller owns its lifetime.
|
|
226
|
+
* - File keys are written into the Provider's CANONICAL variable
|
|
227
|
+
* (the first `credentialEnvVars` entry, e.g. `Z_AI_API_KEY` for zai)
|
|
228
|
+
* so the existing `resolveXApiKey` resolvers discover them without a
|
|
229
|
+
* new code path.
|
|
230
|
+
*
|
|
231
|
+
* A Provider with no matching descriptor, a blank file key, or no
|
|
232
|
+
* `credentialEnvVars` is silently skipped.
|
|
233
|
+
*/
|
|
234
|
+
export function resolveEnvFromConfig(env, config, descriptors) {
|
|
235
|
+
const resolved = { ...env };
|
|
236
|
+
const byId = new Map(descriptors.map((d) => [d.id, d]));
|
|
237
|
+
for (const [providerId, providerConfig] of Object.entries(config.providers)) {
|
|
238
|
+
const fileKey = providerConfig.apiKey;
|
|
239
|
+
if (typeof fileKey !== "string" || fileKey.trim().length === 0)
|
|
240
|
+
continue;
|
|
241
|
+
const descriptor = byId.get(providerId);
|
|
242
|
+
if (!descriptor)
|
|
243
|
+
continue;
|
|
244
|
+
// Env wins: if the Provider is already configured through the
|
|
245
|
+
// injected env (primary OR alias), the file key must not clobber it.
|
|
246
|
+
if (descriptor.isConfigured(env))
|
|
247
|
+
continue;
|
|
248
|
+
const canonical = descriptor.credentialEnvVars?.[0];
|
|
249
|
+
if (typeof canonical !== "string" || canonical.length === 0)
|
|
250
|
+
continue;
|
|
251
|
+
// Only populate when the canonical slot is absent or blank in the
|
|
252
|
+
// resolved view. This guards against an earlier iteration writing a
|
|
253
|
+
// different Provider's alias into the same variable name (none exist
|
|
254
|
+
// today, but the guard keeps the function total).
|
|
255
|
+
const existing = resolved[canonical];
|
|
256
|
+
if (typeof existing === "string" && existing.trim().length > 0)
|
|
257
|
+
continue;
|
|
258
|
+
resolved[canonical] = fileKey;
|
|
259
|
+
}
|
|
260
|
+
return resolved;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Production {@link VerificationPromotionStore}. Reads the live config,
|
|
264
|
+
* flips the matching Provider record's `verification.status` from
|
|
265
|
+
* `unverified` to `verified`, and rewrites the file atomically. A
|
|
266
|
+
* record that is absent, has no verification field, or is already
|
|
267
|
+
* `verified` is a no-op (no write, no error). The read-modify-write is
|
|
268
|
+
* not cross-process locked; Doctor is a single-shot CLI command and the
|
|
269
|
+
* atomic rename keeps the final state crash-safe against partial writes.
|
|
270
|
+
*/
|
|
271
|
+
export function createDefaultVerificationPromoter(options = {}) {
|
|
272
|
+
return {
|
|
273
|
+
async promote(providerId, checkedAt) {
|
|
274
|
+
const inspection = await inspectConfig(options);
|
|
275
|
+
if (inspection.status !== "valid")
|
|
276
|
+
return;
|
|
277
|
+
const existing = inspection.config.providers[providerId];
|
|
278
|
+
if (!existing || !existing.verification)
|
|
279
|
+
return;
|
|
280
|
+
if (existing.verification.status === "verified")
|
|
281
|
+
return;
|
|
282
|
+
const updated = {
|
|
283
|
+
...inspection.config,
|
|
284
|
+
providers: {
|
|
285
|
+
...inspection.config.providers,
|
|
286
|
+
[providerId]: {
|
|
287
|
+
...existing,
|
|
288
|
+
verification: { status: "verified", checkedAt },
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
await writeConfig(updated, options);
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Production {@link HintShownStore}. Reads the live config, sets
|
|
298
|
+
* `hintShown: true` if it is currently unset/false, and rewrites the
|
|
299
|
+
* file atomically. Same read-modify-write caveats as the verification
|
|
300
|
+
* promoter.
|
|
301
|
+
*
|
|
302
|
+
* When the config is ABSENT, the store creates a minimal config file
|
|
303
|
+
* (`{version:1, providers:{}, hintShown:true}`) so the hint does NOT
|
|
304
|
+
* repeat on every subsequent run — the ticket's "one-time marker"
|
|
305
|
+
* contract requires persistence, and absent-config is the common case
|
|
306
|
+
* for a user who just installed scoutline and is running on env vars.
|
|
307
|
+
* A CORRUPT config is a no-op (init is the recovery path; the hint
|
|
308
|
+
* store must not silently rewrite a corrupt file).
|
|
309
|
+
*/
|
|
310
|
+
export function createDefaultHintShownStore(options = {}) {
|
|
311
|
+
return {
|
|
312
|
+
async setHintShown() {
|
|
313
|
+
const inspection = await inspectConfig(options);
|
|
314
|
+
if (inspection.status === "corrupt")
|
|
315
|
+
return;
|
|
316
|
+
if (inspection.status === "valid") {
|
|
317
|
+
if (inspection.config.hintShown === true)
|
|
318
|
+
return;
|
|
319
|
+
const updated = {
|
|
320
|
+
...inspection.config,
|
|
321
|
+
hintShown: true,
|
|
322
|
+
};
|
|
323
|
+
await writeConfig(updated, options);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
// Absent — create a minimal config carrying just the marker so the
|
|
327
|
+
// hint does not repeat. This is the common env-only-install case.
|
|
328
|
+
await writeConfig({ version: CONFIG_VERSION, providers: {}, hintShown: true }, options);
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=config-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/lib/config-store.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -11,11 +11,11 @@ export interface ZaiConfig {
|
|
|
11
11
|
topP: number;
|
|
12
12
|
maxTokens: number;
|
|
13
13
|
}
|
|
14
|
-
export declare function loadConfig(): ZaiConfig;
|
|
14
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): ZaiConfig;
|
|
15
15
|
export declare function getMcpEndpoints(): {
|
|
16
16
|
readonly ZREAD: "https://api.z.ai/api/mcp/zread/mcp";
|
|
17
17
|
readonly WEB_SEARCH: "https://api.z.ai/api/mcp/web_search_prime/mcp";
|
|
18
18
|
readonly WEB_READER: "https://api.z.ai/api/mcp/web_reader/mcp";
|
|
19
19
|
};
|
|
20
|
-
export declare function getApiKey(): string;
|
|
20
|
+
export declare function getApiKey(env?: NodeJS.ProcessEnv): string;
|
|
21
21
|
//# sourceMappingURL=config.d.ts.map
|
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;;GAEG;AAIH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAgCD,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAwB1E;AAED,wBAAgB,eAAe;oBAhDtB,oCAAoC;yBAC/B,+CAA+C;yBAC/C,yCAAyC;EAgDtD;AAED,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAUtE"}
|
package/dist/lib/config.js
CHANGED
|
@@ -20,8 +20,16 @@ const MISSING_KEY_HELP = [
|
|
|
20
20
|
"Get your API key at:",
|
|
21
21
|
" https://z.ai/manage-apikey/apikey-list",
|
|
22
22
|
].join("\n");
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
//
|
|
24
|
+
// T2a — Credential view: `loadConfig` and `getApiKey` accept an explicit
|
|
25
|
+
// `env` parameter (defaulting to `process.env`) so the resolved
|
|
26
|
+
// environment built in `main` — which merges file-configured keys on top
|
|
27
|
+
// of the injected `MainDependencies.env` — reaches every Z.AI credential
|
|
28
|
+
// reader. The signature is additive: existing no-argument callers keep
|
|
29
|
+
// working unchanged against ambient `process.env`.
|
|
30
|
+
//
|
|
31
|
+
export function loadConfig(env = process.env) {
|
|
32
|
+
const apiKey = env.Z_AI_API_KEY || env.ZAI_API_KEY;
|
|
25
33
|
if (!apiKey) {
|
|
26
34
|
// P1-09: throw a normalized ConfigurationError (exit 3) instead of
|
|
27
35
|
// terminating the process. Callers route through invokeCommand, which
|
|
@@ -29,24 +37,24 @@ export function loadConfig() {
|
|
|
29
37
|
// transport is constructed and no process streams are touched here.
|
|
30
38
|
throw new ConfigurationError("Z_AI_API_KEY environment variable is required", MISSING_KEY_HELP);
|
|
31
39
|
}
|
|
32
|
-
const mode = (
|
|
33
|
-
const baseUrl =
|
|
40
|
+
const mode = (env.Z_AI_MODE || env.PLATFORM_MODE || "ZAI").toUpperCase();
|
|
41
|
+
const baseUrl = env.Z_AI_BASE_URL || BASE_URLS[mode] || BASE_URLS.ZAI;
|
|
34
42
|
return {
|
|
35
43
|
apiKey,
|
|
36
44
|
mode,
|
|
37
45
|
baseUrl,
|
|
38
|
-
timeout: parseInt(
|
|
39
|
-
visionModel:
|
|
40
|
-
temperature: parseFloat(
|
|
41
|
-
topP: parseFloat(
|
|
42
|
-
maxTokens: parseInt(
|
|
46
|
+
timeout: parseInt(env.Z_AI_TIMEOUT || "30000", 10),
|
|
47
|
+
visionModel: env.Z_AI_VISION_MODEL || "glm-4.6v",
|
|
48
|
+
temperature: parseFloat(env.Z_AI_TEMPERATURE || "0.8"),
|
|
49
|
+
topP: parseFloat(env.Z_AI_TOP_P || "0.6"),
|
|
50
|
+
maxTokens: parseInt(env.Z_AI_MAX_TOKENS || "32768", 10),
|
|
43
51
|
};
|
|
44
52
|
}
|
|
45
53
|
export function getMcpEndpoints() {
|
|
46
54
|
return MCP_ENDPOINTS;
|
|
47
55
|
}
|
|
48
|
-
export function getApiKey() {
|
|
49
|
-
const apiKey =
|
|
56
|
+
export function getApiKey(env = process.env) {
|
|
57
|
+
const apiKey = env.Z_AI_API_KEY || env.ZAI_API_KEY;
|
|
50
58
|
if (!apiKey) {
|
|
51
59
|
// P1-09: throw instead of process.exit(3); see loadConfig for rationale.
|
|
52
60
|
throw new ConfigurationError("Z_AI_API_KEY environment variable is required", 'export Z_AI_API_KEY="your-api-key"');
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAajD,MAAM,SAAS,GAAG;IAChB,kDAAkD;IAClD,GAAG,EAAE,qCAAqC;IAC1C,KAAK,EAAE,sCAAsC;CACrC,CAAC;AAEX,uBAAuB;AACvB,MAAM,aAAa,GAAG;IACpB,KAAK,EAAE,oCAAoC;IAC3C,UAAU,EAAE,+CAA+C;IAC3D,UAAU,EAAE,yCAAyC;CAC7C,CAAC;AAEX,MAAM,gBAAgB,GAAG;IACvB,YAAY;IACZ,sCAAsC;IACtC,EAAE;IACF,sBAAsB;IACtB,0CAA0C;CAC3C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,UAAU,UAAU
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAajD,MAAM,SAAS,GAAG;IAChB,kDAAkD;IAClD,GAAG,EAAE,qCAAqC;IAC1C,KAAK,EAAE,sCAAsC;CACrC,CAAC;AAEX,uBAAuB;AACvB,MAAM,aAAa,GAAG;IACpB,KAAK,EAAE,oCAAoC;IAC3C,UAAU,EAAE,+CAA+C;IAC3D,UAAU,EAAE,yCAAyC;CAC7C,CAAC;AAEX,MAAM,gBAAgB,GAAG;IACvB,YAAY;IACZ,sCAAsC;IACtC,EAAE;IACF,sBAAsB;IACtB,0CAA0C;CAC3C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,EAAE;AACF,yEAAyE;AACzE,gEAAgE;AAChE,yEAAyE;AACzE,yEAAyE;AACzE,uEAAuE;AACvE,mDAAmD;AACnD,EAAE;AAEF,MAAM,UAAU,UAAU,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC7D,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,WAAW,CAAC;IAEnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,mEAAmE;QACnE,sEAAsE;QACtE,iEAAiE;QACjE,oEAAoE;QACpE,MAAM,IAAI,kBAAkB,CAAC,+CAA+C,EAAE,gBAAgB,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,aAAa,IAAI,KAAK,CAAC,CAAC,WAAW,EAAqB,CAAC;IAC5F,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC;IAEtE,OAAO;QACL,MAAM;QACN,IAAI;QACJ,OAAO;QACP,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,EAAE,EAAE,CAAC;QAClD,WAAW,EAAE,GAAG,CAAC,iBAAiB,IAAI,UAAU;QAChD,WAAW,EAAE,UAAU,CAAC,GAAG,CAAC,gBAAgB,IAAI,KAAK,CAAC;QACtD,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,IAAI,KAAK,CAAC;QACzC,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,EAAE,EAAE,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC5D,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,WAAW,CAAC;IACnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,yEAAyE;QACzE,MAAM,IAAI,kBAAkB,CAC1B,+CAA+C,EAC/C,oCAAoC,CACrC,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consumption event + sink (Plan B — PB-T2).
|
|
3
|
+
*
|
|
4
|
+
* A **typed consumption event** represents one billable Provider
|
|
5
|
+
* transport attempt. Shared execution emits it at the execution seam
|
|
6
|
+
* (`lib/execution.ts`) — after the cache-miss check, around each
|
|
7
|
+
* `operation.invoke()` call — so cache hits emit nothing and a retried
|
|
8
|
+
* operation emits one event per attempt.
|
|
9
|
+
*
|
|
10
|
+
* Boundary rules:
|
|
11
|
+
* - Imports quota-store types (the sink writes to it) and provider
|
|
12
|
+
* identity types. No provider transport, no command presentation.
|
|
13
|
+
* - The sink is **best-effort**: a record failure is converted to a
|
|
14
|
+
* redacted warning and never propagates. A successful Provider
|
|
15
|
+
* result still returns; the retry/fallback classifier is never
|
|
16
|
+
* consulted on accounting state.
|
|
17
|
+
* - The amount is an explicit exact/estimate/unknown discriminated
|
|
18
|
+
* value. There is no `number = 1` default — Research/Vision and
|
|
19
|
+
* other variable-cost capabilities persist `unknown` or an
|
|
20
|
+
* explicit estimate rather than fake-precise consumption.
|
|
21
|
+
*
|
|
22
|
+
* Persistence lifecycle:
|
|
23
|
+
* - The sink's `record()` promise is awaited before the billable
|
|
24
|
+
* invoke returns outward, so the consumption write survives the
|
|
25
|
+
* bin's immediate `process.exit(status)`. A rejection is converted
|
|
26
|
+
* to a stderr warning; the outer promise still resolves.
|
|
27
|
+
*
|
|
28
|
+
* Relation to PB-T1 / PB-T3:
|
|
29
|
+
* - The sink calls PB-T1's `QuotaStore.writeConsumption`, advancing
|
|
30
|
+
* `locallyUpdatedAt` and adjusting the matching category's count
|
|
31
|
+
* set when one is exposed. `observedAt` (ground truth) never moves.
|
|
32
|
+
* - The event carries canonical data (capability ID, category, unit,
|
|
33
|
+
* amount). PB-T3 maps capabilities→categories and PB-T4 ranks;
|
|
34
|
+
* PB-T2 records raw, provider-neutral events and lets later layers
|
|
35
|
+
* interpret them.
|
|
36
|
+
*/
|
|
37
|
+
import type { ProviderId } from "../providers/types.js";
|
|
38
|
+
import type { QuotaUnit, ConsumptionAmount, QuotaStore } from "./quota-store.js";
|
|
39
|
+
/**
|
|
40
|
+
* A single billable Provider transport attempt. Emitted once per
|
|
41
|
+
* `invoke()` inside `executeProviderOperation` — never at wrapper
|
|
42
|
+
* level, never on cache hit, never from `quota`/`doctor`.
|
|
43
|
+
*
|
|
44
|
+
* `attempt` is the 1-based attempt index within one
|
|
45
|
+
* `executeProviderOperation` loop (1 = first try, 2 = first retry...).
|
|
46
|
+
*/
|
|
47
|
+
export interface ConsumptionEvent {
|
|
48
|
+
readonly provider: ProviderId;
|
|
49
|
+
readonly capabilityId: string;
|
|
50
|
+
readonly category?: string;
|
|
51
|
+
readonly unit?: QuotaUnit;
|
|
52
|
+
readonly amount: ConsumptionAmount;
|
|
53
|
+
readonly attempt: number;
|
|
54
|
+
readonly at: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Provider-neutral metadata a billable wrapper passes into
|
|
58
|
+
* `executeProviderOperation`. Identifies *what* is being consumed,
|
|
59
|
+
* independent of *where* the event is recorded. The sink
|
|
60
|
+
* (`ExecutionDependencies.consume`) is the *where*.
|
|
61
|
+
*
|
|
62
|
+
* `amount` defaults to {@link defaultAmountForCapability} when the
|
|
63
|
+
* wrapper does not know a precise cost from the response usage — most
|
|
64
|
+
* providers do not return per-call usage.
|
|
65
|
+
*/
|
|
66
|
+
export interface ConsumptionContext {
|
|
67
|
+
readonly provider: ProviderId;
|
|
68
|
+
readonly capabilityId: string;
|
|
69
|
+
readonly category?: string;
|
|
70
|
+
readonly unit?: QuotaUnit;
|
|
71
|
+
readonly amount: ConsumptionAmount;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Injectable sink. Production wires
|
|
75
|
+
* {@link createQuotaStoreConsumptionSink} (atomic read-merge-write
|
|
76
|
+
* against `~/.scoutline/state.json` via PB-T1's store); tests inject
|
|
77
|
+
* {@link createInMemoryConsumptionSink} so assertions never touch disk.
|
|
78
|
+
*
|
|
79
|
+
* Contract: `record()` MUST NOT throw on accounting failure. The
|
|
80
|
+
* shared-execution emission site does not catch — the sink converts
|
|
81
|
+
* any internal failure to a warning before resolution. This keeps the
|
|
82
|
+
* retry/fallback classifier free of accounting concerns.
|
|
83
|
+
*/
|
|
84
|
+
export interface ConsumptionSink {
|
|
85
|
+
record(event: ConsumptionEvent): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Default {@link ConsumptionAmount} for a capability when the wrapper
|
|
89
|
+
* has no response-usage to derive from. Most providers do not return
|
|
90
|
+
* per-call usage, so the default is **unknown** — never a fake-precise
|
|
91
|
+
* "1".
|
|
92
|
+
*
|
|
93
|
+
* Capabilities whose unit-cost is reliably one (Search, Repository,
|
|
94
|
+
* Reader, Map) get `{ kind: "estimate", value: 1 }`. Capabilities
|
|
95
|
+
* with variable cost (Research = 4–250 credits, Vision = variable
|
|
96
|
+
* tokens, Crawl = per-page) default to `unknown`. PB-T3 refines these
|
|
97
|
+
* mappings; PB-T2 records the honest default.
|
|
98
|
+
*/
|
|
99
|
+
export declare function defaultAmountForCapability(capabilityId: string): ConsumptionAmount;
|
|
100
|
+
export interface ConsumptionSinkOptions {
|
|
101
|
+
readonly store: QuotaStore;
|
|
102
|
+
readonly now?: () => number;
|
|
103
|
+
/**
|
|
104
|
+
* Best-effort warning sink. A write failure is isolated through this
|
|
105
|
+
* callback; the recorded event's promise still resolves. Production
|
|
106
|
+
* wires a stderr notice; tests inject a recorder. Default writes a
|
|
107
|
+
* redacted message to stderr (no event detail, no PII).
|
|
108
|
+
*/
|
|
109
|
+
readonly onWarning?: (message: string) => void;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Build a production {@link ConsumptionSink} that writes through
|
|
113
|
+
* {@link QuotaStore.writeConsumption}. The sink is fail-safe: any
|
|
114
|
+
* internal rejection (disk full, permission, race) is converted to a
|
|
115
|
+
* warning and the recorded promise resolves so shared execution never
|
|
116
|
+
* observes an accounting failure.
|
|
117
|
+
*
|
|
118
|
+
* The store's per-file mutex serializes concurrent writes within the
|
|
119
|
+
* process; cross-process concurrency is last-write-wins (acceptable
|
|
120
|
+
* for an observational heuristic; PB-T1's atomic rename keeps the
|
|
121
|
+
* final state crash-safe).
|
|
122
|
+
*/
|
|
123
|
+
export declare function createQuotaStoreConsumptionSink(options: ConsumptionSinkOptions): ConsumptionSink;
|
|
124
|
+
/**
|
|
125
|
+
* Build an in-memory {@link ConsumptionSink} for hermetic tests. Records
|
|
126
|
+
* every event in `events` (in arrival order); never rejects. Use this
|
|
127
|
+
* to assert exact event sequences for cache-hit suppression, retry
|
|
128
|
+
* emission, and observational-handler silence.
|
|
129
|
+
*/
|
|
130
|
+
export declare function createInMemoryConsumptionSink(): ConsumptionSink & {
|
|
131
|
+
readonly events: ConsumptionEvent[];
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Emit one {@link ConsumptionEvent} through `sink`, deriving the event
|
|
135
|
+
* from `context` + `attempt`. The promise ALWAYS resolves: a sink
|
|
136
|
+
* failure has already been converted to a warning inside the sink, and
|
|
137
|
+
* this helper adds a defensive outer try/catch so an exception in the
|
|
138
|
+
* context-derivation path can never escape into the retry classifier.
|
|
139
|
+
*
|
|
140
|
+
* Returns void — shared execution awaits it before the invoke returns
|
|
141
|
+
* outward, but the resolution value carries no information.
|
|
142
|
+
*/
|
|
143
|
+
export declare function emitConsumption(sink: ConsumptionSink, context: ConsumptionContext, attempt: number, now: () => number): Promise<void>;
|
|
144
|
+
//# sourceMappingURL=consumption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumption.d.ts","sourceRoot":"","sources":["../../src/lib/consumption.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMjF;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;CACpC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,CAoBlF;AAMD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAwBhG;AAMD;;;;;GAKG;AACH,wBAAgB,6BAA6B,IAAI,eAAe,GAAG;IACjE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC;CACrC,CAUA;AAMD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|