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.
Files changed (151) hide show
  1. package/README.md +99 -44
  2. package/dist/capabilities/diagnostics.d.ts +75 -0
  3. package/dist/capabilities/diagnostics.d.ts.map +1 -1
  4. package/dist/capabilities/diagnostics.js.map +1 -1
  5. package/dist/capabilities/quota.d.ts +64 -1
  6. package/dist/capabilities/quota.d.ts.map +1 -1
  7. package/dist/capabilities/quota.js.map +1 -1
  8. package/dist/capabilities/vision.d.ts +4 -3
  9. package/dist/capabilities/vision.d.ts.map +1 -1
  10. package/dist/capabilities/vision.js +7 -5
  11. package/dist/capabilities/vision.js.map +1 -1
  12. package/dist/commands/code.d.ts +9 -1
  13. package/dist/commands/code.d.ts.map +1 -1
  14. package/dist/commands/code.js +4 -4
  15. package/dist/commands/code.js.map +1 -1
  16. package/dist/commands/crawl.d.ts.map +1 -1
  17. package/dist/commands/crawl.js +14 -3
  18. package/dist/commands/crawl.js.map +1 -1
  19. package/dist/commands/doctor.d.ts +71 -1
  20. package/dist/commands/doctor.d.ts.map +1 -1
  21. package/dist/commands/doctor.js +96 -15
  22. package/dist/commands/doctor.js.map +1 -1
  23. package/dist/commands/init.d.ts +186 -0
  24. package/dist/commands/init.d.ts.map +1 -0
  25. package/dist/commands/init.js +1221 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/map.d.ts.map +1 -1
  28. package/dist/commands/map.js +16 -3
  29. package/dist/commands/map.js.map +1 -1
  30. package/dist/commands/quota.d.ts +32 -0
  31. package/dist/commands/quota.d.ts.map +1 -1
  32. package/dist/commands/quota.js +165 -24
  33. package/dist/commands/quota.js.map +1 -1
  34. package/dist/commands/read.d.ts.map +1 -1
  35. package/dist/commands/read.js +9 -3
  36. package/dist/commands/read.js.map +1 -1
  37. package/dist/commands/repo.d.ts.map +1 -1
  38. package/dist/commands/repo.js +5 -3
  39. package/dist/commands/repo.js.map +1 -1
  40. package/dist/commands/research.d.ts +35 -7
  41. package/dist/commands/research.d.ts.map +1 -1
  42. package/dist/commands/research.js +93 -15
  43. package/dist/commands/research.js.map +1 -1
  44. package/dist/commands/tools.d.ts +8 -0
  45. package/dist/commands/tools.d.ts.map +1 -1
  46. package/dist/commands/tools.js +4 -4
  47. package/dist/commands/tools.js.map +1 -1
  48. package/dist/commands/vision.d.ts +10 -0
  49. package/dist/commands/vision.d.ts.map +1 -1
  50. package/dist/commands/vision.js +25 -2
  51. package/dist/commands/vision.js.map +1 -1
  52. package/dist/index.d.ts +136 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +894 -298
  55. package/dist/index.js.map +1 -1
  56. package/dist/lib/api-client.d.ts +1 -1
  57. package/dist/lib/api-client.d.ts.map +1 -1
  58. package/dist/lib/api-client.js +6 -2
  59. package/dist/lib/api-client.js.map +1 -1
  60. package/dist/lib/cache.d.ts +9 -2
  61. package/dist/lib/cache.d.ts.map +1 -1
  62. package/dist/lib/cache.js +9 -2
  63. package/dist/lib/cache.js.map +1 -1
  64. package/dist/lib/code-mode.d.ts +8 -0
  65. package/dist/lib/code-mode.d.ts.map +1 -1
  66. package/dist/lib/code-mode.js +3 -1
  67. package/dist/lib/code-mode.js.map +1 -1
  68. package/dist/lib/config-store.d.ts +165 -0
  69. package/dist/lib/config-store.d.ts.map +1 -0
  70. package/dist/lib/config-store.js +332 -0
  71. package/dist/lib/config-store.js.map +1 -0
  72. package/dist/lib/config.d.ts +2 -2
  73. package/dist/lib/config.d.ts.map +1 -1
  74. package/dist/lib/config.js +19 -11
  75. package/dist/lib/config.js.map +1 -1
  76. package/dist/lib/consumption.d.ts +144 -0
  77. package/dist/lib/consumption.d.ts.map +1 -0
  78. package/dist/lib/consumption.js +161 -0
  79. package/dist/lib/consumption.js.map +1 -0
  80. package/dist/lib/errors.d.ts +11 -0
  81. package/dist/lib/errors.d.ts.map +1 -1
  82. package/dist/lib/errors.js +14 -0
  83. package/dist/lib/errors.js.map +1 -1
  84. package/dist/lib/execution.d.ts +32 -4
  85. package/dist/lib/execution.d.ts.map +1 -1
  86. package/dist/lib/execution.js +156 -13
  87. package/dist/lib/execution.js.map +1 -1
  88. package/dist/lib/mcp-client.d.ts +12 -0
  89. package/dist/lib/mcp-client.d.ts.map +1 -1
  90. package/dist/lib/mcp-client.js +16 -7
  91. package/dist/lib/mcp-client.js.map +1 -1
  92. package/dist/lib/mcp-config.d.ts +10 -0
  93. package/dist/lib/mcp-config.d.ts.map +1 -1
  94. package/dist/lib/mcp-config.js +13 -7
  95. package/dist/lib/mcp-config.js.map +1 -1
  96. package/dist/lib/monitor-client.d.ts +19 -3
  97. package/dist/lib/monitor-client.d.ts.map +1 -1
  98. package/dist/lib/monitor-client.js +21 -5
  99. package/dist/lib/monitor-client.js.map +1 -1
  100. package/dist/lib/provider-fallback.d.ts +150 -0
  101. package/dist/lib/provider-fallback.d.ts.map +1 -0
  102. package/dist/lib/provider-fallback.js +510 -0
  103. package/dist/lib/provider-fallback.js.map +1 -0
  104. package/dist/lib/quota-mapping.d.ts +402 -0
  105. package/dist/lib/quota-mapping.d.ts.map +1 -0
  106. package/dist/lib/quota-mapping.js +539 -0
  107. package/dist/lib/quota-mapping.js.map +1 -0
  108. package/dist/lib/quota-store.d.ts +271 -0
  109. package/dist/lib/quota-store.d.ts.map +1 -0
  110. package/dist/lib/quota-store.js +540 -0
  111. package/dist/lib/quota-store.js.map +1 -0
  112. package/dist/lib/trigger-detection.d.ts +149 -0
  113. package/dist/lib/trigger-detection.d.ts.map +1 -0
  114. package/dist/lib/trigger-detection.js +149 -0
  115. package/dist/lib/trigger-detection.js.map +1 -0
  116. package/dist/lib/tty.d.ts +8 -1
  117. package/dist/lib/tty.d.ts.map +1 -1
  118. package/dist/lib/tty.js +53 -1
  119. package/dist/lib/tty.js.map +1 -1
  120. package/dist/providers/brave/adapter.d.ts +26 -0
  121. package/dist/providers/brave/adapter.d.ts.map +1 -1
  122. package/dist/providers/brave/adapter.js +66 -4
  123. package/dist/providers/brave/adapter.js.map +1 -1
  124. package/dist/providers/brave/client.d.ts +46 -2
  125. package/dist/providers/brave/client.d.ts.map +1 -1
  126. package/dist/providers/brave/client.js +55 -3
  127. package/dist/providers/brave/client.js.map +1 -1
  128. package/dist/providers/exa/adapter.d.ts.map +1 -1
  129. package/dist/providers/exa/adapter.js +10 -1
  130. package/dist/providers/exa/adapter.js.map +1 -1
  131. package/dist/providers/firecrawl/adapter.d.ts.map +1 -1
  132. package/dist/providers/firecrawl/adapter.js +13 -3
  133. package/dist/providers/firecrawl/adapter.js.map +1 -1
  134. package/dist/providers/minimax/adapter.d.ts.map +1 -1
  135. package/dist/providers/minimax/adapter.js +4 -0
  136. package/dist/providers/minimax/adapter.js.map +1 -1
  137. package/dist/providers/selection.d.ts +114 -1
  138. package/dist/providers/selection.d.ts.map +1 -1
  139. package/dist/providers/selection.js +99 -3
  140. package/dist/providers/selection.js.map +1 -1
  141. package/dist/providers/tavily/adapter.d.ts.map +1 -1
  142. package/dist/providers/tavily/adapter.js +2 -0
  143. package/dist/providers/tavily/adapter.js.map +1 -1
  144. package/dist/providers/types.d.ts +33 -1
  145. package/dist/providers/types.d.ts.map +1 -1
  146. package/dist/providers/types.js +8 -0
  147. package/dist/providers/types.js.map +1 -1
  148. package/dist/providers/zai/adapter.d.ts.map +1 -1
  149. package/dist/providers/zai/adapter.js +18 -5
  150. package/dist/providers/zai/adapter.js.map +1 -1
  151. 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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"}
@@ -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
@@ -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;AAuBD,wBAAgB,UAAU,IAAI,SAAS,CA0BtC;AAED,wBAAgB,eAAe;oBAzCtB,oCAAoC;yBAC/B,+CAA+C;yBAC/C,yCAAyC;EAyCtD;AAED,wBAAgB,SAAS,IAAI,MAAM,CAUlC"}
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"}
@@ -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
- export function loadConfig() {
24
- const apiKey = process.env.Z_AI_API_KEY || process.env.ZAI_API_KEY;
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 = (process.env.Z_AI_MODE || process.env.PLATFORM_MODE || "ZAI").toUpperCase();
33
- const baseUrl = process.env.Z_AI_BASE_URL || BASE_URLS[mode] || BASE_URLS.ZAI;
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(process.env.Z_AI_TIMEOUT || "30000", 10),
39
- visionModel: process.env.Z_AI_VISION_MODEL || "glm-4.6v",
40
- temperature: parseFloat(process.env.Z_AI_TEMPERATURE || "0.8"),
41
- topP: parseFloat(process.env.Z_AI_TOP_P || "0.6"),
42
- maxTokens: parseInt(process.env.Z_AI_MAX_TOKENS || "32768", 10),
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 = process.env.Z_AI_API_KEY || process.env.ZAI_API_KEY;
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"');
@@ -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;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAEnE,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,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,KAAK,CAAC,CAAC,WAAW,EAE3E,CAAC;IACZ,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC;IAE9E,OAAO;QACL,MAAM;QACN,IAAI;QACJ,OAAO;QACP,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,EAAE,EAAE,CAAC;QAC1D,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,UAAU;QACxD,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,KAAK,CAAC;QAC9D,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,KAAK,CAAC;QACjD,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,EAAE,EAAE,CAAC;KAChE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IACnE,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"}
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"}