@goxtechnologies/connectwise-psa-mcp 1.3.0 → 1.4.2
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/data/reports.json +29 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/operations/analytics-extended.d.ts.map +1 -1
- package/dist/operations/analytics-extended.js +15 -4
- package/dist/operations/analytics-extended.js.map +1 -1
- package/dist/operations/analytics-msp-schedule.js +12 -2
- package/dist/operations/analytics-msp-schedule.js.map +1 -1
- package/dist/operations/analytics-msp-time-entry.d.ts +68 -0
- package/dist/operations/analytics-msp-time-entry.d.ts.map +1 -0
- package/dist/operations/analytics-msp-time-entry.js +235 -0
- package/dist/operations/analytics-msp-time-entry.js.map +1 -0
- package/dist/operations/analytics-msp-time.js +27 -8
- package/dist/operations/analytics-msp-time.js.map +1 -1
- package/dist/operations/analytics.d.ts.map +1 -1
- package/dist/operations/analytics.js +2 -0
- package/dist/operations/analytics.js.map +1 -1
- package/dist/operations/registry.d.ts.map +1 -1
- package/dist/operations/registry.js +1 -0
- package/dist/operations/registry.js.map +1 -1
- package/dist/scrapers/index.d.ts +4 -0
- package/dist/scrapers/index.d.ts.map +1 -0
- package/dist/scrapers/index.js +10 -0
- package/dist/scrapers/index.js.map +1 -0
- package/dist/scrapers/reports.d.ts +3 -0
- package/dist/scrapers/reports.d.ts.map +1 -0
- package/dist/scrapers/reports.js +443 -0
- package/dist/scrapers/reports.js.map +1 -0
- package/dist/services/load-env.d.ts.map +1 -1
- package/dist/services/load-env.js +11 -1
- package/dist/services/load-env.js.map +1 -1
- package/dist/services/report-cache.d.ts +16 -0
- package/dist/services/report-cache.d.ts.map +1 -0
- package/dist/services/report-cache.js +230 -0
- package/dist/services/report-cache.js.map +1 -0
- package/dist/services/report-config.d.ts +28 -0
- package/dist/services/report-config.d.ts.map +1 -0
- package/dist/services/report-config.js +127 -0
- package/dist/services/report-config.js.map +1 -0
- package/dist/services/totp.d.ts +27 -0
- package/dist/services/totp.d.ts.map +1 -0
- package/dist/services/totp.js +76 -0
- package/dist/services/totp.js.map +1 -0
- package/dist/services/web-scraper.d.ts +76 -0
- package/dist/services/web-scraper.d.ts.map +1 -0
- package/dist/services/web-scraper.js +435 -0
- package/dist/services/web-scraper.js.map +1 -0
- package/dist/tools/reports.d.ts +9 -0
- package/dist/tools/reports.d.ts.map +1 -0
- package/dist/tools/reports.js +388 -0
- package/dist/tools/reports.js.map +1 -0
- package/dist/tools/validation.js +2 -2
- package/dist/tools/validation.js.map +1 -1
- package/dist/types/reports.d.ts +87 -0
- package/dist/types/reports.d.ts.map +1 -0
- package/dist/types/reports.js +3 -0
- package/dist/types/reports.js.map +1 -0
- package/package.json +18 -4
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
// ConnectWise PSA MCP Server — General-purpose browser automation service
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from 'node:fs';
|
|
3
|
+
import { join, dirname } from 'node:path';
|
|
4
|
+
import { generateTOTPSafe } from './totp.js';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Constants
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const STORAGE_STATE_PATH = join(process.env['HOME'] ?? process.env['USERPROFILE'] ?? '', '.config', 'connectwise-psa', 'browser-state.json');
|
|
9
|
+
const DOWNLOADS_PATH = join(process.env['HOME'] ?? process.env['USERPROFILE'] ?? '', '.config', 'connectwise-psa', 'browser-downloads');
|
|
10
|
+
const MAX_REQUESTS_BEFORE_RECYCLE = 50;
|
|
11
|
+
const CONTEXT_MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes
|
|
12
|
+
const PAGE_TIMEOUT_MS = 60_000;
|
|
13
|
+
const SESSION_STALE_WINDOW_MS = 5 * 60 * 1000; // 5 minutes before cookie expiry
|
|
14
|
+
/** Default login steps — checked in order during authentication. */
|
|
15
|
+
const DEFAULT_LOGIN_STEPS = [
|
|
16
|
+
{
|
|
17
|
+
name: 'credentials',
|
|
18
|
+
detect: 'input[type="text"][name*="user"], input#username, input[name="email"]',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'totp',
|
|
22
|
+
detect: 'input[name*="otp"], input[name*="code"], input[name*="totp"], input#mfaCode',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'device_trust',
|
|
26
|
+
detect: '.trust-device, [data-testid="trust-device"], button:has-text("Trust")',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Semaphore — limits concurrent pages
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
class Semaphore {
|
|
33
|
+
max;
|
|
34
|
+
queue = [];
|
|
35
|
+
active = 0;
|
|
36
|
+
constructor(max) {
|
|
37
|
+
this.max = max;
|
|
38
|
+
}
|
|
39
|
+
async acquire() {
|
|
40
|
+
if (this.active < this.max) {
|
|
41
|
+
this.active++;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
await new Promise((resolve) => {
|
|
45
|
+
this.queue.push(resolve);
|
|
46
|
+
});
|
|
47
|
+
this.active++;
|
|
48
|
+
}
|
|
49
|
+
release() {
|
|
50
|
+
this.active = Math.max(0, this.active - 1);
|
|
51
|
+
const next = this.queue.shift();
|
|
52
|
+
if (next)
|
|
53
|
+
next();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Playwright availability check (lazy, cached)
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
let _playwrightAvailable = null;
|
|
60
|
+
/**
|
|
61
|
+
* Returns true if the `playwright` package is installed and importable.
|
|
62
|
+
* Result is cached after the first call.
|
|
63
|
+
*/
|
|
64
|
+
export async function isPlaywrightAvailable() {
|
|
65
|
+
if (_playwrightAvailable !== null)
|
|
66
|
+
return _playwrightAvailable;
|
|
67
|
+
try {
|
|
68
|
+
await import('playwright');
|
|
69
|
+
_playwrightAvailable = true;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
_playwrightAvailable = false;
|
|
73
|
+
}
|
|
74
|
+
return _playwrightAvailable;
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Singleton accessor
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
let _instance = null;
|
|
80
|
+
/** Returns the singleton WebScraper instance (creates it on first call). */
|
|
81
|
+
export function getWebScraper() {
|
|
82
|
+
if (!_instance)
|
|
83
|
+
_instance = new WebScraper();
|
|
84
|
+
return _instance;
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// WebScraper
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
export class WebScraper {
|
|
90
|
+
browser = null;
|
|
91
|
+
context = null;
|
|
92
|
+
initialized = false;
|
|
93
|
+
semaphore;
|
|
94
|
+
requestCount = 0;
|
|
95
|
+
contextCreatedAt = 0;
|
|
96
|
+
cleanupRegistered = false;
|
|
97
|
+
// Circuit breaker — disable auth retries after repeated failures
|
|
98
|
+
authFailCount = 0;
|
|
99
|
+
AUTH_FAIL_LIMIT = 3;
|
|
100
|
+
constructor() {
|
|
101
|
+
const maxPages = parseInt(process.env['CW_WEB_MAX_PAGES'] ?? '1', 10) || 1;
|
|
102
|
+
this.semaphore = new Semaphore(maxPages);
|
|
103
|
+
}
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Lifecycle
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
/**
|
|
108
|
+
* Launch the browser, restore storageState if available, and register
|
|
109
|
+
* process cleanup hooks. Safe to call multiple times — subsequent calls are
|
|
110
|
+
* no-ops if already initialized.
|
|
111
|
+
*/
|
|
112
|
+
async init() {
|
|
113
|
+
if (this.initialized)
|
|
114
|
+
return;
|
|
115
|
+
const pw = await import('playwright');
|
|
116
|
+
const headless = process.env['CW_WEB_HEADLESS'] !== 'false';
|
|
117
|
+
const locale = process.env['CW_LOCALE'] ?? 'en-CA';
|
|
118
|
+
this.browser = await pw.chromium.launch({ headless });
|
|
119
|
+
await this.createContext();
|
|
120
|
+
// Ensure downloads directory exists
|
|
121
|
+
mkdirSync(DOWNLOADS_PATH, { recursive: true });
|
|
122
|
+
this.initialized = true;
|
|
123
|
+
this.registerCleanupHooks();
|
|
124
|
+
}
|
|
125
|
+
/** Close the browser context and browser cleanly. */
|
|
126
|
+
async shutdown() {
|
|
127
|
+
try {
|
|
128
|
+
if (this.context) {
|
|
129
|
+
await this.context.close();
|
|
130
|
+
this.context = null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// ignore close errors
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
if (this.browser) {
|
|
138
|
+
await this.browser.close();
|
|
139
|
+
this.browser = null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// ignore close errors
|
|
144
|
+
}
|
|
145
|
+
this.initialized = false;
|
|
146
|
+
}
|
|
147
|
+
/** Returns true if the browser has been launched and not yet shut down. */
|
|
148
|
+
isInitialized() {
|
|
149
|
+
return this.initialized;
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Authentication
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
/**
|
|
155
|
+
* Ensure the browser session is authenticated.
|
|
156
|
+
* Fast path: checks cookie expiry in storageState.
|
|
157
|
+
* Slow path: navigates to CW and runs the login flow.
|
|
158
|
+
*/
|
|
159
|
+
async ensureAuth() {
|
|
160
|
+
// Circuit breaker — stop retrying after too many consecutive failures
|
|
161
|
+
if (this.authFailCount >= this.AUTH_FAIL_LIMIT) {
|
|
162
|
+
throw new Error(`WebScraper: authentication circuit breaker open after ${this.authFailCount} failures. ` +
|
|
163
|
+
'Check CW_WEB_USERNAME / CW_WEB_PASSWORD / CW_TOTP_SECRET.');
|
|
164
|
+
}
|
|
165
|
+
// Fast path: valid session cookies still present
|
|
166
|
+
if (this.hasValidSession())
|
|
167
|
+
return;
|
|
168
|
+
// Slow path: navigate and authenticate
|
|
169
|
+
const page = await this.context.newPage();
|
|
170
|
+
try {
|
|
171
|
+
const base = this.getCWBase();
|
|
172
|
+
await page.goto(base, { waitUntil: 'domcontentloaded' });
|
|
173
|
+
if (await this.isOnLoginPage(page)) {
|
|
174
|
+
await this.authenticate(page);
|
|
175
|
+
}
|
|
176
|
+
// Persist session state
|
|
177
|
+
const state = await this.context.storageState();
|
|
178
|
+
const stateJson = JSON.stringify(state, null, 2);
|
|
179
|
+
mkdirSync(dirname(STORAGE_STATE_PATH), { recursive: true });
|
|
180
|
+
writeFileSync(STORAGE_STATE_PATH, stateJson, { mode: 0o600 });
|
|
181
|
+
this.authFailCount = 0; // reset on success
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
this.authFailCount++;
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
await page.close();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Returns true if storageState contains at least one non-expired cookie
|
|
193
|
+
* (with more than SESSION_STALE_WINDOW_MS remaining).
|
|
194
|
+
*/
|
|
195
|
+
hasValidSession() {
|
|
196
|
+
if (!existsSync(STORAGE_STATE_PATH))
|
|
197
|
+
return false;
|
|
198
|
+
try {
|
|
199
|
+
const raw = readFileSync(STORAGE_STATE_PATH, 'utf-8');
|
|
200
|
+
const state = JSON.parse(raw);
|
|
201
|
+
if (!state.cookies || state.cookies.length === 0)
|
|
202
|
+
return false;
|
|
203
|
+
const now = Date.now();
|
|
204
|
+
const validCookie = state.cookies.some((c) => {
|
|
205
|
+
if (c.expires == null || c.expires === -1)
|
|
206
|
+
return true; // session cookie
|
|
207
|
+
return c.expires * 1000 > now + SESSION_STALE_WINDOW_MS;
|
|
208
|
+
});
|
|
209
|
+
return validCookie;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Returns true if the current page is showing a login form.
|
|
217
|
+
*/
|
|
218
|
+
async isOnLoginPage(page) {
|
|
219
|
+
const loginSelector = DEFAULT_LOGIN_STEPS[0]?.detect ?? 'input[type="password"]';
|
|
220
|
+
try {
|
|
221
|
+
await page.waitForSelector(loginSelector, { timeout: 3_000 });
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Also check for password field as fallback
|
|
226
|
+
try {
|
|
227
|
+
await page.waitForSelector('input[type="password"]', { timeout: 2_000 });
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Walk through the modular login steps, filling in credentials and TOTP as needed.
|
|
237
|
+
*/
|
|
238
|
+
async authenticate(page) {
|
|
239
|
+
const username = process.env['CW_WEB_USERNAME'] ?? '';
|
|
240
|
+
const password = process.env['CW_WEB_PASSWORD'] ?? '';
|
|
241
|
+
const totpSecret = process.env['CW_TOTP_SECRET'];
|
|
242
|
+
for (const step of DEFAULT_LOGIN_STEPS) {
|
|
243
|
+
let selector;
|
|
244
|
+
try {
|
|
245
|
+
await page.waitForSelector(step.detect, { timeout: step.timeout ?? 4_000 });
|
|
246
|
+
// Find the first matching selector
|
|
247
|
+
const parts = step.detect.split(',').map((s) => s.trim());
|
|
248
|
+
let found = '';
|
|
249
|
+
for (const part of parts) {
|
|
250
|
+
const el = await page.$(part);
|
|
251
|
+
if (el) {
|
|
252
|
+
found = part;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (!found)
|
|
257
|
+
continue;
|
|
258
|
+
selector = found;
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// Step not present on this page — skip
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (step.name === 'credentials') {
|
|
265
|
+
// Fill username into the detected field
|
|
266
|
+
await page.fill(selector, username);
|
|
267
|
+
// Find and fill password field
|
|
268
|
+
const pwField = await page.$('input[type="password"]');
|
|
269
|
+
if (pwField)
|
|
270
|
+
await page.fill('input[type="password"]', password);
|
|
271
|
+
// Submit
|
|
272
|
+
await page.keyboard.press('Enter');
|
|
273
|
+
// Wait briefly for the page to transition
|
|
274
|
+
await page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
275
|
+
}
|
|
276
|
+
else if (step.name === 'totp') {
|
|
277
|
+
if (!totpSecret) {
|
|
278
|
+
throw new Error('CW_TOTP_SECRET is required for TOTP authentication');
|
|
279
|
+
}
|
|
280
|
+
const code = await generateTOTPSafe(totpSecret);
|
|
281
|
+
await page.fill(selector, code);
|
|
282
|
+
await page.keyboard.press('Enter');
|
|
283
|
+
await page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
284
|
+
}
|
|
285
|
+
else if (step.name === 'device_trust') {
|
|
286
|
+
// Click the trust button if present
|
|
287
|
+
const btn = await page.$(selector);
|
|
288
|
+
if (btn) {
|
|
289
|
+
await btn.click();
|
|
290
|
+
await page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
// Page management
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
/**
|
|
299
|
+
* Acquire an authenticated page.
|
|
300
|
+
* Recycles context if needed, ensures auth, waits for semaphore, creates page.
|
|
301
|
+
*/
|
|
302
|
+
async acquirePage() {
|
|
303
|
+
if (!this.initialized)
|
|
304
|
+
await this.init();
|
|
305
|
+
await this.recycleIfNeeded();
|
|
306
|
+
await this.ensureAuth();
|
|
307
|
+
await this.semaphore.acquire();
|
|
308
|
+
const page = await this.context.newPage();
|
|
309
|
+
page.setDefaultTimeout(PAGE_TIMEOUT_MS);
|
|
310
|
+
this.requestCount++;
|
|
311
|
+
return page;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Release a page acquired via acquirePage().
|
|
315
|
+
* Closes the page, releases the semaphore, and cleans the downloads folder.
|
|
316
|
+
*/
|
|
317
|
+
releasePage(page) {
|
|
318
|
+
page.close().catch(() => { });
|
|
319
|
+
this.semaphore.release();
|
|
320
|
+
this.cleanDownloads();
|
|
321
|
+
}
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
// Network capture
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
/**
|
|
326
|
+
* Run `action` while listening for network responses matching `urlPattern`.
|
|
327
|
+
* Resolves with all matched responses once the pattern is satisfied or
|
|
328
|
+
* `timeoutMs` elapses.
|
|
329
|
+
*/
|
|
330
|
+
async captureResponses(page, action, urlPattern, timeoutMs = 15_000) {
|
|
331
|
+
const matched = [];
|
|
332
|
+
const onResponse = (response) => {
|
|
333
|
+
const url = response.url();
|
|
334
|
+
if (typeof urlPattern === 'string'
|
|
335
|
+
? url.includes(urlPattern)
|
|
336
|
+
: urlPattern.test(url)) {
|
|
337
|
+
matched.push(response);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
page.on('response', onResponse);
|
|
341
|
+
try {
|
|
342
|
+
await Promise.race([
|
|
343
|
+
action(),
|
|
344
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('captureResponses timeout')), timeoutMs)),
|
|
345
|
+
]);
|
|
346
|
+
}
|
|
347
|
+
finally {
|
|
348
|
+
page.off('response', onResponse);
|
|
349
|
+
}
|
|
350
|
+
return matched;
|
|
351
|
+
}
|
|
352
|
+
// ---------------------------------------------------------------------------
|
|
353
|
+
// Internal helpers
|
|
354
|
+
// ---------------------------------------------------------------------------
|
|
355
|
+
/** Close the existing context and create a fresh one, restoring storageState if present. */
|
|
356
|
+
async createContext() {
|
|
357
|
+
if (this.context) {
|
|
358
|
+
try {
|
|
359
|
+
await this.context.close();
|
|
360
|
+
}
|
|
361
|
+
catch { /* ignore */ }
|
|
362
|
+
this.context = null;
|
|
363
|
+
}
|
|
364
|
+
const locale = process.env['CW_LOCALE'] ?? 'en-CA';
|
|
365
|
+
const contextOptions = {
|
|
366
|
+
locale,
|
|
367
|
+
acceptDownloads: true,
|
|
368
|
+
};
|
|
369
|
+
if (existsSync(STORAGE_STATE_PATH)) {
|
|
370
|
+
contextOptions['storageState'] = STORAGE_STATE_PATH;
|
|
371
|
+
}
|
|
372
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
373
|
+
this.context = await this.browser.newContext(contextOptions);
|
|
374
|
+
this.contextCreatedAt = Date.now();
|
|
375
|
+
this.requestCount = 0;
|
|
376
|
+
}
|
|
377
|
+
/** Recycle the browser context if it has been used too much or too long. */
|
|
378
|
+
async recycleIfNeeded() {
|
|
379
|
+
const aged = Date.now() - this.contextCreatedAt > CONTEXT_MAX_AGE_MS;
|
|
380
|
+
const overLimit = this.requestCount >= MAX_REQUESTS_BEFORE_RECYCLE;
|
|
381
|
+
if (aged || overLimit) {
|
|
382
|
+
await this.createContext();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/** Register process-level cleanup hooks (once). */
|
|
386
|
+
registerCleanupHooks() {
|
|
387
|
+
if (this.cleanupRegistered)
|
|
388
|
+
return;
|
|
389
|
+
this.cleanupRegistered = true;
|
|
390
|
+
const cleanup = () => {
|
|
391
|
+
this.shutdown().catch(() => { });
|
|
392
|
+
};
|
|
393
|
+
process.once('SIGTERM', cleanup);
|
|
394
|
+
process.once('SIGINT', cleanup);
|
|
395
|
+
process.once('exit', cleanup);
|
|
396
|
+
// Detect stdin close (piped mode — parent process gone)
|
|
397
|
+
if (process.stdin && !process.stdin.destroyed) {
|
|
398
|
+
process.stdin.once('close', cleanup);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/** Delete all files in the downloads directory. */
|
|
402
|
+
cleanDownloads() {
|
|
403
|
+
try {
|
|
404
|
+
if (!existsSync(DOWNLOADS_PATH))
|
|
405
|
+
return;
|
|
406
|
+
const entries = readdirSync(DOWNLOADS_PATH, { withFileTypes: true });
|
|
407
|
+
for (const entry of entries) {
|
|
408
|
+
try {
|
|
409
|
+
rmSync(join(DOWNLOADS_PATH, entry.name), { recursive: true, force: true });
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
// best-effort
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
// ignore
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/** Derive the CW web base URL from CW_API_URL. */
|
|
421
|
+
getCWBase() {
|
|
422
|
+
const apiUrl = process.env['CW_API_URL'] ?? '';
|
|
423
|
+
// Strip the path after the domain+port
|
|
424
|
+
try {
|
|
425
|
+
const parsed = new URL(apiUrl);
|
|
426
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
// Fallback: strip everything after the third slash
|
|
430
|
+
const parts = apiUrl.split('/');
|
|
431
|
+
return parts.slice(0, 3).join('/');
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
//# sourceMappingURL=web-scraper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-scraper.js","sourceRoot":"","sources":["../../src/services/web-scraper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export declare const reportTools: Tool[];
|
|
3
|
+
export declare function handleReportTool(name: string, args: Record<string, unknown>): Promise<{
|
|
4
|
+
content: Array<{
|
|
5
|
+
type: 'text';
|
|
6
|
+
text: string;
|
|
7
|
+
}>;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=reports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../src/tools/reports.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAqB1D,eAAO,MAAM,WAAW,EAAE,IAAI,EAqE7B,CAAC;AAMF,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAW7D"}
|