birdclaw 0.6.0 → 0.7.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.
- package/CHANGELOG.md +48 -0
- package/README.md +25 -0
- package/package.json +6 -1
- package/src/cli.ts +438 -26
- package/src/components/AppNav.tsx +10 -0
- package/src/components/MarkdownViewer.tsx +438 -72
- package/src/components/ProfileAnalysisStream.tsx +428 -0
- package/src/components/ProfilePreview.tsx +120 -9
- package/src/components/SavedTimelineView.tsx +30 -8
- package/src/components/SyncNowButton.tsx +5 -2
- package/src/components/TimelineCard.tsx +20 -4
- package/src/components/TimelineRouteFrame.tsx +16 -0
- package/src/components/TweetRichText.tsx +36 -12
- package/src/components/useTimelineRouteData.ts +74 -6
- package/src/lib/account-sync-job.ts +15 -3
- package/src/lib/archive-finder.ts +1 -1
- package/src/lib/archive-import.ts +245 -7
- package/src/lib/authored-live.ts +1 -0
- package/src/lib/avatar-cache.ts +50 -0
- package/src/lib/backup.ts +4 -3
- package/src/lib/bird.ts +33 -0
- package/src/lib/config.ts +35 -2
- package/src/lib/data-sources.ts +219 -0
- package/src/lib/db.ts +62 -1
- package/src/lib/geocoding.ts +296 -0
- package/src/lib/location.ts +137 -0
- package/src/lib/mention-threads-live.ts +94 -1
- package/src/lib/mentions-live.ts +187 -40
- package/src/lib/network-map.ts +382 -0
- package/src/lib/period-digest.ts +377 -13
- package/src/lib/profile-analysis.ts +1272 -0
- package/src/lib/profile-bio-entities.ts +1 -1
- package/src/lib/queries.ts +14 -4
- package/src/lib/search-discussion.ts +1016 -0
- package/src/lib/timeline-live.ts +272 -19
- package/src/lib/tweet-account-edges.ts +2 -0
- package/src/lib/tweet-render.ts +141 -1
- package/src/lib/tweet-search-live.ts +565 -0
- package/src/lib/types.ts +37 -2
- package/src/lib/ui.ts +1 -1
- package/src/lib/web-sync.ts +7 -2
- package/src/lib/xurl-rate-limits.ts +267 -0
- package/src/lib/xurl.ts +551 -41
- package/src/routeTree.gen.ts +231 -0
- package/src/routes/__root.tsx +5 -6
- package/src/routes/api/data-sources.tsx +24 -0
- package/src/routes/api/network-map.tsx +55 -0
- package/src/routes/api/period-digest.tsx +11 -1
- package/src/routes/api/profile-analysis.tsx +152 -0
- package/src/routes/api/query.tsx +1 -0
- package/src/routes/api/search-discussion.tsx +169 -0
- package/src/routes/api/xurl-rate-limits.tsx +24 -0
- package/src/routes/data-sources.tsx +255 -0
- package/src/routes/discuss.tsx +419 -0
- package/src/routes/network-map.tsx +1035 -0
- package/src/routes/profile-analyze.tsx +112 -0
- package/src/routes/profiles.$handle.tsx +228 -0
- package/src/routes/rate-limits.tsx +309 -0
- package/src/routes/today.tsx +22 -8
- package/src/styles.css +22 -0
package/src/routes/today.tsx
CHANGED
|
@@ -51,6 +51,8 @@ function digestUrl(
|
|
|
51
51
|
const url = new URL("/api/period-digest", window.location.origin);
|
|
52
52
|
url.searchParams.set("period", period);
|
|
53
53
|
url.searchParams.set("includeDms", String(includeDms));
|
|
54
|
+
url.searchParams.set("maxTweets", "5000");
|
|
55
|
+
url.searchParams.set("maxLinks", "20");
|
|
54
56
|
if (refresh) {
|
|
55
57
|
url.searchParams.set("refresh", "true");
|
|
56
58
|
}
|
|
@@ -175,6 +177,7 @@ function useDigestStream(period: PeriodOption, includeDms: boolean) {
|
|
|
175
177
|
const [result, setResult] = useState<PeriodDigestRunResult | null>(null);
|
|
176
178
|
const [error, setError] = useState<string | null>(null);
|
|
177
179
|
const [loading, setLoading] = useState(false);
|
|
180
|
+
const [status, setStatus] = useState("Starting digest");
|
|
178
181
|
const abortRef = useRef<AbortController | null>(null);
|
|
179
182
|
const requestIdRef = useRef(0);
|
|
180
183
|
const hydratedHandlesRef = useRef(new Set<string>());
|
|
@@ -195,6 +198,7 @@ function useDigestStream(period: PeriodOption, includeDms: boolean) {
|
|
|
195
198
|
setContext(null);
|
|
196
199
|
setResult(null);
|
|
197
200
|
setError(null);
|
|
201
|
+
setStatus("Starting digest");
|
|
198
202
|
setLoading(true);
|
|
199
203
|
|
|
200
204
|
fetch(digestUrl(period, includeDms, refresh), {
|
|
@@ -222,16 +226,27 @@ function useDigestStream(period: PeriodOption, includeDms: boolean) {
|
|
|
222
226
|
if (line) {
|
|
223
227
|
const event = JSON.parse(line) as PeriodDigestStreamEvent;
|
|
224
228
|
if (!isActiveRequest()) return;
|
|
225
|
-
if (event.type === "
|
|
229
|
+
if (event.type === "status") {
|
|
230
|
+
setStatus(
|
|
231
|
+
event.detail
|
|
232
|
+
? `${event.label} · ${event.detail}`
|
|
233
|
+
: event.label,
|
|
234
|
+
);
|
|
235
|
+
} else if (event.type === "start") {
|
|
226
236
|
setContext(event.context);
|
|
227
237
|
} else if (event.type === "delta") {
|
|
238
|
+
setStatus("Streaming AI summary");
|
|
228
239
|
setMarkdown((current) => current + event.delta);
|
|
229
240
|
} else if (event.type === "done") {
|
|
230
241
|
setResult(event.result);
|
|
231
242
|
setContext(event.result.context);
|
|
232
243
|
setMarkdown(event.result.markdown);
|
|
244
|
+
setStatus(
|
|
245
|
+
event.result.cached ? "Loaded cached report" : "Ready",
|
|
246
|
+
);
|
|
233
247
|
} else if (event.type === "error") {
|
|
234
248
|
setError(event.error);
|
|
249
|
+
setStatus("Digest failed");
|
|
235
250
|
}
|
|
236
251
|
}
|
|
237
252
|
newline = buffer.indexOf("\n");
|
|
@@ -243,6 +258,7 @@ function useDigestStream(period: PeriodOption, includeDms: boolean) {
|
|
|
243
258
|
.catch((cause: unknown) => {
|
|
244
259
|
if (!isActiveRequest()) return;
|
|
245
260
|
setError(cause instanceof Error ? cause.message : "Digest failed");
|
|
261
|
+
setStatus("Digest failed");
|
|
246
262
|
})
|
|
247
263
|
.finally(() => {
|
|
248
264
|
if (isActiveRequest()) {
|
|
@@ -342,16 +358,14 @@ function useDigestStream(period: PeriodOption, includeDms: boolean) {
|
|
|
342
358
|
};
|
|
343
359
|
}, [result]);
|
|
344
360
|
|
|
345
|
-
return { context, error, loading, markdown, result, run };
|
|
361
|
+
return { context, error, loading, markdown, result, run, status };
|
|
346
362
|
}
|
|
347
363
|
|
|
348
364
|
function TodayRoute() {
|
|
349
365
|
const [period, setPeriod] = useState<PeriodOption>("today");
|
|
350
366
|
const [includeDms, setIncludeDms] = useState(false);
|
|
351
|
-
const { context, error, loading, markdown, result, run } =
|
|
352
|
-
period,
|
|
353
|
-
includeDms,
|
|
354
|
-
);
|
|
367
|
+
const { context, error, loading, markdown, result, run, status } =
|
|
368
|
+
useDigestStream(period, includeDms);
|
|
355
369
|
const sourceLabel = useMemo(
|
|
356
370
|
() => formatCounts(result?.context ?? context),
|
|
357
371
|
[context, result],
|
|
@@ -419,7 +433,7 @@ function TodayRoute() {
|
|
|
419
433
|
<Sparkles className="size-4" aria-hidden="true" />
|
|
420
434
|
)}
|
|
421
435
|
{loading
|
|
422
|
-
?
|
|
436
|
+
? status
|
|
423
437
|
: result
|
|
424
438
|
? `${result.cached ? "Cached" : "Ready"} · ${result.context.window.label}`
|
|
425
439
|
: "Ready"}
|
|
@@ -433,7 +447,7 @@ function TodayRoute() {
|
|
|
433
447
|
/>
|
|
434
448
|
) : (
|
|
435
449
|
<div className="px-4 py-5 text-[14px] text-[var(--ink-soft)]">
|
|
436
|
-
Waiting for the first tokens...
|
|
450
|
+
{loading ? status : "Waiting for the first tokens..."}
|
|
437
451
|
</div>
|
|
438
452
|
)}
|
|
439
453
|
</div>
|
package/src/styles.css
CHANGED
|
@@ -129,6 +129,28 @@ textarea {
|
|
|
129
129
|
background: color-mix(in srgb, var(--ink-soft) 55%, transparent);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
[data-theme="dark"] .mapboxgl-ctrl-group {
|
|
133
|
+
background: var(--bg-elevated);
|
|
134
|
+
border: 1px solid var(--line-strong);
|
|
135
|
+
box-shadow: 0 10px 28px var(--shadow);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
[data-theme="dark"] .mapboxgl-ctrl-group button {
|
|
139
|
+
background-color: var(--bg-elevated);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
[data-theme="dark"] .mapboxgl-ctrl-group button + button {
|
|
143
|
+
border-top-color: var(--line);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
[data-theme="dark"] .mapboxgl-ctrl-group button:not(:disabled):hover {
|
|
147
|
+
background-color: var(--bg-hover);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
[data-theme="dark"] .mapboxgl-ctrl-group .mapboxgl-ctrl-icon {
|
|
151
|
+
filter: invert(0.88);
|
|
152
|
+
}
|
|
153
|
+
|
|
132
154
|
@keyframes theme-circle-transition {
|
|
133
155
|
0% {
|
|
134
156
|
clip-path: circle(
|