wachi 0.1.1 → 0.1.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.
Files changed (2) hide show
  1. package/README.md +204 -17
  2. package/package.json +6 -6
package/README.md CHANGED
@@ -1,38 +1,225 @@
1
1
  # wachi
2
2
 
3
- Subscribe any link and get notified on change.
3
+ [![npm version](https://img.shields.io/npm/v/wachi)](https://www.npmjs.com/package/wachi)
4
+ [![CI](https://github.com/ysm-dev/wachi/actions/workflows/release.yml/badge.svg)](https://github.com/ysm-dev/wachi/actions)
5
+ [![license](https://img.shields.io/npm/l/wachi)](https://github.com/ysm-dev/wachi/blob/main/LICENSE)
4
6
 
5
- ## Quick start
7
+ **Subscribe any link and get notified on change.**
8
+
9
+ wachi monitors any URL for new content and pushes notifications to 90+ services via [apprise](https://github.com/caronc/apprise). It auto-discovers RSS feeds when available, and uses LLM-powered CSS selector identification for everything else.
10
+
11
+ - **Zero config for RSS** -- point at a blog, wachi finds the feed
12
+ - **LLM-powered for the rest** -- no RSS? wachi uses AI to identify content selectors via accessibility tree analysis
13
+ - **90+ notification services** -- Slack, Discord, Telegram, email, and [more](https://github.com/caronc/apprise/wiki)
14
+ - **Stateless by design** -- `wachi check` is a one-shot command, perfect for cron
15
+ - **No interactive prompts** -- built for automation and AI agents
16
+
17
+ ## Install
6
18
 
7
19
  ```bash
8
- bun install
9
- bun run src/index.ts --help
20
+ # npm / bun
21
+ npx wachi --help
22
+ bunx wachi --help
23
+
24
+ # or install globally
25
+ npm i -g wachi
26
+ bun i -g wachi
27
+
28
+ # shell script
29
+ curl -fsSL https://raw.githubusercontent.com/ysm-dev/wachi/main/install.sh | sh
30
+
31
+ # homebrew
32
+ brew tap ysm-dev/tap && brew install wachi
10
33
  ```
11
34
 
12
- ## Commands
35
+ ## Quick Start
13
36
 
14
37
  ```bash
15
- wachi sub <apprise-url> <url>
16
- wachi unsub <apprise-url> [url]
17
- wachi ls
38
+ # 1. Subscribe to any URL (auto-discovers RSS)
39
+ wachi sub "slack://xoxb-token/channel" "https://blog.example.com"
40
+
41
+ # 2. Check for new content (run this on a schedule)
18
42
  wachi check
19
- wachi test <apprise-url>
20
- wachi upgrade
43
+
44
+ # That's it. New posts get pushed to your Slack channel.
45
+ ```
46
+
47
+ ## How It Works
48
+
49
+ ```
50
+ wachi sub <apprise-url> <url>
51
+
52
+
53
+ Is it RSS? ───yes───▶ Store as RSS subscription
54
+ │no
55
+
56
+ Auto-discover RSS ───found───▶ Store URL + discovered feed
57
+ (link tags, common paths)
58
+ │not found
59
+
60
+ LLM identifies content via accessibility tree
61
+
62
+ Derive CSS selectors from DOM (deterministic)
63
+
64
+ Validate selectors against raw HTTP
65
+
66
+ Store URL + selectors + baseline
21
67
  ```
22
68
 
23
- ## Development checks
69
+ On `wachi check`, each subscription is fetched and compared against a dedup table. New items trigger notifications via apprise. Old items are skipped. That's it.
70
+
71
+ ## Commands
72
+
73
+ ```
74
+ wachi sub <apprise-url> <url> Subscribe a URL to a notification channel
75
+ -e, --send-existing Send all current items on next check (skip baseline)
76
+
77
+ wachi unsub <apprise-url> [url] Unsubscribe a URL or remove entire channel
78
+
79
+ wachi ls List all channels and subscriptions
80
+
81
+ wachi check Check all subscriptions for changes
82
+ -c, --channel <apprise-url> Check specific channel only
83
+ -n, --concurrency <number> Max concurrent checks (default: 10)
84
+ -d, --dry-run Preview without sending or recording
85
+
86
+ wachi test <apprise-url> Send a test notification
87
+
88
+ wachi upgrade Update wachi to latest version
89
+ ```
90
+
91
+ **Global flags:** `--json` / `-j` for machine-readable output, `--verbose` / `-V` for detailed logs, `--config` / `-C` for custom config path.
92
+
93
+ ## Examples
24
94
 
25
95
  ```bash
26
- bun run lint
27
- bun run typecheck
28
- bun test
29
- bun run knip
96
+ # Blog (auto-discovers RSS)
97
+ wachi sub "slack://xoxb-token/channel" "https://blog.example.com"
98
+
99
+ # Hacker News front page (LLM identifies content selectors)
100
+ wachi sub "discord://webhook-id/token" "https://news.ycombinator.com"
101
+
102
+ # YouTube channel
103
+ wachi sub "tgram://bot-token/chat-id" "https://youtube.com/@channel"
104
+
105
+ # URL without https:// (auto-prepended)
106
+ wachi sub "slack://token/channel" "blog.example.com"
107
+
108
+ # Send all existing items on next check (no baseline)
109
+ wachi sub -e "discord://webhook-id/token" "https://news.ycombinator.com"
110
+
111
+ # Dry-run: see what would be sent
112
+ wachi check -d
113
+
114
+ # Check specific channel only
115
+ wachi check -c "slack://xoxb-token/channel"
116
+
117
+ # Run every 5 minutes with crnd
118
+ crnd "*/5 * * * *" wachi check
119
+
120
+ # System cron
121
+ crontab -e
122
+ # */5 * * * * wachi check
123
+ ```
124
+
125
+ ## Notifications
126
+
127
+ wachi uses [apprise](https://github.com/caronc/apprise) for delivery -- Slack, Discord, Telegram, Email, Pushover, Gotify, ntfy, and [90+ more](https://github.com/caronc/apprise/wiki).
128
+
129
+ Each new item is sent as a separate message:
130
+
131
+ ```
132
+ https://blog.example.com/post/new-feature
133
+
134
+ New Feature: Faster Builds with Incremental Compilation
135
+ ```
136
+
137
+ Test your channel before subscribing:
138
+
139
+ ```bash
140
+ wachi test "slack://xoxb-token/channel"
141
+ ```
142
+
143
+ ## Configuration
144
+
145
+ Config lives at `~/.config/wachi/config.yml` (XDG-compliant). Auto-created on first `wachi sub`.
146
+
147
+ ```yaml
148
+ # LLM config (only needed for non-RSS sites)
149
+ # Also settable via WACHI_LLM_API_KEY, WACHI_LLM_MODEL env vars
150
+ llm:
151
+ api_key: "sk-..."
152
+ model: "gpt-4.1-mini"
153
+
154
+ # Optional: summarize articles before sending
155
+ summary:
156
+ enabled: true
157
+ language: "en"
158
+ min_reading_time: 3 # minutes
159
+
160
+ # Channels and subscriptions (managed by wachi sub/unsub)
161
+ channels:
162
+ - apprise_url: "slack://xoxb-token/channel"
163
+ subscriptions:
164
+ - url: "https://blog.example.com"
165
+ rss_url: "https://blog.example.com/feed.xml"
166
+ - url: "https://news.ycombinator.com"
167
+ item_selector: "tr.athing"
168
+ title_selector: ".titleline > a"
169
+ link_selector: ".titleline > a"
30
170
  ```
31
171
 
32
- ## Database schema changes
172
+ All fields are optional with sensible defaults. An empty config file is valid.
173
+
174
+ | Variable | Purpose |
175
+ |----------|---------|
176
+ | `WACHI_LLM_API_KEY` | LLM API key |
177
+ | `WACHI_LLM_MODEL` | LLM model name |
178
+ | `WACHI_LLM_BASE_URL` | LLM API base URL (default: OpenAI) |
179
+ | `WACHI_NO_AUTO_UPDATE` | Set to `1` to disable auto-update |
180
+
181
+ ## Design
182
+
183
+ - **Stateless checks** -- `wachi check` is a one-shot command. Bring your own scheduler (cron, crnd, systemd, launchd)
184
+ - **Dedup, not state** -- items tracked by `sha256(link + title + channel)`. If the hash exists, it was already sent
185
+ - **No interactive prompts** -- ever. Errors tell you exactly what to set and where (What / Why / Fix pattern)
186
+ - **Baseline seeding** -- on subscribe, all current items are pre-seeded so your channel isn't flooded
187
+ - **Auto-healing** -- CSS selectors go stale? After 3 consecutive failures, wachi re-identifies them automatically
188
+ - **SQLite WAL mode** -- safe concurrent reads. Two cron jobs won't conflict
189
+ - **Atomic config writes** -- write to temp, then rename. No corruption from concurrent access
190
+ - **JSON envelope** -- `--json` on all commands returns `{"ok": true, "data": {...}}` or `{"ok": false, "error": {"what", "why", "fix"}}`
191
+
192
+ ## Development
33
193
 
34
194
  ```bash
195
+ bun install
196
+ bun run src/index.ts --help
197
+
198
+ # Quality checks
199
+ bun run lint # Biome v2
200
+ bun run typecheck # tsgo
201
+ bun test # Bun test runner
202
+ bun run knip # Dead code detection
203
+
204
+ # Database migrations
35
205
  bun run db:generate
36
206
  ```
37
207
 
38
- This generates Drizzle SQL migrations and updates `src/lib/db/generated-migrations.ts`.
208
+ ### Tech Stack
209
+
210
+ | Component | Choice |
211
+ |-----------|--------|
212
+ | Runtime | Bun (`bun:sqlite`, `bun build --compile`) |
213
+ | Type checker | tsgo (`@typescript/native-preview`) |
214
+ | CLI | [citty](https://github.com/unjs/citty) |
215
+ | Database | [drizzle-orm](https://github.com/drizzle-team/drizzle-orm) + bun:sqlite |
216
+ | HTTP | [ofetch](https://github.com/unjs/ofetch) |
217
+ | LLM | [Vercel AI SDK](https://github.com/vercel/ai) v6 |
218
+ | RSS | [rss-parser](https://github.com/rbren/rss-parser) |
219
+ | HTML | [cheerio](https://github.com/cheeriojs/cheerio) |
220
+ | Notifications | [apprise](https://github.com/caronc/apprise) via uvx |
221
+ | Linter | [Biome](https://biomejs.dev/) v2 |
222
+
223
+ ## License
224
+
225
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wachi",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Subscribe any link and get notified on change",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -53,10 +53,10 @@
53
53
  "zod-validation-error": "5.0.0"
54
54
  },
55
55
  "optionalDependencies": {
56
- "@wachi-cli/darwin-arm64": "0.1.1",
57
- "@wachi-cli/darwin-x64": "0.1.1",
58
- "@wachi-cli/linux-arm64": "0.1.1",
59
- "@wachi-cli/linux-x64": "0.1.1",
60
- "@wachi-cli/win32-x64": "0.1.1"
56
+ "@wachi-cli/darwin-arm64": "0.1.2",
57
+ "@wachi-cli/darwin-x64": "0.1.2",
58
+ "@wachi-cli/linux-arm64": "0.1.2",
59
+ "@wachi-cli/linux-x64": "0.1.2",
60
+ "@wachi-cli/win32-x64": "0.1.2"
61
61
  }
62
62
  }