scoutline 0.1.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 +394 -7
- package/bin/scoutline.js +36 -15
- package/dist/capabilities/diagnostics.d.ts +135 -0
- package/dist/capabilities/diagnostics.d.ts.map +1 -0
- package/dist/capabilities/diagnostics.js +139 -0
- package/dist/capabilities/diagnostics.js.map +1 -0
- package/dist/capabilities/quota.d.ts +99 -0
- package/dist/capabilities/quota.d.ts.map +1 -0
- package/dist/capabilities/quota.js +129 -0
- package/dist/capabilities/quota.js.map +1 -0
- 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/capabilities/search.d.ts +110 -0
- package/dist/capabilities/search.d.ts.map +1 -0
- package/dist/capabilities/search.js +21 -0
- package/dist/capabilities/search.js.map +1 -0
- package/dist/capabilities/vision.d.ts +156 -0
- package/dist/capabilities/vision.d.ts.map +1 -0
- package/dist/capabilities/vision.js +111 -0
- package/dist/capabilities/vision.js.map +1 -0
- package/dist/command-invocation.d.ts +58 -0
- package/dist/command-invocation.d.ts.map +1 -0
- package/dist/command-invocation.js +95 -0
- package/dist/command-invocation.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/code.d.ts +11 -4
- package/dist/commands/code.d.ts.map +1 -1
- package/dist/commands/code.js +16 -42
- package/dist/commands/code.js.map +1 -1
- package/dist/commands/doctor.d.ts +69 -3
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +179 -52
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/quota.d.ts +45 -3
- package/dist/commands/quota.d.ts.map +1 -1
- package/dist/commands/quota.js +116 -60
- package/dist/commands/quota.js.map +1 -1
- package/dist/commands/read.d.ts +76 -2
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +260 -121
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/repo.d.ts +55 -4
- package/dist/commands/repo.d.ts.map +1 -1
- package/dist/commands/repo.js +115 -172
- 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/commands/search.d.ts +27 -2
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +95 -103
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/tools.d.ts +9 -3
- package/dist/commands/tools.d.ts.map +1 -1
- package/dist/commands/tools.js +29 -59
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/vision.d.ts +35 -9
- package/dist/commands/vision.d.ts.map +1 -1
- package/dist/commands/vision.js +184 -131
- package/dist/commands/vision.js.map +1 -1
- package/dist/index.d.ts +62 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +580 -223
- package/dist/index.js.map +1 -1
- package/dist/lib/cache.d.ts +178 -12
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +377 -39
- package/dist/lib/cache.js.map +1 -1
- package/dist/lib/code-mode.d.ts +13 -0
- package/dist/lib/code-mode.d.ts.map +1 -1
- package/dist/lib/code-mode.js +26 -6
- package/dist/lib/code-mode.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +15 -18
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts +89 -11
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +168 -21
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/execution.d.ts +190 -0
- package/dist/lib/execution.d.ts.map +1 -0
- package/dist/lib/execution.js +383 -0
- package/dist/lib/execution.js.map +1 -0
- package/dist/lib/index.d.ts +10 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +10 -2
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/mcp-client.d.ts +75 -16
- package/dist/lib/mcp-client.d.ts.map +1 -1
- package/dist/lib/mcp-client.js +173 -108
- package/dist/lib/mcp-client.js.map +1 -1
- package/dist/lib/mcp-config.d.ts +17 -0
- package/dist/lib/mcp-config.d.ts.map +1 -1
- package/dist/lib/mcp-config.js +29 -0
- package/dist/lib/mcp-config.js.map +1 -1
- package/dist/lib/monitor-client.d.ts +17 -3
- package/dist/lib/monitor-client.d.ts.map +1 -1
- package/dist/lib/monitor-client.js +23 -69
- package/dist/lib/monitor-client.js.map +1 -1
- package/dist/lib/output.d.ts +53 -7
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +126 -39
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/redact.d.ts +62 -3
- package/dist/lib/redact.d.ts.map +1 -1
- package/dist/lib/redact.js +165 -31
- package/dist/lib/redact.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/lib/tty.d.ts +7 -20
- package/dist/lib/tty.d.ts.map +1 -1
- package/dist/lib/tty.js +51 -30
- package/dist/lib/tty.js.map +1 -1
- package/dist/node-command-invocation-adapter.d.ts +28 -0
- package/dist/node-command-invocation-adapter.d.ts.map +1 -0
- package/dist/node-command-invocation-adapter.js +88 -0
- package/dist/node-command-invocation-adapter.js.map +1 -0
- package/dist/providers/minimax/adapter.d.ts +49 -0
- package/dist/providers/minimax/adapter.d.ts.map +1 -0
- package/dist/providers/minimax/adapter.js +450 -0
- package/dist/providers/minimax/adapter.js.map +1 -0
- 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/config.d.ts +32 -0
- package/dist/providers/minimax/config.d.ts.map +1 -0
- package/dist/providers/minimax/config.js +84 -0
- package/dist/providers/minimax/config.js.map +1 -0
- package/dist/providers/minimax/media.d.ts +88 -0
- package/dist/providers/minimax/media.d.ts.map +1 -0
- package/dist/providers/minimax/media.js +232 -0
- package/dist/providers/minimax/media.js.map +1 -0
- package/dist/providers/minimax/quota-client.d.ts +44 -0
- package/dist/providers/minimax/quota-client.d.ts.map +1 -0
- package/dist/providers/minimax/quota-client.js +83 -0
- package/dist/providers/minimax/quota-client.js.map +1 -0
- package/dist/providers/minimax/quota.d.ts +48 -0
- package/dist/providers/minimax/quota.d.ts.map +1 -0
- package/dist/providers/minimax/quota.js +120 -0
- package/dist/providers/minimax/quota.js.map +1 -0
- package/dist/providers/minimax/sdk-client.d.ts +29 -0
- package/dist/providers/minimax/sdk-client.d.ts.map +1 -0
- package/dist/providers/minimax/sdk-client.js +50 -0
- package/dist/providers/minimax/sdk-client.js.map +1 -0
- package/dist/providers/minimax/vision-attestations.d.ts +52 -0
- package/dist/providers/minimax/vision-attestations.d.ts.map +1 -0
- package/dist/providers/minimax/vision-attestations.js +79 -0
- package/dist/providers/minimax/vision-attestations.js.map +1 -0
- package/dist/providers/minimax/vision-conformance.d.ts +186 -0
- package/dist/providers/minimax/vision-conformance.d.ts.map +1 -0
- package/dist/providers/minimax/vision-conformance.js +371 -0
- package/dist/providers/minimax/vision-conformance.js.map +1 -0
- package/dist/providers/minimax/vision-mappings/chart.d.ts +35 -0
- package/dist/providers/minimax/vision-mappings/chart.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings/chart.js +55 -0
- package/dist/providers/minimax/vision-mappings/chart.js.map +1 -0
- package/dist/providers/minimax/vision-mappings/common.d.ts +60 -0
- package/dist/providers/minimax/vision-mappings/common.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings/common.js +75 -0
- package/dist/providers/minimax/vision-mappings/common.js.map +1 -0
- package/dist/providers/minimax/vision-mappings/diagnose-error.d.ts +35 -0
- package/dist/providers/minimax/vision-mappings/diagnose-error.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings/diagnose-error.js +55 -0
- package/dist/providers/minimax/vision-mappings/diagnose-error.js.map +1 -0
- package/dist/providers/minimax/vision-mappings/diagram.d.ts +35 -0
- package/dist/providers/minimax/vision-mappings/diagram.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings/diagram.js +55 -0
- package/dist/providers/minimax/vision-mappings/diagram.js.map +1 -0
- package/dist/providers/minimax/vision-mappings/extract-text.d.ts +35 -0
- package/dist/providers/minimax/vision-mappings/extract-text.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings/extract-text.js +55 -0
- package/dist/providers/minimax/vision-mappings/extract-text.js.map +1 -0
- package/dist/providers/minimax/vision-mappings/ui-artifact.d.ts +35 -0
- package/dist/providers/minimax/vision-mappings/ui-artifact.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings/ui-artifact.js +69 -0
- package/dist/providers/minimax/vision-mappings/ui-artifact.js.map +1 -0
- package/dist/providers/minimax/vision-mappings.generated.d.ts +29 -0
- package/dist/providers/minimax/vision-mappings.generated.d.ts.map +1 -0
- package/dist/providers/minimax/vision-mappings.generated.js +29 -0
- package/dist/providers/minimax/vision-mappings.generated.js.map +1 -0
- package/dist/providers/minimax/vision-revisions.d.ts +29 -0
- package/dist/providers/minimax/vision-revisions.d.ts.map +1 -0
- package/dist/providers/minimax/vision-revisions.js +34 -0
- package/dist/providers/minimax/vision-revisions.js.map +1 -0
- package/dist/providers/registry.d.ts +36 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +45 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/selection.d.ts +44 -0
- package/dist/providers/selection.d.ts.map +1 -0
- package/dist/providers/selection.js +85 -0
- package/dist/providers/selection.js.map +1 -0
- package/dist/providers/types.d.ts +281 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +127 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/providers/zai/adapter.d.ts +35 -0
- package/dist/providers/zai/adapter.d.ts.map +1 -0
- package/dist/providers/zai/adapter.js +685 -0
- package/dist/providers/zai/adapter.js.map +1 -0
- package/dist/providers/zai/credentials.d.ts +38 -0
- package/dist/providers/zai/credentials.d.ts.map +1 -0
- package/dist/providers/zai/credentials.js +60 -0
- package/dist/providers/zai/credentials.js.map +1 -0
- 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/media.d.ts +38 -0
- package/dist/providers/zai/media.d.ts.map +1 -0
- package/dist/providers/zai/media.js +107 -0
- package/dist/providers/zai/media.js.map +1 -0
- package/dist/providers/zai/monitor-client.d.ts +53 -0
- package/dist/providers/zai/monitor-client.d.ts.map +1 -0
- package/dist/providers/zai/monitor-client.js +117 -0
- package/dist/providers/zai/monitor-client.js.map +1 -0
- package/dist/providers/zai/quota.d.ts +47 -0
- package/dist/providers/zai/quota.d.ts.map +1 -0
- package/dist/providers/zai/quota.js +127 -0
- package/dist/providers/zai/quota.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 +11 -6
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diagnostics Capability Contract (DESIGN.md §14, P4-04, P6-06).
|
|
3
|
+
*
|
|
4
|
+
* Defines the schema-version-1 diagnostics report every `doctor`
|
|
5
|
+
* invocation returns, plus the capability contract each Provider
|
|
6
|
+
* Adapter implements so its connectivity can be probed without a
|
|
7
|
+
* generative request.
|
|
8
|
+
*
|
|
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
|
+
*
|
|
14
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
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.
|
|
24
|
+
*
|
|
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.
|
|
36
|
+
*/
|
|
37
|
+
import { ScoutlineError } from "../lib/errors.js";
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
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.
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
/**
|
|
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.
|
|
61
|
+
*/
|
|
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
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return Object.freeze(out);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
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.
|
|
95
|
+
*/
|
|
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
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Failure normalization
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* Map a thrown error into a normalized diagnostic error entry. The
|
|
123
|
+
* caller is responsible for recursive redaction before the entry
|
|
124
|
+
* crosses an outward boundary (the doctor command does this in
|
|
125
|
+
* {@link buildDiagnosticsReport}).
|
|
126
|
+
*/
|
|
127
|
+
export function diagnosticErrorFromError(error) {
|
|
128
|
+
const code = error instanceof ScoutlineError ? error.code : "UNKNOWN_ERROR";
|
|
129
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
130
|
+
const result = {
|
|
131
|
+
code,
|
|
132
|
+
message,
|
|
133
|
+
};
|
|
134
|
+
if (error instanceof ScoutlineError && error.help) {
|
|
135
|
+
result.help = error.help;
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/capabilities/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Capability Contract (DESIGN.md §13, ADR-0001).
|
|
3
|
+
*
|
|
4
|
+
* Defines the normalized Provider-quota Interface shared by every
|
|
5
|
+
* Provider that reports plan usage. Each Adapter maps its Provider
|
|
6
|
+
* response shape into named quota categories with current and optional
|
|
7
|
+
* weekly windows, optional counts, a remaining percentage, and a reset
|
|
8
|
+
* time so callers do not need Provider-specific knowledge.
|
|
9
|
+
*
|
|
10
|
+
* Normalization rules (DESIGN.md §13):
|
|
11
|
+
* - Percentages are REMAINING percentages clamped to 0..100.
|
|
12
|
+
* - A valid explicit remaining percentage wins; otherwise derive
|
|
13
|
+
* `(remaining / limit) * 100` from finite nonnegative counts where
|
|
14
|
+
* used is not greater than limit.
|
|
15
|
+
* - Invalid optional counts are omitted together (not set to zero).
|
|
16
|
+
* - A category that has neither a valid percentage nor valid counts
|
|
17
|
+
* is rejected with `QUOTA_ERROR`.
|
|
18
|
+
* - Nonempty names, finite values, and ISO dates are mandatory.
|
|
19
|
+
*
|
|
20
|
+
* This module imports only Provider identity types and shared errors;
|
|
21
|
+
* it imports no Provider transport and no Provider Adapter.
|
|
22
|
+
*/
|
|
23
|
+
import type { ProviderId } from "../providers/types.js";
|
|
24
|
+
import { type ScoutlineErrorCode } from "../lib/errors.js";
|
|
25
|
+
export interface QuotaWindow {
|
|
26
|
+
durationSeconds?: number;
|
|
27
|
+
used?: number;
|
|
28
|
+
limit?: number;
|
|
29
|
+
remaining?: number;
|
|
30
|
+
remainingPercent: number;
|
|
31
|
+
resetsAt?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface QuotaCategory {
|
|
34
|
+
name: string;
|
|
35
|
+
unit: "requests" | "tokens";
|
|
36
|
+
current: QuotaWindow;
|
|
37
|
+
weekly?: QuotaWindow;
|
|
38
|
+
}
|
|
39
|
+
export interface ProviderQuotaSuccess {
|
|
40
|
+
provider: ProviderId;
|
|
41
|
+
status: "ok";
|
|
42
|
+
plan?: string;
|
|
43
|
+
categories: QuotaCategory[];
|
|
44
|
+
}
|
|
45
|
+
export interface ProviderQuotaFailure {
|
|
46
|
+
provider: ProviderId;
|
|
47
|
+
status: "error";
|
|
48
|
+
error: {
|
|
49
|
+
code: ScoutlineErrorCode;
|
|
50
|
+
message: string;
|
|
51
|
+
help?: string;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export interface QuotaDashboard {
|
|
55
|
+
schemaVersion: 1;
|
|
56
|
+
effectiveProvider: ProviderId;
|
|
57
|
+
providers: Array<ProviderQuotaSuccess | ProviderQuotaFailure>;
|
|
58
|
+
}
|
|
59
|
+
export interface QuotaCapability {
|
|
60
|
+
invoke(): Promise<ProviderQuotaSuccess>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Inputs to {@link buildQuotaWindow}. Every field is optional except
|
|
64
|
+
* that at least one of `explicitRemainingPercent` or a valid count set
|
|
65
|
+
* (`used` + `limit`) must be present, otherwise the window is
|
|
66
|
+
* unrecoverable and `QUOTA_ERROR` is thrown.
|
|
67
|
+
*/
|
|
68
|
+
export interface QuotaWindowInputs {
|
|
69
|
+
durationSeconds?: number;
|
|
70
|
+
used?: number;
|
|
71
|
+
limit?: number;
|
|
72
|
+
resetsAtEpochMs?: number;
|
|
73
|
+
/**
|
|
74
|
+
* A Provider-supplied REMAINING percentage (already in remaining
|
|
75
|
+
* terms, not used terms). A finite value wins over count-derived
|
|
76
|
+
* derivation and is then clamped to 0..100.
|
|
77
|
+
*/
|
|
78
|
+
explicitRemainingPercent?: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build a normalized {@link QuotaWindow} from Provider inputs.
|
|
82
|
+
*
|
|
83
|
+
* Resolution order for `remainingPercent`:
|
|
84
|
+
* 1. A finite explicit remaining percentage wins (then clamped).
|
|
85
|
+
* 2. Otherwise derive from valid counts.
|
|
86
|
+
* 3. Otherwise throw `QUOTA_ERROR` — the category is unrecoverable.
|
|
87
|
+
*
|
|
88
|
+
* Invalid optional counts are omitted together; valid counts populate
|
|
89
|
+
* `used`, `limit`, and a derived `remaining`. `durationSeconds` and
|
|
90
|
+
* `resetsAt` are included only when finite/ISO-valid.
|
|
91
|
+
*/
|
|
92
|
+
export declare function buildQuotaWindow(inputs: QuotaWindowInputs): QuotaWindow;
|
|
93
|
+
/**
|
|
94
|
+
* Map a thrown error into a normalized {@link ProviderQuotaFailure}. The
|
|
95
|
+
* caller is responsible for recursive redaction before the failure
|
|
96
|
+
* crosses an outward boundary (all-provider quota does this in P4-03).
|
|
97
|
+
*/
|
|
98
|
+
export declare function quotaFailureFromError(provider: ProviderId, error: unknown): ProviderQuotaFailure;
|
|
99
|
+
//# sourceMappingURL=quota.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quota.d.ts","sourceRoot":"","sources":["../../src/capabilities/quota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAM3E,MAAM,WAAW,WAAW;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,UAAU,CAAC;IACrB,MAAM,EAAE,IAAI,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,UAAU,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE;QAAE,IAAI,EAAE,kBAAkB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,CAAC,CAAC;IACjB,iBAAiB,EAAE,UAAU,CAAC;IAC9B,SAAS,EAAE,KAAK,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACzC;AAMD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAkDD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW,CAoCvE;AAMD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,oBAAoB,CAahG"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quota Capability Contract (DESIGN.md §13, ADR-0001).
|
|
3
|
+
*
|
|
4
|
+
* Defines the normalized Provider-quota Interface shared by every
|
|
5
|
+
* Provider that reports plan usage. Each Adapter maps its Provider
|
|
6
|
+
* response shape into named quota categories with current and optional
|
|
7
|
+
* weekly windows, optional counts, a remaining percentage, and a reset
|
|
8
|
+
* time so callers do not need Provider-specific knowledge.
|
|
9
|
+
*
|
|
10
|
+
* Normalization rules (DESIGN.md §13):
|
|
11
|
+
* - Percentages are REMAINING percentages clamped to 0..100.
|
|
12
|
+
* - A valid explicit remaining percentage wins; otherwise derive
|
|
13
|
+
* `(remaining / limit) * 100` from finite nonnegative counts where
|
|
14
|
+
* used is not greater than limit.
|
|
15
|
+
* - Invalid optional counts are omitted together (not set to zero).
|
|
16
|
+
* - A category that has neither a valid percentage nor valid counts
|
|
17
|
+
* is rejected with `QUOTA_ERROR`.
|
|
18
|
+
* - Nonempty names, finite values, and ISO dates are mandatory.
|
|
19
|
+
*
|
|
20
|
+
* This module imports only Provider identity types and shared errors;
|
|
21
|
+
* it imports no Provider transport and no Provider Adapter.
|
|
22
|
+
*/
|
|
23
|
+
import { ScoutlineError } from "../lib/errors.js";
|
|
24
|
+
function isFiniteNonnegative(value) {
|
|
25
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
26
|
+
}
|
|
27
|
+
function isFinitePositive(value) {
|
|
28
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
29
|
+
}
|
|
30
|
+
function clampPercent(value) {
|
|
31
|
+
if (value < 0)
|
|
32
|
+
return 0;
|
|
33
|
+
if (value > 100)
|
|
34
|
+
return 100;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validate a count set: both `used` and `limit` must be finite,
|
|
39
|
+
* nonnegative, with `used` not greater than `limit`. Returns the pair
|
|
40
|
+
* or `null` so an invalid set can be omitted together.
|
|
41
|
+
*/
|
|
42
|
+
function validCountSet(used, limit) {
|
|
43
|
+
if (!isFiniteNonnegative(used) || !isFiniteNonnegative(limit))
|
|
44
|
+
return null;
|
|
45
|
+
if (used > limit)
|
|
46
|
+
return null;
|
|
47
|
+
return { used: used, limit: limit };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Derive a remaining percentage from finite nonnegative counts where
|
|
51
|
+
* used is not greater than limit and limit is positive. Returns `null`
|
|
52
|
+
* when the counts cannot yield a percentage.
|
|
53
|
+
*/
|
|
54
|
+
function derivePercentFromCounts(used, limit) {
|
|
55
|
+
const counts = validCountSet(used, limit);
|
|
56
|
+
if (counts === null)
|
|
57
|
+
return null;
|
|
58
|
+
if (counts.limit <= 0)
|
|
59
|
+
return null;
|
|
60
|
+
return ((counts.limit - counts.used) / counts.limit) * 100;
|
|
61
|
+
}
|
|
62
|
+
function epochMsToIso(epochMs) {
|
|
63
|
+
if (!isFinitePositive(epochMs))
|
|
64
|
+
return undefined;
|
|
65
|
+
return new Date(epochMs).toISOString();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build a normalized {@link QuotaWindow} from Provider inputs.
|
|
69
|
+
*
|
|
70
|
+
* Resolution order for `remainingPercent`:
|
|
71
|
+
* 1. A finite explicit remaining percentage wins (then clamped).
|
|
72
|
+
* 2. Otherwise derive from valid counts.
|
|
73
|
+
* 3. Otherwise throw `QUOTA_ERROR` — the category is unrecoverable.
|
|
74
|
+
*
|
|
75
|
+
* Invalid optional counts are omitted together; valid counts populate
|
|
76
|
+
* `used`, `limit`, and a derived `remaining`. `durationSeconds` and
|
|
77
|
+
* `resetsAt` are included only when finite/ISO-valid.
|
|
78
|
+
*/
|
|
79
|
+
export function buildQuotaWindow(inputs) {
|
|
80
|
+
let remainingPercent;
|
|
81
|
+
if (Number.isFinite(inputs.explicitRemainingPercent)) {
|
|
82
|
+
remainingPercent = inputs.explicitRemainingPercent;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const derived = derivePercentFromCounts(inputs.used, inputs.limit);
|
|
86
|
+
if (derived !== null)
|
|
87
|
+
remainingPercent = derived;
|
|
88
|
+
}
|
|
89
|
+
if (remainingPercent === undefined) {
|
|
90
|
+
throw new ScoutlineError("quota category has neither a valid remaining percentage nor valid counts", "QUOTA_ERROR", { exitCode: 1 });
|
|
91
|
+
}
|
|
92
|
+
const window = { remainingPercent: clampPercent(remainingPercent) };
|
|
93
|
+
const counts = validCountSet(inputs.used, inputs.limit);
|
|
94
|
+
if (counts !== null) {
|
|
95
|
+
window.used = counts.used;
|
|
96
|
+
window.limit = counts.limit;
|
|
97
|
+
window.remaining = counts.limit - counts.used;
|
|
98
|
+
}
|
|
99
|
+
if (isFinitePositive(inputs.durationSeconds)) {
|
|
100
|
+
window.durationSeconds = inputs.durationSeconds;
|
|
101
|
+
}
|
|
102
|
+
const iso = epochMsToIso(inputs.resetsAtEpochMs);
|
|
103
|
+
if (iso !== undefined) {
|
|
104
|
+
window.resetsAt = iso;
|
|
105
|
+
}
|
|
106
|
+
return window;
|
|
107
|
+
}
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Failure normalization
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
/**
|
|
112
|
+
* Map a thrown error into a normalized {@link ProviderQuotaFailure}. The
|
|
113
|
+
* caller is responsible for recursive redaction before the failure
|
|
114
|
+
* crosses an outward boundary (all-provider quota does this in P4-03).
|
|
115
|
+
*/
|
|
116
|
+
export function quotaFailureFromError(provider, error) {
|
|
117
|
+
const code = error instanceof ScoutlineError ? error.code : "UNKNOWN_ERROR";
|
|
118
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
119
|
+
const failure = {
|
|
120
|
+
provider,
|
|
121
|
+
status: "error",
|
|
122
|
+
error: { code, message },
|
|
123
|
+
};
|
|
124
|
+
if (error instanceof ScoutlineError && error.help) {
|
|
125
|
+
failure.error.help = error.help;
|
|
126
|
+
}
|
|
127
|
+
return failure;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=quota.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quota.js","sourceRoot":"","sources":["../../src/capabilities/quota.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral Reader Capability Contract (core-flows D1, D2;
|
|
3
|
+
* tech-plan D1, D2).
|
|
4
|
+
*
|
|
5
|
+
* This module declares the single Reader operation (`reader-fetch`), its
|
|
6
|
+
* provider-neutral request, identity, cache, and result shapes, the total
|
|
7
|
+
* normalized cache decoder, and the `ReaderRawResponse` type capturing
|
|
8
|
+
* what the Z.AI WebReader MCP actually returns at runtime.
|
|
9
|
+
*
|
|
10
|
+
* It imports NO concrete Provider, transport, or Adapter. It does no URL
|
|
11
|
+
* rewriting, raw response parsing, Provider field mapping, Provider
|
|
12
|
+
* selection, retries, or presentation.
|
|
13
|
+
*
|
|
14
|
+
* Scope of this file:
|
|
15
|
+
* - request, operation, cache-identity, and result type contracts;
|
|
16
|
+
* - the discriminated `ReaderOperationKind` union;
|
|
17
|
+
* - a total decoder for the cacheable normalized result
|
|
18
|
+
* (`decodeReaderFetchResult`);
|
|
19
|
+
* - the `ReaderRawResponse` type consumed by Ticket 02's `webRead`
|
|
20
|
+
* signature fix.
|
|
21
|
+
*
|
|
22
|
+
* Ticket 01 introduces ONLY this contract and the decoder. Ticket 02
|
|
23
|
+
* fixes `webRead` to return `ReaderRawResponse`. Ticket 03 supplies the
|
|
24
|
+
* Z.AI Reader Adapter. Ticket 04 cuts the handler over. Nothing in this
|
|
25
|
+
* file is allowed to widen that boundary.
|
|
26
|
+
*
|
|
27
|
+
* Evidence base: [`artifacts/reader-webreader-characterization/`](../../../../.traycer/epics/4f065460-3416-4832-95a6-7ac5576fcfbc/artifacts/reader-webreader-characterization/index.md).
|
|
28
|
+
*/
|
|
29
|
+
import type { ProviderId } from "../providers/types.js";
|
|
30
|
+
/**
|
|
31
|
+
* The single Reader Capability operation. Cache identity partitions by
|
|
32
|
+
* the composite `${capability}-${operation}` literal; the v2 partitioned
|
|
33
|
+
* key shape is
|
|
34
|
+
* `v2.reader-reader-fetch.<provider>.<credential-hash>.<request-hash>.json`.
|
|
35
|
+
*
|
|
36
|
+
* `--extract` and `--max-chars` are handler-level projections and do
|
|
37
|
+
* NOT participate in the cache identity (tech-plan D1, D2).
|
|
38
|
+
*/
|
|
39
|
+
export type ReaderOperationKind = "reader-fetch";
|
|
40
|
+
/**
|
|
41
|
+
* Provider-neutral Reader fetch request. `url` MUST be supplied
|
|
42
|
+
* explicitly (the handler rejects non-`http(s)` values at parse time
|
|
43
|
+
* with `VALIDATION_ERROR` before this request reaches the Adapter).
|
|
44
|
+
*
|
|
45
|
+
* Every field except `url` participates in the v0.2 legacy cache key
|
|
46
|
+
* (`buildLegacyReaderCacheKey`) and in the v2 partitioned cache identity
|
|
47
|
+
* (`buildProviderCacheKey`). `--extract`, `--max-chars`, `--full-envelope`,
|
|
48
|
+
* `--no-cache`, and output mode NEVER appear here — they are projections
|
|
49
|
+
* applied after the cached normalized result.
|
|
50
|
+
*
|
|
51
|
+
* Field name parity with the v0.2 `webRead` request shape is intentional;
|
|
52
|
+
* the Adapter maps each field to the Z.AI WebReader MCP argument of the
|
|
53
|
+
* same semantics. The field order in the v0.2 insertion-order key is
|
|
54
|
+
* locked by the legacy helper, not by this interface.
|
|
55
|
+
*/
|
|
56
|
+
export interface ReaderFetchRequest {
|
|
57
|
+
readonly url: string;
|
|
58
|
+
readonly format?: "markdown" | "text";
|
|
59
|
+
readonly retainImages?: boolean;
|
|
60
|
+
readonly withLinksSummary?: boolean;
|
|
61
|
+
readonly noGfm?: boolean;
|
|
62
|
+
readonly keepImgDataUrl?: boolean;
|
|
63
|
+
readonly withImagesSummary?: boolean;
|
|
64
|
+
readonly timeout?: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Normalized Reader fetch result. `schemaVersion: 1` is the breaking
|
|
68
|
+
* migration shape (core-flows D1 — `data`-mode returns the envelope,
|
|
69
|
+
* not a raw string).
|
|
70
|
+
*
|
|
71
|
+
* `truncated` and `originalContentLength` are NOT part of this contract.
|
|
72
|
+
* They are handler-level projections applied by `commands/read.ts` after
|
|
73
|
+
* the cached normalized result is produced (tech-plan D5). The cache
|
|
74
|
+
* stores the full content; truncation state is recomputed on every read.
|
|
75
|
+
*
|
|
76
|
+
* `title` is `string | null`. Every observed Z.AI WebReader response
|
|
77
|
+
* carries a non-empty string title (see characterization artifact), but
|
|
78
|
+
* the contract keeps the nullable arm for forward-compat and for
|
|
79
|
+
* Adapter-side coercion of empty / whitespace-only titles.
|
|
80
|
+
*
|
|
81
|
+
* `metadata` and `external` are typed `unknown` defensively. The
|
|
82
|
+
* characterization probe observed both as flat object maps, but the
|
|
83
|
+
* contract does not promote or restructure them — they pass through
|
|
84
|
+
* verbatim from the Provider.
|
|
85
|
+
*/
|
|
86
|
+
export interface ReaderFetchResult {
|
|
87
|
+
readonly schemaVersion: 1;
|
|
88
|
+
/** Exactly what the caller passed to the operation. */
|
|
89
|
+
readonly url: string;
|
|
90
|
+
/**
|
|
91
|
+
* The URL the operation actually fetched. Differs from `url` only when
|
|
92
|
+
* a Provider-side rewrite occurred (e.g. `gist.github.com/<id>` →
|
|
93
|
+
* `gist.github.com/<id>/raw`).
|
|
94
|
+
*/
|
|
95
|
+
readonly finalUrl: string;
|
|
96
|
+
/** Page title if the Provider returned one; `null` if absent or blank. */
|
|
97
|
+
readonly title: string | null;
|
|
98
|
+
/** Page content as markdown or plain text per `format`. */
|
|
99
|
+
readonly content: string;
|
|
100
|
+
/** Mirrors the request `format`; defaults to `"markdown"`. */
|
|
101
|
+
readonly contentFormat: "markdown" | "text";
|
|
102
|
+
/** Optional Provider-derived metadata blob; preserved verbatim. */
|
|
103
|
+
readonly metadata?: unknown;
|
|
104
|
+
/** Optional Provider-derived external-resource blob; preserved verbatim. */
|
|
105
|
+
readonly external?: unknown;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Object shape of a successful Z.AI WebReader MCP response. Field names
|
|
109
|
+
* mirror the wire shape observed in the characterization probe. Every
|
|
110
|
+
* field is optional at the wire layer — the Capability decoder enforces
|
|
111
|
+
* the stronger invariants (`title`, `url`, `content` must be non-empty
|
|
112
|
+
* strings) before promoting any value into a `ReaderFetchResult`.
|
|
113
|
+
*
|
|
114
|
+
* `description` is declared here so the Adapter can read it without
|
|
115
|
+
* crashing on rich pages (the probe confirmed `description` appears
|
|
116
|
+
* both at the top level and inside `metadata` for rich pages). The v1
|
|
117
|
+
* envelope does NOT surface it; it is dropped during normalization.
|
|
118
|
+
*/
|
|
119
|
+
export interface ReaderRawObjectResponse {
|
|
120
|
+
readonly title?: string;
|
|
121
|
+
readonly description?: string;
|
|
122
|
+
readonly url?: string;
|
|
123
|
+
readonly content?: string;
|
|
124
|
+
readonly metadata?: unknown;
|
|
125
|
+
readonly external?: unknown;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The complete raw shape returned by `scoutline.zai.reader.webReader` at
|
|
129
|
+
* runtime. Either a structured object (the common case) or a bare
|
|
130
|
+
* `string` carrying an MCP-level error envelope (the characterization
|
|
131
|
+
* probe captured the exact shape: `"MCP error -500: ..."`).
|
|
132
|
+
*
|
|
133
|
+
* Ticket 02 widens the existing `webRead` method's TypeScript signature from
|
|
134
|
+
* the inaccurate `Promise<string>` to `Promise<ReaderRawResponse>` so
|
|
135
|
+
* raw-tool callers (`scoutline.zai.reader.*`) and the future Reader
|
|
136
|
+
* Adapter both see an honest path.
|
|
137
|
+
*
|
|
138
|
+
* The Capability decoder (`decodeReaderFetchResult`) only trusts
|
|
139
|
+
* object-shape values that satisfy the required field set. A raw
|
|
140
|
+
* `string` is malformed at the Capability layer — it represents a
|
|
141
|
+
* transport-level error that the Adapter must convert into a normalized
|
|
142
|
+
* `API_ERROR` 502 per the failure-handling table, not a fetch result.
|
|
143
|
+
*/
|
|
144
|
+
export type ReaderRawResponse = ReaderRawObjectResponse | string;
|
|
145
|
+
/**
|
|
146
|
+
* Provider-owned legacy cache candidate. Old Z.AI v0.2 read cache entries
|
|
147
|
+
* encode the raw WebReader response under the public dotted tool name
|
|
148
|
+
* (`scoutline.zai.reader.webReader`). The Adapter supplies the decoder
|
|
149
|
+
* so shared cache code never inspects Provider response shapes. An
|
|
150
|
+
* invalid decode is a cache miss.
|
|
151
|
+
*/
|
|
152
|
+
export interface LegacyReaderCacheCandidate<Result> {
|
|
153
|
+
readonly key: string;
|
|
154
|
+
decode(value: unknown): Result | null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Identity used to read and write a Provider-partitioned Reader cache
|
|
158
|
+
* entry. `credentialFingerprint` is the full lowercase SHA-256 hex
|
|
159
|
+
* digest of the resolved credential and is NEVER re-hashed by cache
|
|
160
|
+
* code. `request` is the normalized Capability request.
|
|
161
|
+
*/
|
|
162
|
+
export interface ReaderCacheIdentity<Request, Result> {
|
|
163
|
+
readonly provider: ProviderId;
|
|
164
|
+
readonly capability: "reader";
|
|
165
|
+
readonly operation: ReaderOperationKind;
|
|
166
|
+
readonly credentialFingerprint: string;
|
|
167
|
+
readonly request: Readonly<Request>;
|
|
168
|
+
readonly legacyCandidates: readonly LegacyReaderCacheCandidate<Result>[];
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Generic Reader operation descriptor. The Adapter supplies one of these
|
|
172
|
+
* for the `reader-fetch` operation it supports. The Adapter owns
|
|
173
|
+
* Provider field mapping, credentials, transport lifecycle, and error
|
|
174
|
+
* normalization. Commands and shared execution call only these four
|
|
175
|
+
* methods.
|
|
176
|
+
*
|
|
177
|
+
* Same shape as P6-02's `RepositoryOperation` — the surface is
|
|
178
|
+
* unchanged; only the operation count differs (Reader has one).
|
|
179
|
+
*/
|
|
180
|
+
export interface ReaderOperation<Request, Result> {
|
|
181
|
+
readonly kind: ReaderOperationKind;
|
|
182
|
+
/**
|
|
183
|
+
* Validate the request before any Provider access. Throws
|
|
184
|
+
* `ValidationError` for missing required fields and
|
|
185
|
+
* `UnsupportedOptionError` for Provider-specific options the Adapter
|
|
186
|
+
* does not accept. Validation MUST occur before credential resolution
|
|
187
|
+
* or transport construction.
|
|
188
|
+
*/
|
|
189
|
+
validate(request: Request): void;
|
|
190
|
+
/**
|
|
191
|
+
* Build the cache identity for a request. Called only after
|
|
192
|
+
* `validate` succeeds. The Adapter resolves its credential once and
|
|
193
|
+
* returns full fingerprint, canonical request, and zero or more
|
|
194
|
+
* legacy candidates. Candidate construction MUST NOT read ambient
|
|
195
|
+
* environment.
|
|
196
|
+
*/
|
|
197
|
+
cacheIdentity(request: Request): ReaderCacheIdentity<Request, Result>;
|
|
198
|
+
/**
|
|
199
|
+
* Total decoder for cached normalized entries. Accepts an `unknown`
|
|
200
|
+
* value, validates shape, and returns the typed result or `null`.
|
|
201
|
+
* NEVER throws, NEVER trusts a generic cast.
|
|
202
|
+
*/
|
|
203
|
+
decodeCached(value: unknown): Result | null;
|
|
204
|
+
/**
|
|
205
|
+
* Invoke the Provider and return the normalized result. The Adapter
|
|
206
|
+
* closes its transport and never retries inside this method; shared
|
|
207
|
+
* execution owns retry policy.
|
|
208
|
+
*/
|
|
209
|
+
invoke(request: Request): Promise<Result>;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Reader Capability contract. Every Adapter that supports reader
|
|
213
|
+
* fetching implements this interface and exposes it as
|
|
214
|
+
* `adapter.reader` (Ticket 03 onwards).
|
|
215
|
+
*/
|
|
216
|
+
export interface ReaderCapability {
|
|
217
|
+
readonly fetch: ReaderOperation<ReaderFetchRequest, ReaderFetchResult>;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Decode a Reader fetch result from the cache. Returns the canonical
|
|
221
|
+
* `ReaderFetchResult` on success, `null` for any malformed value.
|
|
222
|
+
*
|
|
223
|
+
* `title: null` is a valid decoded value (the Adapter coerces missing
|
|
224
|
+
* or blank titles to null before writing; the decoder round-trips it).
|
|
225
|
+
*/
|
|
226
|
+
export declare function decodeReaderFetchResult(value: unknown): ReaderFetchResult | null;
|
|
227
|
+
//# sourceMappingURL=reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/capabilities/reader.ts"],"names":[],"mappings":"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"}
|