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.
- package/README.md +240 -18
- package/dist/capabilities/diagnostics.d.ts +70 -32
- package/dist/capabilities/diagnostics.d.ts.map +1 -1
- package/dist/capabilities/diagnostics.js +97 -46
- package/dist/capabilities/diagnostics.js.map +1 -1
- package/dist/capabilities/reader.d.ts +227 -0
- package/dist/capabilities/reader.d.ts.map +1 -0
- package/dist/capabilities/reader.js +100 -0
- package/dist/capabilities/reader.js.map +1 -0
- package/dist/capabilities/repository.d.ts +221 -0
- package/dist/capabilities/repository.d.ts.map +1 -0
- package/dist/capabilities/repository.js +172 -0
- package/dist/capabilities/repository.js.map +1 -0
- package/dist/commands/cache.d.ts +106 -0
- package/dist/commands/cache.d.ts.map +1 -0
- package/dist/commands/cache.js +203 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/doctor.d.ts +17 -6
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +42 -17
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/read.d.ts +74 -14
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +257 -117
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/repo.d.ts +53 -7
- package/dist/commands/repo.d.ts.map +1 -1
- package/dist/commands/repo.js +104 -123
- package/dist/commands/repo.js.map +1 -1
- package/dist/commands/repository-explorer.d.ts +147 -0
- package/dist/commands/repository-explorer.d.ts.map +1 -0
- package/dist/commands/repository-explorer.js +550 -0
- package/dist/commands/repository-explorer.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +209 -34
- package/dist/index.js.map +1 -1
- package/dist/lib/cache.d.ts +123 -18
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +324 -49
- package/dist/lib/cache.js.map +1 -1
- package/dist/lib/errors.d.ts +24 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +33 -2
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/execution.d.ts +119 -5
- package/dist/lib/execution.d.ts.map +1 -1
- package/dist/lib/execution.js +216 -10
- package/dist/lib/execution.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/mcp-client.d.ts +29 -5
- package/dist/lib/mcp-client.d.ts.map +1 -1
- package/dist/lib/mcp-client.js +88 -88
- package/dist/lib/mcp-client.js.map +1 -1
- package/dist/lib/tool-cache.d.ts +86 -0
- package/dist/lib/tool-cache.d.ts.map +1 -0
- package/dist/lib/tool-cache.js +123 -0
- package/dist/lib/tool-cache.js.map +1 -0
- package/dist/providers/minimax/adapter.d.ts +6 -4
- package/dist/providers/minimax/adapter.d.ts.map +1 -1
- package/dist/providers/minimax/adapter.js +64 -57
- package/dist/providers/minimax/adapter.js.map +1 -1
- package/dist/providers/minimax/coding-plan-client.d.ts +60 -0
- package/dist/providers/minimax/coding-plan-client.d.ts.map +1 -0
- package/dist/providers/minimax/coding-plan-client.js +204 -0
- package/dist/providers/minimax/coding-plan-client.js.map +1 -0
- package/dist/providers/minimax/media.d.ts +60 -6
- package/dist/providers/minimax/media.d.ts.map +1 -1
- package/dist/providers/minimax/media.js +147 -7
- package/dist/providers/minimax/media.js.map +1 -1
- package/dist/providers/minimax/quota-client.d.ts +13 -6
- package/dist/providers/minimax/quota-client.d.ts.map +1 -1
- package/dist/providers/minimax/quota-client.js +5 -0
- package/dist/providers/minimax/quota-client.js.map +1 -1
- package/dist/providers/minimax/vision-attestations.d.ts +23 -0
- package/dist/providers/minimax/vision-attestations.d.ts.map +1 -1
- package/dist/providers/minimax/vision-attestations.js +35 -10
- package/dist/providers/minimax/vision-attestations.js.map +1 -1
- package/dist/providers/minimax/vision-conformance.d.ts +8 -6
- package/dist/providers/minimax/vision-conformance.d.ts.map +1 -1
- package/dist/providers/minimax/vision-conformance.js +8 -6
- package/dist/providers/minimax/vision-conformance.js.map +1 -1
- package/dist/providers/minimax/vision-revisions.d.ts +8 -1
- package/dist/providers/minimax/vision-revisions.d.ts.map +1 -1
- package/dist/providers/minimax/vision-revisions.js +13 -6
- package/dist/providers/minimax/vision-revisions.js.map +1 -1
- package/dist/providers/selection.d.ts +3 -3
- package/dist/providers/selection.js +3 -3
- package/dist/providers/types.d.ts +66 -32
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/zai/adapter.d.ts.map +1 -1
- package/dist/providers/zai/adapter.js +71 -5
- package/dist/providers/zai/adapter.js.map +1 -1
- package/dist/providers/zai/encoded-error.d.ts +90 -0
- package/dist/providers/zai/encoded-error.d.ts.map +1 -0
- package/dist/providers/zai/encoded-error.js +169 -0
- package/dist/providers/zai/encoded-error.js.map +1 -0
- package/dist/providers/zai/reader.d.ts +82 -0
- package/dist/providers/zai/reader.d.ts.map +1 -0
- package/dist/providers/zai/reader.js +490 -0
- package/dist/providers/zai/reader.js.map +1 -0
- package/dist/providers/zai/repository.d.ts +76 -0
- package/dist/providers/zai/repository.d.ts.map +1 -0
- package/dist/providers/zai/repository.js +715 -0
- package/dist/providers/zai/repository.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ npx scoutline --help
|
|
|
73
73
|
|
|
74
74
|
## Provider Selection
|
|
75
75
|
|
|
76
|
-
Shared commands (`search`, `vision`, `quota`, `doctor`) accept a global
|
|
76
|
+
Shared commands (`search`, `vision`, `quota`, `doctor`, `repo`) accept a global
|
|
77
77
|
`--provider <zai|minimax>` flag. Resolution precedence:
|
|
78
78
|
|
|
79
79
|
1. Explicit `--provider <zai|minimax>` on the command line
|
|
@@ -99,9 +99,15 @@ empty credentials leave the Provider unconfigured and shared capabilities will
|
|
|
99
99
|
fail with `AUTH_ERROR` or `CONFIGURATION_ERROR`. Unknown Provider IDs fail
|
|
100
100
|
fast with `VALIDATION_ERROR`.
|
|
101
101
|
|
|
102
|
-
`scoutline
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
`scoutline search`, `scoutline vision`, `scoutline quota`, `scoutline doctor`,
|
|
103
|
+
**`scoutline repo`**, and **`scoutline read`** participate in Provider
|
|
104
|
+
selection. `scoutline tools`, `scoutline tool`, `scoutline call`, and
|
|
105
|
+
`scoutline code` accept the flag but ignore it; they remain Z.AI-only.
|
|
106
|
+
MiniMax does not currently advertise the `repository-exploration` or `reader`
|
|
107
|
+
Capabilities — selecting MiniMax (explicitly or via `SCOUTLINE_PROVIDER`) for
|
|
108
|
+
any `repo` subcommand or for `read` returns `UNSUPPORTED_CAPABILITY` before
|
|
109
|
+
descriptor configuration, Adapter creation, cache identity, or transport
|
|
110
|
+
construction, with no Z.AI fallback.
|
|
105
111
|
|
|
106
112
|
## Capability Matrix
|
|
107
113
|
|
|
@@ -114,14 +120,14 @@ remain Z.AI-only in the base release.
|
|
|
114
120
|
| `vision.diagnose-error` | Yes | Available | Live-attested; conformance-gated |
|
|
115
121
|
| `vision.diagram` | Yes | Pending | Implemented, pending live conformance |
|
|
116
122
|
| `vision.chart` | Yes | Pending | Implemented, pending live conformance |
|
|
117
|
-
| `vision.diff` (image diff) | Yes | No |
|
|
118
|
-
| `vision.video` | Yes | No |
|
|
123
|
+
| `vision.diff` (image diff) | Yes | No | Z.AI-only (never MiniMax-claimable) |
|
|
124
|
+
| `vision.video` | Yes | No | Z.AI-only (never MiniMax-claimable) |
|
|
119
125
|
| `quota` | Yes | Yes | Normalized `QuotaDashboard` (ADR-0001) |
|
|
120
126
|
| `diagnostics` (`doctor`) | Yes | Yes | Lists both Providers; probes configured |
|
|
121
|
-
| `read` (Reader) | Yes | No |
|
|
122
|
-
| `repo`
|
|
123
|
-
| `tools`, `tool`, `call` (Raw tools) | Yes | No |
|
|
124
|
-
| `code` (Code Mode) | Yes | No |
|
|
127
|
+
| `read` (Reader) | Yes | **No** (UNSUPPORTED_CAPABILITY) | Participates in selection; only Z.AI supplies `reader` |
|
|
128
|
+
| `repo search` / `repo read` / `repo tree` | Yes | **No** (UNSUPPORTED_CAPABILITY) | Participates in selection; only Z.AI supplies `repository-exploration` |
|
|
129
|
+
| `tools`, `tool`, `call` (Raw tools) | Yes | No | Z.AI-only; accepts but ignores `--provider` |
|
|
130
|
+
| `code` (Code Mode) | Yes | No | Z.AI-only; accepts but ignores `--provider` |
|
|
125
131
|
|
|
126
132
|
Media limits for general single-image interpretation:
|
|
127
133
|
|
|
@@ -153,9 +159,12 @@ In the current release, `ui-artifact` and `diagnose-error` have offline
|
|
|
153
159
|
`pass`, live `pass`, and compiled attestations — they are **supported at
|
|
154
160
|
runtime** through MiniMax. The remaining three operations (`extract-text`,
|
|
155
161
|
`diagram`, `chart`) have offline `pass` and live `pending`; they are
|
|
156
|
-
**unsupported at runtime**
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
**unsupported at runtime** through MiniMax. Selecting MiniMax explicitly
|
|
163
|
+
for one of these operations fails closed with `UNSUPPORTED_CAPABILITY`
|
|
164
|
+
before credentials, media, transport, cache, or any other Provider is
|
|
165
|
+
touched (FR-023, FR-024). There is **no automatic Z.AI fallback** for an
|
|
166
|
+
explicit MiniMax selection — call without `--provider minimax` (or unset
|
|
167
|
+
`SCOUTLINE_PROVIDER`) to route through Z.AI instead.
|
|
159
168
|
|
|
160
169
|
No environment variable, flag, or configuration value can promote a
|
|
161
170
|
mapping to supported. Support is driven exclusively by the compiled
|
|
@@ -201,6 +210,7 @@ scoutline search --help # Search options
|
|
|
201
210
|
scoutline repo --help # GitHub repo commands
|
|
202
211
|
scoutline doctor --help # Provider diagnostics
|
|
203
212
|
scoutline quota --help # Plan usage
|
|
213
|
+
scoutline cache --help # Local cache inspection and clearing
|
|
204
214
|
```
|
|
205
215
|
|
|
206
216
|
### Examples
|
|
@@ -239,6 +249,10 @@ scoutline quota --all-providers # every configured Provider
|
|
|
239
249
|
scoutline doctor # full diagnostics
|
|
240
250
|
scoutline doctor --no-tools # metadata only, no transport
|
|
241
251
|
scoutline doctor --provider minimax # MiniMax connectivity
|
|
252
|
+
|
|
253
|
+
# Cache - inspect or clear the local cache
|
|
254
|
+
scoutline cache stats # show inventory of both subdirectories
|
|
255
|
+
scoutline cache clear # delete every file under cache/ and tools/
|
|
242
256
|
```
|
|
243
257
|
|
|
244
258
|
## Output Format
|
|
@@ -273,7 +287,8 @@ Quota output is a schema-version-1 `QuotaDashboard`:
|
|
|
273
287
|
```
|
|
274
288
|
|
|
275
289
|
Doctor output is a schema-version-1 `DiagnosticsReport` listing every built-in
|
|
276
|
-
Provider with its configured state, declared capabilities,
|
|
290
|
+
Provider with its configured state, declared capabilities, probe status, and a
|
|
291
|
+
one-line cache summary under the `cache` field.
|
|
277
292
|
|
|
278
293
|
## Notes
|
|
279
294
|
|
|
@@ -283,11 +298,218 @@ Provider with its configured state, declared capabilities, and probe status.
|
|
|
283
298
|
entries are still reported.
|
|
284
299
|
- `doctor` exits 1 when the effective Provider is unconfigured or any
|
|
285
300
|
configured probe fails; successful entries are still reported.
|
|
286
|
-
- `read`
|
|
301
|
+
- `read` returns a schema-version-1 envelope (content read or extract read) in every output mode. `--with-images-summary`, `--no-gfm`, and `--keep-img-data-url` are passed through to the Provider request. `--max-chars` is ignored on extract reads; `--full-envelope` is silently deprecated.
|
|
287
302
|
- Vision tool calls automatically retry transient 5xx/network errors (default: 2 retries). Configure with `ZAI_MCP_VISION_RETRY_COUNT` (or `ZAI_MCP_RETRY_COUNT` for all tools).
|
|
288
|
-
- Tool discovery can be cached to speed `tools`/`tool`/`doctor` (default: on, 24h TTL).
|
|
289
|
-
- The
|
|
290
|
-
|
|
303
|
+
- Tool discovery can be cached to speed `tools`/`tool`/`doctor` (default: on, 24h TTL). The cache shares the unified root with the response cache; configure both via `SCOUTLINE_CACHE`, `SCOUTLINE_CACHE_TTL_MS`, `SCOUTLINE_CACHE_SIZE_MB`, and `SCOUTLINE_CACHE_DIR` (legacy aliases `ZAI_MCP_TOOL_CACHE*`, `ZAI_MCP_CACHE_DIR`, and `ZAI_CACHE*` are accepted silently).
|
|
304
|
+
- The local cache lives at `~/.scoutline/` (`cache/` for responses, `tools/` for tool discovery) on every platform. Inspect or clear it with `scoutline cache stats` and `scoutline cache clear`.
|
|
305
|
+
|
|
306
|
+
## Repository Exploration (P6)
|
|
307
|
+
|
|
308
|
+
`scoutline repo search`, `scoutline repo read`, and `scoutline repo tree`
|
|
309
|
+
participate in `--provider` selection. Z.AI advertises the
|
|
310
|
+
`repository-exploration` Capability and supplies it through the Z.AI
|
|
311
|
+
Repository Adapter. MiniMax does not advertise it; selecting MiniMax returns
|
|
312
|
+
`UNSUPPORTED_CAPABILITY` before descriptor configuration, Adapter creation,
|
|
313
|
+
credential resolution for use, cache identity, or transport construction
|
|
314
|
+
with no fallback to Z.AI.
|
|
315
|
+
|
|
316
|
+
### Breaking data-mode migration (v0.2 → v1)
|
|
317
|
+
|
|
318
|
+
The three `repo` successes return **schema-version-1 structured values** in
|
|
319
|
+
every output mode. This is an intentional breaking change from the v0.2 raw
|
|
320
|
+
Search/File strings and the depth-dependent raw Tree shape:
|
|
321
|
+
|
|
322
|
+
| Command | v0.2 (legacy, now obsolete) | v1 (current) |
|
|
323
|
+
| --- | --- | --- |
|
|
324
|
+
| `repo search` | Raw ZRead text with `<excerpt>` blocks | `{schemaVersion, repository, query, language, excerpts:[{text}], truncated, originalTextLength}` |
|
|
325
|
+
| `repo read` | Raw `<file_content>…</file_content>` body | `{schemaVersion, repository, path, content, truncated, originalContentLength}` |
|
|
326
|
+
| `repo tree` | `<structure>` block (depth 1 returned split/deep routes) | `{schemaVersion, repository, path, depth, snapshots:[{repository, path, entries:[{name, path, kind}]}]}` (structured at every depth, including depth 1) |
|
|
327
|
+
|
|
328
|
+
`data` mode emits the exact object above. `json` and `pretty` wrap it through
|
|
329
|
+
the standard success envelope. Text-oriented modes (`compact`, `markdown`,
|
|
330
|
+
`refs`, `tty`) fall back to the JSON value because the command supplies no
|
|
331
|
+
prose presentation override.
|
|
332
|
+
|
|
333
|
+
**Scripting impact:** any consumer parsing v0.2 raw ZRead text or the v0.2
|
|
334
|
+
split/deep `tree` shape must switch to the v1 structured fields. The raw
|
|
335
|
+
`scoutline.zai.*` namespace remains available for callers that need the
|
|
336
|
+
legacy grammar; it is not wrapped in the v1 envelope.
|
|
337
|
+
|
|
338
|
+
### Canonical repository paths
|
|
339
|
+
|
|
340
|
+
- Tree aliases omitted, empty, `/`, or `.` normalize to the root path `""`.
|
|
341
|
+
- File paths must be non-root; the root is invalid for `repo read`.
|
|
342
|
+
- Leading `./` and leading `/` are accepted on File; leading and trailing `/`
|
|
343
|
+
are stripped and repeated `/` collapses on both.
|
|
344
|
+
- Actual `.`/`..` segments, backslashes, and ASCII control characters are
|
|
345
|
+
rejected. Percent escapes (`%XX`) are never decoded — they remain literal.
|
|
346
|
+
|
|
347
|
+
### `--max-chars` (deterministic, local)
|
|
348
|
+
|
|
349
|
+
`--max-chars` is **never** a summarization model call. It is presentation
|
|
350
|
+
projection applied to the normalized result after caching.
|
|
351
|
+
|
|
352
|
+
- Absent, zero, or negative → no truncation.
|
|
353
|
+
- `repo read` → truncates `content` with the existing ellipsis rule; preserves
|
|
354
|
+
the original length in `originalContentLength` and sets `truncated: true`.
|
|
355
|
+
- `repo search` → applies **one total budget** across `excerpts[].text` in
|
|
356
|
+
Provider order; the final retained excerpt is truncated and later excerpts
|
|
357
|
+
are omitted.
|
|
358
|
+
- `repo tree` → never character-limited.
|
|
359
|
+
- Metadata, JSON envelopes, and Tree snapshots are not part of the budget.
|
|
360
|
+
|
|
361
|
+
### Empty results
|
|
362
|
+
|
|
363
|
+
A future Provider Adapter may explicitly return an empty `excerpts`/`entries`
|
|
364
|
+
array when its own contract distinguishes a valid empty state. The Z.AI
|
|
365
|
+
Adapter requires at least one well-formed `<excerpt>` block per Search;
|
|
366
|
+
unwrapped text is malformed and surfaces as a normalized `API_ERROR 502`, not
|
|
367
|
+
as an empty success. An empty ZRead structure without `entries` is malformed
|
|
368
|
+
the same way.
|
|
369
|
+
|
|
370
|
+
### Cache continuity
|
|
371
|
+
|
|
372
|
+
Repository results use a new key shape
|
|
373
|
+
`v2.repository-exploration-<op>.<provider>.<credential-hash>.<request-hash>.json`.
|
|
374
|
+
The credential hash is supplied by the Adapter (full lowercase SHA-256 hex
|
|
375
|
+
digest of the active credential) and is never re-hashed by cache code.
|
|
376
|
+
|
|
377
|
+
Legacy v0.2 Z.AI cache entries remain readable **read-only**: their key is
|
|
378
|
+
reconstructed from the same Adapter-resolved credential using the exact v0.2
|
|
379
|
+
algorithm, and a valid hit is written through to the new key. Old files are
|
|
380
|
+
never rewritten, migrated, or deleted. `--no-cache` performs no reads or
|
|
381
|
+
writes. Injected credentials drive the fingerprint and legacy-key
|
|
382
|
+
construction; ambient `process.env` is never reread.
|
|
383
|
+
|
|
384
|
+
### Errors and lifecycle
|
|
385
|
+
|
|
386
|
+
Encoded MCP error envelopes are recognized before success parsing:
|
|
387
|
+
`QUOTA_ERROR` 429 (exhausted ZRead quota, code `1310`) is terminal; transient
|
|
388
|
+
429/5xx and a malformed envelope retry once; auth 401/403 and other 4xx are
|
|
389
|
+
terminal. Raw Provider response bodies, reset metadata, and error texts are
|
|
390
|
+
discarded.
|
|
391
|
+
|
|
392
|
+
Transport close is best-effort and called once per constructed attempt. A
|
|
393
|
+
successful operation does not become a failure when close rejects or times
|
|
394
|
+
out, and a primary failure remains the outward failure when close also fails.
|
|
395
|
+
Cache hits construct and close no transport.
|
|
396
|
+
|
|
397
|
+
### Diagnostics inventory
|
|
398
|
+
|
|
399
|
+
`sharedCapabilities` and `zaiOnlyCapabilities` are derived from descriptor
|
|
400
|
+
metadata (intersection across built-in Providers; Z.AI minus the union of
|
|
401
|
+
the others). `repository-exploration` is therefore `zaiOnlyCapabilities`
|
|
402
|
+
while still participating in Provider selection. Doctor help names MiniMax
|
|
403
|
+
as unsupported for `repo`.
|
|
404
|
+
|
|
405
|
+
### Non-goals
|
|
406
|
+
|
|
407
|
+
This release does not add MiniMax repository exploration, a Reader
|
|
408
|
+
migration, automatic summarization, dynamic Provider loading, or an implicit
|
|
409
|
+
Z.AI fallback for unsupported Providers. The P5 specialized Vision mappings
|
|
410
|
+
remain independent and are not claimed complete here.
|
|
411
|
+
|
|
412
|
+
## Reader (P7)
|
|
413
|
+
|
|
414
|
+
`scoutline read` participates in `--provider` selection. Z.AI advertises the
|
|
415
|
+
`reader` Capability and supplies it through the Z.AI Reader Adapter. MiniMax
|
|
416
|
+
does not advertise it; selecting MiniMax returns `UNSUPPORTED_CAPABILITY`
|
|
417
|
+
before descriptor configuration, Adapter creation, credential resolution for
|
|
418
|
+
use, cache identity, or transport construction, with no fallback to Z.AI.
|
|
419
|
+
|
|
420
|
+
### Breaking data-mode migration (v0.2 → v1)
|
|
421
|
+
|
|
422
|
+
`scoutline read` returns **schema-version-1 structured values** in every
|
|
423
|
+
output mode. This is an intentional breaking change from the v0.2 raw content
|
|
424
|
+
string and the bare extract array:
|
|
425
|
+
|
|
426
|
+
| Read shape | v0.2 (legacy, now obsolete) | v1 (current) |
|
|
427
|
+
| --- | --- | --- |
|
|
428
|
+
| Content read (default) | Raw content string | `{schemaVersion, url, finalUrl, title, content, contentFormat, truncated, originalContentLength}` |
|
|
429
|
+
| Extract read (`--extract <mode>`) | Bare JSON array of items | `{schemaVersion, url, finalUrl, mode, items, truncated, originalItemCount}` |
|
|
430
|
+
|
|
431
|
+
`url` is exactly what the caller passed; `finalUrl` is the URL the operation
|
|
432
|
+
actually fetched, which differs only when a Provider-side rewrite occurred
|
|
433
|
+
(e.g. `gist.github.com/<id>` → `gist.github.com/<id>/raw`). The v0.2 stderr
|
|
434
|
+
rewrite notice is gone — the signal now lives in `finalUrl`.
|
|
435
|
+
|
|
436
|
+
The four `--extract` modes (`code`, `links`, `tables`, `headings`) and the
|
|
437
|
+
shape of each item are unchanged from v0.2. Only the outer envelope changed
|
|
438
|
+
(bare array → schema-versioned object with `items`).
|
|
439
|
+
|
|
440
|
+
#### Output-mode behavior
|
|
441
|
+
|
|
442
|
+
| Mode | Content read | Extract read |
|
|
443
|
+
| --- | --- | --- |
|
|
444
|
+
| `data` | The content-read envelope object | The extract-read envelope object |
|
|
445
|
+
| `json` | `{success: true, data: <envelope>, timestamp}` (indent 0) | same |
|
|
446
|
+
| `pretty` | `{success: true, data: <envelope>, timestamp}` (indent 2) | same |
|
|
447
|
+
| `compact` | The `content` string directly | JSON fallback (the envelope object) |
|
|
448
|
+
| `markdown` | The `content` string directly | JSON fallback |
|
|
449
|
+
| `refs` | The `content` string directly | JSON fallback |
|
|
450
|
+
| `tty` | The `content` string directly | JSON fallback |
|
|
451
|
+
|
|
452
|
+
`compact`, `markdown`, `refs`, and `tty` exist to give operators a prose form
|
|
453
|
+
for human reading. A content read supplies one (the page body). An extract
|
|
454
|
+
read does not — extracted items are data, not prose — so those modes fall
|
|
455
|
+
back to JSON. This is the deliberate asymmetry from `repo`, whose results are
|
|
456
|
+
always structured data.
|
|
457
|
+
|
|
458
|
+
**Scripting impact:** any consumer that did `scoutline read URL > file.md`,
|
|
459
|
+
`scoutline read URL | jq -r .content`, or `scoutline read URL --extract code |
|
|
460
|
+
jq -c .[]` against v0.2 output must switch to the v1 envelope. `--max-chars`
|
|
461
|
+
still truncates the content-read `content`; it is **ignored on extract reads**
|
|
462
|
+
(extract reports `originalItemCount` instead). The deprecated
|
|
463
|
+
`--full-envelope` flag is silently accepted and ignored — the envelope is
|
|
464
|
+
always returned at v1.
|
|
465
|
+
|
|
466
|
+
### URL rewrite as `finalUrl`
|
|
467
|
+
|
|
468
|
+
A Provider-side URL rewrite (today: gist URLs to their raw form) is recorded
|
|
469
|
+
as `finalUrl` in the v1 result. The rewrite is idempotent on URLs already
|
|
470
|
+
ending in `/raw` and preserves fragments. The v0.2 stderr notice is removed.
|
|
471
|
+
|
|
472
|
+
### Cache namespace
|
|
473
|
+
|
|
474
|
+
Reader results share the partitioned cache namespace and use the
|
|
475
|
+
`reader-fetch` operation suffix:
|
|
476
|
+
|
|
477
|
+
```text
|
|
478
|
+
v2.reader-reader-fetch.<provider>.<credential-hash>.<request-hash>.json
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
The Adapter resolves its credential once. The canonical request URL is the
|
|
482
|
+
**rewritten** URL so two requests that normalize to the same fetched URL share
|
|
483
|
+
one cache entry. Legacy v0.2 Z.AI entries are reconstructed from the same
|
|
484
|
+
Adapter-resolved credential using the exact v0.2 args-order algorithm and
|
|
485
|
+
remain read-only; a valid hit is written through to the new key; legacy files
|
|
486
|
+
are never migrated, rewritten, or deleted. `--no-cache` performs no reads or
|
|
487
|
+
writes. Injected credentials drive the fingerprint and legacy-key
|
|
488
|
+
construction; ambient `process.env` is never reread.
|
|
489
|
+
|
|
490
|
+
### Errors and lifecycle
|
|
491
|
+
|
|
492
|
+
Encoded MCP error envelopes are recognized before success parsing. The same
|
|
493
|
+
taxonomy that governs `repo` applies: exhausted WebReader quota (code `1310`
|
|
494
|
+
or explicit exhausted-limit meaning) surfaces as a normalized `QUOTA_ERROR`
|
|
495
|
+
429 and is terminal; transient 429/5xx and a malformed envelope retry once;
|
|
496
|
+
auth 401/403 and other 4xx are terminal. Raw Provider body, reset metadata,
|
|
497
|
+
and error-text strings are discarded. Transport close is best-effort and
|
|
498
|
+
called once per constructed attempt; a close failure never masks a primary
|
|
499
|
+
result. Cache hits construct and close no transport.
|
|
500
|
+
|
|
501
|
+
### Diagnostics inventory
|
|
502
|
+
|
|
503
|
+
`sharedCapabilities` and `zaiOnlyCapabilities` are derived from descriptor
|
|
504
|
+
metadata. `reader` is therefore `zaiOnlyCapabilities` while still
|
|
505
|
+
participating in Provider selection, and Doctor help names MiniMax as
|
|
506
|
+
unsupported for `read`.
|
|
507
|
+
|
|
508
|
+
### Non-goals
|
|
509
|
+
|
|
510
|
+
This release does not add a MiniMax Reader Adapter, automatic summarization,
|
|
511
|
+
removal of the deprecated `--full-envelope` flag, or a future `--max-items`
|
|
512
|
+
truncation policy for extract reads.
|
|
291
513
|
|
|
292
514
|
## Contributing
|
|
293
515
|
|
|
@@ -1,34 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Diagnostics Capability Contract (DESIGN.md §14, P4-04).
|
|
2
|
+
* Diagnostics Capability Contract (DESIGN.md §14, P4-04, P6-06).
|
|
3
3
|
*
|
|
4
4
|
* Defines the schema-version-1 diagnostics report every `doctor`
|
|
5
5
|
* invocation returns, plus the capability contract each Provider
|
|
6
6
|
* Adapter implements so its connectivity can be probed without a
|
|
7
7
|
* generative request.
|
|
8
8
|
*
|
|
9
|
-
* The report is built by the doctor command from
|
|
10
|
-
*
|
|
11
|
-
* Each Adapter performs exactly ONE connectivity attempt;
|
|
12
|
-
* execution owns the retry policy.
|
|
9
|
+
* The report is built by the doctor command from descriptor-derived
|
|
10
|
+
* inventory plus the success/failure of each configured Provider
|
|
11
|
+
* probe. Each Adapter performs exactly ONE connectivity attempt;
|
|
12
|
+
* shared execution owns the retry policy.
|
|
13
13
|
*
|
|
14
14
|
* Boundary rules (ARCHITECTURE.md §2):
|
|
15
|
-
* - Imports Provider identity
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* - Imports Provider identity and metadata types (`ProviderCapability`,
|
|
16
|
+
* `ProviderDescriptor`, `ProviderId`) and shared errors. P6-06 keeps
|
|
17
|
+
* the inventory descriptor-derived; no concrete Adapter, no
|
|
18
|
+
* Provider transport, no production registry import lives here.
|
|
19
|
+
* - Imports no Provider transport, no Provider Adapter, no Vision
|
|
20
|
+
* operation→capability mapping, no MiniMax specialized-vision
|
|
21
|
+
* conformance registry, no command presentation. The previous
|
|
22
|
+
* hand-maintained inventory required those imports; the
|
|
23
|
+
* descriptor-derived inventory does not.
|
|
20
24
|
*
|
|
21
|
-
*
|
|
22
|
-
* -
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
25
|
+
* Inventory derivation (P6-06):
|
|
26
|
+
* - `sharedCapabilities` is the intersection across every descriptor
|
|
27
|
+
* passed to `buildDiagnosticsReport`, preserving deterministic
|
|
28
|
+
* canonical order from the FIRST descriptor.
|
|
29
|
+
* - `zaiOnlyCapabilities` is the Z.AI descriptor's capabilities
|
|
30
|
+
* minus the union of every OTHER built-in descriptor's
|
|
31
|
+
* capabilities, preserving Z.AI descriptor order. Values are
|
|
32
|
+
* descriptor capability IDs only — no hand-maintained aliases.
|
|
33
|
+
* - `repository-exploration` is excluded from shared while any
|
|
34
|
+
* built-in lacks it, and included in Z.AI-only the moment Z.AI
|
|
35
|
+
* advertises it and another built-in does not.
|
|
30
36
|
*/
|
|
31
|
-
import type { ProviderCapability, ProviderId } from "../providers/types.js";
|
|
37
|
+
import type { ProviderCapability, ProviderDescriptor, ProviderId } from "../providers/types.js";
|
|
32
38
|
import { type ScoutlineErrorCode } from "../lib/errors.js";
|
|
33
39
|
export interface DiagnosticOptions {
|
|
34
40
|
readonly probe: boolean;
|
|
@@ -55,6 +61,19 @@ export interface DiagnosticsReport {
|
|
|
55
61
|
readonly visionMcpCompatible: boolean;
|
|
56
62
|
};
|
|
57
63
|
readonly providers: readonly ProviderDiagnostic[];
|
|
64
|
+
/**
|
|
65
|
+
* One-line cache summary embedded by the CLI handler
|
|
66
|
+
* (`Cache: enabled, 47 response entries (12.3 MB), 1 tool entry
|
|
67
|
+
* (8.2 KB), ~/.scoutline/`). Optional: present when the dispatcher
|
|
68
|
+
* passes a pre-formatted `cacheSummary` through
|
|
69
|
+
* `DoctorDiagnosticsDependencies`. The Doctor report builder NEVER
|
|
70
|
+
* formats this itself (L1 fix); it only embeds what the caller
|
|
71
|
+
* supplied. Older callers that omit the dependency produce a report
|
|
72
|
+
* without this field.
|
|
73
|
+
*/
|
|
74
|
+
readonly cache?: {
|
|
75
|
+
readonly summary: string;
|
|
76
|
+
};
|
|
58
77
|
}
|
|
59
78
|
/**
|
|
60
79
|
* Capability each Provider Adapter implements for connectivity
|
|
@@ -68,21 +87,40 @@ export interface DiagnosticsCapability {
|
|
|
68
87
|
invoke(options: DiagnosticOptions): Promise<void>;
|
|
69
88
|
}
|
|
70
89
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
90
|
+
* Derive the shared Capabilities inventory: the intersection of every
|
|
91
|
+
* descriptor's `capabilities()` set, preserving deterministic
|
|
92
|
+
* canonical order from the FIRST descriptor in the list.
|
|
93
|
+
*
|
|
94
|
+
* Edge cases:
|
|
95
|
+
* - Empty descriptor list: returns an empty array.
|
|
96
|
+
* - Single descriptor: returns that descriptor's capabilities in
|
|
97
|
+
* their declared order (the intersection of one set is itself).
|
|
98
|
+
* - Two or more: keeps a capability from the first descriptor iff
|
|
99
|
+
* every other descriptor also advertises it.
|
|
100
|
+
*
|
|
101
|
+
* The returned array is frozen so callers cannot mutate the cached
|
|
102
|
+
* derivation in place.
|
|
78
103
|
*/
|
|
79
|
-
export declare
|
|
104
|
+
export declare function deriveSharedCapabilities(descriptors: readonly ProviderDescriptor[]): readonly ProviderCapability[];
|
|
80
105
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
106
|
+
* Derive the Z.AI-only Capabilities inventory: capabilities advertised
|
|
107
|
+
* by the Z.AI descriptor minus the union of capabilities advertised by
|
|
108
|
+
* every OTHER descriptor in the list. Preserves Z.AI descriptor order.
|
|
109
|
+
*
|
|
110
|
+
* Edge cases:
|
|
111
|
+
* - Empty descriptor list: returns an empty array.
|
|
112
|
+
* - Z.AI absent from the list: returns an empty array.
|
|
113
|
+
* - Z.AI present as the only descriptor: returns its capabilities
|
|
114
|
+
* verbatim (the "minus nothing" case).
|
|
115
|
+
* - Z.AI with other descriptors: each capability in Z.AI descriptor
|
|
116
|
+
* order is kept iff no other descriptor advertises it.
|
|
117
|
+
*
|
|
118
|
+
* The returned values are descriptor capability IDs only. No
|
|
119
|
+
* hand-maintained aliases, no parallel base-release list, no
|
|
120
|
+
* invented names. `repository-exploration` lands here naturally the
|
|
121
|
+
* moment Z.AI advertises it and another built-in does not.
|
|
84
122
|
*/
|
|
85
|
-
export declare
|
|
123
|
+
export declare function deriveZaiOnlyCapabilities(descriptors: readonly ProviderDescriptor[]): readonly ProviderCapability[];
|
|
86
124
|
/**
|
|
87
125
|
* Map a thrown error into a normalized diagnostic error entry. The
|
|
88
126
|
* caller is responsible for recursive redaction before the entry
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/capabilities/diagnostics.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/capabilities/diagnostics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAM3E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACrD,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAAC;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,kBAAkB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/E;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,UAAU,CAAC;IACvC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC3D,QAAQ,CAAC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;KACvC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAClD;;;;;;;;;OASG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,SAAS,kBAAkB,EAAE,GACzC,SAAS,kBAAkB,EAAE,CAc/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,SAAS,kBAAkB,EAAE,GACzC,SAAS,kBAAkB,EAAE,CAoB/B;AAMD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG;IACxD,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAYA"}
|
|
@@ -1,69 +1,120 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Diagnostics Capability Contract (DESIGN.md §14, P4-04).
|
|
2
|
+
* Diagnostics Capability Contract (DESIGN.md §14, P4-04, P6-06).
|
|
3
3
|
*
|
|
4
4
|
* Defines the schema-version-1 diagnostics report every `doctor`
|
|
5
5
|
* invocation returns, plus the capability contract each Provider
|
|
6
6
|
* Adapter implements so its connectivity can be probed without a
|
|
7
7
|
* generative request.
|
|
8
8
|
*
|
|
9
|
-
* The report is built by the doctor command from
|
|
10
|
-
*
|
|
11
|
-
* Each Adapter performs exactly ONE connectivity attempt;
|
|
12
|
-
* execution owns the retry policy.
|
|
9
|
+
* The report is built by the doctor command from descriptor-derived
|
|
10
|
+
* inventory plus the success/failure of each configured Provider
|
|
11
|
+
* probe. Each Adapter performs exactly ONE connectivity attempt;
|
|
12
|
+
* shared execution owns the retry policy.
|
|
13
13
|
*
|
|
14
14
|
* Boundary rules (ARCHITECTURE.md §2):
|
|
15
|
-
* - Imports Provider identity
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* - Imports Provider identity and metadata types (`ProviderCapability`,
|
|
16
|
+
* `ProviderDescriptor`, `ProviderId`) and shared errors. P6-06 keeps
|
|
17
|
+
* the inventory descriptor-derived; no concrete Adapter, no
|
|
18
|
+
* Provider transport, no production registry import lives here.
|
|
19
|
+
* - Imports no Provider transport, no Provider Adapter, no Vision
|
|
20
|
+
* operation→capability mapping, no MiniMax specialized-vision
|
|
21
|
+
* conformance registry, no command presentation. The previous
|
|
22
|
+
* hand-maintained inventory required those imports; the
|
|
23
|
+
* descriptor-derived inventory does not.
|
|
20
24
|
*
|
|
21
|
-
*
|
|
22
|
-
* -
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
25
|
+
* Inventory derivation (P6-06):
|
|
26
|
+
* - `sharedCapabilities` is the intersection across every descriptor
|
|
27
|
+
* passed to `buildDiagnosticsReport`, preserving deterministic
|
|
28
|
+
* canonical order from the FIRST descriptor.
|
|
29
|
+
* - `zaiOnlyCapabilities` is the Z.AI descriptor's capabilities
|
|
30
|
+
* minus the union of every OTHER built-in descriptor's
|
|
31
|
+
* capabilities, preserving Z.AI descriptor order. Values are
|
|
32
|
+
* descriptor capability IDs only — no hand-maintained aliases.
|
|
33
|
+
* - `repository-exploration` is excluded from shared while any
|
|
34
|
+
* built-in lacks it, and included in Z.AI-only the moment Z.AI
|
|
35
|
+
* advertises it and another built-in does not.
|
|
30
36
|
*/
|
|
31
37
|
import { ScoutlineError } from "../lib/errors.js";
|
|
32
|
-
import { visionOperationToCapability } from "./vision.js";
|
|
33
|
-
import { listSupportedMiniMaxVisionOperations } from "../providers/minimax/vision-conformance.js";
|
|
34
38
|
// ---------------------------------------------------------------------------
|
|
35
|
-
//
|
|
39
|
+
// Descriptor-derived inventory (P6-06).
|
|
40
|
+
//
|
|
41
|
+
// Pure calculations over the exact descriptor list passed to
|
|
42
|
+
// `buildDiagnosticsReport`. No descriptor.create(), no transport, no
|
|
43
|
+
// production registry import. Empty/single/missing-ZAI lists are
|
|
44
|
+
// handled deterministically; the algorithms never rely on array
|
|
45
|
+
// indexing accidents.
|
|
36
46
|
// ---------------------------------------------------------------------------
|
|
37
47
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
48
|
+
* Derive the shared Capabilities inventory: the intersection of every
|
|
49
|
+
* descriptor's `capabilities()` set, preserving deterministic
|
|
50
|
+
* canonical order from the FIRST descriptor in the list.
|
|
51
|
+
*
|
|
52
|
+
* Edge cases:
|
|
53
|
+
* - Empty descriptor list: returns an empty array.
|
|
54
|
+
* - Single descriptor: returns that descriptor's capabilities in
|
|
55
|
+
* their declared order (the intersection of one set is itself).
|
|
56
|
+
* - Two or more: keeps a capability from the first descriptor iff
|
|
57
|
+
* every other descriptor also advertises it.
|
|
58
|
+
*
|
|
59
|
+
* The returned array is frozen so callers cannot mutate the cached
|
|
60
|
+
* derivation in place.
|
|
45
61
|
*/
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
export function deriveSharedCapabilities(descriptors) {
|
|
63
|
+
if (descriptors.length === 0)
|
|
64
|
+
return Object.freeze([]);
|
|
65
|
+
const [first, ...rest] = descriptors;
|
|
66
|
+
if (rest.length === 0) {
|
|
67
|
+
return Object.freeze([...first.capabilities()]);
|
|
68
|
+
}
|
|
69
|
+
const otherSets = rest.map((d) => d.capabilities());
|
|
70
|
+
const out = [];
|
|
71
|
+
for (const cap of first.capabilities()) {
|
|
72
|
+
if (otherSets.every((set) => set.has(cap))) {
|
|
73
|
+
out.push(cap);
|
|
74
|
+
}
|
|
51
75
|
}
|
|
52
|
-
return Object.freeze(
|
|
76
|
+
return Object.freeze(out);
|
|
53
77
|
}
|
|
54
78
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
79
|
+
* Derive the Z.AI-only Capabilities inventory: capabilities advertised
|
|
80
|
+
* by the Z.AI descriptor minus the union of capabilities advertised by
|
|
81
|
+
* every OTHER descriptor in the list. Preserves Z.AI descriptor order.
|
|
82
|
+
*
|
|
83
|
+
* Edge cases:
|
|
84
|
+
* - Empty descriptor list: returns an empty array.
|
|
85
|
+
* - Z.AI absent from the list: returns an empty array.
|
|
86
|
+
* - Z.AI present as the only descriptor: returns its capabilities
|
|
87
|
+
* verbatim (the "minus nothing" case).
|
|
88
|
+
* - Z.AI with other descriptors: each capability in Z.AI descriptor
|
|
89
|
+
* order is kept iff no other descriptor advertises it.
|
|
90
|
+
*
|
|
91
|
+
* The returned values are descriptor capability IDs only. No
|
|
92
|
+
* hand-maintained aliases, no parallel base-release list, no
|
|
93
|
+
* invented names. `repository-exploration` lands here naturally the
|
|
94
|
+
* moment Z.AI advertises it and another built-in does not.
|
|
58
95
|
*/
|
|
59
|
-
export
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
export function deriveZaiOnlyCapabilities(descriptors) {
|
|
97
|
+
const zai = descriptors.find((d) => d.id === "zai");
|
|
98
|
+
if (!zai)
|
|
99
|
+
return Object.freeze([]);
|
|
100
|
+
const others = descriptors.filter((d) => d.id !== "zai");
|
|
101
|
+
if (others.length === 0) {
|
|
102
|
+
return Object.freeze([...zai.capabilities()]);
|
|
103
|
+
}
|
|
104
|
+
const union = new Set();
|
|
105
|
+
for (const descriptor of others) {
|
|
106
|
+
for (const cap of descriptor.capabilities()) {
|
|
107
|
+
union.add(cap);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const cap of zai.capabilities()) {
|
|
112
|
+
if (!union.has(cap)) {
|
|
113
|
+
out.push(cap);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return Object.freeze(out);
|
|
117
|
+
}
|
|
67
118
|
// ---------------------------------------------------------------------------
|
|
68
119
|
// Failure normalization
|
|
69
120
|
// ---------------------------------------------------------------------------
|