archer-wizard 0.2.5 → 0.2.6
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/ARCHITECTURE.md +6 -6
- package/README.md +1 -1
- package/dist/daemon/process.d.ts.map +1 -1
- package/dist/daemon/process.js +39 -11
- package/dist/daemon/process.js.map +1 -1
- package/package.json +1 -1
- package/src/daemon/process.ts +48 -11
package/ARCHITECTURE.md
CHANGED
|
@@ -11,7 +11,7 @@ graph TB
|
|
|
11
11
|
subgraph "User's Machine"
|
|
12
12
|
CLI["npx archer-wizard<br/>(wizard mode)"]
|
|
13
13
|
MCP["MCP Server<br/>(--mcp mode)"]
|
|
14
|
-
Daemon["Daemon Process<br/>(detached, TCP :
|
|
14
|
+
Daemon["Daemon Process<br/>(detached, TCP :7481)"]
|
|
15
15
|
State["~/.archer/state.json"]
|
|
16
16
|
PID["~/.archer/daemon.pid"]
|
|
17
17
|
end
|
|
@@ -61,7 +61,7 @@ The daemon is the heart of Archer — a **detached Node.js process** that holds
|
|
|
61
61
|
|
|
62
62
|
### IPC Protocol — [types.ts](file:///Users/amirlankalmukhan/archer-mcp/src/daemon/types.ts)
|
|
63
63
|
|
|
64
|
-
Defines JSON-over-TCP protocol on `127.0.0.1:
|
|
64
|
+
Defines JSON-over-TCP protocol on `127.0.0.1:7481`:
|
|
65
65
|
|
|
66
66
|
```typescript
|
|
67
67
|
// Request types (MCP → Daemon)
|
|
@@ -96,7 +96,7 @@ The main daemon loop (~190 lines). On startup:
|
|
|
96
96
|
|
|
97
97
|
1. Loads persisted state from `state.json`
|
|
98
98
|
2. **Reconnects all saved watches** — for each `WatchConfig`, creates a Supabase client + Realtime channel
|
|
99
|
-
3. Starts TCP server on port `
|
|
99
|
+
3. Starts TCP server on port `7481`
|
|
100
100
|
|
|
101
101
|
**IPC request handling:**
|
|
102
102
|
|
|
@@ -122,7 +122,7 @@ Used by MCP tools to talk to the daemon:
|
|
|
122
122
|
Tool → sendIpcRequest() → TCP connect → JSON write → read response → parse
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
- `connectToDaemon()` — creates a `net.Socket`, connects to `127.0.0.1:
|
|
125
|
+
- `connectToDaemon()` — creates a `net.Socket`, connects to `127.0.0.1:7481`
|
|
126
126
|
- `sendIpcRequest()` — sends JSON line, reads response, returns parsed `IpcResponse`
|
|
127
127
|
- 5-second timeout on connections
|
|
128
128
|
|
|
@@ -295,7 +295,7 @@ All shared types in one file, Zod-validated where applicable:
|
|
|
295
295
|
sequenceDiagram
|
|
296
296
|
participant Agent as AI Agent
|
|
297
297
|
participant MCP as MCP Server
|
|
298
|
-
participant Daemon as Daemon (:
|
|
298
|
+
participant Daemon as Daemon (:7481)
|
|
299
299
|
participant SB as Supabase
|
|
300
300
|
participant WH as Webhook URL
|
|
301
301
|
|
|
@@ -373,6 +373,6 @@ src/
|
|
|
373
373
|
|
|
374
374
|
- ✅ TypeScript build (`npm run build`) — zero errors
|
|
375
375
|
- ✅ All source files compiled to `dist/`
|
|
376
|
-
- ✅ IPC protocol uses JSON-over-TCP on `127.0.0.1:
|
|
376
|
+
- ✅ IPC protocol uses JSON-over-TCP on `127.0.0.1:7481`
|
|
377
377
|
- ✅ State persists to `~/.archer/state.json` with atomic writes
|
|
378
378
|
- ✅ 5 AI agents supported across 3 platforms (macOS/Linux/Windows)
|
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ archer_watch({
|
|
|
75
75
|
table: string, // table to watch (required)
|
|
76
76
|
event?: string, // INSERT | UPDATE | DELETE | * (default: *)
|
|
77
77
|
filter?: string, // e.g. "status=eq.active", "amount=gt.1000"
|
|
78
|
-
webhookUrl
|
|
78
|
+
webhookUrl?: string // URL to POST when the event fires (optional)
|
|
79
79
|
})
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/daemon/process.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/daemon/process.ts"],"names":[],"mappings":"AAgKA,wBAAgB,kBAAkB,IAAI,IAAI,CAmFzC"}
|
package/dist/daemon/process.js
CHANGED
|
@@ -4,18 +4,46 @@ import { DAEMON_PORT, DAEMON_HOST, PID_FILE, ARCHER_DIR, LOG_FILE } from './type
|
|
|
4
4
|
import { loadWatches, addWatch, removeWatch } from './store.js';
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
// ─── Simple webhook delivery for daemon context ─────────────
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const MAX_RETRIES = 3;
|
|
8
|
+
const RETRY_DELAY_MS = 2000;
|
|
9
|
+
async function sleep(ms) {
|
|
10
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
|
+
}
|
|
12
|
+
async function deliverWebhook(url, payload, watchId, table, eventType) {
|
|
13
|
+
const webhookPayload = {
|
|
14
|
+
archer: {
|
|
15
|
+
watchId,
|
|
16
|
+
event: eventType,
|
|
17
|
+
table,
|
|
18
|
+
firedAt: new Date().toISOString(),
|
|
13
19
|
},
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
data: payload,
|
|
21
|
+
};
|
|
22
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(url, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
'User-Agent': 'Archer/0.2.0',
|
|
29
|
+
'X-Archer-Event': eventType,
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(webhookPayload),
|
|
32
|
+
});
|
|
33
|
+
if (res.ok) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
log(`[webhook] attempt ${attempt} failed: ${res.status} ${res.statusText}`);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
log(`[webhook] attempt ${attempt} error: ${err instanceof Error ? err.message : String(err)}`);
|
|
40
|
+
}
|
|
41
|
+
if (attempt < MAX_RETRIES) {
|
|
42
|
+
log(`[webhook] retrying in ${RETRY_DELAY_MS / 1000}s...`);
|
|
43
|
+
await sleep(RETRY_DELAY_MS);
|
|
44
|
+
}
|
|
18
45
|
}
|
|
46
|
+
throw new Error(`webhook failed after ${MAX_RETRIES} attempts`);
|
|
19
47
|
}
|
|
20
48
|
// ─── Active Channel Registry ────────────────────────────────
|
|
21
49
|
const channels = new Map();
|
|
@@ -37,7 +65,7 @@ function subscribe(watch) {
|
|
|
37
65
|
log(`[event] ${watch.table} ${payload.eventType} → watch ${watch.id}`);
|
|
38
66
|
if (watch.webhookUrl) {
|
|
39
67
|
try {
|
|
40
|
-
await deliverWebhook(watch.webhookUrl, payload);
|
|
68
|
+
await deliverWebhook(watch.webhookUrl, payload.new ?? payload.old ?? payload, watch.id, watch.table, payload.eventType);
|
|
41
69
|
log(`[webhook] delivered to ${watch.webhookUrl}`);
|
|
42
70
|
}
|
|
43
71
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/daemon/process.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,YAAY,EAA6C,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,+DAA+D;AAE/D,KAAK,UAAU,cAAc,CAAC,GAAW,EAAE,OAAgB;
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/daemon/process.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/daemon/process.ts
CHANGED
|
@@ -7,18 +7,49 @@ import fs from 'node:fs';
|
|
|
7
7
|
|
|
8
8
|
// ─── Simple webhook delivery for daemon context ─────────────
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
const MAX_RETRIES = 3;
|
|
11
|
+
const RETRY_DELAY_MS = 2000;
|
|
12
|
+
|
|
13
|
+
async function sleep(ms: number): Promise<void> {
|
|
14
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function deliverWebhook(url: string, payload: unknown, watchId: string, table: string, eventType: string): Promise<void> {
|
|
18
|
+
const webhookPayload = {
|
|
19
|
+
archer: {
|
|
20
|
+
watchId,
|
|
21
|
+
event: eventType,
|
|
22
|
+
table,
|
|
23
|
+
firedAt: new Date().toISOString(),
|
|
16
24
|
},
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
data: payload,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch(url, {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: {
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
'User-Agent': 'Archer/0.2.0',
|
|
35
|
+
'X-Archer-Event': eventType,
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify(webhookPayload),
|
|
38
|
+
});
|
|
39
|
+
if (res.ok) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
log(`[webhook] attempt ${attempt} failed: ${res.status} ${res.statusText}`);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
log(`[webhook] attempt ${attempt} error: ${err instanceof Error ? err.message : String(err)}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (attempt < MAX_RETRIES) {
|
|
48
|
+
log(`[webhook] retrying in ${RETRY_DELAY_MS / 1000}s...`);
|
|
49
|
+
await sleep(RETRY_DELAY_MS);
|
|
50
|
+
}
|
|
21
51
|
}
|
|
52
|
+
throw new Error(`webhook failed after ${MAX_RETRIES} attempts`);
|
|
22
53
|
}
|
|
23
54
|
|
|
24
55
|
// ─── Active Channel Registry ────────────────────────────────
|
|
@@ -49,7 +80,13 @@ function subscribe(watch: WatchConfig): void {
|
|
|
49
80
|
|
|
50
81
|
if (watch.webhookUrl) {
|
|
51
82
|
try {
|
|
52
|
-
await deliverWebhook(
|
|
83
|
+
await deliverWebhook(
|
|
84
|
+
watch.webhookUrl,
|
|
85
|
+
payload.new ?? payload.old ?? payload,
|
|
86
|
+
watch.id,
|
|
87
|
+
watch.table,
|
|
88
|
+
payload.eventType
|
|
89
|
+
);
|
|
53
90
|
log(`[webhook] delivered to ${watch.webhookUrl}`);
|
|
54
91
|
} catch (err) {
|
|
55
92
|
log(`[webhook] failed: ${err instanceof Error ? err.message : String(err)}`);
|