scoutline 0.6.4 → 0.9.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 +19 -12
- package/bin/scoutline.js +2 -3
- package/dist/capabilities/crawl.d.ts +93 -0
- package/dist/capabilities/crawl.d.ts.map +1 -0
- package/dist/capabilities/crawl.js +62 -0
- package/dist/capabilities/crawl.js.map +1 -0
- package/dist/capabilities/diagnostics.d.ts +45 -43
- package/dist/capabilities/diagnostics.d.ts.map +1 -1
- package/dist/capabilities/diagnostics.js +58 -71
- package/dist/capabilities/diagnostics.js.map +1 -1
- package/dist/capabilities/map.d.ts +81 -0
- package/dist/capabilities/map.d.ts.map +1 -0
- package/dist/capabilities/map.js +60 -0
- package/dist/capabilities/map.js.map +1 -0
- package/dist/capabilities/quota.d.ts +11 -0
- package/dist/capabilities/quota.d.ts.map +1 -1
- package/dist/capabilities/quota.js +1 -1
- package/dist/capabilities/quota.js.map +1 -1
- package/dist/capabilities/research.d.ts +98 -0
- package/dist/capabilities/research.d.ts.map +1 -0
- package/dist/capabilities/research.js +71 -0
- package/dist/capabilities/research.js.map +1 -0
- package/dist/capabilities/search.d.ts +19 -1
- package/dist/capabilities/search.d.ts.map +1 -1
- package/dist/commands/crawl.d.ts +46 -0
- package/dist/commands/crawl.d.ts.map +1 -0
- package/dist/commands/crawl.js +170 -0
- package/dist/commands/crawl.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -8
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +40 -34
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/map.d.ts +39 -0
- package/dist/commands/map.d.ts.map +1 -0
- package/dist/commands/map.js +121 -0
- package/dist/commands/map.js.map +1 -0
- package/dist/commands/quota.d.ts +23 -0
- package/dist/commands/quota.d.ts.map +1 -1
- package/dist/commands/quota.js +21 -4
- package/dist/commands/quota.js.map +1 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +7 -1
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/repo.js +1 -1
- package/dist/commands/research.d.ts +62 -0
- package/dist/commands/research.d.ts.map +1 -0
- package/dist/commands/research.js +314 -0
- package/dist/commands/research.js.map +1 -0
- package/dist/commands/search.d.ts +3 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +26 -10
- package/dist/commands/search.js.map +1 -1
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +291 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/cache.d.ts +13 -0
- package/dist/lib/cache.d.ts.map +1 -1
- package/dist/lib/cache.js +15 -0
- package/dist/lib/cache.js.map +1 -1
- package/dist/lib/execution.d.ts +105 -1
- package/dist/lib/execution.d.ts.map +1 -1
- package/dist/lib/execution.js +73 -1
- package/dist/lib/execution.js.map +1 -1
- package/dist/lib/redact.d.ts +2 -1
- package/dist/lib/redact.d.ts.map +1 -1
- package/dist/lib/redact.js +14 -1
- package/dist/lib/redact.js.map +1 -1
- package/dist/lib/research-state.d.ts +104 -0
- package/dist/lib/research-state.d.ts.map +1 -0
- package/dist/lib/research-state.js +214 -0
- package/dist/lib/research-state.js.map +1 -0
- package/dist/lib/search-topic.d.ts +21 -0
- package/dist/lib/search-topic.d.ts.map +1 -0
- package/dist/lib/search-topic.js +36 -0
- package/dist/lib/search-topic.js.map +1 -0
- package/dist/providers/brave/adapter.d.ts +42 -0
- package/dist/providers/brave/adapter.d.ts.map +1 -0
- package/dist/providers/brave/adapter.js +504 -0
- package/dist/providers/brave/adapter.js.map +1 -0
- package/dist/providers/brave/client.d.ts +161 -0
- package/dist/providers/brave/client.d.ts.map +1 -0
- package/dist/providers/brave/client.js +297 -0
- package/dist/providers/brave/client.js.map +1 -0
- package/dist/providers/brave/credentials.d.ts +33 -0
- package/dist/providers/brave/credentials.d.ts.map +1 -0
- package/dist/providers/brave/credentials.js +55 -0
- package/dist/providers/brave/credentials.js.map +1 -0
- package/dist/providers/brave/diagnostics.d.ts +46 -0
- package/dist/providers/brave/diagnostics.d.ts.map +1 -0
- package/dist/providers/brave/diagnostics.js +76 -0
- package/dist/providers/brave/diagnostics.js.map +1 -0
- package/dist/providers/brave/quota.d.ts +86 -0
- package/dist/providers/brave/quota.d.ts.map +1 -0
- package/dist/providers/brave/quota.js +247 -0
- package/dist/providers/brave/quota.js.map +1 -0
- package/dist/providers/exa/adapter.d.ts +58 -0
- package/dist/providers/exa/adapter.d.ts.map +1 -0
- package/dist/providers/exa/adapter.js +892 -0
- package/dist/providers/exa/adapter.js.map +1 -0
- package/dist/providers/exa/client.d.ts +143 -0
- package/dist/providers/exa/client.d.ts.map +1 -0
- package/dist/providers/exa/client.js +328 -0
- package/dist/providers/exa/client.js.map +1 -0
- package/dist/providers/exa/credentials.d.ts +34 -0
- package/dist/providers/exa/credentials.d.ts.map +1 -0
- package/dist/providers/exa/credentials.js +56 -0
- package/dist/providers/exa/credentials.js.map +1 -0
- package/dist/providers/exa/diagnostics.d.ts +42 -0
- package/dist/providers/exa/diagnostics.d.ts.map +1 -0
- package/dist/providers/exa/diagnostics.js +69 -0
- package/dist/providers/exa/diagnostics.js.map +1 -0
- package/dist/providers/minimax/adapter.d.ts.map +1 -1
- package/dist/providers/minimax/adapter.js +7 -2
- package/dist/providers/minimax/adapter.js.map +1 -1
- package/dist/providers/minimax/vision-conformance.d.ts +2 -2
- package/dist/providers/minimax/vision-conformance.js +2 -2
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +6 -0
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/tavily/adapter.d.ts +62 -0
- package/dist/providers/tavily/adapter.d.ts.map +1 -0
- package/dist/providers/tavily/adapter.js +975 -0
- package/dist/providers/tavily/adapter.js.map +1 -0
- package/dist/providers/tavily/client.d.ts +184 -0
- package/dist/providers/tavily/client.d.ts.map +1 -0
- package/dist/providers/tavily/client.js +486 -0
- package/dist/providers/tavily/client.js.map +1 -0
- package/dist/providers/tavily/credentials.d.ts +34 -0
- package/dist/providers/tavily/credentials.d.ts.map +1 -0
- package/dist/providers/tavily/credentials.js +56 -0
- package/dist/providers/tavily/credentials.js.map +1 -0
- package/dist/providers/tavily/diagnostics.d.ts +44 -0
- package/dist/providers/tavily/diagnostics.d.ts.map +1 -0
- package/dist/providers/tavily/diagnostics.js +70 -0
- package/dist/providers/tavily/diagnostics.js.map +1 -0
- package/dist/providers/tavily/quota.d.ts +60 -0
- package/dist/providers/tavily/quota.d.ts.map +1 -0
- package/dist/providers/tavily/quota.js +186 -0
- package/dist/providers/tavily/quota.js.map +1 -0
- package/dist/providers/types.d.ts +14 -2
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +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 +13 -2
- package/dist/providers/zai/adapter.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Research state file — resume mechanism for interrupted research
|
|
3
|
+
* (tech-plan §3, T07).
|
|
4
|
+
*
|
|
5
|
+
* Research costs 4-250 credits per request. A research task runs
|
|
6
|
+
* asynchronously server-side: POST /research creates it and returns a
|
|
7
|
+
* `request_id`, then GET /research/{id} polls until completion. If the
|
|
8
|
+
* CLI exits (Ctrl-C, crash) mid-poll, the task keeps running and
|
|
9
|
+
* consuming credits. Without a persistence mechanism, the next identical
|
|
10
|
+
* request would POST a SECOND task — a double charge.
|
|
11
|
+
*
|
|
12
|
+
* This module persists `{ requestId, identityHash, createdAt, status }`
|
|
13
|
+
* to `~/.scoutline/research/<state-hash>.json` so the next invocation of
|
|
14
|
+
* the same request detects the in-flight task and polls it instead of
|
|
15
|
+
* creating a new one. The state-hash is deterministic for a given
|
|
16
|
+
* `{provider, capability, credentialFingerprint, request}` tuple (see
|
|
17
|
+
* `computeResearchStateHash`).
|
|
18
|
+
*
|
|
19
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
20
|
+
* - May import cache-root resolution and normalized errors.
|
|
21
|
+
* - Must NOT import transport, command presentation, or a Provider
|
|
22
|
+
* Adapter.
|
|
23
|
+
*
|
|
24
|
+
* Resilience contract (tech-plan §3 / G1-G3):
|
|
25
|
+
* - `write()` uses `{ flag: "wx" }` for atomic creation. A concurrent
|
|
26
|
+
* invocation that finds the file already exists gets EEXIST and
|
|
27
|
+
* polls the existing task instead of creating a new one.
|
|
28
|
+
* - `read()` catches JSON parse errors, deletes the corrupt file, and
|
|
29
|
+
* returns `null` (treated as absent → new task created).
|
|
30
|
+
* - `remove()` deletes the file and ignores ENOENT (already gone).
|
|
31
|
+
*/
|
|
32
|
+
import crypto from "node:crypto";
|
|
33
|
+
import * as fs from "node:fs/promises";
|
|
34
|
+
import path from "node:path";
|
|
35
|
+
import { researchStateDir } from "./cache.js";
|
|
36
|
+
/**
|
|
37
|
+
* Recursively sort object keys so `JSON.stringify` produces a stable
|
|
38
|
+
* representation regardless of insertion order. Mirrors the cache module's
|
|
39
|
+
* `sortKeysDeep` so the same request hashes identically here and in the
|
|
40
|
+
* response-cache key.
|
|
41
|
+
*/
|
|
42
|
+
function sortKeysDeep(value) {
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
return value.map((element) => sortKeysDeep(element));
|
|
45
|
+
}
|
|
46
|
+
if (value && typeof value === "object") {
|
|
47
|
+
const input = value;
|
|
48
|
+
const out = {};
|
|
49
|
+
for (const key of Object.keys(input).sort()) {
|
|
50
|
+
out[key] = sortKeysDeep(input[key]);
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Compute the deterministic state-file identity hash for a research
|
|
58
|
+
* request (tech-plan §3 / CR3).
|
|
59
|
+
*
|
|
60
|
+
* state-hash = SHA-256(recursively-key-sorted-JSON({
|
|
61
|
+
* provider, capability, credentialFingerprint, request
|
|
62
|
+
* }))
|
|
63
|
+
*
|
|
64
|
+
* Same canonical approach as `buildProviderCacheKey`'s request hashing,
|
|
65
|
+
* extended to include provider + capability + credential. Rotating the
|
|
66
|
+
* API key orphans old state files (correct — the old task belongs to the
|
|
67
|
+
* old key's billing). The hash never contains a raw credential.
|
|
68
|
+
*/
|
|
69
|
+
export function computeResearchStateHash(input) {
|
|
70
|
+
const payload = {
|
|
71
|
+
provider: input.provider,
|
|
72
|
+
capability: input.capability,
|
|
73
|
+
credentialFingerprint: input.credentialFingerprint,
|
|
74
|
+
request: sortKeysDeep(input.request),
|
|
75
|
+
};
|
|
76
|
+
return crypto.createHash("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Production state-file implementation
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Build a production {@link ResearchStateFile} backed by files under
|
|
83
|
+
* `~/.scoutline/research/` (via {@link researchStateDir}). One JSON file
|
|
84
|
+
* per in-flight task, named `<state-hash>.json`.
|
|
85
|
+
*
|
|
86
|
+
* - `write()` atomically creates the file with `{ flag: "wx" }`. A
|
|
87
|
+
* concurrent invocation that finds it exists throws EEXIST; the caller
|
|
88
|
+
* catches that and polls the existing task.
|
|
89
|
+
* - `read()` catches JSON parse errors, deletes the corrupt file, and
|
|
90
|
+
* returns `null`.
|
|
91
|
+
* - `remove()` deletes the file and ignores ENOENT.
|
|
92
|
+
*/
|
|
93
|
+
export function createProductionResearchStateFile() {
|
|
94
|
+
function filePath(identityHash) {
|
|
95
|
+
return path.join(researchStateDir(), `${identityHash}.json`);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
async read(identityHash) {
|
|
99
|
+
if (!identityHash)
|
|
100
|
+
return null;
|
|
101
|
+
const file = filePath(identityHash);
|
|
102
|
+
let raw;
|
|
103
|
+
try {
|
|
104
|
+
raw = await fs.readFile(file, "utf8");
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const parsed = JSON.parse(raw);
|
|
111
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
112
|
+
await fs.unlink(file).catch(() => { });
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const obj = parsed;
|
|
116
|
+
const requestId = obj.requestId;
|
|
117
|
+
const storedHash = obj.identityHash;
|
|
118
|
+
const createdAt = obj.createdAt;
|
|
119
|
+
const status = obj.status;
|
|
120
|
+
if (typeof requestId !== "string" ||
|
|
121
|
+
requestId.length === 0 ||
|
|
122
|
+
typeof storedHash !== "string" ||
|
|
123
|
+
typeof createdAt !== "string" ||
|
|
124
|
+
(status !== "pending" && status !== "in_progress")) {
|
|
125
|
+
await fs.unlink(file).catch(() => { });
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return { requestId, identityHash: storedHash, createdAt, status };
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Corrupt JSON — delete the file so the next run creates a fresh
|
|
132
|
+
// task instead of forever reading garbage.
|
|
133
|
+
await fs.unlink(file).catch(() => { });
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
async write(identityHash, state) {
|
|
138
|
+
const dir = researchStateDir();
|
|
139
|
+
await fs.mkdir(dir, { recursive: true });
|
|
140
|
+
const file = filePath(identityHash);
|
|
141
|
+
const payload = JSON.stringify(state);
|
|
142
|
+
// `{ flag: "wx" }` atomically creates the file only if it does not
|
|
143
|
+
// exist. A concurrent invocation that lost the race gets EEXIST;
|
|
144
|
+
// the caller catches it and polls the existing task instead of
|
|
145
|
+
// creating a second one.
|
|
146
|
+
await fs.writeFile(file, payload, { flag: "wx" });
|
|
147
|
+
},
|
|
148
|
+
async remove(identityHash) {
|
|
149
|
+
const file = filePath(identityHash);
|
|
150
|
+
await fs.unlink(file).catch((err) => {
|
|
151
|
+
// ENOENT is expected (already removed, or never written). Swallow
|
|
152
|
+
// it; any other error re-throws.
|
|
153
|
+
if (err && err.code === "ENOENT")
|
|
154
|
+
return;
|
|
155
|
+
throw err;
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Convenience helper exported for the Adapter and tests: builds an
|
|
162
|
+
* in-memory {@link ResearchStateFile} that throws EEXIST on a second
|
|
163
|
+
* write to the same hash, mirroring the production `{ flag: "wx" }`
|
|
164
|
+
* contract exactly. The adapter's lifecycle must not depend on whether
|
|
165
|
+
* the state file is disk-backed or memory-backed.
|
|
166
|
+
*/
|
|
167
|
+
export function createInMemoryResearchStateFile() {
|
|
168
|
+
const store = new Map();
|
|
169
|
+
return {
|
|
170
|
+
store,
|
|
171
|
+
async read(identityHash) {
|
|
172
|
+
const raw = store.get(identityHash);
|
|
173
|
+
if (raw === undefined)
|
|
174
|
+
return null;
|
|
175
|
+
try {
|
|
176
|
+
const parsed = JSON.parse(raw);
|
|
177
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
178
|
+
store.delete(identityHash);
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const obj = parsed;
|
|
182
|
+
const requestId = obj.requestId;
|
|
183
|
+
const storedHash = obj.identityHash;
|
|
184
|
+
const createdAt = obj.createdAt;
|
|
185
|
+
const status = obj.status;
|
|
186
|
+
if (typeof requestId !== "string" ||
|
|
187
|
+
requestId.length === 0 ||
|
|
188
|
+
typeof storedHash !== "string" ||
|
|
189
|
+
typeof createdAt !== "string" ||
|
|
190
|
+
(status !== "pending" && status !== "in_progress")) {
|
|
191
|
+
store.delete(identityHash);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
return { requestId, identityHash: storedHash, createdAt, status };
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
store.delete(identityHash);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
async write(identityHash, state) {
|
|
202
|
+
if (store.has(identityHash)) {
|
|
203
|
+
const err = new Error(`EEXIST: file already exists, write '${identityHash}.json'`);
|
|
204
|
+
err.code = "EEXIST";
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
store.set(identityHash, JSON.stringify(state));
|
|
208
|
+
},
|
|
209
|
+
async remove(identityHash) {
|
|
210
|
+
store.delete(identityHash);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=research-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"research-state.js","sourceRoot":"","sources":["../../src/lib/research-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search topic keyword appendage (DESIGN.md §7 — T03).
|
|
3
|
+
*
|
|
4
|
+
* Providers that lack a native topic parameter (Z.AI, MiniMax) express
|
|
5
|
+
* a non-`general` topic by appending a keyword to the query string.
|
|
6
|
+
* This is adapter-owned field mapping performed inside each Adapter's
|
|
7
|
+
* `invoke()`, never at the command layer. The Tavily adapter passes the
|
|
8
|
+
* topic natively (T04) and does not use this helper.
|
|
9
|
+
*
|
|
10
|
+
* Guard: when the query already ends with the topic word
|
|
11
|
+
* (case-insensitive) the appendage is skipped, so `"rust news"` with
|
|
12
|
+
* `--topic news` stays `"rust news"` rather than `"rust news latest news"`.
|
|
13
|
+
*/
|
|
14
|
+
import type { SearchTopic } from "../capabilities/search.js";
|
|
15
|
+
/**
|
|
16
|
+
* Append the topic keyword to `query` unless the topic is `general`,
|
|
17
|
+
* absent, or the query already ends with the topic word. Returns the
|
|
18
|
+
* query unchanged in all skip cases.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applySearchTopic(query: string, topic: SearchTopic | undefined): string;
|
|
21
|
+
//# sourceMappingURL=search-topic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-topic.d.ts","sourceRoot":"","sources":["../../src/lib/search-topic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAO7D;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAQtF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search topic keyword appendage (DESIGN.md §7 — T03).
|
|
3
|
+
*
|
|
4
|
+
* Providers that lack a native topic parameter (Z.AI, MiniMax) express
|
|
5
|
+
* a non-`general` topic by appending a keyword to the query string.
|
|
6
|
+
* This is adapter-owned field mapping performed inside each Adapter's
|
|
7
|
+
* `invoke()`, never at the command layer. The Tavily adapter passes the
|
|
8
|
+
* topic natively (T04) and does not use this helper.
|
|
9
|
+
*
|
|
10
|
+
* Guard: when the query already ends with the topic word
|
|
11
|
+
* (case-insensitive) the appendage is skipped, so `"rust news"` with
|
|
12
|
+
* `--topic news` stays `"rust news"` rather than `"rust news latest news"`.
|
|
13
|
+
*/
|
|
14
|
+
const TOPIC_APPENDAGES = {
|
|
15
|
+
news: " latest news",
|
|
16
|
+
finance: " financial",
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Append the topic keyword to `query` unless the topic is `general`,
|
|
20
|
+
* absent, or the query already ends with the topic word. Returns the
|
|
21
|
+
* query unchanged in all skip cases.
|
|
22
|
+
*/
|
|
23
|
+
export function applySearchTopic(query, topic) {
|
|
24
|
+
if (!topic || topic === "general")
|
|
25
|
+
return query;
|
|
26
|
+
const appendage = TOPIC_APPENDAGES[topic];
|
|
27
|
+
if (appendage === undefined)
|
|
28
|
+
return query;
|
|
29
|
+
const trimmed = query.trimEnd();
|
|
30
|
+
if (trimmed.length === 0)
|
|
31
|
+
return query;
|
|
32
|
+
if (trimmed.toLowerCase().endsWith(topic))
|
|
33
|
+
return query;
|
|
34
|
+
return trimmed + appendage;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=search-topic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-topic.js","sourceRoot":"","sources":["../../src/lib/search-topic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,gBAAgB,GAA8D;IAClF,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,YAAY;CACtB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,KAA8B;IAC5E,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IAChC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,OAAO,GAAG,SAAS,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brave Provider Adapter (brave-tech-plan §2, §5, §6).
|
|
3
|
+
*
|
|
4
|
+
* T2 wires the Search Capability (web + news). The descriptor
|
|
5
|
+
* advertises `"search"` and `create()` returns an Adapter whose
|
|
6
|
+
* `search` Capability owns credentials, transport, Provider field
|
|
7
|
+
* mapping, and failure normalization. Credentials, the direct-HTTP GET
|
|
8
|
+
* transport, and the header-bearing fetch seam come from T1; later
|
|
9
|
+
* tickets widen the capability set (reader, etc.). T5 wires the
|
|
10
|
+
* Diagnostics Capability (one-query doctor probe); T6 wires the Quota
|
|
11
|
+
* Capability (1-query rate-limit-header probe with a spend caveat).
|
|
12
|
+
*
|
|
13
|
+
* Boundary rules (ARCHITECTURE.md §2):
|
|
14
|
+
* - May import capability types, normalized errors, Provider identity
|
|
15
|
+
* types, and the Adapter-local credential and transport Modules.
|
|
16
|
+
* - Must NOT import command presentation, output mode, or another
|
|
17
|
+
* Provider's Adapter.
|
|
18
|
+
*/
|
|
19
|
+
import type { ProviderDescriptor } from "../types.js";
|
|
20
|
+
import { type BraveTransportDeps } from "./client.js";
|
|
21
|
+
/**
|
|
22
|
+
* Dependencies the Brave Adapter accepts. The unified `transport`
|
|
23
|
+
* seam carries `fetch` and timer injection; the Search Capability
|
|
24
|
+
* threads it through to the direct-HTTP transport.
|
|
25
|
+
*/
|
|
26
|
+
export interface BraveAdapterDependencies {
|
|
27
|
+
/** Optional transport injection (fetch, timers, env). */
|
|
28
|
+
readonly transport?: BraveTransportDeps;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build the Brave Provider Descriptor. The descriptor advertises the
|
|
32
|
+
* Search (T2), Diagnostics (T5), and Quota (T6) capabilities and
|
|
33
|
+
* constructs an Adapter whose `search`/`diagnostics`/`quota`
|
|
34
|
+
* Capabilities own credentials, transport, Provider field mapping, and
|
|
35
|
+
* failure normalization. Construction is side-effect-free; the
|
|
36
|
+
* transport is invoked per Capability call. Tests pass `transport`
|
|
37
|
+
* (typically a fake-fetch wrapper); production uses the no-argument
|
|
38
|
+
* factory which resolves to the global `fetch` and timers inside the
|
|
39
|
+
* transport Module.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createBraveDescriptor(dependencies?: BraveAdapterDependencies): ProviderDescriptor;
|
|
42
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/brave/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAIV,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAqBrB,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAIrB;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAweD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,CAAC,EAAE,wBAAwB,GAAG,kBAAkB,CAqBjG"}
|