@rockhopper-co/mcp-server 2.0.1 → 2.1.1
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 +2 -1
- package/dist/api-client.d.ts +136 -2
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +185 -2
- package/dist/api-client.js.map +1 -1
- package/dist/capabilities.d.ts +5 -6
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +6 -9
- package/dist/capabilities.js.map +1 -1
- package/dist/drive-search.d.ts +162 -0
- package/dist/drive-search.d.ts.map +1 -0
- package/dist/drive-search.js +210 -0
- package/dist/drive-search.js.map +1 -0
- package/dist/enrollment.d.ts +121 -0
- package/dist/enrollment.d.ts.map +1 -0
- package/dist/enrollment.js +247 -0
- package/dist/enrollment.js.map +1 -0
- package/dist/resources/orchestration-guide.md +58 -8
- package/dist/tools/connect-microsoft.d.ts +21 -0
- package/dist/tools/connect-microsoft.d.ts.map +1 -0
- package/dist/tools/connect-microsoft.js +138 -0
- package/dist/tools/connect-microsoft.js.map +1 -0
- package/dist/tools/drive-search-lanes.d.ts +65 -0
- package/dist/tools/drive-search-lanes.d.ts.map +1 -0
- package/dist/tools/drive-search-lanes.js +95 -0
- package/dist/tools/drive-search-lanes.js.map +1 -0
- package/dist/tools/drive-search.contract.d.ts +94 -0
- package/dist/tools/drive-search.contract.d.ts.map +1 -0
- package/dist/tools/drive-search.contract.js +235 -0
- package/dist/tools/drive-search.contract.js.map +1 -0
- package/dist/tools/drive-search.d.ts +31 -0
- package/dist/tools/drive-search.d.ts.map +1 -0
- package/dist/tools/drive-search.js +209 -0
- package/dist/tools/drive-search.js.map +1 -0
- package/dist/tools/enroll-file.contract.d.ts +52 -0
- package/dist/tools/enroll-file.contract.d.ts.map +1 -0
- package/dist/tools/enroll-file.contract.js +105 -0
- package/dist/tools/enroll-file.contract.js.map +1 -0
- package/dist/tools/enroll-file.d.ts +4 -0
- package/dist/tools/enroll-file.d.ts.map +1 -0
- package/dist/tools/enroll-file.js +184 -0
- package/dist/tools/enroll-file.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +12 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +25 -2
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/write-files.d.ts.map +1 -1
- package/dist/tools/write-files.js +5 -0
- package/dist/tools/write-files.js.map +1 -1
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { inputRequired, inputResponse, } from '@modelcontextprotocol/server';
|
|
3
|
+
import { CandidateRegistry, SearchBudget, classifyDriveSearchFailure, ADMIN_CONSENT_TEXT, isAdminConsentRequired, isNoDelegatedToken, toCandidate, } from '../drive-search.js';
|
|
4
|
+
import { log } from '../logger.js';
|
|
5
|
+
import { BUDGET_EXHAUSTED_TEXT, DECLINE_CHOICE, DRIVE_SEARCH_ANNOTATIONS, DRIVE_SEARCH_DESCRIPTION, DRIVE_SEARCH_INPUT_SCHEMA, confirmationForm, confirmationPrompt, confirmedAnswer, connectPrompt, declinedAnswer, toolResult, unknownCandidateAnswer, } from './drive-search.contract.js';
|
|
6
|
+
import { CONFIRM_KEY, readRequestState, selectLane, } from './drive-search-lanes.js';
|
|
7
|
+
/**
|
|
8
|
+
* ENG-2204 (SP08) — the half of ENG-1647 that ENG-2200 did not fix.
|
|
9
|
+
*
|
|
10
|
+
* ENG-2200 built the enroll tool the customer could not find. This finds the
|
|
11
|
+
* FILE: a workbook Rockhopper has never seen, in the user's own OneDrive or
|
|
12
|
+
* SharePoint, confirmed with them before anything is written.
|
|
13
|
+
*
|
|
14
|
+
* Three things here are load-bearing and none is obvious from the happy path:
|
|
15
|
+
*
|
|
16
|
+
* 1. **The search set IS the permission trim.** Every candidate came back from
|
|
17
|
+
* a delegated Microsoft call made as this user. Nothing is added to it,
|
|
18
|
+
* nothing is inferred into it, and no file outside it is ever offered.
|
|
19
|
+
* 2. **A confirmation resolves against SERVER memory, never against what the
|
|
20
|
+
* client sent.** The confirmation carries a position and a nonce; the file
|
|
21
|
+
* it names is looked up in the set this session actually returned. A model
|
|
22
|
+
* that has read a hostile file name cannot conjure a `driveMsId` and have
|
|
23
|
+
* the tool bless it.
|
|
24
|
+
* 3. **The budget is claimed BEFORE the network call.** A cap that discards an
|
|
25
|
+
* answer already fetched has not capped anything — the enumeration already
|
|
26
|
+
* happened, and Microsoft already answered it.
|
|
27
|
+
*/
|
|
28
|
+
export function registerDriveSearchTool(server, api, session) {
|
|
29
|
+
// Per-server, never per-module: two servers in one process (a test file, a
|
|
30
|
+
// gateway serving two sessions) must not share a ceiling, and a module-level
|
|
31
|
+
// counter is exactly the shape that silently does.
|
|
32
|
+
const budget = session?.budget ?? new SearchBudget();
|
|
33
|
+
const registry = session?.registry ?? new CandidateRegistry();
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a (nonce, position) pair against what this session offered.
|
|
36
|
+
*
|
|
37
|
+
* Position, never identifier — the only thing a client can send is a number,
|
|
38
|
+
* and a number that does not index a set this session returned resolves to
|
|
39
|
+
* nothing. `0` and the elicitation form's "none of these" are the same
|
|
40
|
+
* answer: the user was asked and chose no file.
|
|
41
|
+
*/
|
|
42
|
+
function resolvePick(nonce, choice) {
|
|
43
|
+
if (choice === DECLINE_CHOICE || choice === 0)
|
|
44
|
+
return declinedAnswer();
|
|
45
|
+
if (!nonce)
|
|
46
|
+
return unknownCandidateAnswer();
|
|
47
|
+
const position = typeof choice === 'number' ? choice : Number(choice);
|
|
48
|
+
const candidate = registry.resolve(nonce, position - 1);
|
|
49
|
+
return candidate ? confirmedAnswer(candidate) : unknownCandidateAnswer();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Put the question through the best lane this request can reach.
|
|
53
|
+
*
|
|
54
|
+
* Lane 2 is awaited INSIDE the call and lane 3 returns out of it; both end
|
|
55
|
+
* at the same three answers, and lane 1 hands the question to the model.
|
|
56
|
+
*/
|
|
57
|
+
async function ask(ctx, candidates, nonce) {
|
|
58
|
+
const lane = selectLane(ctx, server.server?.getClientCapabilities?.());
|
|
59
|
+
const form = confirmationForm(candidates);
|
|
60
|
+
if (lane === 'input_required') {
|
|
61
|
+
return inputRequired({
|
|
62
|
+
inputRequests: { [CONFIRM_KEY]: inputRequired.elicit(form) },
|
|
63
|
+
requestState: nonce,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (lane === 'elicitation' && ctx?.mcpReq?.elicitInput) {
|
|
67
|
+
try {
|
|
68
|
+
const answer = await ctx.mcpReq.elicitInput({ ...form, mode: 'form' });
|
|
69
|
+
if (answer?.action === 'accept') {
|
|
70
|
+
const choice = answer.content
|
|
71
|
+
?.choice;
|
|
72
|
+
return resolvePick(nonce, choice ?? DECLINE_CHOICE);
|
|
73
|
+
}
|
|
74
|
+
// Declined or cancelled. Both mean the user did not choose a file, and
|
|
75
|
+
// neither is an error: a person is allowed to say no.
|
|
76
|
+
return declinedAnswer();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// The client advertised elicitation and could not deliver it. Falling
|
|
80
|
+
// back to the universal lane keeps the question answerable instead of
|
|
81
|
+
// turning a capability mismatch into a dead end.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return toolResult({
|
|
85
|
+
outcome: 'candidates',
|
|
86
|
+
text: confirmationPrompt(candidates, nonce),
|
|
87
|
+
detail: { confirmToken: nonce, candidateCount: candidates.length },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
server.registerTool('search_drive_files', {
|
|
91
|
+
title: "Find a File in the User's Microsoft Drive",
|
|
92
|
+
description: DRIVE_SEARCH_DESCRIPTION,
|
|
93
|
+
inputSchema: DRIVE_SEARCH_INPUT_SCHEMA,
|
|
94
|
+
annotations: DRIVE_SEARCH_ANNOTATIONS,
|
|
95
|
+
}, async ({ query, scope, limit, confirm_index, confirm_token }, ctx) => {
|
|
96
|
+
// A retried multi-round-trip request arrives with the user's answer
|
|
97
|
+
// embedded. It is checked FIRST and it never searches again: re-running
|
|
98
|
+
// the query on a retry would spend a second unit of budget and could
|
|
99
|
+
// return a different set than the one the user was looking at.
|
|
100
|
+
const embedded = inputResponse(ctx?.mcpReq?.inputResponses, CONFIRM_KEY);
|
|
101
|
+
if (embedded.kind === 'elicit') {
|
|
102
|
+
if (embedded.action !== 'accept')
|
|
103
|
+
return declinedAnswer();
|
|
104
|
+
const choice = embedded.content
|
|
105
|
+
?.choice;
|
|
106
|
+
return resolvePick(readRequestState(ctx), choice ?? DECLINE_CHOICE);
|
|
107
|
+
}
|
|
108
|
+
// The universal lane's confirmation: the model relaying a number the
|
|
109
|
+
// user said out loud. Same resolution, same server-side lookup.
|
|
110
|
+
if (confirm_index !== undefined || confirm_token !== undefined) {
|
|
111
|
+
return resolvePick(confirm_token ?? null, confirm_index ?? NaN);
|
|
112
|
+
}
|
|
113
|
+
if (!budget.claim()) {
|
|
114
|
+
log.warn({
|
|
115
|
+
event: 'drive_search_capped',
|
|
116
|
+
searches: budget.spent,
|
|
117
|
+
budget: budget.ceiling,
|
|
118
|
+
}, 'drive_search_capped');
|
|
119
|
+
return toolResult({
|
|
120
|
+
outcome: 'search_limit_reached',
|
|
121
|
+
isError: true,
|
|
122
|
+
text: BUDGET_EXHAUSTED_TEXT,
|
|
123
|
+
detail: { searchesUsed: budget.spent, searchBudget: budget.ceiling },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
let items;
|
|
127
|
+
try {
|
|
128
|
+
const answer = await api.searchDriveFiles({
|
|
129
|
+
q: query,
|
|
130
|
+
scope,
|
|
131
|
+
limit: limit ?? 10,
|
|
132
|
+
});
|
|
133
|
+
items = answer.items;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
// ORDER MATTERS. Both refusals arrive as `NO_DELEGATED_TOKEN`, so
|
|
137
|
+
// checking "not connected" first would swallow the administrator
|
|
138
|
+
// case and hand the user a connect link that Microsoft refuses —
|
|
139
|
+
// which returns them here, with the same link, forever (ENG-2614).
|
|
140
|
+
if (isAdminConsentRequired(error)) {
|
|
141
|
+
return toolResult({
|
|
142
|
+
outcome: 'microsoft_admin_approval_required',
|
|
143
|
+
text: ADMIN_CONSENT_TEXT,
|
|
144
|
+
isError: true,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (isNoDelegatedToken(error))
|
|
148
|
+
return connectAnswer(api);
|
|
149
|
+
const { outcome, message } = classifyDriveSearchFailure(error);
|
|
150
|
+
return toolResult({ outcome, text: message, isError: true });
|
|
151
|
+
}
|
|
152
|
+
// Mirrors the backend's own discovery log (`[DRIVE-SEARCH]`): the query
|
|
153
|
+
// LENGTH, never its text, and a count, never a name. Enough to tell an
|
|
154
|
+
// empty probe from a real one while reading an incident, and none of the
|
|
155
|
+
// customer's content.
|
|
156
|
+
log.info({
|
|
157
|
+
event: 'drive_search',
|
|
158
|
+
scope: scope ?? 'search',
|
|
159
|
+
queryLength: query?.length ?? 0,
|
|
160
|
+
results: items.length,
|
|
161
|
+
searches: budget.spent,
|
|
162
|
+
budget: budget.ceiling,
|
|
163
|
+
}, 'drive_search');
|
|
164
|
+
if (items.length === 0) {
|
|
165
|
+
return toolResult({
|
|
166
|
+
outcome: 'no_matches',
|
|
167
|
+
text: 'Microsoft returned no spreadsheets matching that. The search ran ' +
|
|
168
|
+
'and came back empty — it did not fail. Ask the user to try a ' +
|
|
169
|
+
'different part of the name, or call again with scope="recent" ' +
|
|
170
|
+
'to list what they have worked on lately.',
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const candidates = items.map(toCandidate);
|
|
174
|
+
const nonce = randomUUID();
|
|
175
|
+
registry.remember(nonce, candidates);
|
|
176
|
+
return ask(ctx, candidates, nonce);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The `NO_DELEGATED_TOKEN` answer: a link the BACKEND built.
|
|
181
|
+
*
|
|
182
|
+
* The tool takes no authorize URL, no redirect and no client id, and it never
|
|
183
|
+
* asks the model to compose one. An MCP tool's arguments are chosen by a model
|
|
184
|
+
* reading content it did not author, so a caller-supplied sign-in link is a
|
|
185
|
+
* consent-phishing lever — the user would see a genuine Microsoft consent
|
|
186
|
+
* screen the whole way while approving somebody else's application. Same
|
|
187
|
+
* reasoning as `connect_microsoft`, which is where this link comes from.
|
|
188
|
+
*/
|
|
189
|
+
async function connectAnswer(api) {
|
|
190
|
+
try {
|
|
191
|
+
const handoff = await api.beginMicrosoftConnect();
|
|
192
|
+
return toolResult({
|
|
193
|
+
outcome: 'microsoft_not_connected',
|
|
194
|
+
text: connectPrompt(handoff.authorizeUrl, handoff.expiresAt),
|
|
195
|
+
detail: { authorizeUrl: handoff.authorizeUrl },
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return toolResult({
|
|
200
|
+
outcome: 'microsoft_not_connected',
|
|
201
|
+
isError: true,
|
|
202
|
+
text: 'This user has no connected Microsoft account, and Rockhopper could ' +
|
|
203
|
+
'not produce a sign-in link just now. Ask them to run ' +
|
|
204
|
+
'`connect_microsoft`, or to paste the workbook link for `enroll_file`. ' +
|
|
205
|
+
'Do not compose a Microsoft sign-in link yourself.',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=drive-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive-search.js","sourceRoot":"","sources":["../../src/tools/drive-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ENG-2200 — everything `enroll_file` SAYS, split from everything it DOES
|
|
3
|
+
* (`enroll-file.ts`).
|
|
4
|
+
*
|
|
5
|
+
* The seam is not arbitrary. This half is the only interface a language model
|
|
6
|
+
* ever sees: it cannot read the handler, so the schema descriptions and the
|
|
7
|
+
* tool description ARE the contract, and a wrong word here is a behaviour bug
|
|
8
|
+
* that no type checks. Keeping it apart means it can be reviewed as prose —
|
|
9
|
+
* and read by a person deciding whether a model would do the right thing —
|
|
10
|
+
* without the branch logic in the way.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { EnrollOutcome } from '../enrollment.js';
|
|
14
|
+
export declare const ENROLL_INPUT_SCHEMA: z.ZodObject<{
|
|
15
|
+
url: z.ZodOptional<z.ZodString>;
|
|
16
|
+
driveMsId: z.ZodOptional<z.ZodString>;
|
|
17
|
+
msId: z.ZodOptional<z.ZodString>;
|
|
18
|
+
share_with: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
me: "me";
|
|
20
|
+
team: "team";
|
|
21
|
+
}>>;
|
|
22
|
+
confirm_restore: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export declare const ENROLL_DESCRIPTION: string;
|
|
25
|
+
export declare const ENROLL_ANNOTATIONS: {
|
|
26
|
+
readonly readOnlyHint: false;
|
|
27
|
+
readonly destructiveHint: false;
|
|
28
|
+
readonly idempotentHint: true;
|
|
29
|
+
readonly openWorldHint: true;
|
|
30
|
+
};
|
|
31
|
+
/** The question the model puts to the user when `share_with` was omitted. */
|
|
32
|
+
export declare const SHARE_QUESTION: string;
|
|
33
|
+
/** The machine-readable half of every answer, so a model can branch on it. */
|
|
34
|
+
export interface EnrollAnswer {
|
|
35
|
+
outcome: EnrollOutcome;
|
|
36
|
+
text: string;
|
|
37
|
+
isError?: boolean;
|
|
38
|
+
detail?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Render an answer as a tool result: prose for the human, then one JSON line
|
|
42
|
+
* for the model. Both, because prose alone invites the model to paraphrase a
|
|
43
|
+
* refusal into a success, and JSON alone gives the user nothing to read.
|
|
44
|
+
*/
|
|
45
|
+
export declare function toolResult(answer: EnrollAnswer): {
|
|
46
|
+
isError?: true | undefined;
|
|
47
|
+
content: {
|
|
48
|
+
type: "text";
|
|
49
|
+
text: string;
|
|
50
|
+
}[];
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=enroll-file.contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enroll-file.contract.d.ts","sourceRoot":"","sources":["../../src/tools/enroll-file.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,mBAAmB;;;;;;;;;iBAkD9B,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAqB4C,CAAC;AAE5E,eAAO,MAAM,kBAAkB;;;;;CAQrB,CAAC;AAEX,6EAA6E;AAC7E,eAAO,MAAM,cAAc,QAG+C,CAAC;AAE3E,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY;;;;;;EAW9C"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ENG-2200 — everything `enroll_file` SAYS, split from everything it DOES
|
|
3
|
+
* (`enroll-file.ts`).
|
|
4
|
+
*
|
|
5
|
+
* The seam is not arbitrary. This half is the only interface a language model
|
|
6
|
+
* ever sees: it cannot read the handler, so the schema descriptions and the
|
|
7
|
+
* tool description ARE the contract, and a wrong word here is a behaviour bug
|
|
8
|
+
* that no type checks. Keeping it apart means it can be reviewed as prose —
|
|
9
|
+
* and read by a person deciding whether a model would do the right thing —
|
|
10
|
+
* without the branch logic in the way.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
export const ENROLL_INPUT_SCHEMA = z.object({
|
|
14
|
+
url: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("The workbook's SharePoint or OneDrive address, exactly as copied from " +
|
|
18
|
+
'the browser bar. Use this whenever the user can paste a link — it is ' +
|
|
19
|
+
'the only input that names one specific file with no guessing.'),
|
|
20
|
+
driveMsId: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Microsoft drive id. Only for a file already identified by another tool; ' +
|
|
24
|
+
'must be sent together with `msId`, and never alongside `url`.'),
|
|
25
|
+
msId: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Microsoft drive-item id. Must be sent together with `driveMsId`, and ' +
|
|
29
|
+
'never alongside `url`.'),
|
|
30
|
+
/**
|
|
31
|
+
* Optional in the SCHEMA and required by the HANDLER, deliberately.
|
|
32
|
+
*
|
|
33
|
+
* A required field turns an omission into a protocol-level validation error,
|
|
34
|
+
* and the model then sees a rejection instead of the question it is supposed
|
|
35
|
+
* to put to the user. D5/D6 say ask every time, so the tool answers an
|
|
36
|
+
* omission with the question. What it must never do is pick a value:
|
|
37
|
+
* enrolling privately when the user meant "my team" is invisible until
|
|
38
|
+
* somebody cannot find the file.
|
|
39
|
+
*/
|
|
40
|
+
share_with: z
|
|
41
|
+
.enum(['me', 'team'])
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('REQUIRED. Who may see this file: "me" (just the user) or "team" ' +
|
|
44
|
+
'(everyone on their team). ASK THE USER every time and use their ' +
|
|
45
|
+
'answer — never assume, never carry an answer over from an earlier ' +
|
|
46
|
+
'file. Omitting it does not enroll anything; the tool returns the ' +
|
|
47
|
+
'question to put to them.'),
|
|
48
|
+
confirm_restore: z
|
|
49
|
+
.boolean()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Set to true only after the user has confirmed they want a file they ' +
|
|
52
|
+
'previously removed to be restored. Ignored otherwise.'),
|
|
53
|
+
});
|
|
54
|
+
export const ENROLL_DESCRIPTION = 'Add a Microsoft Excel workbook to Rockhopper so it can be versioned, ' +
|
|
55
|
+
"reviewed and tracked. Takes the file's SharePoint or OneDrive link (best), " +
|
|
56
|
+
'or a `driveMsId` + `msId` pair. ' +
|
|
57
|
+
'MICROSOFT ONLY — Google Sheets and Drive links are refused. ' +
|
|
58
|
+
'You MUST ask the user who may see the file and pass their answer as ' +
|
|
59
|
+
'`share_with` ("me" or "team"); calling without it returns the question ' +
|
|
60
|
+
'instead of enrolling. ' +
|
|
61
|
+
'If the file was previously removed from Rockhopper, this reports ' +
|
|
62
|
+
'`restore_confirmation_required` and changes nothing — ask the user, then ' +
|
|
63
|
+
'call again with `confirm_restore: true`. ' +
|
|
64
|
+
'Safe to call again if you lose the answer: a file that is already there ' +
|
|
65
|
+
'reports `already_enrolled` and is not duplicated. ' +
|
|
66
|
+
'Use this whenever `search_files` or `list_files` cannot find a file the ' +
|
|
67
|
+
'user is asking about — a file Rockhopper does not know about is not a ' +
|
|
68
|
+
'missing file, it is an un-enrolled one. ' +
|
|
69
|
+
// ENG-2204: the `driveMsId` + `msId` pair has one honest source, and naming
|
|
70
|
+
// it here is what keeps a model from assembling a pair out of ids it read
|
|
71
|
+
// somewhere else and enrolling a file the user never named.
|
|
72
|
+
'If the user cannot produce a link, call `search_drive_files` first, have ' +
|
|
73
|
+
'them confirm which candidate they meant, and pass the `driveMsId` + `msId` ' +
|
|
74
|
+
'that confirmation returned. Never enroll a file the user has not named.';
|
|
75
|
+
export const ENROLL_ANNOTATIONS = {
|
|
76
|
+
readOnlyHint: false,
|
|
77
|
+
// Enrolling adds a file; it never removes or overwrites one, and a repeat
|
|
78
|
+
// call on an already-enrolled file changes nothing.
|
|
79
|
+
destructiveHint: false,
|
|
80
|
+
idempotentHint: true,
|
|
81
|
+
// It reaches SharePoint / OneDrive through Rockhopper.
|
|
82
|
+
openWorldHint: true,
|
|
83
|
+
};
|
|
84
|
+
/** The question the model puts to the user when `share_with` was omitted. */
|
|
85
|
+
export const SHARE_QUESTION = 'Before this file can be added, ask the user: "Should this workbook be ' +
|
|
86
|
+
'visible to just you, or to your whole team?" Then call `enroll_file` again ' +
|
|
87
|
+
'with share_with="me" or share_with="team". Nothing has been added yet.';
|
|
88
|
+
/**
|
|
89
|
+
* Render an answer as a tool result: prose for the human, then one JSON line
|
|
90
|
+
* for the model. Both, because prose alone invites the model to paraphrase a
|
|
91
|
+
* refusal into a success, and JSON alone gives the user nothing to read.
|
|
92
|
+
*/
|
|
93
|
+
export function toolResult(answer) {
|
|
94
|
+
const payload = { outcome: answer.outcome, ...(answer.detail ?? {}) };
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: 'text',
|
|
99
|
+
text: `${answer.text}\n${JSON.stringify(payload)}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
...(answer.isError ? { isError: true } : {}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=enroll-file.contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enroll-file.contract.js","sourceRoot":"","sources":["../../src/tools/enroll-file.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,wEAAwE;QACtE,uEAAuE;QACvE,+DAA+D,CAClE;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,0EAA0E;QACxE,+DAA+D,CAClE;IACH,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,uEAAuE;QACrE,wBAAwB,CAC3B;IACH;;;;;;;;;OASG;IACH,UAAU,EAAE,CAAC;SACV,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;SACpB,QAAQ,EAAE;SACV,QAAQ,CACP,kEAAkE;QAChE,kEAAkE;QAClE,oEAAoE;QACpE,mEAAmE;QACnE,0BAA0B,CAC7B;IACH,eAAe,EAAE,CAAC;SACf,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CACP,sEAAsE;QACpE,uDAAuD,CAC1D;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAC7B,uEAAuE;IACvE,6EAA6E;IAC7E,kCAAkC;IAClC,8DAA8D;IAC9D,sEAAsE;IACtE,yEAAyE;IACzE,wBAAwB;IACxB,mEAAmE;IACnE,2EAA2E;IAC3E,2CAA2C;IAC3C,0EAA0E;IAC1E,oDAAoD;IACpD,0EAA0E;IAC1E,wEAAwE;IACxE,0CAA0C;IAC1C,4EAA4E;IAC5E,0EAA0E;IAC1E,4DAA4D;IAC5D,2EAA2E;IAC3E,6EAA6E;IAC7E,yEAAyE,CAAC;AAE5E,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,YAAY,EAAE,KAAK;IACnB,0EAA0E;IAC1E,oDAAoD;IACpD,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,uDAAuD;IACvD,aAAa,EAAE,IAAI;CACX,CAAC;AAEX,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GACzB,wEAAwE;IACxE,6EAA6E;IAC7E,wEAAwE,CAAC;AAU3E;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IACtE,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;aACnD;SACF;QACD,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enroll-file.d.ts","sourceRoot":"","sources":["../../src/tools/enroll-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAmDlD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CA2N9E"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { classifyEnrollmentFailure, describeServerOutcome, outcomeForState, resolveTeamShareTargets, TeamUnresolvedError, } from '../enrollment.js';
|
|
2
|
+
import { ENROLL_ANNOTATIONS, ENROLL_DESCRIPTION, ENROLL_INPUT_SCHEMA, SHARE_QUESTION, toolResult, } from './enroll-file.contract.js';
|
|
3
|
+
export function registerEnrollFileTool(server, api) {
|
|
4
|
+
/**
|
|
5
|
+
* Turn whichever input arrived into `(identity, current state)`.
|
|
6
|
+
*
|
|
7
|
+
* Both branches learn the state BEFORE writing anything, because the whole
|
|
8
|
+
* point of the tool is that `enrolled`, `hidden` and `not_enrolled` lead to
|
|
9
|
+
* three different conversations.
|
|
10
|
+
*/
|
|
11
|
+
async function resolveTarget(args) {
|
|
12
|
+
if (args.url) {
|
|
13
|
+
const resolved = await api.resolveEnrollmentUrl(args.url);
|
|
14
|
+
return {
|
|
15
|
+
msId: resolved.msId,
|
|
16
|
+
driveMsId: resolved.driveMsId,
|
|
17
|
+
name: resolved.name,
|
|
18
|
+
state: resolved.enrollmentState,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const msId = args.msId;
|
|
22
|
+
const driveMsId = args.driveMsId;
|
|
23
|
+
const [info] = await api.getEnrollmentInfo([msId]);
|
|
24
|
+
return {
|
|
25
|
+
msId,
|
|
26
|
+
driveMsId,
|
|
27
|
+
// The bulk read withholds `name` for a hidden or stub row, and an id
|
|
28
|
+
// enroll has no other source for it. The backend fills the real name
|
|
29
|
+
// from Graph during the enroll, so an empty string here is a placeholder
|
|
30
|
+
// that never reaches a user, not a guess at what the file is called.
|
|
31
|
+
name: info?.name ?? '',
|
|
32
|
+
state: info?.enrollmentState ?? 'not_enrolled',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* ENG-2536 — the server's own verdict, or null when it did not give one.
|
|
37
|
+
*
|
|
38
|
+
* Null is not hypothetical: this package publishes to npm on its own clock
|
|
39
|
+
* and a customer's `npx` picks up `latest` immediately, so a backend that
|
|
40
|
+
* predates the field is a live case. The caller falls back to what the
|
|
41
|
+
* pre-write lookup said, which is exactly the behaviour that shipped before.
|
|
42
|
+
*/
|
|
43
|
+
function serverOutcomeOf(queued, target) {
|
|
44
|
+
const files = queued.files ?? [];
|
|
45
|
+
const mine = files.find((f) => f.msId === target.msId || f.platformId === target.msId) ??
|
|
46
|
+
(files.length === 1 ? files[0] : undefined);
|
|
47
|
+
return mine?.outcome ?? null;
|
|
48
|
+
}
|
|
49
|
+
async function enroll(target, shareWith) {
|
|
50
|
+
const file = {
|
|
51
|
+
msId: target.msId,
|
|
52
|
+
driveMsId: target.driveMsId,
|
|
53
|
+
name: target.name,
|
|
54
|
+
};
|
|
55
|
+
if (shareWith === 'me') {
|
|
56
|
+
const queued = await api.createEnrolledFile(file);
|
|
57
|
+
return {
|
|
58
|
+
enrollmentId: queued.enrollmentId,
|
|
59
|
+
sharedWith: 0,
|
|
60
|
+
serverOutcome: serverOutcomeOf(queued, target),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const targets = await resolveTeamShareTargets(api);
|
|
64
|
+
const queued = await api.enrollFileSharedWith(file, targets);
|
|
65
|
+
return {
|
|
66
|
+
enrollmentId: queued.enrollmentId,
|
|
67
|
+
sharedWith: targets.length,
|
|
68
|
+
serverOutcome: serverOutcomeOf(queued, target),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
server.registerTool('enroll_file', {
|
|
72
|
+
title: 'Add a File to Rockhopper',
|
|
73
|
+
description: ENROLL_DESCRIPTION,
|
|
74
|
+
inputSchema: ENROLL_INPUT_SCHEMA,
|
|
75
|
+
annotations: ENROLL_ANNOTATIONS,
|
|
76
|
+
}, async ({ url, driveMsId, msId, share_with, confirm_restore }) => {
|
|
77
|
+
const hasUrl = !!url?.trim();
|
|
78
|
+
const hasIds = !!msId?.trim() && !!driveMsId?.trim();
|
|
79
|
+
if (hasUrl && hasIds) {
|
|
80
|
+
return toolResult({
|
|
81
|
+
outcome: 'unresolvable',
|
|
82
|
+
isError: true,
|
|
83
|
+
text: 'Send either `url` or the `driveMsId` + `msId` pair, not both — ' +
|
|
84
|
+
'they can name different files and Rockhopper will not guess ' +
|
|
85
|
+
'which one you meant. Nothing was changed.',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (!hasUrl && !hasIds) {
|
|
89
|
+
return toolResult({
|
|
90
|
+
outcome: 'unresolvable',
|
|
91
|
+
isError: true,
|
|
92
|
+
text: 'No file was named. Ask the user to open the workbook and paste ' +
|
|
93
|
+
'the address from their browser bar, then call `enroll_file` with ' +
|
|
94
|
+
'that `url`. Nothing was changed.',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Checked BEFORE the resolve so an omitted `share_with` costs no network
|
|
98
|
+
// call and, more importantly, cannot be answered by a half-done enroll.
|
|
99
|
+
if (share_with === undefined) {
|
|
100
|
+
return toolResult({
|
|
101
|
+
outcome: 'share_with_required',
|
|
102
|
+
text: SHARE_QUESTION,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
let target;
|
|
106
|
+
try {
|
|
107
|
+
target = await resolveTarget({ url, driveMsId, msId });
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const { outcome, message } = classifyEnrollmentFailure(error);
|
|
111
|
+
return toolResult({
|
|
112
|
+
outcome: outcome === 'error' ? 'unresolvable' : outcome,
|
|
113
|
+
text: outcome === 'error'
|
|
114
|
+
? `Rockhopper could not look that file up: ${message}`
|
|
115
|
+
: message,
|
|
116
|
+
isError: true,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const known = outcomeForState(target.state);
|
|
120
|
+
if (known === 'already_enrolled') {
|
|
121
|
+
return toolResult({
|
|
122
|
+
outcome: 'already_enrolled',
|
|
123
|
+
text: `"${target.name}" is already in Rockhopper — nothing to do. Its ` +
|
|
124
|
+
'versions and history are available through `get_file_versions` ' +
|
|
125
|
+
'and `get_cell_history`.',
|
|
126
|
+
detail: { fileMsId: target.msId, name: target.name },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (known === 'restore_confirmation_required' && !confirm_restore) {
|
|
130
|
+
return toolResult({
|
|
131
|
+
outcome: 'restore_confirmation_required',
|
|
132
|
+
text: `"${target.name || 'That workbook'}" was previously removed from ` +
|
|
133
|
+
'Rockhopper\'s file lists. Its versions, comments and history were ' +
|
|
134
|
+
'kept. Ask the user whether they want it restored, and if they do, ' +
|
|
135
|
+
'call `enroll_file` again with the same arguments plus ' +
|
|
136
|
+
'confirm_restore: true. Nothing has been changed.',
|
|
137
|
+
detail: { fileMsId: target.msId, name: target.name || null },
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const restoring = known === 'restore_confirmation_required';
|
|
141
|
+
try {
|
|
142
|
+
const { enrollmentId, sharedWith, serverOutcome } = await enroll(target, share_with);
|
|
143
|
+
const who = share_with === 'team'
|
|
144
|
+
? ` and shared with ${sharedWith} teammate(s)`
|
|
145
|
+
: ' — visible to you only';
|
|
146
|
+
// ENG-2536: the SERVER's verdict wins over the one inferred from the
|
|
147
|
+
// lookup taken before the write. The two can disagree, and when they
|
|
148
|
+
// do the server is right: the lookup happened earlier, so a file
|
|
149
|
+
// somebody else added in between reads `not_enrolled` here and would
|
|
150
|
+
// otherwise be reported as a fresh add. The fallback is what shipped
|
|
151
|
+
// before, for a backend older than the field.
|
|
152
|
+
const { outcome, text } = describeServerOutcome(serverOutcome ?? (restoring ? 'restored' : 'enrolled'), target.name, who);
|
|
153
|
+
return toolResult({
|
|
154
|
+
outcome,
|
|
155
|
+
text,
|
|
156
|
+
detail: {
|
|
157
|
+
fileMsId: target.msId,
|
|
158
|
+
name: target.name || null,
|
|
159
|
+
enrollmentId,
|
|
160
|
+
shareWith: share_with,
|
|
161
|
+
sharedWithCount: sharedWith,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof TeamUnresolvedError) {
|
|
167
|
+
return toolResult({
|
|
168
|
+
outcome: 'share_with_required',
|
|
169
|
+
text: error.message,
|
|
170
|
+
isError: true,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const { outcome, message } = classifyEnrollmentFailure(error);
|
|
174
|
+
return toolResult({
|
|
175
|
+
outcome: outcome === 'error' ? 'unresolvable' : outcome,
|
|
176
|
+
text: outcome === 'error'
|
|
177
|
+
? `Rockhopper could not add that file: ${message}`
|
|
178
|
+
: message,
|
|
179
|
+
isError: true,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=enroll-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enroll-file.js","sourceRoot":"","sources":["../../src/tools/enroll-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAc5B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,8BAA8B,EAC9B,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAcD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,aAAa,EAAE,CAUjB;AAWD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,oBAAoB,GAC7B,IAAI,CAwBN"}
|
package/dist/tools/index.js
CHANGED
|
@@ -5,6 +5,8 @@ import { registerGetCommentsTool } from './get-comments.js';
|
|
|
5
5
|
import { registerGetReviewsTool } from './get-reviews.js';
|
|
6
6
|
import { registerGetCellHistoryTool } from './get-cell-history.js';
|
|
7
7
|
import { registerSearchTool } from './search.js';
|
|
8
|
+
import { registerDriveSearchTool } from './drive-search.js';
|
|
9
|
+
import { registerConnectMicrosoftTool } from './connect-microsoft.js';
|
|
8
10
|
import { registerWriteCommentTools } from './write-comments.js';
|
|
9
11
|
import { registerWriteReviewTools } from './write-reviews.js';
|
|
10
12
|
import { registerWriteVersionTools } from './write-versions.js';
|
|
@@ -55,6 +57,16 @@ export function registerTools(server, api, options) {
|
|
|
55
57
|
registerGetReviewsTool(server, api);
|
|
56
58
|
registerGetCellHistoryTool(server, api);
|
|
57
59
|
registerSearchTool(server, api);
|
|
60
|
+
// ENG-2204 — discovery of files Rockhopper has NEVER seen. On the read floor
|
|
61
|
+
// for the same reason `connect_microsoft` is: finding a file writes nothing,
|
|
62
|
+
// and a read-only token is exactly the caller who needs to be told a file is
|
|
63
|
+
// un-enrolled rather than missing.
|
|
64
|
+
registerDriveSearchTool(server, api);
|
|
65
|
+
// ENG-2198 — connecting a Microsoft account is an account action, not a
|
|
66
|
+
// write to Rockhopper data, so it rides with the read floor: a read-only
|
|
67
|
+
// token can still connect, check and disconnect. The backend requires an
|
|
68
|
+
// interactive login for the disconnect itself.
|
|
69
|
+
registerConnectMicrosoftTool(server, api);
|
|
58
70
|
// Write tools — one registrar per granted family, so a token holding
|
|
59
71
|
// `comments:write` alone cannot reach `discard_changes`.
|
|
60
72
|
for (const capability of resolveCapabilities(options)) {
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,8BAA8B,GAE/B,MAAM,oBAAoB,CAAC;AAiC5B;;;;;;;;;GASG;AACH,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAElE,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACxD,OAAO,KAAK,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA8B;IAE9B,IAAI,OAAO,EAAE,YAAY,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAsB,EAAE,CACpD,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CACtB,CACF,CAAC;QACF,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,GAEZ;IACF,gBAAgB,EAAE,yBAAyB;IAC3C,eAAe,EAAE,wBAAwB;IACzC,gBAAgB,EAAE,yBAAyB;IAC3C,aAAa,EAAE,qBAAqB;CACrC,CAAC;AAEF,MAAM,UAAU,aAAa,CAC3B,MAAiB,EACjB,GAAc,EACd,OAA8B;IAE9B,0EAA0E;IAC1E,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOlD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOlD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,CA8ON"}
|