birdclaw 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 (74) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/README.md +389 -0
  4. package/bin/birdclaw.mjs +28 -0
  5. package/package.json +100 -0
  6. package/playwright.config.ts +31 -0
  7. package/public/favicon.ico +0 -0
  8. package/public/logo192.png +0 -0
  9. package/public/logo512.png +0 -0
  10. package/public/manifest.json +25 -0
  11. package/public/robots.txt +3 -0
  12. package/src/cli-moderation.ts +210 -0
  13. package/src/cli.ts +450 -0
  14. package/src/components/AppNav.tsx +49 -0
  15. package/src/components/AvatarChip.tsx +47 -0
  16. package/src/components/DmWorkspace.tsx +246 -0
  17. package/src/components/EmbeddedTweetCard.tsx +44 -0
  18. package/src/components/InboxCard.tsx +136 -0
  19. package/src/components/ProfilePreview.tsx +55 -0
  20. package/src/components/ThemeSlider.tsx +124 -0
  21. package/src/components/TimelineCard.tsx +118 -0
  22. package/src/components/TweetMediaGrid.tsx +39 -0
  23. package/src/components/TweetRichText.tsx +85 -0
  24. package/src/lib/actions-transport.ts +173 -0
  25. package/src/lib/archive-finder.ts +128 -0
  26. package/src/lib/archive-import.ts +736 -0
  27. package/src/lib/avatar-cache.ts +184 -0
  28. package/src/lib/bird-actions.ts +200 -0
  29. package/src/lib/bird.ts +183 -0
  30. package/src/lib/blocklist.ts +119 -0
  31. package/src/lib/blocks-write.ts +118 -0
  32. package/src/lib/blocks.ts +326 -0
  33. package/src/lib/config.ts +152 -0
  34. package/src/lib/db.ts +326 -0
  35. package/src/lib/dms-live.ts +279 -0
  36. package/src/lib/inbox.ts +210 -0
  37. package/src/lib/mentions-export.ts +147 -0
  38. package/src/lib/mentions-live.ts +475 -0
  39. package/src/lib/moderation-target.ts +171 -0
  40. package/src/lib/moderation-write.ts +72 -0
  41. package/src/lib/mutes-write.ts +118 -0
  42. package/src/lib/mutes.ts +77 -0
  43. package/src/lib/openai.ts +86 -0
  44. package/src/lib/present.ts +20 -0
  45. package/src/lib/profile-hydration.ts +144 -0
  46. package/src/lib/profile-replies.ts +60 -0
  47. package/src/lib/queries.ts +725 -0
  48. package/src/lib/seed.ts +486 -0
  49. package/src/lib/sync-cache.ts +65 -0
  50. package/src/lib/theme-transition.ts +117 -0
  51. package/src/lib/theme.tsx +157 -0
  52. package/src/lib/tweet-render.ts +115 -0
  53. package/src/lib/types.ts +316 -0
  54. package/src/lib/ui.ts +270 -0
  55. package/src/lib/x-profile.ts +203 -0
  56. package/src/lib/x-web.ts +168 -0
  57. package/src/lib/xurl.ts +492 -0
  58. package/src/routeTree.gen.ts +282 -0
  59. package/src/router.tsx +20 -0
  60. package/src/routes/__root.tsx +64 -0
  61. package/src/routes/api/action.tsx +88 -0
  62. package/src/routes/api/avatar.tsx +41 -0
  63. package/src/routes/api/blocks.tsx +32 -0
  64. package/src/routes/api/inbox.tsx +35 -0
  65. package/src/routes/api/query.tsx +72 -0
  66. package/src/routes/api/status.tsx +15 -0
  67. package/src/routes/blocks.tsx +352 -0
  68. package/src/routes/dms.tsx +262 -0
  69. package/src/routes/inbox.tsx +201 -0
  70. package/src/routes/index.tsx +125 -0
  71. package/src/routes/mentions.tsx +125 -0
  72. package/src/styles.css +109 -0
  73. package/tsconfig.json +30 -0
  74. package/vite.config.ts +23 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # CHANGELOG
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 0.1.0 - 2026-04-27
6
+
7
+ ### Added
8
+
9
+ - Add X web cookie fallback for block and unblock actions when the X API rejects OAuth2 block writes.
10
+ - Add `profiles replies` so moderation triage can inspect a user's recent reply pattern before blocking.
11
+ - Add `blocks import <path>` for one-shot blocklist application from a file.
12
+ - Add paged `mentions export --mode xurl --all --max-pages <n>` so moderation loops can scan the full retrievable mentions window.
13
+ - Add `actions.transport` config plus shared action transport routing for `bird`, `xurl`, and `auto`.
14
+ - Add transport-aware mute/unmute support to the API action route.
15
+ - Add the first packaged `birdclaw` CLI release.
16
+
17
+ ### Fixed
18
+
19
+ - Capture `xurl` mutation error bodies so transport fallbacks can key off the real API failure.
20
+ - Make `birdclaw` block and unblock flows succeed remotely again on Peter's current auth setup.
21
+ - Verify forced `xurl` mute/block writes through `bird status` before mutating local sqlite.
22
+ - Cache authenticated `xurl whoami` lookups so repeated moderation writes do less redundant auth work.
23
+ - Strip inherited `--localstorage-file` from the Playwright web-server env to avoid noisy cross-repo test warnings.
24
+ - Override Node 25 native web storage in jsdom test setup so Vitest runs stop emitting `--localstorage-file` warnings.
25
+
26
+ ### Docs
27
+
28
+ - Document block transport behavior and fallback path in the CLI/docs.
29
+ - Document the reply-pattern inspection flow for borderline AI/slop accounts.
30
+ - Document blocklist import file format and usage.
31
+ - Document paged xurl mention export for agent moderation runs.
32
+ - Document that mention reads and moderation writes use separate config knobs.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Peter Steinberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,389 @@
1
+ # birdclaw
2
+
3
+ `birdclaw` is a local-first X workspace: archive import, cached live reads, focused triage, and reply flows in one local web app + CLI.
4
+
5
+ Status: WIP. Real and usable. Not done. Expect schema churn, transport gaps, and rough edges while the core settles.
6
+
7
+ ## What It Does
8
+
9
+ - keeps your X data in local SQLite
10
+ - stores media and avatar cache under `~/.birdclaw`
11
+ - imports archives when you have them
12
+ - still works when you do not
13
+ - gives you a clean local UI for home, mentions, DMs, inbox, and blocks
14
+ - exposes scriptable JSON for agents and automation
15
+
16
+ ## What Works Today
17
+
18
+ ### Local data + storage
19
+
20
+ - one shared SQLite DB for multiple accounts
21
+ - FTS5 search over tweets and DMs
22
+ - archive autodiscovery on macOS
23
+ - archive import for tweets, likes, profiles, and full DMs
24
+ - profile hydration from live X metadata
25
+ - local avatar cache
26
+ - local media cache root under `~/.birdclaw`
27
+
28
+ ### Web UI
29
+
30
+ - `Home` timeline
31
+ - `Mentions` queue
32
+ - `DMs` workspace with two-column layout
33
+ - `Inbox` for mixed mention + DM triage
34
+ - `Blocks` for local blocklist maintenance
35
+ - constrained timeline lane instead of full-width dashboard UI
36
+ - tweet expansion with URLs, inline images, quoted tweets, replies, and profile hover cards
37
+ - sender bio and influence context in the DM detail header
38
+ - system / light / dark theme switcher with animated transition
39
+
40
+ ### Triage + filtering
41
+
42
+ - replied / unreplied filters for timelines
43
+ - DM filters by participant, followers, and derived influence score
44
+ - AI-ranked inbox for mentions + DMs
45
+ - OpenAI scoring hook for low-signal filtering
46
+ - cached live mentions export in `xurl`-compatible JSON
47
+ - live profile-reply inspection for borderline AI/slop triage
48
+ - one-shot blocklist import from a file for batch moderation passes
49
+
50
+ ### Actions
51
+
52
+ - post tweets
53
+ - reply to tweets
54
+ - reply to DMs
55
+ - add / remove local blocks
56
+ - import batch blocklists in one call
57
+ - add / remove local mutes
58
+ - sync remote blocks through `xurl` when available
59
+ - fall back to the X web cookie session when OAuth2 block writes are rejected
60
+
61
+ ### Safety
62
+
63
+ - local-first by default
64
+ - tests disable live writes
65
+ - CI disables live writes
66
+ - app has no auth layer because it is a local-only tool
67
+
68
+ ## Still In Progress
69
+
70
+ - broader resumable live sync beyond the targeted paths already wired
71
+ - fuller media fetch pipeline
72
+ - richer multi-account UX
73
+ - more complete transport coverage
74
+ - more archive edge-case handling
75
+
76
+ If you need polished product-grade sync parity today, this is not there yet.
77
+
78
+ ## Screens
79
+
80
+ - `Home`: read and reply without fighting the main X timeline
81
+ - `Mentions`: work the reply queue with clean filters
82
+ - `DMs`: triage by sender context, follower count, and influence
83
+ - `Inbox`: let heuristics / OpenAI float likely-important items
84
+ - `Blocks`: maintain a local-first account-scoped blocklist
85
+
86
+ ## Storage
87
+
88
+ Default root:
89
+
90
+ ```text
91
+ ~/.birdclaw
92
+ ```
93
+
94
+ Important paths:
95
+
96
+ - DB: `~/.birdclaw/birdclaw.sqlite`
97
+ - media cache: `~/.birdclaw/media`
98
+ - avatar cache: `~/.birdclaw/media/thumbs/avatars`
99
+ - Playwright test home: `.playwright-home`
100
+
101
+ Override the root:
102
+
103
+ ```bash
104
+ export BIRDCLAW_HOME=/path/to/custom/root
105
+ ```
106
+
107
+ ## Requirements
108
+
109
+ - Node `25.8.1`
110
+ - `pnpm`
111
+ - macOS recommended for Spotlight archive discovery
112
+ - `xurl` optional for live reads / writes
113
+ - OpenAI API key optional for inbox scoring
114
+
115
+ ## Install
116
+
117
+ Homebrew:
118
+
119
+ ```bash
120
+ brew install steipete/tap/birdclaw
121
+ ```
122
+
123
+ From source:
124
+
125
+ ```bash
126
+ fnm use
127
+ pnpm install
128
+ ```
129
+
130
+ ## Run
131
+
132
+ ```bash
133
+ pnpm dev
134
+ ```
135
+
136
+ Open:
137
+
138
+ ```text
139
+ http://localhost:3000
140
+ ```
141
+
142
+ ## Quick Start
143
+
144
+ Initialize local state:
145
+
146
+ ```bash
147
+ birdclaw init
148
+ birdclaw auth status --json
149
+ birdclaw db stats --json
150
+ ```
151
+
152
+ Find and import an archive:
153
+
154
+ ```bash
155
+ birdclaw archive find --json
156
+ birdclaw import archive --json
157
+ birdclaw import archive ~/Downloads/twitter-archive-2025.zip --json
158
+ birdclaw import hydrate-profiles --json
159
+ ```
160
+
161
+ Start the app:
162
+
163
+ ```bash
164
+ birdclaw serve
165
+ ```
166
+
167
+ First moderation pass:
168
+
169
+ ```bash
170
+ pnpm cli mentions export --mode xurl --refresh --all --max-pages 9 --limit 100
171
+ pnpm cli profiles replies @borderline_handle --limit 12 --json
172
+ pnpm cli blocks import ~/triage/blocklist.txt --account acct_primary --json
173
+ ```
174
+
175
+ ## CLI Highlights
176
+
177
+ ### Search local tweets
178
+
179
+ ```bash
180
+ pnpm cli search tweets "local-first" --json
181
+ pnpm cli search tweets "sync engine" --limit 20 --json
182
+ ```
183
+
184
+ ### Export mentions for agents
185
+
186
+ Default `birdclaw` mode returns normalized items with `text`, `plainText`, `markdown`, author metadata, and canonical URLs:
187
+
188
+ ```bash
189
+ pnpm cli mentions export "agent" --unreplied --limit 10
190
+ ```
191
+
192
+ Cached live modes return `xurl`-compatible `data/includes/meta`, but stay in the local SQLite cache so repeat reads do not keep spending live calls:
193
+
194
+ ```bash
195
+ pnpm cli mentions export --mode bird --limit 20
196
+ pnpm cli mentions export --mode bird --refresh --limit 20
197
+ pnpm cli mentions export --mode xurl --limit 5
198
+ pnpm cli mentions export --mode xurl --refresh --limit 5
199
+ pnpm cli mentions export --mode xurl --refresh --all --max-pages 9 --limit 100
200
+ pnpm cli mentions export "courtesy" --mode xurl --limit 5
201
+ ```
202
+
203
+ Home config lives in `~/.birdclaw/config.json`. Example:
204
+
205
+ ```json
206
+ {
207
+ "actions": {
208
+ "transport": "auto"
209
+ },
210
+ "mentions": {
211
+ "dataSource": "bird",
212
+ "birdCommand": "/Users/steipete/Projects/bird/bird"
213
+ }
214
+ }
215
+ ```
216
+
217
+ Notes:
218
+
219
+ - `--refresh` forces a live fetch
220
+ - `--cache-ttl <seconds>` tunes freshness
221
+ - `--all` walks every retrievable mentions page; `--max-pages` caps that scan
222
+ - in paged `xurl` mode, `--limit` is the per-page size
223
+ - `mentions.dataSource` controls live mention reads only
224
+ - `actions.transport` controls live block/mute writes only
225
+ - `actions.transport` accepts `auto`, `bird`, or `xurl`
226
+ - `bird` mode uses your local `bird` CLI and caches its mentions output into birdclaw's canonical store
227
+ - filters still work in `xurl` mode; filtered payloads are rebuilt from the local canonical store after sync
228
+
229
+ ### Search and triage DMs
230
+
231
+ ```bash
232
+ pnpm cli search dms "prototype" --json
233
+ pnpm cli search dms "layout" --min-followers 1000 --min-influence-score 120 --sort influence --json
234
+ pnpm cli dms sync --limit 50 --refresh --json
235
+ pnpm cli dms list --refresh --limit 10 --json
236
+ pnpm cli dms list --unreplied --min-followers 500 --min-influence-score 90 --sort influence --json
237
+ ```
238
+
239
+ ### AI inbox
240
+
241
+ ```bash
242
+ pnpm cli inbox --json
243
+ pnpm cli inbox --kind dms --limit 10 --json
244
+ pnpm cli inbox --score --hide-low-signal --limit 8 --json
245
+ ```
246
+
247
+ ### Blocklist
248
+
249
+ ```bash
250
+ pnpm cli blocks list --account acct_primary --json
251
+ pnpm cli blocks sync --account acct_primary --json
252
+ pnpm cli blocks import ~/triage/blocklist.txt --account acct_primary --json
253
+ pnpm cli blocks add @amelia --account acct_primary --json
254
+ pnpm cli blocks record @amelia --account acct_primary --json
255
+ pnpm cli blocks remove @amelia --account acct_primary --json
256
+ pnpm cli ban @amelia --account acct_primary --transport auto --json
257
+ pnpm cli unban @amelia --account acct_primary --transport bird --json
258
+ ```
259
+
260
+ Notes:
261
+
262
+ - `ban` / `unban` accept `--transport auto|bird|xurl`
263
+ - `auto` tries `bird` first, then falls back to `xurl` when bird fails
264
+ - forced `xurl` writes still verify through `bird status` before sqlite changes
265
+ - X still rejects pure OAuth2 block writes, so `auto` is the safe default for block/unblock
266
+ - `blocks import` accepts newline-delimited blocklists with comments and markdown bullets
267
+ - `blocks sync` is for slow/manual remote reconciliation; not for a hot cron loop
268
+ - `blocks record` stores a known-good remote block locally without issuing another live write
269
+
270
+ Example blocklist file:
271
+
272
+ ```text
273
+ # crypto / AI slop
274
+ @jpctan
275
+ @SystemDaddyAi
276
+ - @Pepe202579 memecoin bait
277
+ https://x.com/someone/status/2030857479001960633?s=20
278
+ ```
279
+
280
+ ### Profile reply scan
281
+
282
+ ```bash
283
+ pnpm cli profiles replies @jpctan --limit 12 --json
284
+ ```
285
+
286
+ Notes:
287
+
288
+ - for the "unsure if AI" case
289
+ - scans recent authored tweets, excludes retweets, keeps replies
290
+ - useful for spotting repeated generic praise, abstraction soup, or cross-thread templated cadence
291
+
292
+ Typical tell:
293
+
294
+ - same upbeat, generic reply shape across unrelated threads in a short time window
295
+
296
+ ### Mutes
297
+
298
+ ```bash
299
+ pnpm cli mutes list --account acct_primary --json
300
+ pnpm cli mute @amelia --account acct_primary --transport xurl --json
301
+ pnpm cli mutes record @amelia --account acct_primary --json
302
+ pnpm cli unmute @amelia --account acct_primary --transport auto --json
303
+ ```
304
+
305
+ Notes:
306
+
307
+ - `mute` / `unmute` accept `--transport auto|bird|xurl`
308
+ - target profile resolution prefers `bird user --json` before any `xurl /2/users` lookup
309
+ - `auto` tries `bird` first, then falls back to `xurl` when bird fails
310
+ - forced `xurl` writes still verify through `bird status` before sqlite changes
311
+ - `mutes record` stores a known-good remote mute locally without issuing another live write
312
+
313
+ ### Test env hardening
314
+
315
+ - Playwright strips inherited `--localstorage-file` from `NODE_OPTIONS` before starting Vite
316
+ - this avoids cross-repo test warnings when another repo injected that flag
317
+
318
+ ### Compose / reply
319
+
320
+ ```bash
321
+ pnpm cli compose post "Ship local software."
322
+ pnpm cli compose reply tweet_004 "On it."
323
+ pnpm cli compose dm dm_003 "Send it over."
324
+ ```
325
+
326
+ ## Typical Workflow
327
+
328
+ 1. import your archive if you have one
329
+ 2. hydrate imported profiles from live X metadata
330
+ 3. use `Home` for reading
331
+ 4. use `Mentions` for reply triage
332
+ 5. when one account feels borderline, inspect `profiles replies`
333
+ 6. collect keepers into a blocklist file and run `blocks import`
334
+ 7. use `DMs` for high-context conversation work
335
+ 8. use `Inbox` when you want AI help cutting noise
336
+ 9. use CLI exports when agents need stable JSON
337
+
338
+ ## Live Transport
339
+
340
+ Current preference:
341
+
342
+ - `xurl` first
343
+
344
+ Without `xurl`, `birdclaw` still works in local/archive mode.
345
+
346
+ Check transport:
347
+
348
+ ```bash
349
+ pnpm cli auth status --json
350
+ ```
351
+
352
+ ## Architecture
353
+
354
+ - SQLite is the canonical local truth
355
+ - archive import and live transport should converge on the same model
356
+ - CLI and web UI share the same normalized core
357
+ - AI ranking is layered on top of local data, not the source of truth
358
+
359
+ ## Testing
360
+
361
+ ```bash
362
+ fnm exec --using 25.8.1 pnpm check
363
+ fnm exec --using 25.8.1 pnpm test
364
+ fnm exec --using 25.8.1 pnpm coverage
365
+ fnm exec --using 25.8.1 pnpm build
366
+ fnm exec --using 25.8.1 pnpm e2e
367
+ ```
368
+
369
+ Current bar:
370
+
371
+ - branch coverage above `80%`
372
+ - Playwright coverage for core UI flows
373
+
374
+ ## CI
375
+
376
+ GitHub Actions runs:
377
+
378
+ - `pnpm check`
379
+ - `pnpm coverage`
380
+ - `pnpm build`
381
+ - `pnpm e2e`
382
+
383
+ Workflow: [ci.yml](/Users/steipete/Projects/birdclaw/.github/workflows/ci.yml)
384
+
385
+ ## Docs
386
+
387
+ - [spec.md](/Users/steipete/Projects/birdclaw/docs/spec.md)
388
+ - [cli.md](/Users/steipete/Projects/birdclaw/docs/cli.md)
389
+ - [data-architecture.md](/Users/steipete/Projects/birdclaw/docs/data-architecture.md)
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
7
+ const tsxCli = join(packageRoot, "node_modules", "tsx", "dist", "cli.mjs");
8
+ const birdclawCli = join(packageRoot, "src", "cli.ts");
9
+
10
+ const result = spawnSync(
11
+ process.execPath,
12
+ [tsxCli, birdclawCli, ...process.argv.slice(2)],
13
+ {
14
+ stdio: "inherit",
15
+ env: process.env,
16
+ },
17
+ );
18
+
19
+ if (result.error) {
20
+ console.error(result.error.message);
21
+ process.exit(1);
22
+ }
23
+
24
+ if (result.signal) {
25
+ process.kill(process.pid, result.signal);
26
+ }
27
+
28
+ process.exit(result.status ?? 0);
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "birdclaw",
3
+ "version": "0.1.0",
4
+ "description": "Local-first X workspace for archives, DMs, mentions, and moderation",
5
+ "homepage": "https://github.com/steipete/birdclaw#readme",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/steipete/birdclaw.git"
10
+ },
11
+ "bin": {
12
+ "birdclaw": "bin/birdclaw.mjs"
13
+ },
14
+ "files": [
15
+ "bin/",
16
+ "src/",
17
+ "!src/**/*.test.ts",
18
+ "!src/**/*.test.tsx",
19
+ "!src/test/",
20
+ "public/",
21
+ "CHANGELOG.md",
22
+ "LICENSE",
23
+ "README.md",
24
+ "package.json",
25
+ "playwright.config.ts",
26
+ "pnpm-lock.yaml",
27
+ "tsconfig.json",
28
+ "vite.config.ts"
29
+ ],
30
+ "type": "module",
31
+ "imports": {
32
+ "#/*": "./src/*"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "dev": "vite dev --port 3000",
39
+ "build": "vite build",
40
+ "preview": "vite preview",
41
+ "test": "env -u NODE_OPTIONS node ./scripts/run-vitest.mjs run",
42
+ "coverage": "env -u NODE_OPTIONS node ./scripts/run-vitest.mjs run --coverage",
43
+ "e2e": "playwright test",
44
+ "format": "oxfmt --write src scripts playwright vite.config.ts vitest.config.ts playwright.config.ts",
45
+ "format:check": "oxfmt --check src scripts playwright vite.config.ts vitest.config.ts playwright.config.ts",
46
+ "lint": "oxlint --import-plugin --node-plugin --vitest-plugin --deny-warnings -A require-mock-type-parameters -A no-control-regex src scripts playwright vite.config.ts vitest.config.ts playwright.config.ts",
47
+ "check": "pnpm run format:check && pnpm run lint",
48
+ "cli": "tsx src/cli.ts"
49
+ },
50
+ "dependencies": {
51
+ "@steipete/sweet-cookie": "^0.2.0",
52
+ "@tailwindcss/vite": "^4.2.4",
53
+ "@tanstack/devtools-vite": "0.6.0",
54
+ "@tanstack/react-devtools": "0.10.2",
55
+ "@tanstack/react-router": "1.168.24",
56
+ "@tanstack/react-router-devtools": "1.166.13",
57
+ "@tanstack/react-router-ssr-query": "1.166.12",
58
+ "@tanstack/react-start": "1.167.49",
59
+ "@tanstack/router-plugin": "^1.167.27",
60
+ "@vitejs/plugin-react": "^6.0.1",
61
+ "better-sqlite3": "^12.9.0",
62
+ "commander": "^14.0.3",
63
+ "kysely": "^0.28.16",
64
+ "lucide-react": "^1.11.0",
65
+ "react": "^19.2.5",
66
+ "react-dom": "^19.2.5",
67
+ "tailwindcss": "^4.2.4",
68
+ "tsx": "^4.21.0",
69
+ "vite": "^8.0.10",
70
+ "zod": "^4.3.6"
71
+ },
72
+ "devDependencies": {
73
+ "@playwright/test": "^1.59.1",
74
+ "@tailwindcss/typography": "^0.5.19",
75
+ "@testing-library/dom": "^10.4.1",
76
+ "@testing-library/jest-dom": "^6.9.1",
77
+ "@testing-library/react": "^16.3.2",
78
+ "@types/better-sqlite3": "^7.6.13",
79
+ "@types/node": "^25.6.0",
80
+ "@types/react": "^19.2.14",
81
+ "@types/react-dom": "^19.2.3",
82
+ "@vitest/coverage-v8": "^4.1.5",
83
+ "jsdom": "^29.0.2",
84
+ "oxfmt": "^0.46.0",
85
+ "oxlint": "^1.61.0",
86
+ "typescript": "^6.0.3",
87
+ "vitest": "^4.1.5"
88
+ },
89
+ "engines": {
90
+ "node": ">=25.8.1 <26"
91
+ },
92
+ "packageManager": "pnpm@10.31.0",
93
+ "pnpm": {
94
+ "onlyBuiltDependencies": [
95
+ "better-sqlite3",
96
+ "esbuild",
97
+ "lightningcss"
98
+ ]
99
+ }
100
+ }
@@ -0,0 +1,31 @@
1
+ import path from "node:path";
2
+ import { defineConfig, devices } from "@playwright/test";
3
+
4
+ const testHome = path.join(process.cwd(), ".playwright-home");
5
+
6
+ export default defineConfig({
7
+ testDir: "./playwright",
8
+ fullyParallel: false,
9
+ retries: 0,
10
+ workers: 1,
11
+ use: {
12
+ baseURL: "http://127.0.0.1:3000",
13
+ trace: "on-first-retry",
14
+ },
15
+ projects: [
16
+ {
17
+ name: "chromium",
18
+ use: { ...devices["Desktop Chrome"] },
19
+ },
20
+ ],
21
+ webServer: {
22
+ command: "node ./scripts/start-test-server.mjs",
23
+ url: "http://127.0.0.1:3000",
24
+ reuseExistingServer: false,
25
+ timeout: 120000,
26
+ env: {
27
+ BIRDCLAW_HOME: testHome,
28
+ BIRDCLAW_DISABLE_LIVE_WRITES: "1",
29
+ },
30
+ },
31
+ });
Binary file
Binary file
Binary file
@@ -0,0 +1,25 @@
1
+ {
2
+ "short_name": "TanStack App",
3
+ "name": "Create TanStack App Sample",
4
+ "icons": [
5
+ {
6
+ "src": "favicon.ico",
7
+ "sizes": "64x64 32x32 24x24 16x16",
8
+ "type": "image/x-icon"
9
+ },
10
+ {
11
+ "src": "logo192.png",
12
+ "type": "image/png",
13
+ "sizes": "192x192"
14
+ },
15
+ {
16
+ "src": "logo512.png",
17
+ "type": "image/png",
18
+ "sizes": "512x512"
19
+ }
20
+ ],
21
+ "start_url": ".",
22
+ "display": "standalone",
23
+ "theme_color": "#000000",
24
+ "background_color": "#ffffff"
25
+ }
@@ -0,0 +1,3 @@
1
+ # https://www.robotstxt.org/robotstxt.html
2
+ User-agent: *
3
+ Disallow: