scoutline 0.2.0 → 0.6.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 (110) hide show
  1. package/README.md +240 -18
  2. package/dist/capabilities/diagnostics.d.ts +70 -32
  3. package/dist/capabilities/diagnostics.d.ts.map +1 -1
  4. package/dist/capabilities/diagnostics.js +97 -46
  5. package/dist/capabilities/diagnostics.js.map +1 -1
  6. package/dist/capabilities/reader.d.ts +227 -0
  7. package/dist/capabilities/reader.d.ts.map +1 -0
  8. package/dist/capabilities/reader.js +100 -0
  9. package/dist/capabilities/reader.js.map +1 -0
  10. package/dist/capabilities/repository.d.ts +221 -0
  11. package/dist/capabilities/repository.d.ts.map +1 -0
  12. package/dist/capabilities/repository.js +172 -0
  13. package/dist/capabilities/repository.js.map +1 -0
  14. package/dist/commands/cache.d.ts +106 -0
  15. package/dist/commands/cache.d.ts.map +1 -0
  16. package/dist/commands/cache.js +203 -0
  17. package/dist/commands/cache.js.map +1 -0
  18. package/dist/commands/doctor.d.ts +17 -6
  19. package/dist/commands/doctor.d.ts.map +1 -1
  20. package/dist/commands/doctor.js +42 -17
  21. package/dist/commands/doctor.js.map +1 -1
  22. package/dist/commands/read.d.ts +74 -14
  23. package/dist/commands/read.d.ts.map +1 -1
  24. package/dist/commands/read.js +257 -117
  25. package/dist/commands/read.js.map +1 -1
  26. package/dist/commands/repo.d.ts +53 -7
  27. package/dist/commands/repo.d.ts.map +1 -1
  28. package/dist/commands/repo.js +104 -123
  29. package/dist/commands/repo.js.map +1 -1
  30. package/dist/commands/repository-explorer.d.ts +147 -0
  31. package/dist/commands/repository-explorer.d.ts.map +1 -0
  32. package/dist/commands/repository-explorer.js +550 -0
  33. package/dist/commands/repository-explorer.js.map +1 -0
  34. package/dist/index.d.ts +20 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +209 -34
  37. package/dist/index.js.map +1 -1
  38. package/dist/lib/cache.d.ts +123 -18
  39. package/dist/lib/cache.d.ts.map +1 -1
  40. package/dist/lib/cache.js +324 -49
  41. package/dist/lib/cache.js.map +1 -1
  42. package/dist/lib/errors.d.ts +24 -1
  43. package/dist/lib/errors.d.ts.map +1 -1
  44. package/dist/lib/errors.js +33 -2
  45. package/dist/lib/errors.js.map +1 -1
  46. package/dist/lib/execution.d.ts +119 -5
  47. package/dist/lib/execution.d.ts.map +1 -1
  48. package/dist/lib/execution.js +216 -10
  49. package/dist/lib/execution.js.map +1 -1
  50. package/dist/lib/index.d.ts +1 -1
  51. package/dist/lib/index.d.ts.map +1 -1
  52. package/dist/lib/index.js +1 -1
  53. package/dist/lib/index.js.map +1 -1
  54. package/dist/lib/mcp-client.d.ts +29 -5
  55. package/dist/lib/mcp-client.d.ts.map +1 -1
  56. package/dist/lib/mcp-client.js +88 -88
  57. package/dist/lib/mcp-client.js.map +1 -1
  58. package/dist/lib/tool-cache.d.ts +86 -0
  59. package/dist/lib/tool-cache.d.ts.map +1 -0
  60. package/dist/lib/tool-cache.js +123 -0
  61. package/dist/lib/tool-cache.js.map +1 -0
  62. package/dist/providers/minimax/adapter.d.ts +6 -4
  63. package/dist/providers/minimax/adapter.d.ts.map +1 -1
  64. package/dist/providers/minimax/adapter.js +64 -57
  65. package/dist/providers/minimax/adapter.js.map +1 -1
  66. package/dist/providers/minimax/coding-plan-client.d.ts +60 -0
  67. package/dist/providers/minimax/coding-plan-client.d.ts.map +1 -0
  68. package/dist/providers/minimax/coding-plan-client.js +204 -0
  69. package/dist/providers/minimax/coding-plan-client.js.map +1 -0
  70. package/dist/providers/minimax/media.d.ts +60 -6
  71. package/dist/providers/minimax/media.d.ts.map +1 -1
  72. package/dist/providers/minimax/media.js +147 -7
  73. package/dist/providers/minimax/media.js.map +1 -1
  74. package/dist/providers/minimax/quota-client.d.ts +13 -6
  75. package/dist/providers/minimax/quota-client.d.ts.map +1 -1
  76. package/dist/providers/minimax/quota-client.js +5 -0
  77. package/dist/providers/minimax/quota-client.js.map +1 -1
  78. package/dist/providers/minimax/vision-attestations.d.ts +23 -0
  79. package/dist/providers/minimax/vision-attestations.d.ts.map +1 -1
  80. package/dist/providers/minimax/vision-attestations.js +35 -10
  81. package/dist/providers/minimax/vision-attestations.js.map +1 -1
  82. package/dist/providers/minimax/vision-conformance.d.ts +8 -6
  83. package/dist/providers/minimax/vision-conformance.d.ts.map +1 -1
  84. package/dist/providers/minimax/vision-conformance.js +8 -6
  85. package/dist/providers/minimax/vision-conformance.js.map +1 -1
  86. package/dist/providers/minimax/vision-revisions.d.ts +8 -1
  87. package/dist/providers/minimax/vision-revisions.d.ts.map +1 -1
  88. package/dist/providers/minimax/vision-revisions.js +13 -6
  89. package/dist/providers/minimax/vision-revisions.js.map +1 -1
  90. package/dist/providers/selection.d.ts +3 -3
  91. package/dist/providers/selection.js +3 -3
  92. package/dist/providers/types.d.ts +66 -32
  93. package/dist/providers/types.d.ts.map +1 -1
  94. package/dist/providers/types.js.map +1 -1
  95. package/dist/providers/zai/adapter.d.ts.map +1 -1
  96. package/dist/providers/zai/adapter.js +71 -5
  97. package/dist/providers/zai/adapter.js.map +1 -1
  98. package/dist/providers/zai/encoded-error.d.ts +90 -0
  99. package/dist/providers/zai/encoded-error.d.ts.map +1 -0
  100. package/dist/providers/zai/encoded-error.js +169 -0
  101. package/dist/providers/zai/encoded-error.js.map +1 -0
  102. package/dist/providers/zai/reader.d.ts +82 -0
  103. package/dist/providers/zai/reader.d.ts.map +1 -0
  104. package/dist/providers/zai/reader.js +490 -0
  105. package/dist/providers/zai/reader.js.map +1 -0
  106. package/dist/providers/zai/repository.d.ts +76 -0
  107. package/dist/providers/zai/repository.d.ts.map +1 -0
  108. package/dist/providers/zai/repository.js +715 -0
  109. package/dist/providers/zai/repository.js.map +1 -0
  110. package/package.json +3 -3
@@ -0,0 +1,490 @@
1
+ /**
2
+ * Z.AI Reader Adapter (DESIGN.md §18; reader-migration-tech-plan D4;
3
+ * PRD FR-??? — reader migration Ticket 03).
4
+ *
5
+ * Owns the Provider-facing half of the provider-neutral Reader
6
+ * Capability defined in `src/capabilities/reader.ts`:
7
+ *
8
+ * - URL rewrite (gist.github.com/<user>/<id> -> /raw) applied BEFORE
9
+ * invocation; the rewritten URL surfaces as `finalUrl` in the
10
+ * result. The rewrite is Z.AI-specific because Z.AI's WebReader
11
+ * MCP recognizes the rewritten URL.
12
+ * - a total parser for the characterized Z.AI WebReader response
13
+ * (`ReaderRawResponse`: object on success, bare string for MCP-
14
+ * level error envelopes);
15
+ * - encoded MCP error classification BEFORE success parsing
16
+ * (`quota` is terminal `QUOTA_ERROR`; the rest of the taxonomy
17
+ * uses the shared retry/terminal classification); the parsing
18
+ * helpers live in `./encoded-error.ts` and are shared with
19
+ * `./repository.ts`;
20
+ * - a single resolved-credential fingerprint per cache identity and
21
+ * exact per-operation legacy cache candidate using Ticket 01's
22
+ * `buildLegacyReaderCacheKey` helper;
23
+ * - `decodeCached` delegates to Ticket 01's total decoder
24
+ * (`decodeReaderFetchResult`);
25
+ * - a fresh transport per invocation attempt and exactly one
26
+ * best-effort close in `finally`; close failure never replaces
27
+ * success nor masks the primary failure;
28
+ * - no leakage of raw WebReader response types outside this module.
29
+ *
30
+ * Boundary rules (ARCHITECTURE.md §2):
31
+ * - May import capability types, normalized errors, the Z.AI MCP
32
+ * tool-name helpers, the legacy cache-key helper, the shared
33
+ * `ZaiAdapterClientPort` typed client port, and the shared
34
+ * encoded-error helpers.
35
+ * - Must NOT import another Provider's Adapter, command
36
+ * presentation, or extract/maxChars projection logic.
37
+ *
38
+ * Scope:
39
+ * - implements the single `reader-fetch` operation only. URL scheme
40
+ * validation, `--extract`, `--max-chars`, and `--full-envelope`
41
+ * belong to the command layer (Ticket 04 cuts the handler over).
42
+ * - descriptor metadata sequencing: Ticket 03 introduces this Adapter
43
+ * handle and wires it through `ProviderAdapter.reader` WITHOUT
44
+ * advertising `reader` on `createZaiDescriptor.capabilities()`;
45
+ * Ticket 04 then flips the descriptor to advertise `reader` so
46
+ * Provider selection and Doctor inventory derive from a single
47
+ * source of truth, AND cuts `commands/read.ts` over to dispatch
48
+ * through `adapter.reader.fetch`. This module owns no registry,
49
+ * selection, or command cutover.
50
+ */
51
+ import crypto from "node:crypto";
52
+ import { ApiError, ScoutlineError, ValidationError } from "../../lib/errors.js";
53
+ import { getMcpToolName } from "../../lib/mcp-config.js";
54
+ import { buildLegacyReaderCacheKey } from "../../lib/cache.js";
55
+ import { requireZaiApiKey } from "./credentials.js";
56
+ import { classifyEncodedMcpError, looksLikeEncodedMcpError } from "./encoded-error.js";
57
+ import { decodeReaderFetchResult, } from "../../capabilities/reader.js";
58
+ /**
59
+ * Production close bound (ms). Matches the existing
60
+ * `ZaiMcpClient.close(timeoutMs = 2000)` semantic; the Adapter races
61
+ * the close against a 2 second timer that resolves silently so a stuck
62
+ * close cannot stall the attempt. Tests may inject a shorter bound via
63
+ * {@link ZaiReaderCapabilityOptions.closeTimeoutMs}.
64
+ */
65
+ export const ZAI_READER_CLOSE_BOUND_MS = 2000;
66
+ // ---------------------------------------------------------------------------
67
+ // Public dotted MCP tool name — the Adapter invokes through this so the
68
+ // `ZaiMcpClient.callToolRaw` path resolves the discovered internal
69
+ // identity on a miss, exactly as it does for Search/Vision/ZRead.
70
+ // ---------------------------------------------------------------------------
71
+ const READER_TOOL_PUBLIC_NAME = getMcpToolName("reader", "webReader");
72
+ // ---------------------------------------------------------------------------
73
+ // Operation label passed to the shared encoded-error classifier. The
74
+ // label surfaces in the sanitized outward ApiError / QuotaError message
75
+ // ("Z.AI reader request failed", "Z.AI reader quota has been exhausted").
76
+ // Auth messages (401, 403) do not carry the label.
77
+ // ---------------------------------------------------------------------------
78
+ const ENCODED_ERROR_LABEL = "reader";
79
+ // ---------------------------------------------------------------------------
80
+ // URL rewrite (gist -> /raw). Duplicated from `commands/read.ts`
81
+ // `maybeRewriteToRaw` because the legacy read command still owns its own
82
+ // copy until Ticket 04 cuts the handler over. Once Ticket 04 lands, the
83
+ // command copy is removed; this is the single Adapter source of truth.
84
+ //
85
+ // The rewrite is Z.AI-specific because Z.AI's WebReader MCP is the thing
86
+ // that recognizes the rewritten URL. A future Provider's reader Adapter
87
+ // decides its own rewriting (or none).
88
+ //
89
+ // Behaviour matches the v0.2 command:
90
+ // - Already raw (matching `/raw`, optionally followed by `/`, `?`, or
91
+ // `#`)? Leave alone.
92
+ // - Only rewrite `gist.github.com/<user>/<id>` (NOT
93
+ // `github.com/<owner>/<repo>`).
94
+ // - Preserve the fragment (file anchor still meaningful); drop the
95
+ // query path segment before appending `/raw`.
96
+ // ---------------------------------------------------------------------------
97
+ /**
98
+ * Rewrite rendered GitHub gist/file URLs to their raw form so Z.AI's
99
+ * reader returns pure file content instead of the rendered HTML page
100
+ * chrome.
101
+ *
102
+ * gist.github.com/<user>/<id> -> gist.github.com/<user>/<id>/raw
103
+ * gist.github.com/<user>/<id>#file-... -> gist.github.com/<user>/<id>/raw#file-...
104
+ *
105
+ * Leaves alone: URLs that already end in /raw, /raw/<rev>, or have a
106
+ * query string. Non-gist URLs pass through unchanged.
107
+ */
108
+ function maybeRewriteToRaw(url) {
109
+ // Already raw? Leave alone.
110
+ if (/\/raw(\/|$|\?|#)/.test(url))
111
+ return url;
112
+ // Only rewrite gist.github.com (not github.com/owner/repo — that's different)
113
+ const m = url.match(/^(https?:\/\/gist\.github\.com\/[^/]+\/[^/#?]+)(?:[/?#]|$)/);
114
+ if (!m)
115
+ return url;
116
+ const base = m[1];
117
+ // Append /raw, preserve any fragment (file anchor still meaningful)
118
+ const frag = url.indexOf("#") >= 0 ? url.slice(url.indexOf("#")) : "";
119
+ return `${base}/raw${frag}`;
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Total parser for the characterized WebReader response (DESIGN.md §18,
123
+ // reader-webreader-characterization artifact). The parser is total over
124
+ // the `ReaderRawResponse` union:
125
+ //
126
+ // - Object shape (the common success case): extract `title`, `url`,
127
+ // `content`, optional `metadata`, optional `external`. The
128
+ // `description` field is dropped (the v1 envelope does not surface
129
+ // it). Blank / missing titles coerce to `null`. Missing `content`
130
+ // or non-string `content` is malformed (retryable 502).
131
+ // - String shape (MCP-level error envelope): if the string matches
132
+ // the encoded MCP error pattern (`MCP error -<status>...`), route
133
+ // through `classifyEncodedMcpError`. Any other bare string is a
134
+ // degenerate shape the Adapter rejects as malformed (retryable 502)
135
+ // — the characterization shows bare strings occur only for MCP-
136
+ // level error envelopes, so any other string is unexpected.
137
+ //
138
+ // The parser accepts the operation's resolved `finalUrl` (the rewritten
139
+ // URL) and the original `request.url` so the v1 envelope carries both
140
+ // fields per the contract: `url` is exactly what the caller passed;
141
+ // `finalUrl` is the URL the operation actually fetched.
142
+ // ---------------------------------------------------------------------------
143
+ function isPlainObject(value) {
144
+ return typeof value === "object" && value !== null && !Array.isArray(value);
145
+ }
146
+ /**
147
+ * Parse a WebReader response into a normalized `ReaderFetchResult`.
148
+ *
149
+ * @param raw The raw WebReader response (object | string).
150
+ * @param request The caller's request (used for `url`, `format`).
151
+ * @param finalUrl The rewritten URL the Adapter actually fetched.
152
+ */
153
+ function parseZaiReader(raw, request, finalUrl) {
154
+ // Bare string → encoded MCP error path or malformed.
155
+ if (typeof raw === "string") {
156
+ if (looksLikeEncodedMcpError(raw)) {
157
+ throw classifyEncodedMcpError(raw, ENCODED_ERROR_LABEL);
158
+ }
159
+ // The characterization shows bare strings occur only for MCP-level
160
+ // error envelopes. Any other string is a degenerate shape.
161
+ throw new ApiError("Z.AI reader returned a malformed response", 502);
162
+ }
163
+ if (!isPlainObject(raw)) {
164
+ throw new ApiError("Z.AI reader returned a malformed response", 502);
165
+ }
166
+ // Title: string (blank coerced to null), missing → null, non-string → malformed.
167
+ let title;
168
+ const rawTitle = raw.title;
169
+ if (rawTitle === undefined || rawTitle === null) {
170
+ title = null;
171
+ }
172
+ else if (typeof rawTitle === "string") {
173
+ title = rawTitle.trim().length > 0 ? rawTitle : null;
174
+ }
175
+ else {
176
+ throw new ApiError("Z.AI reader returned a malformed response", 502);
177
+ }
178
+ // Content: must be a non-empty string.
179
+ const content = raw.content;
180
+ if (typeof content !== "string" || content.length === 0) {
181
+ throw new ApiError("Z.AI reader returned a malformed response", 502);
182
+ }
183
+ // The Capability contract requires contentFormat to be exactly
184
+ // "markdown" or "text". The Adapter resolves this from the request,
185
+ // NOT from the response: the Provider does not echo the requested
186
+ // format, so the Adapter is authoritative for which format was
187
+ // requested. Defaults to "markdown" per the v0.2 command default.
188
+ const contentFormat = request.format ?? "markdown";
189
+ // Build the envelope. Optional metadata/external preserved verbatim
190
+ // when present, omitted when absent so the round-trip equals the
191
+ // input shape. Built in one shot so `readonly` invariants on
192
+ // `ReaderFetchResult` are honored.
193
+ const hasMetadata = raw.metadata !== undefined;
194
+ const hasExternal = raw.external !== undefined;
195
+ const envelope = {
196
+ schemaVersion: 1,
197
+ url: request.url,
198
+ finalUrl,
199
+ title,
200
+ content,
201
+ contentFormat,
202
+ ...(hasMetadata ? { metadata: raw.metadata } : {}),
203
+ ...(hasExternal ? { external: raw.external } : {}),
204
+ };
205
+ return envelope;
206
+ }
207
+ // ---------------------------------------------------------------------------
208
+ // Adapter-owned credential fingerprint (DESIGN.md §18). Identical
209
+ // algorithm to the Repository Capability: full lowercase SHA-256 hex
210
+ // digest of the active credential; the cache key uses this verbatim.
211
+ // ---------------------------------------------------------------------------
212
+ function credentialFingerprint(apiKey) {
213
+ return crypto.createHash("sha256").update(apiKey).digest("hex");
214
+ }
215
+ // ---------------------------------------------------------------------------
216
+ // Validation helpers
217
+ //
218
+ // Request validation throws `ValidationError` for invalid URL types or
219
+ // URL schemes — distinct from parser/envelope failures, which remain
220
+ // retryable `ApiError` 502. `ValidationError` is terminal at the
221
+ // request layer (the retry classifier treats `VALIDATION_ERROR` as non-
222
+ // retryable) and never reaches a transport.
223
+ // ---------------------------------------------------------------------------
224
+ /**
225
+ * Validate the request URL. Only `http://` and `https://` schemes are
226
+ * accepted; everything else is a terminal `ValidationError` (mirrors
227
+ * the v0.2 command-level parse check). The Adapter runs this BEFORE
228
+ * credential resolution and transport construction so an invalid URL
229
+ * never reaches the network.
230
+ *
231
+ * Note: the v0.2 command's parse-level URL-scheme check is preserved
232
+ * by Ticket 04's handler cutover; the Adapter repeats it as defence
233
+ * in depth (the contract on `ReaderFetchRequest.url` requires http(s)
234
+ * but the Adapter cannot trust callers to honour it).
235
+ */
236
+ function assertHttpUrl(url) {
237
+ if (typeof url !== "string" || url.length === 0) {
238
+ throw new ValidationError("Z.AI reader URL must be a non-empty string");
239
+ }
240
+ if (!/^https?:\/\//.test(url)) {
241
+ throw new ValidationError("URL must start with http:// or https://");
242
+ }
243
+ }
244
+ // ---------------------------------------------------------------------------
245
+ // Per-invocation transport lifecycle (DESIGN.md §18 "Transport close
246
+ // semantics"). Each uncached attempt constructs a fresh client and
247
+ // closes it exactly once in `finally`. Close rejection or timeout
248
+ // never replaces success and never masks the primary operation failure.
249
+ //
250
+ // The Adapter NEVER retries internally — shared execution owns retry
251
+ // policy. A retry constructs a fresh Adapter attempt and therefore a
252
+ // fresh client.
253
+ //
254
+ // The lifecycle helpers are structurally identical to the Repository
255
+ // Adapter's `invokeRepositoryOperation` / `closeWithBound` /
256
+ // `normalizeMcpInvokeError`. They are duplicated rather than shared
257
+ // because factoring them would widen this ticket's scope (modifying
258
+ // repository.ts further). Future consolidation is a separate refactor.
259
+ // ---------------------------------------------------------------------------
260
+ async function invokeReaderFetch(clientFactory, publicToolName, args, parse, closeTimeoutMs) {
261
+ const clientOptions = {
262
+ enableVision: false,
263
+ noCache: true,
264
+ disableRetry: true,
265
+ };
266
+ const client = clientFactory(clientOptions);
267
+ // The success and primary-failure paths must survive a close
268
+ // rejection or timeout. We capture both outcomes separately so a
269
+ // failing close cannot replace a successful result and cannot mask a
270
+ // primary Provider failure.
271
+ let primaryError;
272
+ let result;
273
+ try {
274
+ try {
275
+ // Invoke through the public dotted tool name so the underlying
276
+ // client resolves the discovered internal identity (P6-01A fix
277
+ // path, mirrored by Ticket 02 for the Reader tool). No retry is
278
+ // performed inside this Adapter attempt; shared execution owns
279
+ // the retry policy.
280
+ result = parse(await client.callToolRaw(publicToolName, args));
281
+ }
282
+ catch (error) {
283
+ // Wrap any thrown MCP error into the normalized Adapter error.
284
+ primaryError = normalizeMcpInvokeError(error);
285
+ throw primaryError;
286
+ }
287
+ return result;
288
+ }
289
+ finally {
290
+ // Best-effort close. Matches the existing `ZaiMcpClient.close`
291
+ // semantic: race the close against a timeout that resolves
292
+ // silently so a stuck close cannot stall the Adapter attempt.
293
+ // Close rejection is also silently swallowed.
294
+ await closeWithBound(client, closeTimeoutMs);
295
+ }
296
+ }
297
+ /**
298
+ * Close the client with a bounded timeout that matches the existing
299
+ * `ZaiMcpClient.close(timeoutMs = 2000)` semantic. The timeout
300
+ * resolves silently (not rejects) so the close never throws and the
301
+ * Adapter attempt never stalls on a stuck close. Any close rejection
302
+ * is also silently swallowed.
303
+ */
304
+ async function closeWithBound(client, timeoutMs) {
305
+ let timer;
306
+ const timeoutPromise = new Promise((resolve) => {
307
+ timer = setTimeout(() => resolve(), timeoutMs);
308
+ if (timer && typeof timer === "object" && "unref" in timer) {
309
+ timer.unref();
310
+ }
311
+ });
312
+ try {
313
+ await Promise.race([client.close().catch(() => undefined), timeoutPromise]);
314
+ }
315
+ finally {
316
+ if (timer !== undefined)
317
+ clearTimeout(timer);
318
+ }
319
+ }
320
+ /**
321
+ * Normalize a Provider failure surfaced through `callToolRaw`. The
322
+ * underlying client already normalizes typed transport errors
323
+ * (`AuthError`, `NetworkError`, `TimeoutError`, `ApiError`,
324
+ * `QuotaError`); this function preserves ANY normalized
325
+ * `ScoutlineError` so the shared retry classifier sees the original
326
+ * `code` and `statusCode`. This base-class check also covers the
327
+ * reader-local `ScoutlineError` constructed for an encoded 403 (which
328
+ * intentionally does not widen the global `AuthError` constructor).
329
+ * Untyped throwables surface as sanitized retryable `ApiError` 502 —
330
+ * the Adapter never embeds a raw Provider string into the public
331
+ * envelope.
332
+ */
333
+ function normalizeMcpInvokeError(error) {
334
+ if (error instanceof ScoutlineError) {
335
+ return error;
336
+ }
337
+ // Defensive: never let a raw Provider string reach the public
338
+ // envelope. An untyped throwable is a sanitized 502-equivalent.
339
+ return new ApiError("Z.AI reader request failed", 502);
340
+ }
341
+ // ---------------------------------------------------------------------------
342
+ // Legacy decoder — total over `unknown`, returns normalized Result or
343
+ // `null`. The legacy decoder runs the raw Provider string through the
344
+ // same production parser so the read-through path validates the same
345
+ // grammar the cache decoder does. `JSON.stringify(raw)` is NOT used;
346
+ // raw object values are passed through unchanged, raw strings are
347
+ // routed through the parser (which rejects anything that is not an
348
+ // object success or a recognized encoded MCP error envelope).
349
+ // ---------------------------------------------------------------------------
350
+ function decodeLegacyZaiReader(raw, request, finalUrl) {
351
+ try {
352
+ return parseZaiReader(raw, request, finalUrl);
353
+ }
354
+ catch {
355
+ return null;
356
+ }
357
+ }
358
+ function createZaiReaderFetchOperation(options) {
359
+ const { env, clientFactory } = options;
360
+ function resolveApiKey() {
361
+ return requireZaiApiKey(env);
362
+ }
363
+ const operation = {
364
+ kind: "reader-fetch",
365
+ validate(request) {
366
+ assertHttpUrl(request.url);
367
+ },
368
+ cacheIdentity(request) {
369
+ const apiKey = resolveApiKey();
370
+ // Canonical request: URL is REWRITTEN so two requests that
371
+ // normalize to the same fetched URL share the same cache entry
372
+ // (e.g. `gist.github.com/<id>` and `gist.github.com/<id>/raw`
373
+ // both fetch the same Provider content).
374
+ const finalUrl = maybeRewriteToRaw(request.url);
375
+ const canonicalRequest = { ...request, url: finalUrl };
376
+ // Legacy v0.2 argument insertion order is fixed (DESIGN.md §18 /
377
+ // reader-webreader-characterization artifact):
378
+ // 1. url (always)
379
+ // 2. timeout (optional, only if request.timeout !== undefined)
380
+ // 3. no_cache (NEVER set by the Adapter — the Capability surface has no noCache field)
381
+ // 4. return_format (optional, only if request.format is truthy)
382
+ // 5. retain_images (optional)
383
+ // 6. with_links_summary (optional)
384
+ // 7. no_gfm (optional)
385
+ // 8. keep_img_data_url (optional)
386
+ // 9. with_images_summary (optional)
387
+ //
388
+ // The legacy args.url is the REWRITTEN url, matching what the
389
+ // v0.2 path sent to WebReader. The Adapter never sends
390
+ // `no_cache` (the Capability surface has no noCache field), so
391
+ // legacy args never include it — this means the new Adapter
392
+ // matches the common-case v0.2 cache entries (those written
393
+ // without --no-cache). The v0.2 --no-cache entries were
394
+ // intentionally uncached and remain unreconstructible, which is
395
+ // correct behavior.
396
+ const legacyArgs = { url: finalUrl };
397
+ if (request.timeout !== undefined) {
398
+ legacyArgs.timeout = request.timeout;
399
+ }
400
+ if (request.format) {
401
+ legacyArgs.return_format = request.format;
402
+ }
403
+ if (request.retainImages !== undefined) {
404
+ legacyArgs.retain_images = request.retainImages;
405
+ }
406
+ if (request.withLinksSummary !== undefined) {
407
+ legacyArgs.with_links_summary = request.withLinksSummary;
408
+ }
409
+ if (request.noGfm !== undefined) {
410
+ legacyArgs.no_gfm = request.noGfm;
411
+ }
412
+ if (request.keepImgDataUrl !== undefined) {
413
+ legacyArgs.keep_img_data_url = request.keepImgDataUrl;
414
+ }
415
+ if (request.withImagesSummary !== undefined) {
416
+ legacyArgs.with_images_summary = request.withImagesSummary;
417
+ }
418
+ return {
419
+ provider: "zai",
420
+ capability: "reader",
421
+ operation: "reader-fetch",
422
+ credentialFingerprint: credentialFingerprint(apiKey),
423
+ request: canonicalRequest,
424
+ legacyCandidates: [
425
+ {
426
+ key: buildLegacyReaderCacheKey(apiKey, READER_TOOL_PUBLIC_NAME, legacyArgs),
427
+ decode: (raw) => decodeLegacyZaiReader(raw, canonicalRequest, finalUrl),
428
+ },
429
+ ],
430
+ };
431
+ },
432
+ decodeCached(value) {
433
+ // Total normalized cache decoder: delegate to the shared Ticket 01
434
+ // `decodeReaderFetchResult`. Shared decoder rejects missing
435
+ // required fields (`url`, `finalUrl`, `content`), unknown
436
+ // `contentFormat`, and primitives/arrays at the top level. Any
437
+ // malformed shape is a cache miss.
438
+ return decodeReaderFetchResult(value);
439
+ },
440
+ async invoke(request) {
441
+ // Validate before any transport access (DESIGN.md §18 / §2).
442
+ operation.validate(request);
443
+ const finalUrl = maybeRewriteToRaw(request.url);
444
+ // Build args in the documented v0.2 insertion order minus
445
+ // `no_cache` (the Capability surface has no noCache field).
446
+ const args = { url: finalUrl };
447
+ if (request.timeout !== undefined) {
448
+ args.timeout = request.timeout;
449
+ }
450
+ if (request.format) {
451
+ args.return_format = request.format;
452
+ }
453
+ if (request.retainImages !== undefined) {
454
+ args.retain_images = request.retainImages;
455
+ }
456
+ if (request.withLinksSummary !== undefined) {
457
+ args.with_links_summary = request.withLinksSummary;
458
+ }
459
+ if (request.noGfm !== undefined) {
460
+ args.no_gfm = request.noGfm;
461
+ }
462
+ if (request.keepImgDataUrl !== undefined) {
463
+ args.keep_img_data_url = request.keepImgDataUrl;
464
+ }
465
+ if (request.withImagesSummary !== undefined) {
466
+ args.with_images_summary = request.withImagesSummary;
467
+ }
468
+ return invokeReaderFetch(clientFactory, READER_TOOL_PUBLIC_NAME, args, (raw) => parseZaiReader(raw, request, finalUrl), options.closeTimeoutMs);
469
+ },
470
+ };
471
+ return operation;
472
+ }
473
+ /**
474
+ * Build the Z.AI Reader Capability. The capability is composed of a
475
+ * single typed `ReaderOperation` descriptor (`fetch`); the Adapter
476
+ * owns credentials, transport lifecycle, raw request/response mapping,
477
+ * URL rewrite, and error normalization. No transport, credential
478
+ * resolution, or I/O happens during construction.
479
+ */
480
+ export function createZaiReaderCapability(options) {
481
+ const closeTimeoutMs = options.closeTimeoutMs ?? ZAI_READER_CLOSE_BOUND_MS;
482
+ return {
483
+ fetch: createZaiReaderFetchOperation({
484
+ env: options.env,
485
+ clientFactory: options.clientFactory,
486
+ closeTimeoutMs,
487
+ }),
488
+ };
489
+ }
490
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/providers/zai/reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Z.AI Repository Adapter (DESIGN.md §18, PRD FR-081, FR-087,
3
+ * FR-089–FR-091, FR-093; NFR-004, NFR-006).
4
+ *
5
+ * Owns the Provider-facing half of the provider-neutral Repository
6
+ * Capability defined in `src/capabilities/repository.ts`:
7
+ *
8
+ * - total parsers for the characterized ZRead Search, File, and
9
+ * Directory Listing responses (`<excerpt>`, `<file_content>`,
10
+ * `<structure>`);
11
+ * - per-operation Z.AI descriptors with `validate`, `cacheIdentity`,
12
+ * `decodeCached`, and `invoke`;
13
+ * - a single resolved-credential fingerprint per cache identity and
14
+ * exact per-operation legacy cache candidates/decoders;
15
+ * - encoded MCP error classification BEFORE success parsing
16
+ * (exhausted quota is terminal `QUOTA_ERROR`; the rest of the
17
+ * taxonomy uses the shared retry/terminal classification);
18
+ * - a fresh transport per invocation attempt and exactly one
19
+ * best-effort close in `finally`; close failure never replaces
20
+ * success nor masks the primary failure;
21
+ * - no leakage of raw ZRead response types outside this module.
22
+ *
23
+ * Boundary rules (ARCHITECTURE.md §2):
24
+ * - May import capability types, normalized errors, the Z.AI MCP
25
+ * tool-name helpers, the legacy cache-key helper, and the
26
+ * shared `ZaiAdapterClientPort` typed client port.
27
+ * - Must NOT import another Provider's Adapter, command
28
+ * presentation, BFS/Explorer logic, or path canonicalization.
29
+ *
30
+ * Scope:
31
+ * - implements Search, File, and Directory Listing only. Tree
32
+ * projection, BFS, depth/path policy, and `--max-chars` all
33
+ * belong to the Explorer layer (P6-05+) or the command layer.
34
+ * - descriptor metadata sequencing: P6-04 introduced this Adapter
35
+ * handle and wired it through `ProviderAdapter.repository`
36
+ * WITHOUT advertising `repository-exploration` on
37
+ * `createZaiDescriptor.capabilities()`; P6-06 then flipped the
38
+ * descriptor to advertise `repository-exploration` so Provider
39
+ * selection and Doctor inventory derive from a single source of
40
+ * truth. This module itself still owns no registry, selection,
41
+ * or command cutover — `commands/repo.ts` continues to dispatch
42
+ * through the legacy `ZReadMcpClient` until P6-07 exclusively
43
+ * owns that dispatch cutover.
44
+ */
45
+ import type { ZaiAdapterClientPort, ZaiMcpClientOptions } from "../types.js";
46
+ import { type RepositoryCapability } from "../../capabilities/repository.js";
47
+ /**
48
+ * Production close bound (ms). Matches the existing
49
+ * `ZaiMcpClient.close(timeoutMs = 2000)` semantic; the Adapter races
50
+ * the close against a 2 second timer that resolves silently so a stuck
51
+ * close cannot stall the attempt. Tests may inject a shorter bound via
52
+ * {@link ZaiRepositoryCapabilityOptions.closeTimeoutMs}.
53
+ */
54
+ export declare const ZAI_REPOSITORY_CLOSE_BOUND_MS = 2000;
55
+ /**
56
+ * Options accepted by {@link createZaiRepositoryCapability}.
57
+ *
58
+ * `closeTimeoutMs` defaults to {@link ZAI_REPOSITORY_CLOSE_BOUND_MS}
59
+ * (2000 ms) — the existing `ZaiMcpClient.close(timeoutMs = 2000)`
60
+ * semantic. Tests may inject a shorter bound to bound a never-
61
+ * resolving `close()` without waiting for the production default.
62
+ */
63
+ export interface ZaiRepositoryCapabilityOptions {
64
+ readonly env: NodeJS.ProcessEnv;
65
+ readonly clientFactory: (options: ZaiMcpClientOptions) => ZaiAdapterClientPort;
66
+ readonly closeTimeoutMs?: number;
67
+ }
68
+ /**
69
+ * Build the Z.AI Repository Capability. The capability is composed of
70
+ * three typed `RepositoryOperation` descriptors; the Adapter owns
71
+ * credentials, transport lifecycle, raw request/response mapping, and
72
+ * error normalization. No transport, credential resolution, or I/O
73
+ * happens during construction.
74
+ */
75
+ export declare function createZaiRepositoryCapability(options: ZaiRepositoryCapabilityOptions): RepositoryCapability;
76
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../src/providers/zai/repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAM7E,OAAO,EAKL,KAAK,oBAAoB,EAS1B,MAAM,kCAAkC,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAmvBlD;;;;;;;GAOG;AACH,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,oBAAoB,CAAC;IAC/E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,8BAA8B,GACtC,oBAAoB,CAYtB"}