@onedotmint/siftpath 0.0.0-stage → 2.0.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/LICENSE +21 -0
- package/README.md +165 -2
- package/THIRD_PARTY_NOTICES.md +26 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +116 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +144 -0
- package/dist/client.js +130 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +107 -0
- package/dist/config.js +127 -0
- package/dist/config.js.map +1 -0
- package/dist/defaults.d.ts +38 -0
- package/dist/defaults.js +31 -0
- package/dist/defaults.js.map +1 -0
- package/dist/diagnostics.d.ts +158 -0
- package/dist/diagnostics.js +202 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +16 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs.d.ts +25 -0
- package/dist/inputs.js +27 -0
- package/dist/inputs.js.map +1 -0
- package/dist/mcp/stdio.d.ts +2 -0
- package/dist/mcp/stdio.js +43 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/output.d.ts +23 -0
- package/dist/output.js +118 -0
- package/dist/output.js.map +1 -0
- package/dist/router.d.ts +20 -0
- package/dist/router.js +85 -0
- package/dist/router.js.map +1 -0
- package/dist/setup-ui.d.ts +8 -0
- package/dist/setup-ui.js +3032 -0
- package/dist/setup-ui.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +50 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools.d.ts +35 -0
- package/dist/tools.js +17 -0
- package/dist/tools.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/docs/ARCHITECTURE.md +33 -0
- package/docs/CONFIGURATION.md +127 -0
- package/docs/DIAGNOSTICS.md +109 -0
- package/docs/MIGRATION.md +13 -0
- package/docs/PROVIDERS.md +43 -0
- package/docs/SECURITY.md +15 -0
- package/docs/TESTING.md +138 -0
- package/examples/anonymous.json +36 -0
- package/extensions/siftpath.mjs +32 -0
- package/package.json +60 -4
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { lstat, readFile } from 'node:fs/promises';
|
|
3
|
+
import { basename, dirname, join } from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { AjvJsonSchemaValidator } from '@modelcontextprotocol/sdk/validation/ajv';
|
|
7
|
+
import { StreamableHTTPError } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
8
|
+
import { McpClients } from './client.js';
|
|
9
|
+
import { configPath, diagnostics, providerStatus, resolveSecret, writePrivateJson } from './config.js';
|
|
10
|
+
import { SiftpathError } from './errors.js';
|
|
11
|
+
import { normalize } from './output.js';
|
|
12
|
+
import { mapArguments } from './router.js';
|
|
13
|
+
import { packageVersion } from './version.js';
|
|
14
|
+
const reasons = {
|
|
15
|
+
NOT_CONFIGURED: 'Provider is not configured.', DISABLED: 'Provider is disabled.', MISSING_CREDENTIALS: 'Required credential references are missing.',
|
|
16
|
+
CONNECTION_FAILED: 'Cannot connect. Check the MCP command/URL, credentials and connectivity.',
|
|
17
|
+
AUTH_FAILED: 'Authentication rejected. Check credentials and account access.', RATE_LIMITED: 'Rate or quota limit reached.',
|
|
18
|
+
DISCOVERY_FAILED: 'Cannot list official MCP tools.', TOOL_NOT_FOUND: 'A configured tool was not found in tools/list.',
|
|
19
|
+
INVALID_UPSTREAM_ARGUMENTS: 'Official MCP rejected the mapped test arguments; check its current schema.',
|
|
20
|
+
UPSTREAM_ERROR: 'Official MCP tool failed. Check account permissions/quota and tool configuration.',
|
|
21
|
+
INVALID_UPSTREAM_RESPONSE: 'Official MCP result violates its declared output schema.', TASK_REQUIRED: 'Configured tool requires task execution, not a synchronous search/read call.',
|
|
22
|
+
OUTPUT_LIMIT: 'Source metadata exceeded maxOutputChars.', EMPTY_RESPONSE: 'Official MCP returned no readable text.', NO_SOURCES: 'Official MCP returned no traceable public source.',
|
|
23
|
+
UNSUPPORTED_OPERATION: 'No search or read binding is configured.', PROVIDER_TIMEOUT: 'Provider test deadline exceeded.', ABORTED: 'Test cancelled.',
|
|
24
|
+
};
|
|
25
|
+
const codeSchema = z.enum(Object.keys(reasons));
|
|
26
|
+
const stage = z.enum(['not_tested', 'passed', 'failed']);
|
|
27
|
+
const testSchema = z.strictObject({
|
|
28
|
+
provider: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/), testedAt: z.iso.datetime(), durationMs: z.number().nonnegative(),
|
|
29
|
+
outcome: z.enum(['passed', 'failed', 'skipped']), code: codeSchema.optional(),
|
|
30
|
+
stages: z.strictObject({ connection: stage, discovery: stage, request: stage }),
|
|
31
|
+
operations: z.array(z.strictObject({ operation: z.enum(['search', 'read']), state: stage, durationMs: z.number().nonnegative(), code: codeSchema.optional() })).max(2),
|
|
32
|
+
});
|
|
33
|
+
const historySchema = z.strictObject({ version: z.literal(1), tests: z.record(z.string(), z.strictObject({ fingerprint: z.string().regex(/^[a-f0-9]{64}$/), result: testSchema })) });
|
|
34
|
+
const maxHistoryBytes = 1048576;
|
|
35
|
+
export function testHistoryPath(path = configPath()) { return join(dirname(path), '.' + basename(path) + '.siftpath-tests.json'); }
|
|
36
|
+
function fingerprint(id, config, env) {
|
|
37
|
+
const provider = Object.hasOwn(config.providers, id) ? config.providers[id] : undefined;
|
|
38
|
+
return createHash('sha256').update(packageVersion).update(JSON.stringify(provider ?? null))
|
|
39
|
+
.update(JSON.stringify({ timeoutMs: Math.min(config.timeoutMs, provider?.timeoutMs ?? config.providerTimeoutMs), maxOutputChars: config.maxOutputChars })).update(provider ? resolveSecret(JSON.stringify(provider.connection), config, env) : '').digest('hex');
|
|
40
|
+
}
|
|
41
|
+
async function readHistory(path) {
|
|
42
|
+
try {
|
|
43
|
+
const stat = await lstat(path);
|
|
44
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > maxHistoryBytes)
|
|
45
|
+
throw new Error();
|
|
46
|
+
return { data: historySchema.parse(JSON.parse(await readFile(path, 'utf8'))) };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return { data: { version: 1, tests: {} }, ...(error.code === 'ENOENT' ? {} : { warning: 'TEST_HISTORY_UNREADABLE' }) };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function errorCode(error) {
|
|
53
|
+
if (error instanceof StreamableHTTPError && [401, 403].includes(error.code ?? 0))
|
|
54
|
+
return 'AUTH_FAILED';
|
|
55
|
+
if (error instanceof StreamableHTTPError && error.code === 429)
|
|
56
|
+
return 'RATE_LIMITED';
|
|
57
|
+
if (error instanceof McpError && error.code === -32602)
|
|
58
|
+
return 'INVALID_UPSTREAM_ARGUMENTS';
|
|
59
|
+
if (error instanceof SiftpathError && Object.hasOwn(reasons, error.code))
|
|
60
|
+
return error.code;
|
|
61
|
+
return 'UPSTREAM_ERROR';
|
|
62
|
+
}
|
|
63
|
+
/** A strict provider contract probe, not an equivalent execution of Router selection, fallback or focus. */
|
|
64
|
+
export async function providerTest(id, config, env = process.env, caller) {
|
|
65
|
+
const start = performance.now(), status = providerStatus(id, config, env), provider = config.providers[id];
|
|
66
|
+
const result = { provider: id, testedAt: new Date().toISOString(), durationMs: 0, outcome: 'skipped',
|
|
67
|
+
stages: { connection: 'not_tested', discovery: 'not_tested', request: 'not_tested' }, operations: [] };
|
|
68
|
+
if (status.code !== 'READY') {
|
|
69
|
+
result.code = status.code;
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
const operations = ['search', 'read'].filter(kind => !!provider?.[kind]);
|
|
73
|
+
if (!operations.length) {
|
|
74
|
+
result.code = 'UNSUPPORTED_OPERATION';
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
result.operations = operations.map(operation => ({ operation, state: 'not_tested', durationMs: 0 }));
|
|
78
|
+
const clients = new McpClients(config, env), timeout = AbortSignal.timeout(Math.min(config.timeoutMs, provider.timeoutMs ?? config.providerTimeoutMs));
|
|
79
|
+
const signal = AbortSignal.any([timeout, ...(caller ? [caller] : [])]);
|
|
80
|
+
let current = 'connection';
|
|
81
|
+
try {
|
|
82
|
+
await clients.connect(id, signal);
|
|
83
|
+
result.stages.connection = 'passed';
|
|
84
|
+
current = 'discovery';
|
|
85
|
+
const tools = new Map(), validator = new AjvJsonSchemaValidator(), cursors = new Set();
|
|
86
|
+
let cursor;
|
|
87
|
+
do {
|
|
88
|
+
const page = await clients.listTools(id, signal, cursor);
|
|
89
|
+
for (const tool of page.tools)
|
|
90
|
+
tools.set(tool.name, tool);
|
|
91
|
+
cursor = page.nextCursor;
|
|
92
|
+
if (cursor && cursors.has(cursor))
|
|
93
|
+
throw new SiftpathError('DISCOVERY_FAILED', reasons.DISCOVERY_FAILED);
|
|
94
|
+
if (cursor)
|
|
95
|
+
cursors.add(cursor);
|
|
96
|
+
} while (cursor);
|
|
97
|
+
if (operations.some(kind => !tools.has(provider[kind].name)))
|
|
98
|
+
throw new SiftpathError('TOOL_NOT_FOUND', reasons.TOOL_NOT_FOUND);
|
|
99
|
+
result.stages.discovery = 'passed';
|
|
100
|
+
current = 'request';
|
|
101
|
+
for (const operation of result.operations) {
|
|
102
|
+
const at = performance.now();
|
|
103
|
+
try {
|
|
104
|
+
const binding = provider[operation.operation];
|
|
105
|
+
// At most one small request per configured capability; no focus/rerank/agent calls or fallback.
|
|
106
|
+
const input = operation.operation === 'search' ? { query: 'example.com', intent: 'general', maxResults: 5 } : { url: 'https://example.com' };
|
|
107
|
+
const tool = tools.get(binding.name);
|
|
108
|
+
if (tool.execution?.taskSupport === 'required')
|
|
109
|
+
throw new SiftpathError('TASK_REQUIRED', reasons.TASK_REQUIRED);
|
|
110
|
+
const raw = await clients.call(id, binding.name, mapArguments(binding.arguments, input), signal);
|
|
111
|
+
if (!raw.isError && tool.outputSchema && (!raw.structuredContent || !validator.getValidator(tool.outputSchema)(raw.structuredContent).valid))
|
|
112
|
+
throw new SiftpathError('INVALID_UPSTREAM_RESPONSE', reasons.INVALID_UPSTREAM_RESPONSE);
|
|
113
|
+
normalize(raw, id, binding.name, config.maxOutputChars, operation.operation === 'read' ? 'https://example.com' : undefined);
|
|
114
|
+
operation.state = 'passed';
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
operation.state = 'failed';
|
|
118
|
+
operation.code = errorCode(error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
operation.durationMs = Math.round(performance.now() - at);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
result.stages.request = 'passed';
|
|
126
|
+
result.outcome = 'passed';
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
result.outcome = 'failed';
|
|
130
|
+
result.stages[current] = 'failed';
|
|
131
|
+
result.code = caller?.aborted ? 'ABORTED' : timeout.aborted ? 'PROVIDER_TIMEOUT' : current === 'discovery' && errorCode(error) === 'UPSTREAM_ERROR' ? 'DISCOVERY_FAILED' : errorCode(error);
|
|
132
|
+
const failed = result.operations.find(operation => operation.state === 'failed');
|
|
133
|
+
if (failed)
|
|
134
|
+
failed.code = result.code;
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
await clients.close();
|
|
138
|
+
result.durationMs = Math.round(performance.now() - start);
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
export async function statusReport(config, path = configPath(), env = process.env) {
|
|
143
|
+
const history = await readHistory(testHistoryPath(path));
|
|
144
|
+
const local = diagnostics(config, env);
|
|
145
|
+
return { version: packageVersion, ok: true, ...local, warnings: history.warning ? [history.warning] : [],
|
|
146
|
+
providers: local.providers.map(provider => {
|
|
147
|
+
const saved = Object.hasOwn(history.data.tests, provider.provider) ? history.data.tests[provider.provider] : undefined;
|
|
148
|
+
return { ...provider, configured: Object.hasOwn(config.providers, provider.provider), lastTest: saved?.result ?? null,
|
|
149
|
+
lastTestStale: saved ? saved.fingerprint !== fingerprint(provider.provider, config, env) : false };
|
|
150
|
+
}) };
|
|
151
|
+
}
|
|
152
|
+
export async function testReport(config, target, path = configPath(), env = process.env, signal) {
|
|
153
|
+
if (target !== 'all' && !/^[a-z][a-z0-9_-]{0,63}$/.test(target))
|
|
154
|
+
throw new SiftpathError('INVALID_INPUT', 'Use siftpath test <provider|all>.');
|
|
155
|
+
const results = [], warnings = new Set();
|
|
156
|
+
for (const id of target === 'all' ? Object.keys(config.providers) : [target]) {
|
|
157
|
+
if (signal?.aborted)
|
|
158
|
+
break;
|
|
159
|
+
const result = await providerTest(id, config, env, signal);
|
|
160
|
+
results.push(result);
|
|
161
|
+
const history = await readHistory(testHistoryPath(path));
|
|
162
|
+
if (history.warning) {
|
|
163
|
+
warnings.add(history.warning);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
// shortcut: concurrent CLI writers are last-writer-wins; add locking only if concurrent diagnostics become a real workflow.
|
|
167
|
+
history.data.tests[id] = { fingerprint: fingerprint(id, config, env), result };
|
|
168
|
+
const oldest = Object.keys(history.data.tests).filter(key => key !== id).sort((a, b) => history.data.tests[a].result.testedAt.localeCompare(history.data.tests[b].result.testedAt));
|
|
169
|
+
for (const key of oldest) {
|
|
170
|
+
if (Buffer.byteLength(JSON.stringify(history.data, null, 2) + '\n') <= maxHistoryBytes)
|
|
171
|
+
break;
|
|
172
|
+
delete history.data.tests[key];
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
await writePrivateJson(testHistoryPath(path), history.data);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
warnings.add('TEST_HISTORY_WRITE_FAILED');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { version: packageVersion, ok: results.length > 0 && results.every(result => result.outcome === 'passed') && !signal?.aborted,
|
|
182
|
+
networkChecked: results.some(result => result.stages.connection !== 'not_tested'),
|
|
183
|
+
results: results.map(result => ({ ...result, configuration: providerStatus(result.provider, config, env).code })), warnings: [...warnings] };
|
|
184
|
+
}
|
|
185
|
+
export function formatStatus(report) {
|
|
186
|
+
const route = report.routes;
|
|
187
|
+
return [`Siftpath ${report.version} — status (offline)`, ...report.providers.map(provider => {
|
|
188
|
+
const recent = provider.lastTest;
|
|
189
|
+
return `${provider.provider}: ${provider.code}${provider.needs?.length ? ' (' + provider.needs.join(', ') + ')' : ''} | ${provider.operations.join('/') || 'no tools'} | ` +
|
|
190
|
+
(recent ? `${provider.lastTestStale ? 'CONFIG_CHANGED; ' : ''}last test ${recent.outcome} ${recent.testedAt} ${recent.durationMs}ms${recent.code ? ' — ' + recent.code : ''}` : 'NOT_TESTED');
|
|
191
|
+
}), `Search: default=${route.search}; intent=${route.defaultIntent}; ${Object.entries(route.intents).map(([intent, id]) => intent + '=' + id).join(', ')}; fallback=${route.searchFallback.join(' → ') || 'none'}`,
|
|
192
|
+
`Read: ${route.read}; fallback=${route.readFallback.join(' → ') || 'none'}`, ...report.warnings,
|
|
193
|
+
'READY means configuration/credentials only, not verified availability. Test explicitly: /siftpath test <provider|all> (may use API quota).'].join('\n');
|
|
194
|
+
}
|
|
195
|
+
export function formatTests(report) {
|
|
196
|
+
return [`Siftpath ${report.version} — provider tests (no fallback)`, ...report.results.flatMap(result => [
|
|
197
|
+
`${result.provider}: ${result.outcome.toUpperCase()} ${result.durationMs}ms — config=${result.configuration}, connect=${result.stages.connection}, tools=${result.stages.discovery}, request=${result.stages.request}`,
|
|
198
|
+
...result.operations.map(operation => ` ${operation.operation}: ${operation.state} ${operation.durationMs}ms`),
|
|
199
|
+
...(result.code ? [` ${result.code}: ${reasons[result.code]}`] : []),
|
|
200
|
+
]), ...report.warnings, ...(report.results.length ? [] : ['No providers tested.']), 'Results record this test only; no fallback or retries.'].join('\n');
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAa,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oDAAoD,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAsB,MAAM,aAAa,CAAC;AAC3H,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,OAAO,GAAG;IACd,cAAc,EAAE,6BAA6B,EAAE,QAAQ,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,6CAA6C;IACpJ,iBAAiB,EAAE,0EAA0E;IAC7F,WAAW,EAAE,gEAAgE,EAAE,YAAY,EAAE,8BAA8B;IAC3H,gBAAgB,EAAE,iCAAiC,EAAE,cAAc,EAAE,gDAAgD;IACrH,0BAA0B,EAAE,4EAA4E;IACxG,cAAc,EAAE,mFAAmF;IACnG,yBAAyB,EAAE,0DAA0D,EAAE,aAAa,EAAE,8EAA8E;IACpL,YAAY,EAAE,0CAA0C,EAAE,cAAc,EAAE,yCAAyC,EAAE,UAAU,EAAE,mDAAmD;IACpL,qBAAqB,EAAE,0CAA0C,EAAE,gBAAgB,EAAE,kCAAkC,EAAE,OAAO,EAAE,iBAAiB;CAC3I,CAAC;AACX,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAwD,CAAC,CAAC;AACvG,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AACzD,MAAM,UAAU,GAAG,CAAC,CAAC,YAAY,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,yBAAyB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;IACvH,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE;IAC7E,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC/E,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CACvK,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,CAAC,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAEtL,MAAM,eAAe,GAAG,OAAO,CAAC;AAChC,MAAM,UAAU,eAAe,CAAC,IAAI,GAAG,UAAU,EAAE,IAAY,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;AAC3I,SAAS,WAAW,CAAC,EAAU,EAAE,MAAqB,EAAE,GAAsB;IAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;SACxF,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,MAAM,CAAC,iBAAiB,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrQ,CAAC;AACD,KAAK,UAAU,WAAW,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,IAAI,CAAC,IAAI,GAAG,eAAe;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QAC9F,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,GAAG,CAAE,KAA+B,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,EAAE,CAAC;IACpJ,CAAC;AACH,CAAC;AACD,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,KAAK,YAAY,mBAAmB,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QAAE,OAAO,aAAa,CAAC;IACvG,IAAI,KAAK,YAAY,mBAAmB,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG;QAAE,OAAO,cAAc,CAAC;IACtF,IAAI,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK;QAAE,OAAO,4BAA4B,CAAC;IAC5F,IAAI,KAAK,YAAY,aAAa,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,IAA4B,CAAC;IACpH,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AACD,4GAA4G;AAC5G,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,MAAqB,EAAE,MAAyB,OAAO,CAAC,GAAG,EAAE,MAAoB;IAC9H,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC3G,MAAM,MAAM,GAAiB,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS;QAChH,MAAM,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IACzG,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAAC,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAA4B,CAAC;QAAC,OAAO,MAAM,CAAC;IAAC,CAAC;IAClG,MAAM,UAAU,GAAI,CAAC,QAAQ,EAAE,MAAM,CAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACpF,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QAAC,MAAM,CAAC,IAAI,GAAG,uBAAuB,CAAC;QAAC,OAAO,MAAM,CAAC;IAAC,CAAC;IACjF,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrG,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,QAAS,CAAC,SAAS,IAAI,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACxJ,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvE,IAAI,OAAO,GAAiC,YAAY,CAAC;IACzD,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAAC,MAAM,CAAC,MAAM,CAAC,UAAU,GAAG,QAAQ,CAAC;QACvE,OAAO,GAAG,WAAW,CAAC;QACtB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgB,EAAE,SAAS,GAAG,IAAI,sBAAsB,EAAE,EAAE,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAAC,IAAI,MAA0B,CAAC;QAC7I,GAAG,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YACzD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;gBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC1D,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;YACzB,IAAI,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,MAAM,IAAI,aAAa,CAAC,kBAAkB,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;YACzG,IAAI,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC,QAAQ,MAAM,EAAE;QACjB,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,QAAS,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,aAAa,CAAC,gBAAgB,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QAClI,MAAM,CAAC,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC;QAAC,OAAO,GAAG,SAAS,CAAC;QACxD,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,QAAS,CAAC,SAAS,CAAC,SAAS,CAAE,CAAC;gBAChD,gGAAgG;gBAChG,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,qBAAqB,EAAE,CAAC;gBAC7I,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAE,CAAC;gBACtC,IAAI,IAAI,CAAC,SAAS,EAAE,WAAW,KAAK,UAAU;oBAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;gBAChH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;gBACjG,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC;oBAC1I,MAAM,IAAI,aAAa,CAAC,2BAA2B,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;gBAC1F,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,cAAc,EAAE,SAAS,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;gBAC5H,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC;YAC7B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAAC,SAAS,CAAC,KAAK,GAAG,QAAQ,CAAC;gBAAC,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;gBAAC,MAAM,KAAK,CAAC;YAAC,CAAC;oBACvF,CAAC;gBAAC,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAAC,CAAC;QACxE,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;QAAC,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;IAC9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;QAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC;QAC7D,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,KAAK,WAAW,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5L,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC;QAAC,IAAI,MAAM;YAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC1H,CAAC;YAAS,CAAC;QAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;IAAC,CAAC;IAC/F,OAAO,MAAM,CAAC;AAChB,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAqB,EAAE,IAAI,GAAG,UAAU,EAAE,EAAE,MAAyB,OAAO,CAAC,GAAG;IACjH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;QACtG,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YACxC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvH,OAAO,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,IAAI,IAAI;gBACnH,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,KAAK,WAAW,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QACvG,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAqB,EAAE,MAAc,EAAE,IAAI,GAAG,UAAU,EAAE,EAAE,MAAyB,OAAO,CAAC,GAAG,EAAE,MAAoB;IACrJ,IAAI,MAAM,KAAK,KAAK,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,mCAAmC,CAAC,CAAC;IAC/I,MAAM,OAAO,GAAmB,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACjE,KAAK,MAAM,EAAE,IAAI,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7E,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM;QAC3B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QACjE,4HAA4H;QAC5H,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;QAC/E,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtL,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,eAAe;gBAAE,MAAM;YAC9F,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,CAAC;YAAC,MAAM,gBAAgB,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,QAAQ,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QAAC,CAAC;IAC3H,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO;QAClI,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,KAAK,YAAY,CAAC;QACjF,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,cAAc,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AACjJ,CAAC;AACD,MAAM,UAAU,YAAY,CAAC,MAAgD;IAC3E,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5B,OAAO,CAAC,YAAY,MAAM,CAAC,OAAO,qBAAqB,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAC1F,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC;YACjC,OAAO,GAAG,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,KAAK;gBACxK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,aAAa,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAClM,CAAC,CAAC,EAAE,mBAAmB,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,aAAa,KAAK,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,EAAE;QAClN,SAAS,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,EAAE,EAAE,GAAG,MAAM,CAAC,QAAQ;QAC/F,4IAA4I,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3J,CAAC;AACD,MAAM,UAAU,WAAW,CAAC,MAA8C;IACxE,OAAO,CAAC,YAAY,MAAM,CAAC,OAAO,iCAAiC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACvG,GAAG,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,UAAU,eAAe,MAAM,CAAC,aAAa,aAAa,MAAM,CAAC,MAAM,CAAC,UAAU,WAAW,MAAM,CAAC,MAAM,CAAC,SAAS,aAAa,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;YACtN,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,SAAS,KAAK,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,UAAU,IAAI,CAAC;YAC/G,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,EAAE,wDAAwD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3J,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface Diagnostic {
|
|
2
|
+
provider: string;
|
|
3
|
+
code: string;
|
|
4
|
+
needs?: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class SiftpathError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
readonly diagnostics: Diagnostic[];
|
|
9
|
+
constructor(code: string, message: string, diagnostics?: Diagnostic[]);
|
|
10
|
+
}
|
|
11
|
+
export declare function safeError(error: unknown): {
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
diagnostics: Diagnostic[];
|
|
15
|
+
};
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class SiftpathError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
diagnostics;
|
|
4
|
+
constructor(code, message, diagnostics = []) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.diagnostics = diagnostics;
|
|
8
|
+
this.name = 'SiftpathError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function safeError(error) {
|
|
12
|
+
return error instanceof SiftpathError
|
|
13
|
+
? { code: error.code, message: error.message, diagnostics: error.diagnostics }
|
|
14
|
+
: { code: 'INTERNAL_ERROR', message: 'Operation failed. Run siftpath doctor; external errors are not exposed.', diagnostics: [] };
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AACA,MAAM,OAAO,aAAc,SAAQ,KAAK;IACV;IAA+C;IAA3E,YAA4B,IAAY,EAAE,OAAe,EAAkB,cAA4B,EAAE;QACvG,KAAK,CAAC,OAAO,CAAC,CAAC;QADW,SAAI,GAAJ,IAAI,CAAQ;QAAmC,gBAAW,GAAX,WAAW,CAAmB;QACvF,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9C,CAAC;CACF;AACD,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,aAAa;QACnC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;QAC9E,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,yEAAyE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;AACtI,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Siftpath } from './router.js';
|
|
2
|
+
export { SiftpathError, safeError } from './errors.js';
|
|
3
|
+
export type { Diagnostic } from './errors.js';
|
|
4
|
+
export { readConfiguration, parseConfiguration, configPath, diagnostics } from './config.js';
|
|
5
|
+
export type { Configuration, Provider, Binding } from './config.js';
|
|
6
|
+
export type { SearchInput, ReadInput, Intent } from './inputs.js';
|
|
7
|
+
export type { WebResult, Source } from './output.js';
|
|
8
|
+
export { toolDefinitions, invokeTool } from './tools.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Siftpath } from './router.js';
|
|
2
|
+
export { SiftpathError, safeError } from './errors.js';
|
|
3
|
+
export { readConfiguration, parseConfiguration, configPath, diagnostics } from './config.js';
|
|
4
|
+
export { toolDefinitions, invokeTool } from './tools.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI7F,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/inputs.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const intentSchema: z.ZodEnum<{
|
|
3
|
+
general: "general";
|
|
4
|
+
semantic: "semantic";
|
|
5
|
+
research: "research";
|
|
6
|
+
}>;
|
|
7
|
+
export declare const searchSchema: z.ZodObject<{
|
|
8
|
+
query: z.ZodString;
|
|
9
|
+
intent: z.ZodOptional<z.ZodEnum<{
|
|
10
|
+
general: "general";
|
|
11
|
+
semantic: "semantic";
|
|
12
|
+
research: "research";
|
|
13
|
+
}>>;
|
|
14
|
+
maxResults: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export declare const readSchema: z.ZodObject<{
|
|
17
|
+
url: z.ZodString;
|
|
18
|
+
focus: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type SearchInput = z.infer<typeof searchSchema>;
|
|
21
|
+
export type ReadInput = z.infer<typeof readSchema>;
|
|
22
|
+
export type Intent = z.infer<typeof intentSchema>;
|
|
23
|
+
export declare function parseInput<T>(schema: z.ZodType<T>, value: unknown): T;
|
|
24
|
+
/** Page URLs go to hosted readers, never to a local arbitrary-URL fetcher. */
|
|
25
|
+
export declare function publicUrl(value: string): string;
|
package/dist/inputs.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { isIP } from 'node:net';
|
|
3
|
+
import { SiftpathError } from './errors.js';
|
|
4
|
+
export const intentSchema = z.enum(['general', 'semantic', 'research']);
|
|
5
|
+
const text = z.string().trim().min(1).max(2000);
|
|
6
|
+
export const searchSchema = z.strictObject({ query: text, intent: intentSchema.optional(), maxResults: z.number().int().min(1).max(20).optional() });
|
|
7
|
+
export const readSchema = z.strictObject({ url: z.string().max(4096), focus: text.optional() });
|
|
8
|
+
export function parseInput(schema, value) {
|
|
9
|
+
const parsed = schema.safeParse(value);
|
|
10
|
+
if (!parsed.success)
|
|
11
|
+
throw new SiftpathError('INVALID_INPUT', 'Invalid tool arguments. Check the tool input schema.');
|
|
12
|
+
return parsed.data;
|
|
13
|
+
}
|
|
14
|
+
/** Page URLs go to hosted readers, never to a local arbitrary-URL fetcher. */
|
|
15
|
+
export function publicUrl(value) {
|
|
16
|
+
try {
|
|
17
|
+
const url = new URL(value), host = url.hostname.toLowerCase().replace(/\.$/, '').replace(/^\[|\]$/g, '');
|
|
18
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || isIP(host) || !host.includes('.') ||
|
|
19
|
+
/(^|\.)(localhost|local|internal|lan|home|invalid|arpa)$/.test(host))
|
|
20
|
+
throw new Error();
|
|
21
|
+
return value; // Preserve original signed query strings and fragments.
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new SiftpathError('INVALID_INPUT', 'Only credential-free HTTP(S) URLs with public DNS hostnames are accepted.');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=inputs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.js","sourceRoot":"","sources":["../src/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;AACxE,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACrJ,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAIhG,MAAM,UAAU,UAAU,CAAI,MAAoB,EAAE,KAAc;IAChE,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,sDAAsD,CAAC,CAAC;IACtH,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AACD,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACzG,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAClH,yDAAyD,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QAC1F,OAAO,KAAK,CAAC,CAAC,wDAAwD;IACxE,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,IAAI,aAAa,CAAC,eAAe,EAAE,2EAA2E,CAAC,CAAC;IAAC,CAAC;AACpI,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { safeError } from '../errors.js';
|
|
5
|
+
import { invokeTool, toolDefinitions } from '../tools.js';
|
|
6
|
+
import { packageVersion } from '../version.js';
|
|
7
|
+
export async function serveStdio(router) {
|
|
8
|
+
const server = new Server({ name: 'siftpath', version: packageVersion }, { capabilities: { tools: {} } });
|
|
9
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: toolDefinitions }));
|
|
10
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
11
|
+
try {
|
|
12
|
+
const result = await invokeTool(router, request.params.name, request.params.arguments, { signal: extra.signal });
|
|
13
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }], isError: false };
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return { content: [{ type: 'text', text: JSON.stringify(safeError(error)) }], isError: true };
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
await new Promise((resolve, reject) => {
|
|
20
|
+
let closing = false;
|
|
21
|
+
const stop = () => {
|
|
22
|
+
if (closing)
|
|
23
|
+
return;
|
|
24
|
+
closing = true;
|
|
25
|
+
process.off('SIGINT', stop);
|
|
26
|
+
process.off('SIGTERM', stop);
|
|
27
|
+
process.stdin.off('end', stop);
|
|
28
|
+
process.stdout.off('error', stop);
|
|
29
|
+
void Promise.allSettled([router.close(), server.close()]).then(() => resolve());
|
|
30
|
+
};
|
|
31
|
+
process.once('SIGINT', stop);
|
|
32
|
+
process.once('SIGTERM', stop);
|
|
33
|
+
process.stdin.once('end', stop);
|
|
34
|
+
process.stdout.once('error', stop);
|
|
35
|
+
server.onclose = stop;
|
|
36
|
+
server.onerror = () => { }; // SDK transport errors are not safe to print verbatim.
|
|
37
|
+
server.connect(new StdioServerTransport(process.stdin, process.stdout, { maxBufferSize: 1024 * 1024 })).catch(() => {
|
|
38
|
+
stop();
|
|
39
|
+
reject(new Error('Cannot start MCP stdio transport.'));
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export interface Source {
|
|
3
|
+
url: string;
|
|
4
|
+
title?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface WebResult {
|
|
7
|
+
provider: string;
|
|
8
|
+
tool: string;
|
|
9
|
+
retrievedAt: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
content: string;
|
|
12
|
+
sources: Source[];
|
|
13
|
+
truncated: boolean;
|
|
14
|
+
sourcesTruncated: boolean;
|
|
15
|
+
warnings: {
|
|
16
|
+
provider?: string;
|
|
17
|
+
code: string;
|
|
18
|
+
}[];
|
|
19
|
+
}
|
|
20
|
+
/** Preserve the official tool's text/order. Only collect citation URLs, never score or extract passages. */
|
|
21
|
+
export declare function normalize(result: CallToolResult, provider: string, tool: string, limit: number, url?: string, warnings?: WebResult['warnings']): WebResult;
|
|
22
|
+
/** Bound the entire JSON envelope, including provenance and fallback diagnostics. */
|
|
23
|
+
export declare function fitOutput(output: WebResult, limit: number): WebResult;
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { SiftpathError } from './errors.js';
|
|
2
|
+
import { publicUrl } from './inputs.js';
|
|
3
|
+
/** Preserve the official tool's text/order. Only collect citation URLs, never score or extract passages. */
|
|
4
|
+
export function normalize(result, provider, tool, limit, url, warnings = []) {
|
|
5
|
+
if (result.isError)
|
|
6
|
+
throw new SiftpathError('UPSTREAM_ERROR', 'Official MCP tool reported an error.');
|
|
7
|
+
const parts = result.content.flatMap(block => block.type === 'text' ? [block.text] :
|
|
8
|
+
block.type === 'resource_link' ? [block.uri] : block.type === 'resource' && 'text' in block.resource ? [block.resource.text] : []);
|
|
9
|
+
const structured = result.structuredContent ? JSON.stringify(result.structuredContent) : '';
|
|
10
|
+
const duplicatesStructured = structured && parts.some(part => { try {
|
|
11
|
+
return JSON.stringify(JSON.parse(part)) === structured;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
} });
|
|
16
|
+
const content = [...parts, ...(structured && !duplicatesStructured ? [structured] : [])].join('\n\n');
|
|
17
|
+
if (!content.trim())
|
|
18
|
+
throw new SiftpathError('EMPTY_RESPONSE', 'Official MCP returned no text.');
|
|
19
|
+
const sources = new Map();
|
|
20
|
+
let sourcesTruncated = false;
|
|
21
|
+
const add = (value, title) => {
|
|
22
|
+
if (value.length > 4096)
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
publicUrl(value);
|
|
26
|
+
if (sources.has(value))
|
|
27
|
+
return;
|
|
28
|
+
if (sources.size >= 50) {
|
|
29
|
+
sourcesTruncated = true;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
sources.set(value, { url: value, ...(title ? { title: title.slice(0, 200) } : {}) });
|
|
33
|
+
}
|
|
34
|
+
catch { /* Non-public citations are not forwarded as usable sources. */ }
|
|
35
|
+
};
|
|
36
|
+
if (url)
|
|
37
|
+
add(url);
|
|
38
|
+
const visit = (value, depth = 0) => {
|
|
39
|
+
if (!value || typeof value !== 'object' || depth > 12)
|
|
40
|
+
return;
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
for (const row of value.slice(0, 100))
|
|
43
|
+
visit(row, depth + 1);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const row = value;
|
|
47
|
+
for (const key of ['url', 'uri', 'link'])
|
|
48
|
+
if (typeof row[key] === 'string')
|
|
49
|
+
add(row[key], typeof row.title === 'string' ? row.title : undefined);
|
|
50
|
+
for (const [key, child] of Object.entries(row)) {
|
|
51
|
+
if (key.startsWith('https://') || key.startsWith('http://'))
|
|
52
|
+
add(key);
|
|
53
|
+
visit(child, depth + 1);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
visit(result.structuredContent);
|
|
57
|
+
for (const part of parts) {
|
|
58
|
+
try {
|
|
59
|
+
visit(JSON.parse(part));
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
catch { /* Official tools may return plain text or Markdown. */ }
|
|
63
|
+
for (const match of part.matchAll(/https?:\/\/[^\s<>"\\`]+/g)) {
|
|
64
|
+
let tail = match[0].length;
|
|
65
|
+
while (tail > 0 && '.,;'.includes(match[0][tail - 1]))
|
|
66
|
+
tail--;
|
|
67
|
+
let candidate = match[0].slice(0, tail);
|
|
68
|
+
for (const [open, close] of [['(', ')'], ['[', ']'], ['{', '}']]) {
|
|
69
|
+
// Count once, rather than rescanning the URL for every trailing delimiter.
|
|
70
|
+
let unmatched = 0, end = candidate.length;
|
|
71
|
+
for (const char of candidate) {
|
|
72
|
+
if (char === close)
|
|
73
|
+
unmatched++;
|
|
74
|
+
else if (char === open)
|
|
75
|
+
unmatched--;
|
|
76
|
+
}
|
|
77
|
+
while (unmatched > 0 && candidate[end - 1] === close) {
|
|
78
|
+
end--;
|
|
79
|
+
unmatched--;
|
|
80
|
+
}
|
|
81
|
+
candidate = candidate.slice(0, end);
|
|
82
|
+
}
|
|
83
|
+
add(candidate);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!sources.size)
|
|
87
|
+
throw new SiftpathError('NO_SOURCES', 'Official MCP returned no traceable public source URL.');
|
|
88
|
+
const output = { provider, tool, retrievedAt: new Date().toISOString(), ...(url ? { url } : {}),
|
|
89
|
+
content, sources: [...sources.values()], truncated: false, sourcesTruncated,
|
|
90
|
+
warnings: [{ code: 'UNTRUSTED_WEB_CONTENT' }, ...warnings] };
|
|
91
|
+
return fitOutput(output, limit);
|
|
92
|
+
}
|
|
93
|
+
/** Bound the entire JSON envelope, including provenance and fallback diagnostics. */
|
|
94
|
+
export function fitOutput(output, limit) {
|
|
95
|
+
while (JSON.stringify({ ...output, content: '' }).length > limit && output.sources.length > 1) {
|
|
96
|
+
output.sources.pop();
|
|
97
|
+
output.sourcesTruncated = true;
|
|
98
|
+
}
|
|
99
|
+
if (JSON.stringify(output).length > limit) {
|
|
100
|
+
output.truncated = true;
|
|
101
|
+
const original = output.content;
|
|
102
|
+
let low = 0, high = original.length;
|
|
103
|
+
// JSON escaping is not one byte/character: choose a prefix using its actual serialized size.
|
|
104
|
+
while (low < high) {
|
|
105
|
+
const mid = Math.ceil((low + high) / 2);
|
|
106
|
+
output.content = original.slice(0, mid);
|
|
107
|
+
if (JSON.stringify(output).length <= limit)
|
|
108
|
+
low = mid;
|
|
109
|
+
else
|
|
110
|
+
high = mid - 1;
|
|
111
|
+
}
|
|
112
|
+
output.content = original.slice(0, low).replace(/[\uD800-\uDBFF]$/, '');
|
|
113
|
+
}
|
|
114
|
+
if (JSON.stringify(output).length > limit)
|
|
115
|
+
throw new SiftpathError('OUTPUT_LIMIT', 'Source metadata exceeds maxOutputChars; increase the configured limit.');
|
|
116
|
+
return output;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Binding, type Configuration } from './config.js';
|
|
2
|
+
import { type ReadInput, type SearchInput } from './inputs.js';
|
|
3
|
+
import { type WebResult } from './output.js';
|
|
4
|
+
/** $field references tool input; missing optional fields are omitted, not sent as null. */
|
|
5
|
+
export declare function mapArguments(template: Binding['arguments'], input: Record<string, unknown>): Record<string, unknown>;
|
|
6
|
+
export declare class Siftpath {
|
|
7
|
+
private env;
|
|
8
|
+
readonly configuration: Configuration;
|
|
9
|
+
private clients;
|
|
10
|
+
private shutdown;
|
|
11
|
+
constructor(config?: unknown, env?: NodeJS.ProcessEnv);
|
|
12
|
+
search(input: SearchInput, options?: {
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}): Promise<WebResult>;
|
|
15
|
+
read(input: ReadInput, options?: {
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}): Promise<WebResult>;
|
|
18
|
+
close(): Promise<void>;
|
|
19
|
+
private route;
|
|
20
|
+
}
|