+57
-1
@@ -29,3 +29,3 @@ /** | ||
| import { listEvents } from './providers.js'; | ||
| import { createWait, listWaits, cancelWait, sessionToken } from './waits.js'; | ||
| import { createWait, listWaits, cancelWait, sessionToken, driftFetch } from './waits.js'; | ||
| import { fetchHistory, replayStored } from './history.js'; | ||
@@ -746,2 +746,58 @@ const { version } = createRequire(import.meta.url)('../package.json'); | ||
| }); | ||
| server.registerTool('schema_drift', { | ||
| title: 'Payload Drift Watch', | ||
| description: 'Payload Drift Watch for a webhook endpoint: OtterKit baselines the JSON shape of arriving ' + | ||
| 'requests per event group (first path segment + a type/event/action discriminator; ~20 ' + | ||
| "samples arm a group), then records findings when a provider's payloads change - " + | ||
| 'new_field, missing_field, type_change, format_change, new_event_type. Findings dedupe ' + | ||
| 'by (group, path, kind) and email the owner (throttled). Actions: status (config + ' + | ||
| 'groups + findings), enable, disable, accept (close a finding - the baseline already ' + | ||
| 'follows reality), ignore (close and mute that path forever), unignore (re-watch paths).', | ||
| inputSchema: { | ||
| subdomain: z.string().describe('A live webhook endpoint'), | ||
| action: z.enum(['status', 'enable', 'disable', 'accept', 'ignore', 'unignore']), | ||
| findingId: z.string().optional().describe('accept/ignore: finding id from status'), | ||
| paths: z | ||
| .array(z.string()) | ||
| .optional() | ||
| .describe('unignore: dot paths to start watching again'), | ||
| token: z | ||
| .string() | ||
| .optional() | ||
| .describe('Session connect token (defaults to a local daemon record)'), | ||
| }, | ||
| }, async (args) => { | ||
| const token = sessionToken(args.subdomain, args.token); | ||
| if (!token) | ||
| return err('no_session_token', { hint: 'pass token from the connectUrl' }); | ||
| try { | ||
| if (args.action === 'status') { | ||
| return ok(await driftFetch(args.subdomain, token)); | ||
| } | ||
| if (args.action === 'enable' || args.action === 'disable') { | ||
| return ok(await driftFetch(args.subdomain, token, { | ||
| method: 'PATCH', | ||
| body: { enabled: args.action === 'enable' }, | ||
| })); | ||
| } | ||
| if (args.action === 'unignore') { | ||
| if (!args.paths?.length) | ||
| return err('paths_required'); | ||
| return ok(await driftFetch(args.subdomain, token, { | ||
| method: 'PATCH', | ||
| body: { unignore: args.paths }, | ||
| })); | ||
| } | ||
| if (!args.findingId) | ||
| return err('finding_id_required'); | ||
| return ok(await driftFetch(args.subdomain, token, { | ||
| method: 'POST', | ||
| path: `/${args.findingId}/resolve`, | ||
| body: { action: args.action }, | ||
| })); | ||
| } | ||
| catch (e) { | ||
| return mapError(e); | ||
| } | ||
| }); | ||
| const transport = new StdioServerTransport(); | ||
@@ -748,0 +804,0 @@ await server.connect(transport); |
+6
-0
@@ -82,2 +82,8 @@ export interface WaitView { | ||
| }): Promise<void>; | ||
| /** Drift Watch agent-API client: GET state, PATCH config, resolve findings. */ | ||
| export declare function driftFetch(subdomain: string, token: string, opts?: { | ||
| method?: string; | ||
| path?: string; | ||
| body?: unknown; | ||
| }): Promise<Record<string, unknown>>; | ||
| export declare function listWaits(subdomain: string, token: string): Promise<WaitView[]>; | ||
@@ -84,0 +90,0 @@ export declare function cancelWait(subdomain: string, token: string, id: string): Promise<void>; |
+13
-0
@@ -80,2 +80,15 @@ /** | ||
| } | ||
| /** Drift Watch agent-API client: GET state, PATCH config, resolve findings. */ | ||
| export async function driftFetch(subdomain, token, opts = {}) { | ||
| const resp = await fetch(`${TUNNEL_SERVER}/api/agent/tunnels/${subdomain}/drift${opts.path ?? ''}?token=${encodeURIComponent(token)}`, { | ||
| method: opts.method ?? 'GET', | ||
| headers: opts.body ? { 'Content-Type': 'application/json' } : undefined, | ||
| body: opts.body ? JSON.stringify(opts.body) : undefined, | ||
| }); | ||
| const data = (await resp.json().catch(() => ({}))); | ||
| if (!resp.ok) { | ||
| throw new WaitError(data.error || `drift request failed (${resp.status})`, resp.status); | ||
| } | ||
| return data; | ||
| } | ||
| export async function listWaits(subdomain, token) { | ||
@@ -82,0 +95,0 @@ const data = (await waitFetch(subdomain, token, '')); |
+1
-1
| { | ||
| "name": "otterkit", | ||
| "version": "0.44.0", | ||
| "version": "0.45.0", | ||
| "description": "OtterKit CLI - provision and connect tunnels for AI agents", | ||
@@ -5,0 +5,0 @@ "mcpName": "io.github.useotterkit/otterkit", |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
300784
1.58%6947
1.4%27
3.85%