archer-wizard 0.2.0 → 0.2.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.
@@ -6,16 +6,32 @@ import { logSuccess, logError, logAction } from '../lib/ascii.js';
6
6
  import { getConfigKey } from './detector.js';
7
7
  import type { AgentInfo, InjectionResult, McpServerEntry } from '../types/index.js';
8
8
 
9
- // ─── Archer MCP Entry ───────────────────────────────────────
9
+ // ─── Archer MCP Entry (agent-aware) ─────────────────────────
10
10
 
11
- function buildArcherEntry(supabaseUrl: string, serviceRoleKey: string): McpServerEntry {
11
+ function buildArcherEntry(
12
+ agentName: string,
13
+ supabaseUrl: string,
14
+ serviceRoleKey: string,
15
+ ): McpServerEntry {
16
+ const envVars = {
17
+ SUPABASE_URL: supabaseUrl,
18
+ SUPABASE_SERVICE_ROLE_KEY: serviceRoleKey,
19
+ };
20
+
21
+ // opencode uses { type, command[], environment }
22
+ if (agentName === 'opencode') {
23
+ return {
24
+ type: 'local',
25
+ command: ['npx', '-y', 'archer-wizard@latest', '--mcp'],
26
+ environment: envVars,
27
+ };
28
+ }
29
+
30
+ // cursor, claude-code, windsurf, antigravity use { command, args, env }
12
31
  return {
13
32
  command: 'npx',
14
33
  args: ['-y', 'archer-wizard@latest', '--mcp'],
15
- env: {
16
- SUPABASE_URL: supabaseUrl,
17
- SUPABASE_SERVICE_ROLE_KEY: serviceRoleKey,
18
- },
34
+ env: envVars,
19
35
  };
20
36
  }
21
37
 
@@ -51,7 +67,7 @@ function injectIntoAgent(
51
67
  try {
52
68
  const configKey = getConfigKey(agent.name);
53
69
  const config = readConfig(agent.configPath);
54
- const archerEntry = buildArcherEntry(supabaseUrl, serviceRoleKey);
70
+ const archerEntry = buildArcherEntry(agent.name, supabaseUrl, serviceRoleKey);
55
71
 
56
72
  // Ensure the config key object exists
57
73
  if (!config[configKey] || typeof config[configKey] !== 'object') {
@@ -9,53 +9,75 @@ import type { AgentInfo } from '../types/index.js';
9
9
  const RULE_CONTENT = `
10
10
  # Archer — Event Intelligence for AI Agents
11
11
 
12
- Archer is the event intelligence layer for AI agents. It connects to your data sources (Supabase, GitHub, Stripe, Linear, etc.), watches for conditions you define in plain english, and fires your AI agent the moment those conditions are true, with full context already loaded.
12
+ Archer is the universal event intelligence layer for AI agents. It watches your data sources in real time, detects changes the moment they happen, and delivers full context to your webhook so your agent can react instantly, without polling.
13
13
 
14
- ## Available Tool: archer.watch
14
+ ## Available MCP Tools
15
15
 
16
- You can watch real-time events from data sources using the \`archer.watch\` MCP tool.
16
+ ### archer_watch
17
+ Create a persistent real-time watch on a data source. Watches survive agent session restarts.
17
18
 
18
- ### When to Use Archer
19
+ **Parameters:**
20
+ - **table** *(required)* — name of the table or resource to watch
21
+ - **event** — type of change: \`INSERT\`, \`UPDATE\`, \`DELETE\`, or \`*\` (all). Default: \`*\`
22
+ - **filter** — optional filter expression, e.g. \`"status=eq.active"\` or \`"amount=gt.1000"\`
23
+ - **webhookUrl** — URL to receive a POST with full event payload when a match fires
19
24
 
20
- Use Archer whenever you need to:
21
- - Monitor database changes (inserts, updates, deletes)
22
- - Watch for new user signups
23
- - React to events in external services
24
- - Automate responses to data changes
25
- - Set up real-time notifications
25
+ ### archer_unwatch
26
+ Remove an active watch by its ID. Stops listening and cleans up.
26
27
 
27
- ### Parameters
28
+ **Parameters:**
29
+ - **watchId** *(required)* — the watch ID returned by \`archer_watch\`
28
30
 
29
- - **source**: data source (currently \`"supabase"\`)
30
- - **event**: one of \`"auth.signup"\`, \`"table.insert"\`, \`"table.update"\`, \`"table.delete"\`
31
- - **table**: the table name (required for table events)
32
- - **condition**: optional filter like \`"email ends with @gmail.com"\`
33
- - **webhookUrl**: URL to receive POST notifications when events match
31
+ ### archer_watches
32
+ List all active watches their IDs, tables, events, filters, and webhook URLs.
34
33
 
35
- ### Examples
34
+ ## When to Use Archer
36
35
 
37
- 1. Watch for new user signups:
36
+ Use Archer any time the user wants to:
37
+ - **Monitor data changes** — new rows, updates, deletions in any table
38
+ - **React to events** — trigger automations when conditions are met
39
+ - **Set up alerts** — notify on signups, new orders, status changes, threshold breaches
40
+ - **Build event-driven workflows** — chain watches with webhooks for real-time pipelines
41
+ - **Track activity** — audit logs, user actions, system events
42
+
43
+ ## Examples
44
+
45
+ 1. Watch for new rows in a table:
46
+ \`\`\`
47
+ archer_watch({ table: "users", event: "INSERT", webhookUrl: "https://hooks.example.com/new-users" })
48
+ \`\`\`
49
+
50
+ 2. Watch for updates with a filter:
38
51
  \`\`\`
39
- archer.watch({ source: "supabase", event: "auth.signup", webhookUrl: "https://hooks.example.com/signups" })
52
+ archer_watch({ table: "orders", event: "UPDATE", filter: "status=eq.shipped", webhookUrl: "https://hooks.example.com/shipped" })
40
53
  \`\`\`
41
54
 
42
- 2. Watch for inserts to the orders table:
55
+ 3. Watch all changes on a table:
43
56
  \`\`\`
44
- archer.watch({ source: "supabase", event: "table.insert", table: "orders", webhookUrl: "https://hooks.example.com/orders" })
57
+ archer_watch({ table: "payments", webhookUrl: "https://hooks.example.com/payments" })
45
58
  \`\`\`
46
59
 
47
- 3. Watch with a condition:
60
+ 4. List active watches:
48
61
  \`\`\`
49
- archer.watch({ source: "supabase", event: "table.insert", table: "users", condition: "email ends with @company.com", webhookUrl: "https://hooks.example.com/vip" })
62
+ archer_watches()
50
63
  \`\`\`
51
64
 
52
- ### Best Practices
65
+ 5. Stop a watch:
66
+ \`\`\`
67
+ archer_unwatch({ watchId: "abc-123" })
68
+ \`\`\`
69
+
70
+ ## Best Practices
71
+
72
+ - Add filters to reduce noise — only fire on events that matter
73
+ - Use descriptive webhook URLs that map to specific actions
74
+ - Chain multiple watches for complex event-driven workflows
75
+ - Use \`archer_watches\` to inspect and manage active watchers
76
+ - Clean up watches you no longer need with \`archer_unwatch\`
53
77
 
54
- - Use descriptive webhook URLs that indicate the action to take
55
- - Add conditions to filter events and reduce noise
56
- - Combine with your existing workflows for maximum impact
78
+ ## Trigger Words
57
79
 
58
- When the user asks to "watch", "monitor", "notify", or "fire" something, use Archer.
80
+ When the user says **"watch"**, **"monitor"**, **"notify me"**, **"alert me"**, **"track"**, **"listen for"**, or **"fire when"** use Archer.
59
81
  `.trim();
60
82
 
61
83
  // ─── Archer Block Markers ───────────────────────────────────
@@ -2,7 +2,6 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import * as clack from '@clack/prompts';
4
4
  import { z } from 'zod';
5
- import { logSuccess, logError, maskCredential } from '../lib/ascii.js';
6
5
  import type { ScanResult, Framework } from '../types/index.js';
7
6
 
8
7
  // Helper to search for keys in files
@@ -236,28 +235,6 @@ export async function scanProject(cwd: string): Promise<ScanResult> {
236
235
 
237
236
  const { framework, hasSupabaseInstalled } = detectFramework(cwd);
238
237
 
239
- // Log found credentials
240
- if (supabaseUrl) {
241
- logSuccess(`SUPABASE_URL = ${maskCredential(supabaseUrl)}`);
242
- } else {
243
- logError('missing SUPABASE_URL');
244
- }
245
-
246
- if (serviceRoleKey) {
247
- logSuccess(`SUPABASE_SERVICE_ROLE_KEY = ${maskCredential(serviceRoleKey)}`);
248
- } else {
249
- logError('missing SUPABASE_SERVICE_ROLE_KEY');
250
- }
251
-
252
- if (anonKey) {
253
- logSuccess(`SUPABASE_ANON_KEY = ${maskCredential(anonKey)}`);
254
- }
255
-
256
- if (foundInFile) {
257
- logSuccess(`found credentials in ${foundInFile}`);
258
- } else if (codebaseResults.size > 0) {
259
- logSuccess(`found credentials in codebase`);
260
- }
261
238
 
262
239
  return {
263
240
  supabaseUrl,