preflight-mcp 0.1.2 → 0.1.4

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.
@@ -138,15 +138,34 @@ async function writeJson(targetPath, obj) {
138
138
  await ensureDir(path.dirname(targetPath));
139
139
  await fs.writeFile(targetPath, JSON.stringify(obj, null, 2) + '\n', 'utf8');
140
140
  }
141
+ async function sleep(ms) {
142
+ return new Promise((resolve) => setTimeout(resolve, ms));
143
+ }
141
144
  async function callOrThrow(client, name, args) {
142
- const res = await client.callTool({ name, arguments: args });
143
- if (res.isError) {
144
- throw new Error(textFromToolResult(res) || `${name} failed`);
145
+ const maxRetries = 3;
146
+ let lastError;
147
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
148
+ try {
149
+ const res = await client.callTool({ name, arguments: args });
150
+ if (res.isError) {
151
+ throw new Error(textFromToolResult(res) || `${name} failed`);
152
+ }
153
+ return {
154
+ text: textFromToolResult(res),
155
+ structured: res.structuredContent,
156
+ };
157
+ }
158
+ catch (err) {
159
+ lastError = err instanceof Error ? err : new Error(String(err));
160
+ // Don't retry on last attempt
161
+ if (attempt < maxRetries - 1) {
162
+ // Exponential backoff: 1s, 2s, 4s
163
+ const delayMs = Math.pow(2, attempt) * 1000;
164
+ await sleep(delayMs);
165
+ }
166
+ }
145
167
  }
146
- return {
147
- text: textFromToolResult(res),
148
- structured: res.structuredContent,
149
- };
168
+ throw lastError || new Error(`${name} failed after ${maxRetries} retries`);
150
169
  }
151
170
  async function resolveContext7Id(client, input) {
152
171
  const notes = [];
@@ -154,38 +173,48 @@ async function resolveContext7Id(client, input) {
154
173
  if (trimmed.startsWith('/')) {
155
174
  return { id: trimmed, notes };
156
175
  }
157
- try {
158
- const res = await client.callTool({
159
- name: 'resolve-library-id',
160
- arguments: { libraryName: trimmed },
161
- });
162
- if (res.isError) {
163
- notes.push(`resolve-library-id error: ${textFromToolResult(res)}`);
164
- return { notes };
165
- }
166
- const text = textFromToolResult(res);
167
- // Prefer parsing the structured list output for better selection.
168
- const parsed = parseResolveEntries(text);
169
- const chosen = chooseBestEntry(parsed, trimmed);
170
- if (chosen.id) {
171
- notes.push(...chosen.notes);
172
- return { id: chosen.id, notes };
173
- }
174
- // Fallback: regex/structured extraction.
175
- const ids = extractContext7IdsFromResult(res);
176
- if (ids.length === 0) {
177
- notes.push('resolve-library-id returned no Context7 IDs');
178
- return { notes };
176
+ const maxRetries = 3;
177
+ let lastError;
178
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
179
+ try {
180
+ const res = await client.callTool({
181
+ name: 'resolve-library-id',
182
+ arguments: { libraryName: trimmed },
183
+ });
184
+ if (res.isError) {
185
+ notes.push(`resolve-library-id error: ${textFromToolResult(res)}`);
186
+ return { notes };
187
+ }
188
+ const text = textFromToolResult(res);
189
+ // Prefer parsing the structured list output for better selection.
190
+ const parsed = parseResolveEntries(text);
191
+ const chosen = chooseBestEntry(parsed, trimmed);
192
+ if (chosen.id) {
193
+ notes.push(...chosen.notes);
194
+ return { id: chosen.id, notes };
195
+ }
196
+ // Fallback: regex/structured extraction.
197
+ const ids = extractContext7IdsFromResult(res);
198
+ if (ids.length === 0) {
199
+ notes.push('resolve-library-id returned no Context7 IDs');
200
+ return { notes };
201
+ }
202
+ if (ids.length > 1) {
203
+ notes.push(`resolve-library-id returned multiple IDs; using first: ${ids[0]}`);
204
+ }
205
+ return { id: ids[0], notes };
179
206
  }
180
- if (ids.length > 1) {
181
- notes.push(`resolve-library-id returned multiple IDs; using first: ${ids[0]}`);
207
+ catch (err) {
208
+ lastError = err instanceof Error ? err : new Error(String(err));
209
+ // Don't retry on last attempt
210
+ if (attempt < maxRetries - 1) {
211
+ const delayMs = Math.pow(2, attempt) * 1000;
212
+ await sleep(delayMs);
213
+ }
182
214
  }
183
- return { id: ids[0], notes };
184
- }
185
- catch (err) {
186
- notes.push(`resolve-library-id threw: ${err instanceof Error ? err.message : String(err)}`);
187
- return { notes };
188
215
  }
216
+ notes.push(`resolve-library-id failed after ${maxRetries} retries: ${lastError?.message ?? 'unknown error'}`);
217
+ return { notes };
189
218
  }
190
219
  export async function ingestContext7Libraries(params) {
191
220
  const libs = (params.libraries ?? []).map((s) => s.trim()).filter(Boolean);