archer-wizard 0.1.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.
Files changed (59) hide show
  1. package/.env.example +6 -0
  2. package/README.md +140 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +77 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/ascii.d.ts +14 -0
  8. package/dist/lib/ascii.d.ts.map +1 -0
  9. package/dist/lib/ascii.js +88 -0
  10. package/dist/lib/ascii.js.map +1 -0
  11. package/dist/lib/supabase.d.ts +7 -0
  12. package/dist/lib/supabase.d.ts.map +1 -0
  13. package/dist/lib/supabase.js +54 -0
  14. package/dist/lib/supabase.js.map +1 -0
  15. package/dist/lib/webhook.d.ts +4 -0
  16. package/dist/lib/webhook.d.ts.map +1 -0
  17. package/dist/lib/webhook.js +53 -0
  18. package/dist/lib/webhook.js.map +1 -0
  19. package/dist/tools/watch.d.ts +35 -0
  20. package/dist/tools/watch.d.ts.map +1 -0
  21. package/dist/tools/watch.js +178 -0
  22. package/dist/tools/watch.js.map +1 -0
  23. package/dist/types/index.d.ts +84 -0
  24. package/dist/types/index.d.ts.map +1 -0
  25. package/dist/types/index.js +24 -0
  26. package/dist/types/index.js.map +1 -0
  27. package/dist/wizard/detector.d.ts +5 -0
  28. package/dist/wizard/detector.d.ts.map +1 -0
  29. package/dist/wizard/detector.js +125 -0
  30. package/dist/wizard/detector.js.map +1 -0
  31. package/dist/wizard/index.d.ts +2 -0
  32. package/dist/wizard/index.d.ts.map +1 -0
  33. package/dist/wizard/index.js +50 -0
  34. package/dist/wizard/index.js.map +1 -0
  35. package/dist/wizard/injector.d.ts +3 -0
  36. package/dist/wizard/injector.d.ts.map +1 -0
  37. package/dist/wizard/injector.js +91 -0
  38. package/dist/wizard/injector.js.map +1 -0
  39. package/dist/wizard/rules.d.ts +3 -0
  40. package/dist/wizard/rules.d.ts.map +1 -0
  41. package/dist/wizard/rules.js +94 -0
  42. package/dist/wizard/rules.js.map +1 -0
  43. package/dist/wizard/scanner.d.ts +7 -0
  44. package/dist/wizard/scanner.d.ts.map +1 -0
  45. package/dist/wizard/scanner.js +201 -0
  46. package/dist/wizard/scanner.js.map +1 -0
  47. package/package.json +28 -0
  48. package/src/index.ts +90 -0
  49. package/src/lib/ascii.ts +109 -0
  50. package/src/lib/supabase.ts +78 -0
  51. package/src/lib/webhook.ts +69 -0
  52. package/src/tools/watch.ts +223 -0
  53. package/src/types/index.ts +120 -0
  54. package/src/wizard/detector.ts +151 -0
  55. package/src/wizard/index.ts +69 -0
  56. package/src/wizard/injector.ts +115 -0
  57. package/src/wizard/rules.ts +112 -0
  58. package/src/wizard/scanner.ts +250 -0
  59. package/tsconfig.json +20 -0
package/.env.example ADDED
@@ -0,0 +1,6 @@
1
+ # Archer — event intelligence for AI agents
2
+ # Copy this to .env and fill in your Supabase credentials
3
+
4
+ SUPABASE_URL=https://your-project.supabase.co
5
+ SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
6
+ SUPABASE_ANON_KEY=your-anon-key
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # 🏹 Archer
2
+
3
+ **Event intelligence for AI agents.** One command connects your backend to Cursor, Claude Code, Windsurf, and any MCP-compatible agent.
4
+
5
+ ```
6
+ npx archer
7
+ ```
8
+
9
+ ## What it does
10
+
11
+ Archer gives your AI agent a `watch` tool. The agent can monitor real-time events from your backend — database changes, auth events, webhooks — and react when conditions match.
12
+
13
+ ```
14
+ "Watch my users table for new signups from @company.com"
15
+ ```
16
+
17
+ → Archer subscribes to the event, filters by condition, and POSTs to your webhook URL.
18
+
19
+ ## Supported Sources
20
+
21
+ | Source | Events | Status |
22
+ |--------|--------|--------|
23
+ | **Supabase** | `auth.signup`, `table.insert`, `table.update`, `table.delete` | ✅ Available |
24
+ | **Firebase** | Auth, Firestore, Realtime DB | 🔜 Coming soon |
25
+ | **Stripe** | Payments, subscriptions, invoices | 🔜 Coming soon |
26
+ | **GitHub** | Push, PR, issues, deployments | 🔜 Coming soon |
27
+ | **Custom Webhooks** | Any incoming webhook | 🔜 Coming soon |
28
+
29
+ > Want a source added? [Open an issue →](https://github.com/archer-mcp/archer/issues)
30
+
31
+ ## Setup
32
+
33
+ ```bash
34
+ npx archer
35
+ ```
36
+
37
+ The interactive wizard will:
38
+
39
+ 1. **Scan** your project for credentials (`.env`, `.env.local`, etc.)
40
+ 2. **Detect** installed AI agents (Cursor, Claude Code, Windsurf, etc.)
41
+ 3. **Inject** the Archer MCP server into each agent's config
42
+ 4. **Write** agent rules so the LLM knows how to use the tool
43
+
44
+ ## Supported Agents
45
+
46
+ | Agent | Config Path | Status |
47
+ |-------|------------|--------|
48
+ | Cursor | `~/.cursor/mcp.json` | ✅ |
49
+ | Claude Code | Platform-specific | ✅ |
50
+ | Windsurf | `~/.codeium/windsurf/mcp_config.json` | ✅ |
51
+ | OpenCode | `~/.config/opencode/config.json` | ✅ |
52
+
53
+ ## The `archer_watch` Tool
54
+
55
+ ### Parameters
56
+
57
+ | Parameter | Type | Required | Description |
58
+ |-----------|------|----------|-------------|
59
+ | `source` | `string` | Yes | Event source (`"supabase"`, more coming) |
60
+ | `event` | `string` | Yes | Event type (source-specific) |
61
+ | `table` | `string` | Depends | Resource name (e.g. table for Supabase) |
62
+ | `condition` | `string` | No | Filter like `"email ends with @gmail.com"` |
63
+ | `webhookUrl` | `string` | Yes | URL to receive POST notifications |
64
+
65
+ ### Condition Operators
66
+
67
+ - `ends with` — `"email ends with @company.com"`
68
+ - `starts with` — `"name starts with John"`
69
+ - `contains` — `"status contains active"`
70
+ - `equals` — `"role equals admin"`
71
+
72
+ ### Example: Supabase
73
+
74
+ ```json
75
+ {
76
+ "source": "supabase",
77
+ "event": "auth.signup",
78
+ "webhookUrl": "https://hooks.example.com/signups"
79
+ }
80
+ ```
81
+
82
+ ```json
83
+ {
84
+ "source": "supabase",
85
+ "event": "table.insert",
86
+ "table": "orders",
87
+ "condition": "total equals 0",
88
+ "webhookUrl": "https://hooks.example.com/free-orders"
89
+ }
90
+ ```
91
+
92
+ ### Webhook Payload
93
+
94
+ Every webhook POST follows the same envelope format, regardless of source:
95
+
96
+ ```json
97
+ {
98
+ "archer": {
99
+ "watchId": "watch_a1b2c3d4",
100
+ "event": "table.insert",
101
+ "source": "supabase",
102
+ "firedAt": "2025-01-15T10:30:00.000Z"
103
+ },
104
+ "data": { ... }
105
+ }
106
+ ```
107
+
108
+ ## Architecture
109
+
110
+ ```
111
+ npx archer → Interactive wizard (scan, detect, inject, configure)
112
+ npx archer --mcp → MCP server mode (stdio transport, used by agents)
113
+ ```
114
+
115
+ The wizard injects this into each agent's config:
116
+
117
+ ```json
118
+ {
119
+ "mcpServers": {
120
+ "archer": {
121
+ "command": "npx",
122
+ "args": ["-y", "archer", "--mcp"],
123
+ "env": {
124
+ "SUPABASE_URL": "...",
125
+ "SUPABASE_SERVICE_ROLE_KEY": "..."
126
+ }
127
+ }
128
+ }
129
+ }
130
+ ```
131
+
132
+ ## Requirements
133
+
134
+ - Node.js 18+
135
+ - At least one supported AI agent installed
136
+ - Credentials for your event source (e.g. Supabase URL + service role key)
137
+
138
+ ## License
139
+
140
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ // ─── Mode Detection ─────────────────────────────────────────
4
+ const isMcpMode = process.argv.includes('--mcp');
5
+ if (isMcpMode) {
6
+ // ─── MCP Server Mode ─────────────────────────────────────
7
+ const { Server } = await import('@modelcontextprotocol/sdk/server/index.js');
8
+ const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');
9
+ const { CallToolRequestSchema, ListToolsRequestSchema, } = await import('@modelcontextprotocol/sdk/types.js');
10
+ const { executeWatch, WATCH_TOOL_SCHEMA } = await import('./tools/watch.js');
11
+ const { stderrReady, stderrError } = await import('./lib/ascii.js');
12
+ const server = new Server({
13
+ name: 'archer',
14
+ version: '0.1.0',
15
+ }, {
16
+ capabilities: {
17
+ tools: {},
18
+ },
19
+ });
20
+ // Register tool listing
21
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
22
+ return {
23
+ tools: [WATCH_TOOL_SCHEMA],
24
+ };
25
+ });
26
+ // Register tool execution
27
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
28
+ const { name, arguments: args } = request.params;
29
+ if (name === 'archer_watch') {
30
+ const result = executeWatch(args);
31
+ return {
32
+ content: [
33
+ {
34
+ type: 'text',
35
+ text: JSON.stringify(result, null, 2),
36
+ },
37
+ ],
38
+ };
39
+ }
40
+ return {
41
+ content: [
42
+ {
43
+ type: 'text',
44
+ text: JSON.stringify({ error: `unknown tool: ${name}` }),
45
+ },
46
+ ],
47
+ isError: true,
48
+ };
49
+ });
50
+ // Start server
51
+ try {
52
+ const transport = new StdioServerTransport();
53
+ await server.connect(transport);
54
+ stderrReady('archer MCP server running on stdio');
55
+ }
56
+ catch (err) {
57
+ const message = err instanceof Error ? err.message : String(err);
58
+ stderrError(`failed to start MCP server: ${message}`);
59
+ process.exit(1);
60
+ }
61
+ }
62
+ else {
63
+ // ─── Wizard Mode ─────────────────────────────────────────
64
+ const { runWizard } = await import('./wizard/index.js');
65
+ try {
66
+ await runWizard();
67
+ }
68
+ catch (err) {
69
+ if (err instanceof Error && err.message.includes('cancel')) {
70
+ console.log('\n cancelled.\n');
71
+ process.exit(0);
72
+ }
73
+ console.error(err);
74
+ process.exit(1);
75
+ }
76
+ }
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare function showAsciiArt(): void;
2
+ export declare function logAction(message: string): void;
3
+ export declare function logSuccess(message: string): void;
4
+ export declare function logError(message: string): void;
5
+ export declare function logProgress(message: string): void;
6
+ export declare function logReady(message: string): void;
7
+ export declare function maskCredential(value: string): string;
8
+ export declare function showSuccessBox(agentCount: number): void;
9
+ export declare function stderrLog(message: string): void;
10
+ export declare function stderrAction(message: string): void;
11
+ export declare function stderrSuccess(message: string): void;
12
+ export declare function stderrError(message: string): void;
13
+ export declare function stderrReady(message: string): void;
14
+ //# sourceMappingURL=ascii.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ascii.d.ts","sourceRoot":"","sources":["../../src/lib/ascii.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,IAAI,IAAI,CA0BnC;AAID,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE9C;AAID,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKpD;AAID,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAqBvD;AAID,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEjD"}
@@ -0,0 +1,88 @@
1
+ import pc from 'picocolors';
2
+ // ─── ASCII Art ──────────────────────────────────────────────
3
+ export function showAsciiArt() {
4
+ const lines = [
5
+ '█████╗ ██████╗ ██████╗██╗ ██╗███████╗██████╗ ',
6
+ '██╔══██╗██╔══██╗██╔════╝██║ ██║██╔════╝██╔══██╗',
7
+ '███████║██████╔╝██║ ███████║█████╗ ██████╔╝',
8
+ '██╔══██║██╔══██╗██║ ██╔══██║██╔══╝ ██╔══██╗',
9
+ '██║ ██║██║ ██║╚██████╗██║ ██║███████╗██║ ██║',
10
+ '╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝',
11
+ ];
12
+ // Column boundaries for coloring:
13
+ // A: cols 0-5, R: 6-13, C: 14-21, H: 22-29, E: 30-37, R: 38-45
14
+ // ARCH = white, ER = green
15
+ const archEnd = 30; // columns 0-29 are A R C H
16
+ const erEnd = 46; // columns 30-45 are E R
17
+ for (const line of lines) {
18
+ const archPart = line.slice(0, archEnd);
19
+ const erPart = line.slice(archEnd, erEnd);
20
+ const rest = line.slice(erEnd);
21
+ process.stdout.write(pc.white(archPart) + pc.green(erPart) + rest + '\n');
22
+ }
23
+ console.log();
24
+ console.log(pc.dim(' v0.1.0 · event intelligence for AI agents'));
25
+ console.log();
26
+ }
27
+ // ─── Status Logger ──────────────────────────────────────────
28
+ export function logAction(message) {
29
+ console.log(`${pc.blue('◆')} ${message}`);
30
+ }
31
+ export function logSuccess(message) {
32
+ console.log(`${pc.green('✓')} ${message}`);
33
+ }
34
+ export function logError(message) {
35
+ console.log(`${pc.red('✗')} ${message}`);
36
+ }
37
+ export function logProgress(message) {
38
+ console.log(`${pc.white('●')} ${message}`);
39
+ }
40
+ export function logReady(message) {
41
+ console.log(`${pc.green('▶')} ${message}`);
42
+ }
43
+ // ─── Credential Masking ─────────────────────────────────────
44
+ export function maskCredential(value) {
45
+ if (value.length <= 8) {
46
+ return value.slice(0, 3) + '******';
47
+ }
48
+ return value.slice(0, 8) + '******';
49
+ }
50
+ // ─── Success Box ────────────────────────────────────────────
51
+ export function showSuccessBox(agentCount) {
52
+ const lines = [
53
+ '',
54
+ ` ${pc.green('▶')} Archer is ready`,
55
+ '',
56
+ ` injected into ${agentCount} agent${agentCount !== 1 ? 's' : ''}`,
57
+ ' connected to your Supabase project',
58
+ '',
59
+ ' open your AI agent and say:',
60
+ ` ${pc.dim('"watch my users table for new signups"')}`,
61
+ '',
62
+ ];
63
+ const maxLen = 46;
64
+ console.log(` ┌${'─'.repeat(maxLen)}┐`);
65
+ for (const line of lines) {
66
+ const stripped = line.replace(/\x1b\[[0-9;]*m/g, '');
67
+ const padding = maxLen - stripped.length;
68
+ console.log(` │${line}${' '.repeat(Math.max(0, padding))}│`);
69
+ }
70
+ console.log(` └${'─'.repeat(maxLen)}┘`);
71
+ }
72
+ // ─── Stderr Logger (for MCP mode) ───────────────────────────
73
+ export function stderrLog(message) {
74
+ process.stderr.write(`${message}\n`);
75
+ }
76
+ export function stderrAction(message) {
77
+ process.stderr.write(`${pc.blue('◆')} ${message}\n`);
78
+ }
79
+ export function stderrSuccess(message) {
80
+ process.stderr.write(`${pc.green('✓')} ${message}\n`);
81
+ }
82
+ export function stderrError(message) {
83
+ process.stderr.write(`${pc.red('✗')} ${message}\n`);
84
+ }
85
+ export function stderrReady(message) {
86
+ process.stderr.write(`${pc.green('▶')} ${message}\n`);
87
+ }
88
+ //# sourceMappingURL=ascii.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ascii.js","sourceRoot":"","sources":["../../src/lib/ascii.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type SupabaseClient, type RealtimeChannel } from '@supabase/supabase-js';
2
+ import type { PostgresEvent } from '../types/index.js';
3
+ export declare function getSupabaseClient(): SupabaseClient;
4
+ export declare function createAuthChannel(channelName: string, onEvent: (payload: Record<string, unknown>) => void): RealtimeChannel;
5
+ export declare function createTableChannel(channelName: string, table: string, event: PostgresEvent, onEvent: (payload: Record<string, unknown>) => void): RealtimeChannel;
6
+ export declare function removeChannel(channel: RealtimeChannel): Promise<void>;
7
+ //# sourceMappingURL=supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEhG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAiBvD,wBAAgB,iBAAiB,IAAI,cAAc,CAclD;AAID,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAClD,eAAe,CAWjB;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAClD,eAAe,CAYjB;AAID,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E"}
@@ -0,0 +1,54 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+ import { stderrError } from './ascii.js';
3
+ // ─── Env Validation ─────────────────────────────────────────
4
+ function getEnvVar(name) {
5
+ const value = process.env[name];
6
+ if (!value) {
7
+ stderrError(`missing required env var: ${name}`);
8
+ throw new Error(`Missing env var: ${name}`);
9
+ }
10
+ return value;
11
+ }
12
+ // ─── Supabase Client ────────────────────────────────────────
13
+ let _client = null;
14
+ export function getSupabaseClient() {
15
+ if (_client)
16
+ return _client;
17
+ const url = getEnvVar('SUPABASE_URL');
18
+ const key = getEnvVar('SUPABASE_SERVICE_ROLE_KEY');
19
+ _client = createClient(url, key, {
20
+ auth: {
21
+ autoRefreshToken: false,
22
+ persistSession: false,
23
+ },
24
+ });
25
+ return _client;
26
+ }
27
+ // ─── Realtime Channel Helpers ───────────────────────────────
28
+ export function createAuthChannel(channelName, onEvent) {
29
+ const client = getSupabaseClient();
30
+ const channel = client
31
+ .channel(channelName)
32
+ .on('postgres_changes', { event: 'INSERT', schema: 'auth', table: 'users' }, (payload) => {
33
+ onEvent(payload.new);
34
+ })
35
+ .subscribe();
36
+ return channel;
37
+ }
38
+ export function createTableChannel(channelName, table, event, onEvent) {
39
+ const client = getSupabaseClient();
40
+ const channel = client
41
+ .channel(channelName)
42
+ .on('postgres_changes', { event, schema: 'public', table }, (payload) => {
43
+ const data = event === 'DELETE' ? payload.old : payload.new;
44
+ onEvent(data);
45
+ })
46
+ .subscribe();
47
+ return channel;
48
+ }
49
+ // ─── Cleanup ────────────────────────────────────────────────
50
+ export async function removeChannel(channel) {
51
+ const client = getSupabaseClient();
52
+ await client.removeChannel(channel);
53
+ }
54
+ //# sourceMappingURL=supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,+DAA+D;AAE/D,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,WAAW,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+DAA+D;AAE/D,IAAI,OAAO,GAA0B,IAAI,CAAC;AAE1C,MAAM,UAAU,iBAAiB;IAC/B,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAE5B,MAAM,GAAG,GAAG,SAAS,CAAC,cAAc,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAEnD,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE;QAC/B,IAAI,EAAE;YACJ,gBAAgB,EAAE,KAAK;YACvB,cAAc,EAAE,KAAK;SACtB;KACF,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+DAA+D;AAE/D,MAAM,UAAU,iBAAiB,CAC/B,WAAmB,EACnB,OAAmD;IAEnD,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IAEnC,MAAM,OAAO,GAAG,MAAM;SACnB,OAAO,CAAC,WAAW,CAAC;SACpB,EAAE,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE;QACvF,OAAO,CAAC,OAAO,CAAC,GAA8B,CAAC,CAAC;IAClD,CAAC,CAAC;SACD,SAAS,EAAE,CAAC;IAEf,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,KAAa,EACb,KAAoB,EACpB,OAAmD;IAEnD,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IAEnC,MAAM,OAAO,GAAG,MAAM;SACnB,OAAO,CAAC,WAAW,CAAC;SACpB,EAAE,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE;QACtE,MAAM,IAAI,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;QAC5D,OAAO,CAAC,IAA+B,CAAC,CAAC;IAC3C,CAAC,CAAC;SACD,SAAS,EAAE,CAAC;IAEf,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+DAA+D;AAE/D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAwB;IAC1D,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;IACnC,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { WebhookOptions, WebhookPayload } from '../types/index.js';
2
+ export declare function fireWebhook(options: WebhookOptions): Promise<boolean>;
3
+ export declare function buildWebhookPayload(watchId: string, event: string, data: Record<string, unknown>): WebhookPayload;
4
+ //# sourceMappingURL=webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/lib/webhook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAaxE,wBAAsB,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAoC3E;AAID,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,cAAc,CAUhB"}
@@ -0,0 +1,53 @@
1
+ import { stderrAction, stderrSuccess, stderrError } from './ascii.js';
2
+ // ─── Retry Config ───────────────────────────────────────────
3
+ const MAX_RETRIES = 3;
4
+ const RETRY_DELAY_MS = 2000;
5
+ function sleep(ms) {
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
7
+ }
8
+ // ─── Fire Webhook ───────────────────────────────────────────
9
+ export async function fireWebhook(options) {
10
+ const { url, payload, event } = options;
11
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
12
+ try {
13
+ stderrAction(`webhook → ${url} (attempt ${attempt}/${MAX_RETRIES})`);
14
+ const response = await fetch(url, {
15
+ method: 'POST',
16
+ headers: {
17
+ 'Content-Type': 'application/json',
18
+ 'User-Agent': 'Archer/0.1.0',
19
+ 'X-Archer-Event': event,
20
+ },
21
+ body: JSON.stringify(payload),
22
+ });
23
+ if (response.ok) {
24
+ stderrSuccess(`webhook delivered → ${response.status}`);
25
+ return true;
26
+ }
27
+ stderrError(`webhook failed → ${response.status} ${response.statusText}`);
28
+ }
29
+ catch (err) {
30
+ const message = err instanceof Error ? err.message : String(err);
31
+ stderrError(`webhook error → ${message}`);
32
+ }
33
+ if (attempt < MAX_RETRIES) {
34
+ stderrAction(`retrying in ${RETRY_DELAY_MS / 1000}s...`);
35
+ await sleep(RETRY_DELAY_MS);
36
+ }
37
+ }
38
+ stderrError(`webhook exhausted all ${MAX_RETRIES} retries`);
39
+ return false;
40
+ }
41
+ // ─── Build Payload ──────────────────────────────────────────
42
+ export function buildWebhookPayload(watchId, event, data) {
43
+ return {
44
+ archer: {
45
+ watchId,
46
+ event,
47
+ source: 'supabase',
48
+ firedAt: new Date().toISOString(),
49
+ },
50
+ data,
51
+ };
52
+ }
53
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/lib/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGtE,+DAA+D;AAE/D,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,+DAA+D;AAE/D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAuB;IACvD,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAExC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,YAAY,CAAC,aAAa,GAAG,aAAa,OAAO,IAAI,WAAW,GAAG,CAAC,CAAC;YAErE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,YAAY,EAAE,cAAc;oBAC5B,gBAAgB,EAAE,KAAK;iBACxB;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAC9B,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAChB,aAAa,CAAC,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBACxD,OAAO,IAAI,CAAC;YACd,CAAC;YAED,WAAW,CAAC,oBAAoB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,WAAW,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;YAC1B,YAAY,CAAC,eAAe,cAAc,GAAG,IAAI,MAAM,CAAC,CAAC;YACzD,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,WAAW,CAAC,yBAAyB,WAAW,UAAU,CAAC,CAAC;IAC5D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+DAA+D;AAE/D,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,KAAa,EACb,IAA6B;IAE7B,OAAO;QACL,MAAM,EAAE;YACN,OAAO;YACP,KAAK;YACL,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAClC;QACD,IAAI;KACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { type WatchResult } from '../types/index.js';
2
+ export declare function executeWatch(rawInput: unknown): WatchResult;
3
+ export declare const WATCH_TOOL_SCHEMA: {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: {
7
+ type: "object";
8
+ properties: {
9
+ source: {
10
+ type: "string";
11
+ enum: string[];
12
+ description: string;
13
+ };
14
+ event: {
15
+ type: "string";
16
+ enum: string[];
17
+ description: string;
18
+ };
19
+ table: {
20
+ type: "string";
21
+ description: string;
22
+ };
23
+ condition: {
24
+ type: "string";
25
+ description: string;
26
+ };
27
+ webhookUrl: {
28
+ type: "string";
29
+ description: string;
30
+ };
31
+ };
32
+ required: string[];
33
+ };
34
+ };
35
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/tools/watch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqC,KAAK,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AAmG5G,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,WAAW,CAoF3D;AAID,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiC7B,CAAC"}